diff --git a/README.md b/README.md index b455022a29e32fa2476aa5ef40425d7b8845b2a3..97489da489920b579a693ca4c8305ce75fb33e23 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,29 @@ From the root of the project: and navigate to `build/viewer` +### Code generation +**CIF schemas** + node build/node_modules/apps/schema-generator/schema-from-cif-dic.js -ts -o src/mol-io/reader/cif/schema/mmcif.ts --fieldNamesPath data/mmcif-field-names.csv --name mmCIF + node build/node_modules/apps/schema-generator/schema-from-cif-dic.js -ts -o src/mol-io/reader/cif/schema/ccd.ts --fieldNamesPath data/ccd-field-names.csv --name CCD + + node build/node_modules/apps/schema-generator/schema-from-cif-dic.js -ts -o src/mol-io/reader/cif/schema/bird.ts --fieldNamesPath data/bird-field-names.csv --name BIRD + + node --max-old-space-size=8192 build/node_modules/apps/chem-comp-bond/create-table.js build/data/ccb.bcif -b + +**GraphQL schemas** + + node data/rcsb-graphql/codegen.js + +### Other scripts +**Create chem comp bond table** + + node --max-old-space-size=8192 build/node_modules/apps/chem-comp-bond/create-table.js build/data/ccb.bcif -b + +**Test model server** + + node build/node_modules/servers/model/test.js ## Contributing Just open an issue or make a pull request. All contributions are welcome. diff --git a/package-lock.json b/package-lock.json index c636c8c3a9724d0b5b5cc0e420e8a3485628cbfe..4d46805a5edccbc2fb5c26a992a06e77ac016ed1 100644 Binary files a/package-lock.json and b/package-lock.json differ diff --git a/package.json b/package.json index 9caf1160560df158a9f7e53497c95bcb5143a2b8..31377fcba688342aebbb61ffdffcbdbf544d1ce1 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,8 @@ "test": "jest", "build-viewer": "webpack build/node_modules/apps/viewer/index.js --mode development -o build/viewer/index.js", "watch-viewer": "webpack build/node_modules/apps/viewer/index.js -w --mode development -o build/viewer/index.js", + "build-canvas": "webpack build/node_modules/apps/canvas/index.js --mode development -o build/canvas/index.js", + "watch-canvas": "webpack build/node_modules/apps/canvas/index.js -w --mode development -o build/canvas/index.js", "model-server": "node build/node_modules/servers/model/server.js", "model-server-watch": "nodemon --watch build/node_modules build/node_modules/servers/model/server.js" }, @@ -74,34 +76,34 @@ "@types/compression": "0.0.36", "@types/express": "^4.16.0", "@types/jest": "^23.3.1", - "@types/node": "^10.7.0", + "@types/node": "^10.7.1", "@types/node-fetch": "^2.1.2", - "@types/react": "^16.4.10", + "@types/react": "^16.4.11", "@types/react-dom": "^16.0.7", "benchmark": "^2.1.4", "cpx": "^1.5.0", "css-loader": "^1.0.0", "extra-watch-webpack-plugin": "^1.0.3", - "file-loader": "^1.1.11", + "file-loader": "^2.0.0", "glslify-import": "^3.1.0", "glslify-loader": "^1.0.2", - "graphql-code-generator": "^0.10.7", - "graphql-codegen-typescript-template": "^0.10.7", + "graphql-code-generator": "^0.11.0", + "graphql-codegen-typescript-template": "^0.11.0", "graphql-tag": "^2.9.2", "jest": "^23.5.0", "jest-raw-loader": "^1.0.1", - "mini-css-extract-plugin": "^0.4.1", + "mini-css-extract-plugin": "^0.4.2", "node-sass": "^4.9.3", "raw-loader": "^0.5.1", "resolve-url-loader": "^2.3.0", "sass-loader": "^7.1.0", "style-loader": "^0.22.1", - "ts-jest": "^23.1.3", + "ts-jest": "^23.1.4", "tslint": "^5.11.0", "typescript": "^3.0.1", "uglify-js": "^3.4.7", "util.promisify": "^1.0.0", - "webpack": "^4.16.5", + "webpack": "^4.17.1", "webpack-cli": "^3.1.0" }, "dependencies": { diff --git a/src/apps/canvas/index.html b/src/apps/canvas/index.html new file mode 100644 index 0000000000000000000000000000000000000000..3aa50333eec315dc64f79dce7366971dda63cc71 --- /dev/null +++ b/src/apps/canvas/index.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> + <title>Mol* Canvas</title> + </head> + <body> + <div id="container" style="width:800px; height: 600px;"> + <canvas id="canvas"></canvas> + </div> + <span id="info"></span> + <script type="text/javascript" src="./index.js"></script> + </body> +</html> \ No newline at end of file diff --git a/src/apps/canvas/index.ts b/src/apps/canvas/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5166630cac8f8059edde039026cabcaaf9bade2c --- /dev/null +++ b/src/apps/canvas/index.ts @@ -0,0 +1,154 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import './index.html' + +import Viewer from 'mol-view/viewer'; +import CIF, { CifBlock } from 'mol-io/reader/cif' +// import { parse as parseObj } from 'mol-io/reader/obj/parser' +import { readUrlAs } from 'mol-util/read' +import { Model, Format, Structure, StructureSymmetry } from 'mol-model/structure'; +import { CartoonRepresentation } from 'mol-geo/representation/structure/representation/cartoon'; +import { BallAndStickRepresentation } from 'mol-geo/representation/structure/representation/ball-and-stick'; +import { EveryLoci } from 'mol-model/loci'; +import { MarkerAction } from 'mol-geo/util/marker-data'; +import { labelFirst } from 'mol-view/label'; +import { Queries as Q, StructureProperties as SP, StructureSelection, StructureQuery } from 'mol-model/structure'; +import { MeshBuilder } from 'mol-geo/mesh/mesh-builder'; +import { ShapeRepresentation } from 'mol-geo/representation/shape'; +import { Vec3, Mat4 } from 'mol-math/linear-algebra'; +import { Shape } from 'mol-model/shape'; +import { Color } from 'mol-util/color'; +import { addSphere } from 'mol-geo/mesh/builder/sphere'; +import { Box } from 'mol-geo/primitive/box'; + +const container = document.getElementById('container') +if (!container) throw new Error('Can not find element with id "container".') + +const canvas = document.getElementById('canvas') as HTMLCanvasElement +if (!canvas) throw new Error('Can not find element with id "canvas".') + +const info = document.getElementById('info') as HTMLCanvasElement +if (!info) throw new Error('Can not find element with id "info".') + +const viewer = Viewer.create(canvas, container) +viewer.animate() + +viewer.input.resize.subscribe(() => { + // do whatever appropriate +}) + +viewer.input.move.subscribe(({x, y, inside, buttons}) => { + if (!inside || buttons) return + const p = viewer.identify(x, y) + const loci = viewer.getLoci(p) + + viewer.mark(EveryLoci, MarkerAction.RemoveHighlight) + viewer.mark(loci, MarkerAction.Highlight) + + const label = labelFirst(loci) + info.innerText = `${label}` +}) + + +// async function getObjFromUrl(url: string) { +// const data = await readUrlAs(url, false) as string +// const comp = parseObj(data) +// const parsed = await comp.run() +// if (parsed.isError) throw parsed +// return parsed.result +// } + +async function getCifFromUrl(url: string) { + const data = await readUrlAs(url, false) + const comp = CIF.parse(data) + const parsed = await comp.run() + if (parsed.isError) throw parsed + return parsed.result.blocks[0] +} + +async function getModelFromMmcif(cif: CifBlock) { + const models = await Model.create(Format.mmCIF(cif)).run() + return models[0] +} + +async function getStructureFromModel(model: Model, assembly = '1') { + const assemblies = model.symmetry.assemblies + if (assemblies.length) { + return await StructureSymmetry.buildAssembly(Structure.ofModel(model), assembly).run() + } else { + return Structure.ofModel(model) + } +} + +async function init() { + const cif = await getCifFromUrl('https://files.rcsb.org/download/1crn.cif') + const model = await getModelFromMmcif(cif) + const structure = await getStructureFromModel(model) + + viewer.center(structure.boundary.sphere.center) + + // cartoon for whole structure + const cartoonRepr = CartoonRepresentation() + await cartoonRepr.create(structure, { + colorTheme: { name: 'chain-id' }, + sizeTheme: { name: 'uniform', value: 0.2 }, + useFog: false // TODO fog not working properly + }).run() + viewer.add(cartoonRepr) + + // create new structure via query + const q1 = Q.generators.atoms({ + residueTest: qtx => SP.residue.label_seq_id(qtx.element) < 7 + }); + const newStructure = StructureSelection.unionStructure(await StructureQuery.run(q1, structure)); + + // ball+stick for new structure + const ballStickRepr = BallAndStickRepresentation() + await ballStickRepr.create(newStructure, { + colorTheme: { name: 'element-symbol' }, + sizeTheme: { name: 'uniform', value: 0.1 }, + useFog: false // TODO fog not working properly + }).run() + viewer.add(ballStickRepr) + + // create a mesh + const meshBuilder = MeshBuilder.create(256, 128) + const colors: Color[] = [] + const labels: string[] = [] + // red sphere + meshBuilder.setGroup(0) + colors[0] = Color(0xFF2233) + labels[0] = 'red sphere' + addSphere(meshBuilder, Vec3.create(0, 0, 0), 4, 2) + // green cube + meshBuilder.setGroup(1) + colors[1] = Color(0x2233FF) + labels[1] = 'blue cube' + const t = Mat4.identity() + Mat4.fromTranslation(t, Vec3.create(10, 0, 0)) + Mat4.scale(t, t, Vec3.create(3, 3, 3)) + meshBuilder.add(t, Box()) + const mesh = meshBuilder.getMesh() + // const mesh = getObjFromUrl('mesh.obj') + + // create shape from mesh + const shape = Shape.create('myShape', mesh, colors, labels) + + // add representation from shape + const customRepr = ShapeRepresentation() + await customRepr.create(shape, { + colorTheme: { name: 'shape-group' }, + // colorTheme: { name: 'uniform', value: Color(0xFFCC22) }, + useFog: false // TODO fog not working properly + }).run() + viewer.add(customRepr) + + // ensure the added representations get rendered, i.e. without mouse input + viewer.requestDraw() +} + +init() \ No newline at end of file diff --git a/src/apps/schema-generator/schema-from-mmcif-dic.ts b/src/apps/schema-generator/schema-from-cif-dic.ts similarity index 100% rename from src/apps/schema-generator/schema-from-mmcif-dic.ts rename to src/apps/schema-generator/schema-from-cif-dic.ts diff --git a/src/apps/schema-generator/util/cif-dic.ts b/src/apps/schema-generator/util/cif-dic.ts index 6036c7c82f1e12dfd1817fdd5f897315ebd60306..9b16bc602beec6be83d60887658d8cd9b8f8fcf8 100644 --- a/src/apps/schema-generator/util/cif-dic.ts +++ b/src/apps/schema-generator/util/cif-dic.ts @@ -77,7 +77,7 @@ interface FrameData { } // get field from given or linked category -function getField ( category: string, field: string, d: Data.CifFrame, ctx: FrameData): Data.CifField|undefined { +function getField (category: string, field: string, d: Data.CifFrame, ctx: FrameData): Data.CifField|undefined { const { categories, links } = ctx const cat = d.categories[category] @@ -130,6 +130,7 @@ function getSubCategory (d: Data.CifFrame, ctx: FrameData): string|undefined { function getDescription (d: Data.CifFrame, ctx: FrameData): string|undefined { const value = getField('item_description', 'description', d, ctx) if (value) { + // trim (after newlines) and remove references to square brackets return value.str(0).trim() .replace(/(\r\n|\r|\n)([ \t]+)/g, '\n') .replace(/(\[[1-3]\])+ element/, 'elements') @@ -195,6 +196,40 @@ export function generateSchema (frames: CifFrame[]) { const links: FrameLinks = {} const ctx = { categories, links } + // get category metadata + frames.forEach(d => { + if (d.header[0] === '_') return + const categoryKeyNames = new Set<string>() + const categoryKey = d.categories['category_key'] + if (categoryKey) { + const categoryKey_names = categoryKey.getField('name') + if (categoryKey_names) { + for (let i = 0, il = categoryKey_names.rowCount; i < il; ++i) { + categoryKeyNames.add(categoryKey_names.str(i)) + } + } + } + let description = '' + const category = d.categories['category'] + if (category) { + const category_description = category.getField('description') + if (category_description) { + description = category_description.str(0).trim() + .replace(/(\r\n|\r|\n)([ \t]+)/g, '\n') // remove padding after newlines + } else { + console.log(`no description given for category '${category}'`) + } + } + if (categoryKeyNames.size === 0) { + console.log(`no key given for category '${category}'`) + } + schema[d.header] = { description, key: categoryKeyNames, columns: {} } + // console.log('++++++++++++++++++++++++++++++++++++++++++') + // console.log('name', d.header) + // console.log('desc', description) + // console.log('key', categoryKeyNames) + }) + // build list of links between categories frames.forEach(d => { if (d.header[0] !== '_') return @@ -216,6 +251,7 @@ export function generateSchema (frames: CifFrame[]) { } }) + // get field data Object.keys(categories).forEach(fullName => { const d = categories[fullName] if (!d) { @@ -226,10 +262,15 @@ export function generateSchema (frames: CifFrame[]) { const itemName = d.header.substring(d.header.indexOf('.') + 1) let fields: { [k: string]: Column } if (categoryName in schema) { - fields = schema[categoryName] + fields = schema[categoryName].columns } else { + console.log(`category '${categoryName}' has no metadata`) fields = {} - schema[categoryName] = fields + schema[categoryName] = { + description: '', + key: new Set(), + columns: fields + } } const description = getDescription(d, ctx) || '' diff --git a/src/apps/schema-generator/util/generate.ts b/src/apps/schema-generator/util/generate.ts index 8b57095a893353998ca7f8c92b54df584ea6a94d..ecf33b4955a02f66877089644c1557ca07c7448d 100644 --- a/src/apps/schema-generator/util/generate.ts +++ b/src/apps/schema-generator/util/generate.ts @@ -18,17 +18,7 @@ function header (name: string, info: string, importDatabasePath = 'mol-data/db') import { Database, Column } from '${importDatabasePath}' -import Schema = Column.Schema - -const str = Schema.str; -const int = Schema.int; -const float = Schema.float; -const coord = Schema.coord; - -const Aliased = Schema.Aliased; -const Matrix = Schema.Matrix; -const Vector = Schema.Vector; -const List = Schema.List;` +import Schema = Column.Schema` } function footer (name: string) { @@ -37,6 +27,32 @@ export type ${name}_Schema = typeof ${name}_Schema; export interface ${name}_Database extends Database<${name}_Schema> {}` } +function getTypeShorthands(schema: Database, fields?: Filter) { + const types = new Set<string>() + Object.keys(schema).forEach(table => { + if (fields && !fields[table]) return + const { columns} = schema[table] + Object.keys(columns).forEach(columnName => { + if (fields && !fields[table][columnName]) return + types.add(schema[table].columns[columnName].type) + }) + }) + const shorthands: string[] = [] + types.forEach(type => { + switch (type) { + case 'str': shorthands.push('const str = Schema.str;'); break + case 'int': shorthands.push('const int = Schema.int;'); break + case 'float': shorthands.push('const float = Schema.float;'); break + case 'coord': shorthands.push('const coord = Schema.coord;'); break + case 'enum': shorthands.push('const Aliased = Schema.Aliased;'); break + case 'matrix': shorthands.push('const Matrix = Schema.Matrix;'); break + case 'vector': shorthands.push('const Vector = Schema.Vector;'); break + case 'list': shorthands.push('const List = Schema.List;'); break + } + }) + return shorthands.join('\n') +} + function getTypeDef(c: Column): string { switch (c.type) { case 'str': return 'str' @@ -63,27 +79,34 @@ function getTypeDef(c: Column): string { const reSafePropertyName = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/ function safePropertyString(name: string) { return name.match(reSafePropertyName) ? name : `'${name}'` } +function doc(description: string, spacesCount: number) { + const spaces = ' '.repeat(spacesCount) + return [ + `${spaces}/**`, + `${indentString(description, 1, `${spaces} * `)}`.replace(/ +\n/g, '\n'), + `${spaces} */` + ].join('\n') +} + export function generate (name: string, info: string, schema: Database, fields?: Filter, importDatabasePath?: string) { const codeLines: string[] = [] codeLines.push(`export const ${name}_Schema = {`) Object.keys(schema).forEach(table => { if (fields && !fields[table]) return + const { description, columns} = schema[table] + if (description) codeLines.push(doc(description, 4)) codeLines.push(` ${safePropertyString(table)}: {`) - const columns = schema[table] Object.keys(columns).forEach(columnName => { if (fields && !fields[table][columnName]) return - const typeDef = getTypeDef(columns[columnName]) - if (columns[columnName].description) { - codeLines.push(` /**`) - codeLines.push(`${indentString(columns[columnName].description, 1, ' * ')}`) - codeLines.push(` */`) - } + const c = columns[columnName] + const typeDef = getTypeDef(c) + if (c.description) codeLines.push(doc(c.description, 8)) codeLines.push(` ${safePropertyString(columnName)}: ${typeDef},`) }) codeLines.push(' },') }) codeLines.push('}') - return `${header(name, info, importDatabasePath)}\n\n${codeLines.join('\n')}\n${footer(name)}` + return `${header(name, info, importDatabasePath)}\n\n${getTypeShorthands(schema, fields)}\n\n${codeLines.join('\n')}\n${footer(name)}` } diff --git a/src/apps/schema-generator/util/schema.ts b/src/apps/schema-generator/util/schema.ts index 3cc2026e741448c7a3575096642adcc3b389e891..c18668e94d9c92cc6c51f4f34f3bed5e2218063b 100644 --- a/src/apps/schema-generator/util/schema.ts +++ b/src/apps/schema-generator/util/schema.ts @@ -5,7 +5,11 @@ */ export interface Database { [ tableName: string ]: Table } -export interface Table { [ columnName: string ]: Column } +export interface Table { + description: string + key: Set<string> + columns: { [ columnName: string ]: Column } +} export type Column = IntCol | StrCol | FloatCol | CoordCol | EnumCol | VectorCol | MatrixCol | ListCol type BaseCol = { description: string } diff --git a/src/apps/viewer/index.html b/src/apps/viewer/index.html index f3faa04f95f9e915ba493d25fdc471b69489e913..b2c505caf8929418a0dbe3e3107fd945179a6855 100644 --- a/src/apps/viewer/index.html +++ b/src/apps/viewer/index.html @@ -3,7 +3,7 @@ <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> - <title>Mol* Render Test</title> + <title>Mol* Viewer</title> <link href='./app.css', rel="stylesheet"> </head> <body> diff --git a/src/mol-app/ui/visualization/viewport.tsx b/src/mol-app/ui/visualization/viewport.tsx index ba402a6d7d1f6e81e1968b11a02d635bc78c209c..d23f182e1b5bbfa3731d1f98edc7fa2cb9243692 100644 --- a/src/mol-app/ui/visualization/viewport.tsx +++ b/src/mol-app/ui/visualization/viewport.tsx @@ -151,7 +151,7 @@ export class Viewport extends View<ViewportController, ViewportState, { noWebGl? images: { 'object': viewer.getImageData('pickObject'), 'instance': viewer.getImageData('pickInstance'), - 'element': viewer.getImageData('pickElement') + 'group': viewer.getImageData('pickGroup') } }) }) @@ -168,7 +168,7 @@ export class Viewport extends View<ViewportController, ViewportState, { noWebGl? // TODO use LabelLoci event and make configurable const label = labelFirst(loci) - const info = `Object: ${p.objectId}, Instance: ${p.instanceId}, Element: ${p.elementId}, Label: ${label}` + const info = `Object: ${p.objectId}, Instance: ${p.instanceId}, Group: ${p.groupId}, Label: ${label}` this.setState({ info }) }) diff --git a/src/mol-geo/mesh/builder/cylinder.ts b/src/mol-geo/mesh/builder/cylinder.ts new file mode 100644 index 0000000000000000000000000000000000000000..b4538c1c81a0a802392a622ece8199e2f997e77e --- /dev/null +++ b/src/mol-geo/mesh/builder/cylinder.ts @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Vec3, Mat4 } from 'mol-math/linear-algebra'; +import { MeshBuilder } from '../mesh-builder'; +import { Primitive } from '../../primitive/primitive'; +import { Cylinder, CylinderProps } from '../../primitive/cylinder'; + +const cylinderMap = new Map<string, Primitive>() +const up = Vec3.create(0, 1, 0) + +const tmpCylinderDir = Vec3.zero() +const tmpCylinderMatDir = Vec3.zero() +const tmpCylinderCenter = Vec3.zero() +const tmpCylinderMat = Mat4.zero() +const tmpCylinderStart = Vec3.zero() +const tmpUp = Vec3.zero() + +function setCylinderMat(m: Mat4, start: Vec3, dir: Vec3, length: number) { + Vec3.setMagnitude(tmpCylinderMatDir, dir, length / 2) + Vec3.add(tmpCylinderCenter, start, tmpCylinderMatDir) + // ensure the direction used to create the rotation is always pointing in the same + // direction so the triangles of adjacent cylinder will line up + Vec3.copy(tmpUp, up) + if (Vec3.dot(tmpCylinderMatDir, tmpUp) < 0) Vec3.scale(tmpUp, tmpUp, -1) + Vec3.makeRotation(m, tmpUp, tmpCylinderMatDir) + return Mat4.setTranslation(m, tmpCylinderCenter) +} + +function getCylinder(props: CylinderProps) { + const key = JSON.stringify(props) + let cylinder = cylinderMap.get(key) + if (cylinder === undefined) { + cylinder = Cylinder(props) + cylinderMap.set(key, cylinder) + } + return cylinder +} + +export function addCylinder(builder: MeshBuilder, start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) { + const d = Vec3.distance(start, end) * lengthScale + props.height = d + Vec3.sub(tmpCylinderDir, end, start) + setCylinderMat(tmpCylinderMat, start, tmpCylinderDir, d) + builder.add(tmpCylinderMat, getCylinder(props)) +} + +export function addDoubleCylinder(builder: MeshBuilder, start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps) { + const d = Vec3.distance(start, end) * lengthScale + props.height = d + const cylinder = getCylinder(props) + Vec3.sub(tmpCylinderDir, end, start) + // positivly shifted cylinder + Vec3.add(tmpCylinderStart, start, shift) + setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) + builder.add(tmpCylinderMat, cylinder) + // negativly shifted cylinder + Vec3.sub(tmpCylinderStart, start, shift) + setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) + builder.add(tmpCylinderMat, cylinder) +} + +export function addFixedCountDashedCylinder(builder: MeshBuilder, start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps) { + const s = Math.floor(segmentCount / 2) + const step = 1 / segmentCount + + // automatically adjust length so links/bonds that are rendered as two half cylinders + // have evenly spaced dashed cylinders + if (lengthScale < 1) { + const bias = lengthScale / 2 / segmentCount + lengthScale += segmentCount % 2 === 1 ? bias : -bias + } + + const d = Vec3.distance(start, end) * lengthScale + props.height = d * step + const cylinder = getCylinder(props) + Vec3.sub(tmpCylinderDir, end, start) + + for (let j = 0; j < s; ++j) { + const f = step * (j * 2 + 1) + Vec3.setMagnitude(tmpCylinderDir, tmpCylinderDir, d * f) + Vec3.add(tmpCylinderStart, start, tmpCylinderDir) + setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d * step) + builder.add(tmpCylinderMat, cylinder) + } +} \ No newline at end of file diff --git a/src/mol-geo/primitive/sheet.ts b/src/mol-geo/mesh/builder/sheet.ts similarity index 92% rename from src/mol-geo/primitive/sheet.ts rename to src/mol-geo/mesh/builder/sheet.ts index e4130a5be57e25d9204754ed0dcf265b5f26ab66..c0d7a473318356bcf891dcb8088d45411065e91a 100644 --- a/src/mol-geo/primitive/sheet.ts +++ b/src/mol-geo/mesh/builder/sheet.ts @@ -7,7 +7,7 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { ChunkedArray } from 'mol-data/util'; -import { MeshBuilderState } from '../shape/mesh-builder'; +import { MeshBuilder } from '../mesh-builder'; const tA = Vec3.zero() const tB = Vec3.zero() @@ -25,8 +25,8 @@ const p2 = Vec3.zero() const p3 = Vec3.zero() const p4 = Vec3.zero() -export function addSheet(controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean, state: MeshBuilderState) { - const { vertices, normals, indices } = state +export function addSheet(builder: MeshBuilder, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean) { + const { currentGroup, vertices, normals, indices, groups } = builder.state let vertexCount = vertices.elementCount let offsetLength = 0 @@ -173,5 +173,6 @@ export function addSheet(controlPoints: ArrayLike<number>, normalVectors: ArrayL ChunkedArray.add3(indices, vertexCount, vertexCount + 3, vertexCount + 2); } - return (linearSegments + 1) * 8 + (startCap ? 4 : 0) + (endCap && arrowHeight === 0 ? 4 : 0) + const addedVertexCount = (linearSegments + 1) * 8 + (startCap ? 4 : 0) + (endCap && arrowHeight === 0 ? 4 : 0) + for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup) } \ No newline at end of file diff --git a/src/mol-geo/mesh/builder/sphere.ts b/src/mol-geo/mesh/builder/sphere.ts new file mode 100644 index 0000000000000000000000000000000000000000..d9196c3a2840223e833369e133c79c237b3e4c63 --- /dev/null +++ b/src/mol-geo/mesh/builder/sphere.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Vec3, Mat4 } from 'mol-math/linear-algebra'; +import { MeshBuilder } from '../mesh-builder'; +import { Primitive } from '../../primitive/primitive'; +import { Sphere } from '../../primitive/sphere'; + +const sphereMap = new Map<number, Primitive>() +const tmpSphereMat = Mat4.identity() + +function setSphereMat(m: Mat4, center: Vec3, radius: number) { + return Mat4.scaleUniformly(m, Mat4.fromTranslation(m, center), radius) +} + +function getSphere(detail: number) { + let sphere = sphereMap.get(detail) + if (sphere === undefined) { + sphere = Sphere(detail) + sphereMap.set(detail, sphere) + } + return sphere +} + +export function addSphere(builder: MeshBuilder, center: Vec3, radius: number, detail: number) { + builder.add(setSphereMat(tmpSphereMat, center, radius), getSphere(detail)) +} \ No newline at end of file diff --git a/src/mol-geo/primitive/tube.ts b/src/mol-geo/mesh/builder/tube.ts similarity index 87% rename from src/mol-geo/primitive/tube.ts rename to src/mol-geo/mesh/builder/tube.ts index 92d8a182cd787892cc7b0a7b55f193edcd942eda..944429468a81cbf653b99bc69295b8c5ca012c9a 100644 --- a/src/mol-geo/primitive/tube.ts +++ b/src/mol-geo/mesh/builder/tube.ts @@ -7,7 +7,7 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { ChunkedArray } from 'mol-data/util'; -import { MeshBuilderState } from '../shape/mesh-builder'; +import { MeshBuilder } from '../mesh-builder'; const normalVector = Vec3.zero() const binormalVector = Vec3.zero() @@ -18,8 +18,8 @@ const b = Vec3.zero() const u = Vec3.zero() const v = Vec3.zero() -export function addTube(controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean, state: MeshBuilderState) { - const { vertices, normals, indices } = state +export function addTube(builder: MeshBuilder, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean) { + const { currentGroup, vertices, normals, indices, groups } = builder.state let vertexCount = vertices.elementCount const di = 1 / linearSegments @@ -127,7 +127,7 @@ export function addTube(controlPoints: ArrayLike<number>, normalVectors: ArrayLi vertexCount = vertices.elementCount for (let i = 0; i < radialSegments; ++i) { - const t = 2 * Math.PI * i / radialSegments; + const t = 2 * Math.PI * i / radialSegments Vec3.copy(a, u) Vec3.copy(b, v) @@ -150,5 +150,6 @@ export function addTube(controlPoints: ArrayLike<number>, normalVectors: ArrayLi } } - return (linearSegments + 1) * radialSegments + (startCap ? radialSegments + 1 : 0) + (endCap ? radialSegments + 1 : 0) + const addedVertexCount = (linearSegments + 1) * radialSegments + (startCap ? radialSegments + 1 : 0) + (endCap ? radialSegments + 1 : 0) + for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(groups, currentGroup) } \ No newline at end of file diff --git a/src/mol-geo/mesh/mesh-builder.ts b/src/mol-geo/mesh/mesh-builder.ts new file mode 100644 index 0000000000000000000000000000000000000000..d7d264bfc777b0a5548aa229e43b620862c6af95 --- /dev/null +++ b/src/mol-geo/mesh/mesh-builder.ts @@ -0,0 +1,81 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ValueCell } from 'mol-util/value-cell' +import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra'; +import { ChunkedArray } from 'mol-data/util'; +import { Mesh } from './mesh'; +import { getNormalMatrix } from '../util'; +import { Primitive } from '../primitive/primitive'; + +export interface MeshBuilderState { + readonly currentGroup: number + readonly vertices: ChunkedArray<number, 3> + readonly normals: ChunkedArray<number, 3> + readonly indices: ChunkedArray<number, 3> + readonly groups: ChunkedArray<number, 1> +} + +export interface MeshBuilder { + state: MeshBuilderState + add(t: Mat4, primitive: Primitive): void + setGroup(id: number): void + getMesh(): Mesh +} + +const tmpV = Vec3.zero() +const tmpMat3 = Mat3.zero() + +export namespace MeshBuilder { + export function create(initialCount = 2048, chunkSize = 1024, mesh?: Mesh): MeshBuilder { + const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.vertexBuffer.ref.value : initialCount); + const normals = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.normalBuffer.ref.value : initialCount); + const indices = ChunkedArray.create(Uint32Array, 3, chunkSize * 3, mesh ? mesh.indexBuffer.ref.value : initialCount * 3); + const groups = ChunkedArray.create(Float32Array, 1, chunkSize, mesh ? mesh.groupBuffer.ref.value : initialCount); + + let currentGroup = -1 + + function add(t: Mat4, primitive: Primitive) { + const { vertices: va, normals: na, indices: ia } = primitive + const offset = vertices.elementCount + const n = getNormalMatrix(tmpMat3, t) + for (let i = 0, il = va.length; i < il; i += 3) { + // position + Vec3.transformMat4(tmpV, Vec3.fromArray(tmpV, va, i), t) + ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]); + // normal + Vec3.transformMat3(tmpV, Vec3.fromArray(tmpV, na, i), n) + ChunkedArray.add3(normals, tmpV[0], tmpV[1], tmpV[2]); + // group + ChunkedArray.add(groups, currentGroup); + } + for (let i = 0, il = ia.length; i < il; i += 3) { + ChunkedArray.add3(indices, ia[i] + offset, ia[i + 1] + offset, ia[i + 2] + offset); + } + } + + return { + state: { get currentGroup() { return currentGroup }, vertices, normals, indices, groups }, + add, + setGroup: (group: number) => { currentGroup = group }, + getMesh: () => { + const vb = ChunkedArray.compact(vertices, true) as Float32Array + const ib = ChunkedArray.compact(indices, true) as Uint32Array + const nb = ChunkedArray.compact(normals, true) as Float32Array + const gb = ChunkedArray.compact(groups, true) as Float32Array + return { + vertexCount: vertices.elementCount, + triangleCount: indices.elementCount, + vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb), + indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib), + normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb), + groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, gb) : ValueCell.create(gb), + normalsComputed: true, + } + } + } + } +} \ No newline at end of file diff --git a/src/mol-geo/shape/mesh.ts b/src/mol-geo/mesh/mesh.ts similarity index 89% rename from src/mol-geo/shape/mesh.ts rename to src/mol-geo/mesh/mesh.ts index 9447404a353e906a8ee0d27708bd6b7743509160..c1dc5673e15ae1ec66a5a63c086220f805af1b35 100644 --- a/src/mol-geo/shape/mesh.ts +++ b/src/mol-geo/mesh/mesh.ts @@ -15,24 +15,18 @@ export interface Mesh { vertexCount: number, /** Number of triangles in the mesh */ triangleCount: number, - /** Number of offsets in the mesh */ - offsetCount: number, /** Vertex buffer as array of xyz values wrapped in a value cell */ - vertexBuffer: ValueCell<Float32Array>, + readonly vertexBuffer: ValueCell<Float32Array>, /** Index buffer as array of vertex index triplets wrapped in a value cell */ - indexBuffer: ValueCell<Uint32Array>, + readonly indexBuffer: ValueCell<Uint32Array>, /** Normal buffer as array of xyz values for each vertex wrapped in a value cell */ - normalBuffer: ValueCell<Float32Array>, - /** Id buffer as array of ids for each vertex wrapped in a value cell */ - idBuffer: ValueCell<Float32Array>, - /** Offset buffer as array of offsets for id ranges wrapped in a value cell */ - offsetBuffer: ValueCell<Uint32Array>, + readonly normalBuffer: ValueCell<Float32Array>, + /** Group buffer as array of group ids for each vertex wrapped in a value cell */ + readonly groupBuffer: ValueCell<Float32Array>, /** Flag indicating if normals are computed for the current set of vertices */ normalsComputed: boolean, - /** Flag indicating if offsets are computed for the current set of ids */ - offsetsComputed: boolean, /** Bounding sphere of the mesh */ boundingSphere?: Sphere3D @@ -43,19 +37,15 @@ export namespace Mesh { const vb = mesh ? mesh.vertexBuffer.ref.value : new Float32Array(0) const ib = mesh ? mesh.indexBuffer.ref.value : new Uint32Array(0) const nb = mesh ? mesh.normalBuffer.ref.value : new Float32Array(0) - const idb = mesh ? mesh.idBuffer.ref.value : new Float32Array(0) - const ob = mesh ? mesh.offsetBuffer.ref.value : new Uint32Array(0) + const idb = mesh ? mesh.groupBuffer.ref.value : new Float32Array(0) return { vertexCount: 0, triangleCount: 0, - offsetCount: 0, vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb), indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib), normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb), - idBuffer: mesh ? ValueCell.update(mesh.idBuffer, idb) : ValueCell.create(idb), - offsetBuffer: mesh ? ValueCell.update(mesh.offsetBuffer, ob) : ValueCell.create(ob), + groupBuffer: mesh ? ValueCell.update(mesh.groupBuffer, idb) : ValueCell.create(idb), normalsComputed: true, - offsetsComputed: true, } } @@ -92,7 +82,7 @@ export namespace Mesh { // console.log([normals[i], normals[i + 1], normals[i + 2]], [v[i], v[i + 1], v[i + 2]]) } - surface.normalBuffer = ValueCell.update(surface.normalBuffer, normals); + ValueCell.update(surface.normalBuffer, normals); surface.normalsComputed = true; } diff --git a/src/mol-geo/primitive/box.ts b/src/mol-geo/primitive/box.ts index 990730641206701eda7102ee6e4fb8441398dd95..d3fa7f74dd3bf158dd0756d2101aca4921e66931 100644 --- a/src/mol-geo/primitive/box.ts +++ b/src/mol-geo/primitive/box.ts @@ -33,8 +33,8 @@ function createBox(perforated: boolean): Primitive { Vec3.set(b, points[2], points[3], -0.5) Vec3.set(c, points[4], points[5], -0.5) Vec3.set(d, points[6], points[7], -0.5) - builder.add(a, b, c) - if (!perforated) builder.add(c, d, a) + builder.add(c, b, a) + if (!perforated) builder.add(a, d, c) Vec3.set(a, points[0], points[1], 0.5) Vec3.set(b, points[2], points[3], 0.5) Vec3.set(c, points[4], points[5], 0.5) diff --git a/src/mol-geo/primitive/plane.ts b/src/mol-geo/primitive/plane.ts index aeeeb371d933a4f18a333709790d626cd505a19b..2f30c427d4fd4ccf7794b135ae2169aa3793e917 100644 --- a/src/mol-geo/primitive/plane.ts +++ b/src/mol-geo/primitive/plane.ts @@ -6,31 +6,25 @@ import { Primitive } from './primitive'; * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -export const DefaultPlaneProps = { - width: 1, - height: 1 +const plane: Primitive = { + vertices: new Float32Array([ + -0.5, 0.5, 0, + 0.5, 0.5, 0, + -0.5, -0.5, 0, + 0.5, -0.5, 0 + ]), + normals: new Float32Array([ + 0, 0, 1, + 0, 0, 1, + 0, 0, 1, + 0, 0, 1 + ]), + indices: new Uint32Array([ + 0, 2, 1, + 1, 2, 3 + ]) } -export type PlaneProps = Partial<typeof DefaultPlaneProps> -export function Plane(props?: PlaneProps): Primitive { - const { width, height } = { ...DefaultPlaneProps, ...props } - - return { - vertices: new Float32Array([ - -width / 2, height / 2, 0, - width / 2, height / 2, 0, - -width / 2, -height / 2, 0, - width / 2, -height / 2, 0 - ]), - normals: new Float32Array([ - 0, 0, 1, - 0, 0, 1, - 0, 0, 1, - 0, 0, 1 - ]), - indices: new Uint32Array([ - 0, 2, 1, - 1, 2, 3 - ]) - } +export function Plane(): Primitive { + return plane } \ No newline at end of file diff --git a/src/mol-geo/primitive/prism.ts b/src/mol-geo/primitive/prism.ts index d7ad601033b04cd4429ae07d725dc2ba57e5beef..02bbee0b26176c27c36d6502cd83523fba8b3ace 100644 --- a/src/mol-geo/primitive/prism.ts +++ b/src/mol-geo/primitive/prism.ts @@ -16,7 +16,7 @@ const a = Vec3.zero(), b = Vec3.zero(), c = Vec3.zero(), d = Vec3.zero() */ export function Prism(points: ArrayLike<number>): Primitive { const sideCount = points.length / 2 - if (sideCount < 5) throw new Error('need at least 5 points to build a prism') + if (sideCount < 4) throw new Error('need at least 5 points to build a prism') const count = 4 * sideCount const builder = PrimitiveBuilder(count) @@ -37,10 +37,10 @@ export function Prism(points: ArrayLike<number>): Primitive { const ni = (i + 1) % sideCount Vec3.set(a, points[i * 2], points[i * 2 + 1], -0.5) Vec3.set(b, points[ni * 2], points[ni * 2 + 1], -0.5) - builder.add(a, b, on) + builder.add(on, b, a) Vec3.set(a, points[i * 2], points[i * 2 + 1], 0.5) Vec3.set(b, points[ni * 2], points[ni * 2 + 1], 0.5) - builder.add(op, b, a) + builder.add(a, b, op) } return builder.getPrimitive() diff --git a/src/mol-geo/primitive/pyramid.ts b/src/mol-geo/primitive/pyramid.ts index 1a0fb1ae9bf801d9eb575f1c0e67950be5288d70..c00b84320cd714f967c8a89519fef216f5b95487 100644 --- a/src/mol-geo/primitive/pyramid.ts +++ b/src/mol-geo/primitive/pyramid.ts @@ -12,9 +12,9 @@ const on = Vec3.create(0, 0, -0.5), op = Vec3.create(0, 0, 0.5) const a = Vec3.zero(), b = Vec3.zero(), c = Vec3.zero(), d = Vec3.zero() /** - * Create a pyramide with a poligonal base + * Create a pyramid with a poligonal base */ -export function Pyramide(points: ArrayLike<number>): Primitive { +export function Pyramid(points: ArrayLike<number>): Primitive { const sideCount = points.length / 2 const baseCount = sideCount === 3 ? 1 : sideCount === 4 ? 2 : sideCount const count = 2 * baseCount + 2 * sideCount @@ -33,37 +33,37 @@ export function Pyramide(points: ArrayLike<number>): Primitive { Vec3.set(a, points[0], points[1], -0.5) Vec3.set(b, points[2], points[3], -0.5) Vec3.set(c, points[4], points[5], -0.5) - builder.add(a, b, c) + builder.add(c, b, a) } else if (sideCount === 4) { Vec3.set(a, points[0], points[1], -0.5) Vec3.set(b, points[2], points[3], -0.5) Vec3.set(c, points[4], points[5], -0.5) Vec3.set(d, points[6], points[7], -0.5) - builder.add(a, b, c) - builder.add(c, d, a) + builder.add(c, b, a) + builder.add(a, d, c) } else { for (let i = 0; i < sideCount; ++i) { const ni = (i + 1) % sideCount Vec3.set(a, points[i * 2], points[i * 2 + 1], -0.5) Vec3.set(b, points[ni * 2], points[ni * 2 + 1], -0.5) - builder.add(a, b, on) + builder.add(on, b, a) } } return builder.getPrimitive() } -let octagonalPyramide: Primitive -export function OctagonalPyramide() { - if (!octagonalPyramide) octagonalPyramide = Pyramide(polygon(8, true)) - return octagonalPyramide +let octagonalPyramid: Primitive +export function OctagonalPyramid() { + if (!octagonalPyramid) octagonalPyramid = Pyramid(polygon(8, true)) + return octagonalPyramid } // -let perforatedOctagonalPyramide: Primitive -export function PerforatedOctagonalPyramide() { - if (!perforatedOctagonalPyramide) { +let perforatedOctagonalPyramid: Primitive +export function PerforatedOctagonalPyramid() { + if (!perforatedOctagonalPyramid) { const points = polygon(8, true) const vertices = new Float32Array(8 * 3 + 6) for (let i = 0; i < 8; ++i) { @@ -81,7 +81,7 @@ export function PerforatedOctagonalPyramide() { 0, 1, 8, 1, 2, 8, 4, 5, 8, 5, 6, 8, 2, 3, 9, 3, 4, 9, 6, 7, 9, 7, 0, 9 ]; - perforatedOctagonalPyramide = createPrimitive(vertices, indices) + perforatedOctagonalPyramid = createPrimitive(vertices, indices) } - return perforatedOctagonalPyramide + return perforatedOctagonalPyramid } \ No newline at end of file diff --git a/src/mol-geo/primitive/sphere.ts b/src/mol-geo/primitive/sphere.ts index bcf1460dca677832fa68f057e4ef87b2ca6d87b8..25704b7c1be233d7240a7521795d09db3cde41b2 100644 --- a/src/mol-geo/primitive/sphere.ts +++ b/src/mol-geo/primitive/sphere.ts @@ -15,13 +15,7 @@ export function sphereVertexCount(detail: number) { return 10 * Math.pow(Math.pow(2, detail), 2) + 2 } -export const DefaultSphereProps = { - radius: 1, - detail: 0 -} -export type SphereProps = Partial<typeof DefaultSphereProps> - /** Create sphere by subdividing an icosahedron */ -export function Sphere(props?: SphereProps): Primitive { - return Polyhedron(vertices, indices, { ...DefaultSphereProps, ...props }) +export function Sphere(detail: number): Primitive { + return Polyhedron(vertices, indices, { detail, radius: 1 }) } \ No newline at end of file diff --git a/src/mol-geo/primitive/star.ts b/src/mol-geo/primitive/star.ts index f24ac248bfe1e48276434564a695364ad909a413..2cb94620c3d450b47f58fb57422a221bc9b2839d 100644 --- a/src/mol-geo/primitive/star.ts +++ b/src/mol-geo/primitive/star.ts @@ -46,9 +46,9 @@ export function Star(props?: StarProps): Primitive { Vec3.set(c, outerPoints[ni * 2], outerPoints[ni * 2 + 1], 0) builder.add(op, a, b) - builder.add(on, a, b) + builder.add(b, a, on) builder.add(op, b, c) - builder.add(on, b, c) + builder.add(c, b, on) } return builder.getPrimitive() diff --git a/src/mol-geo/primitive/wedge.ts b/src/mol-geo/primitive/wedge.ts index 3b2d317b9e3575e1aaf527e3697638692179c648..cfd912b53533d0b1283af25f257d3d72c88a8030 100644 --- a/src/mol-geo/primitive/wedge.ts +++ b/src/mol-geo/primitive/wedge.ts @@ -32,11 +32,11 @@ export function createWedge(): Primitive { Vec3.set(a, points[0], points[1], -0.5) Vec3.set(b, points[2], points[3], -0.5) Vec3.set(c, points[4], points[5], -0.5) - builder.add(a, b, c) + builder.add(c, b, a) Vec3.set(a, points[0], points[1], 0.5) Vec3.set(b, points[2], points[3], 0.5) Vec3.set(c, points[4], points[5], 0.5) - builder.add(c, b, a) + builder.add(a, b, c) return builder.getPrimitive() } diff --git a/src/mol-geo/representation/shape/index.ts b/src/mol-geo/representation/shape/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9272af8df70789e128b6dc0be8d095f46504462 --- /dev/null +++ b/src/mol-geo/representation/shape/index.ts @@ -0,0 +1,128 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Task } from 'mol-task' +import { RenderObject, createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; +import { RepresentationProps, Representation } from '..'; +import { PickingId } from '../../util/picking'; +import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci'; +import { MarkerAction, applyMarkerAction, createMarkers } from '../../util/marker-data'; +import { createRenderableState, createMeshValues, createIdentityTransform, DefaultMeshProps } from '../util'; +import { getMeshData } from '../../util/mesh-data'; +import { MeshValues } from 'mol-gl/renderable'; +import { ValueCell } from 'mol-util'; +import { ColorThemeProps } from 'mol-view/theme/color'; +import { Shape } from 'mol-model/shape'; +import { LocationIterator } from '../../util/location-iterator'; +import { createColors } from '../structure/visual/util/common'; +import { OrderedSet, Interval } from 'mol-data/int'; + +export interface ShapeRepresentation<P extends RepresentationProps = {}> extends Representation<Shape, P> { } + +export const DefaultShapeProps = { + ...DefaultMeshProps, + colorTheme: { name: 'shape-group' } as ColorThemeProps +} +export type ShapeProps = typeof DefaultShapeProps + +export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation<P> { + const renderObjects: RenderObject[] = [] + let _renderObject: MeshRenderObject + let _shape: Shape + let _props: P + + function create(shape: Shape, props: Partial<P> = {}) { + _props = Object.assign({}, DefaultShapeProps, _props, props) + _shape = shape + + return Task.create('ShapeRepresentation.create', async ctx => { + renderObjects.length = 0 + + const mesh = shape.mesh + const locationIt = ShapeGroupIterator.fromShape(shape) + const { groupCount, instanceCount } = locationIt + + const color = createColors(locationIt, _props.colorTheme) + const marker = createMarkers(instanceCount * groupCount) + const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount } + + const values: MeshValues = { + ...getMeshData(mesh), + ...createMeshValues(_props, counts), + aTransform: createIdentityTransform(), + ...color, + ...marker, + + elements: mesh.indexBuffer, + } + const state = createRenderableState(_props) + + _renderObject = createMeshRenderObject(values, state) + console.log(_renderObject) + renderObjects.push(_renderObject) + }); + } + + function update(props: Partial<P>) { + return Task.create('ShapeRepresentation.update', async ctx => { + // TODO handle general update + // TODO check shape.colors.ref.version + }) + } + + return { + get renderObjects () { return renderObjects }, + get props () { return _props }, + create, + update, + getLoci(pickingId: PickingId) { + const { objectId, groupId } = pickingId + if (_renderObject.id === objectId) { + return Shape.Loci([ { shape: _shape, ids: OrderedSet.ofSingleton(groupId) } ]) + } + return EmptyLoci + }, + mark(loci: Loci, action: MarkerAction) { + const { tMarker } = _renderObject.values + let changed = false + if (isEveryLoci(loci)) { + if (applyMarkerAction(tMarker.ref.value.array, 0, _shape.mesh.triangleCount, action)) changed = true + } else if (Shape.isLoci(loci)) { + for (const g of loci.groups) { + if (Interval.is(g.ids)) { + const start = Interval.start(g.ids) + const end = Interval.end(g.ids) + if (applyMarkerAction(tMarker.ref.value.array, start, end, action)) changed = true + } else { + for (let i = 0, _i = g.ids.length; i < _i; i++) { + const idx = g.ids[i]; + if (applyMarkerAction(tMarker.ref.value.array, idx, idx + 1, action)) changed = true + } + } + } + } + if (changed) { + ValueCell.update(tMarker, tMarker.ref.value) + } + }, + destroy() { + // TODO + } + } +} + +export namespace ShapeGroupIterator { + export function fromShape(shape: Shape): LocationIterator { + const { groupCount } = shape + const instanceCount = 1 + const location = Shape.Location(shape) + const getLocation = (groupIndex: number) => { + location.group = groupIndex + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } +} \ No newline at end of file diff --git a/src/mol-geo/representation/structure/complex-representation.ts b/src/mol-geo/representation/structure/complex-representation.ts index d19f96b263525cd4fe6ac280e3cd890ccd675391..6a258b24ca99cf9ccc9edc5d1297b306ac483051 100644 --- a/src/mol-geo/representation/structure/complex-representation.ts +++ b/src/mol-geo/representation/structure/complex-representation.ts @@ -22,7 +22,7 @@ export function ComplexRepresentation<P extends StructureProps>(visualCtor: () = function create(structure: Structure, props: Partial<P> = {}) { _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, structure)) - _props.colorTheme!.structure = structure + _props.colorTheme.structure = structure return Task.create('Creating StructureRepresentation', async ctx => { if (!_structure) { @@ -44,7 +44,7 @@ export function ComplexRepresentation<P extends StructureProps>(visualCtor: () = function update(props: Partial<P>) { return Task.create('Updating StructureRepresentation', async ctx => { _props = Object.assign({}, DefaultStructureProps, _props, props, getQualityProps(props, _structure)) - _props.colorTheme!.structure = _structure + _props.colorTheme.structure = _structure if (!await visual.update(ctx, _props)) { await visual.create(ctx, _structure, _props) diff --git a/src/mol-geo/representation/structure/complex-visual.ts b/src/mol-geo/representation/structure/complex-visual.ts index 083a610e728721a6c293aa595f0ce1b44ac84a78..063ecf36dc20499485644fb736b9f853f2b1b4bf 100644 --- a/src/mol-geo/representation/structure/complex-visual.ts +++ b/src/mol-geo/representation/structure/complex-visual.ts @@ -7,9 +7,9 @@ import { Structure } from 'mol-model/structure'; import { Visual } from '..'; import { MeshRenderObject } from 'mol-gl/render-object'; -import { Mesh } from '../../shape/mesh'; +import { Mesh } from '../../mesh/mesh'; import { RuntimeContext } from 'mol-task'; -import { LocationIterator } from './visual/util/location-iterator'; +import { LocationIterator } from '../../util/location-iterator'; import { createComplexMeshRenderObject, createColors } from './visual/util/common'; import { StructureProps, DefaultStructureMeshProps, MeshUpdateState } from '.'; import { deepEqual, ValueCell } from 'mol-util'; @@ -96,7 +96,7 @@ export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMe }, mark(loci: Loci, action: MarkerAction) { const { tMarker } = renderObject.values - const { elementCount, instanceCount } = locationIt + const { groupCount, instanceCount } = locationIt function apply(interval: Interval) { const start = Interval.start(interval) @@ -106,7 +106,7 @@ export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMe let changed = false if (isEveryLoci(loci)) { - apply(Interval.ofBounds(0, elementCount * instanceCount)) + apply(Interval.ofBounds(0, groupCount * instanceCount)) changed = true } else { changed = mark(loci, currentStructure, apply) diff --git a/src/mol-geo/representation/structure/representation/cartoon.ts b/src/mol-geo/representation/structure/representation/cartoon.ts index 904b43360dbf70d971a659dccd69d610b6345d7d..bc9b43e09a2c19f225b88a7ca122b4cbf362d807 100644 --- a/src/mol-geo/representation/structure/representation/cartoon.ts +++ b/src/mol-geo/representation/structure/representation/cartoon.ts @@ -33,7 +33,8 @@ export function CartoonRepresentation(): StructureRepresentation<CartoonProps> { return { get renderObjects() { return [ ...traceRepr.renderObjects, ...gapRepr.renderObjects, - ...blockRepr.renderObjects, ...directionRepr.renderObjects ] + ...blockRepr.renderObjects // , ...directionRepr.renderObjects + ] }, get props() { return { ...traceRepr.props, ...gapRepr.props, ...blockRepr.props } diff --git a/src/mol-geo/representation/structure/units-visual.ts b/src/mol-geo/representation/structure/units-visual.ts index 9118f2b48afdc14ae21957ac2f56f8e8a3c563d6..d7ebb4b9bc5ccc140c3091671ba836e8fbc87f6a 100644 --- a/src/mol-geo/representation/structure/units-visual.ts +++ b/src/mol-geo/representation/structure/units-visual.ts @@ -9,8 +9,8 @@ import { RepresentationProps, Visual } from '..'; import { DefaultStructureMeshProps, MeshUpdateState } from '.'; import { RuntimeContext } from 'mol-task'; import { PickingId } from '../../util/picking'; -import { LocationIterator } from './visual/util/location-iterator'; -import { Mesh } from '../../shape/mesh'; +import { LocationIterator } from '../../util/location-iterator'; +import { Mesh } from '../../mesh/mesh'; import { MarkerAction, applyMarkerAction } from '../../util/marker-data'; import { Loci, isEveryLoci } from 'mol-model/loci'; import { MeshRenderObject } from 'mol-gl/render-object'; @@ -101,7 +101,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu }, mark(loci: Loci, action: MarkerAction) { const { tMarker } = renderObject.values - const { elementCount, instanceCount } = locationIt + const { groupCount, instanceCount } = locationIt function apply(interval: Interval) { const start = Interval.start(interval) @@ -111,7 +111,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu let changed = false if (isEveryLoci(loci)) { - apply(Interval.ofBounds(0, elementCount * instanceCount)) + apply(Interval.ofBounds(0, groupCount * instanceCount)) changed = true } else { changed = mark(loci, currentGroup, apply) diff --git a/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts index a315ba72dbc38bc18bc8ea4116f4ca100e02155e..6526391f04326d93df99dd68f5c35c69de5d16c0 100644 --- a/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts @@ -7,12 +7,12 @@ import { Unit, Structure, Link, StructureElement } from 'mol-model/structure'; import { DefaultStructureProps, ComplexVisual, MeshUpdateState } from '..'; import { RuntimeContext } from 'mol-task' -import { Mesh } from '../../../shape/mesh'; +import { Mesh } from '../../../mesh/mesh'; import { PickingId } from '../../../util/picking'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { DefaultMeshProps } from '../../util'; import { Vec3 } from 'mol-math/linear-algebra'; -import { LocationIterator } from './util/location-iterator'; +import { LocationIterator } from '../../../util/location-iterator'; import { createLinkCylinderMesh, DefaultLinkCylinderProps, LinkCylinderProps } from './util/link'; import { OrderedSet, Interval } from 'mol-data/int'; import { ComplexMeshVisual } from '../complex-visual'; @@ -85,11 +85,11 @@ export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkProps> { function CarbohydrateLinkIterator(structure: Structure): LocationIterator { const { elements, links } = structure.carbohydrates - const elementCount = links.length + const groupCount = links.length const instanceCount = 1 const location = Link.Location() - const getLocation = (elementIndex: number, instanceIndex: number) => { - const link = links[elementIndex] + const getLocation = (groupIndex: number) => { + const link = links[groupIndex] const carbA = elements[link.carbohydrateIndexA] const carbB = elements[link.carbohydrateIndexB] const indexA = OrderedSet.findPredecessorIndex(carbA.unit.elements, carbA.anomericCarbon) @@ -100,14 +100,14 @@ function CarbohydrateLinkIterator(structure: Structure): LocationIterator { location.bIndex = indexB as StructureElement.UnitIndex return location } - return LocationIterator(elementCount, instanceCount, getLocation) + return LocationIterator(groupCount, instanceCount, getLocation) } function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { - const { objectId, elementId } = pickingId + const { objectId, groupId } = pickingId if (id === objectId) { const { links, elements } = structure.carbohydrates - const l = links[elementId] + const l = links[groupId] const carbA = elements[l.carbohydrateIndexA] const carbB = elements[l.carbohydrateIndexB] const indexA = OrderedSet.findPredecessorIndex(carbA.unit.elements, carbA.anomericCarbon) diff --git a/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts index 142791e62b0ad390e04ce01df6aee8b0a25f4a7b..6546a2b2ac14106953307cabfb2655f3db9b7311 100644 --- a/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts @@ -7,16 +7,22 @@ import { Unit, Structure, StructureElement } from 'mol-model/structure'; import { ComplexVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { Mesh } from '../../../shape/mesh'; +import { Mesh } from '../../../mesh/mesh'; import { PickingId } from '../../../util/picking'; import { Loci, EmptyLoci } from 'mol-model/loci'; -import { MeshBuilder } from '../../../shape/mesh-builder'; +import { MeshBuilder } from '../../../mesh/mesh-builder'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants'; -import { LocationIterator } from './util/location-iterator'; +import { LocationIterator } from '../../../util/location-iterator'; import { OrderedSet, Interval } from 'mol-data/int'; import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; +import { addSphere } from '../../../mesh/builder/sphere'; +import { Box, PerforatedBox } from '../../../primitive/box'; +import { OctagonalPyramid, PerforatedOctagonalPyramid } from '../../../primitive/pyramid'; +import { Star } from '../../../primitive/star'; +import { Octahedron, PerforatedOctahedron } from '../../../primitive/octahedron'; +import { DiamondPrism, PentagonalPrism, HexagonalPrism } from '../../../primitive/prism'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -25,6 +31,17 @@ const pd = Vec3.zero() const sideFactor = 1.75 * 2 * 0.806; // 0.806 == Math.cos(Math.PI / 4) const radiusFactor = 1.75 +const box = Box() +const perforatedBox = PerforatedBox() +const octagonalPyramid = OctagonalPyramid() +const perforatedOctagonalPyramid = PerforatedOctagonalPyramid() +const star = Star({ outerRadius: 1, innerRadius: 0.5, thickness: 0.5, pointCount: 5 }) +const octahedron = Octahedron() +const perforatedOctahedron = PerforatedOctahedron() +const diamondPrism = DiamondPrism() +const pentagonalPrism = PentagonalPrism() +const hexagonalPrism = HexagonalPrism() + async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Structure, props: CarbohydrateSymbolProps, mesh?: Mesh) { const builder = MeshBuilder.create(256, 128, mesh) @@ -49,71 +66,72 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru Mat4.targetTo(t, center, pd, normal) Mat4.setTranslation(t, center) - builder.setId(i * 2) + builder.setGroup(i * 2) switch (shapeType) { case SaccharideShapes.FilledSphere: - builder.addSphere(center, radius, detail) + addSphere(builder, center, radius, detail) break; case SaccharideShapes.FilledCube: Mat4.scaleUniformly(t, t, side) - builder.addBox(t) + builder.add(t, box) break; case SaccharideShapes.CrossedCube: Mat4.scaleUniformly(t, t, side) - builder.addPerforatedBox(t) + builder.add(t, perforatedBox) Mat4.mul(t, t, Mat4.rotZ90X180) - builder.setId(i * 2 + 1) - builder.addPerforatedBox(t) + builder.setGroup(i * 2 + 1) + builder.add(t, perforatedBox) break; case SaccharideShapes.FilledCone: Mat4.scaleUniformly(t, t, side * 1.2) - builder.addOctagonalPyramid(t) + builder.add(t, octagonalPyramid) break case SaccharideShapes.DevidedCone: Mat4.scaleUniformly(t, t, side * 1.2) - builder.addPerforatedOctagonalPyramid(t) + builder.add(t, perforatedOctagonalPyramid) Mat4.mul(t, t, Mat4.rotZ90) - builder.setId(i * 2 + 1) - builder.addPerforatedOctagonalPyramid(t) + builder.setGroup(i * 2 + 1) + builder.add(t, perforatedOctagonalPyramid) break case SaccharideShapes.FlatBox: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) - builder.addBox(t) + builder.add(t, box) break case SaccharideShapes.FilledStar: + Mat4.scaleUniformly(t, t, side) Mat4.mul(t, t, Mat4.rotZY90) - builder.addStar(t, { outerRadius: side, innerRadius: side / 2, thickness: side / 2, pointCount: 5 }) + builder.add(t, star) break case SaccharideShapes.FilledDiamond: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side * 1.4, side * 1.4, side * 1.4)) - builder.addOctahedron(t) + builder.add(t, octahedron) break case SaccharideShapes.DividedDiamond: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side * 1.4, side * 1.4, side * 1.4)) - builder.addPerforatedOctahedron(t) + builder.add(t, perforatedOctahedron) Mat4.mul(t, t, Mat4.rotY90) - builder.setId(i * 2 + 1) - builder.addPerforatedOctahedron(t) + builder.setGroup(i * 2 + 1) + builder.add(t, perforatedOctahedron) break case SaccharideShapes.FlatDiamond: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side, side / 2, side / 2)) - builder.addDiamondPrism(t) + builder.add(t, diamondPrism) break case SaccharideShapes.Pentagon: Mat4.mul(t, t, Mat4.rotZY90) Mat4.scale(t, t, Vec3.set(sVec, side, side, side / 2)) - builder.addPentagonalPrism(t) + builder.add(t, pentagonalPrism) break case SaccharideShapes.FlatHexagon: default: Mat4.mul(t, t, Mat4.rotZYZ90) Mat4.scale(t, t, Vec3.set(sVec, side / 1.5, side , side / 2)) - builder.addHexagonalPrism(t) + builder.add(t, hexagonalPrism) break } } @@ -142,11 +160,11 @@ export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolProp function CarbohydrateElementIterator(structure: Structure): LocationIterator { const carbElements = structure.carbohydrates.elements - const elementCount = carbElements.length * 2 + const groupCount = carbElements.length * 2 const instanceCount = 1 const location = StructureElement.create() - function getLocation (elementIndex: number, instanceIndex: number) { - const carb = carbElements[Math.floor(elementIndex / 2)] + function getLocation (groupIndex: number, instanceIndex: number) { + const carb = carbElements[Math.floor(groupIndex / 2)] location.unit = carb.unit location.element = carb.anomericCarbon return location @@ -154,13 +172,13 @@ function CarbohydrateElementIterator(structure: Structure): LocationIterator { function isSecondary (elementIndex: number, instanceIndex: number) { return (elementIndex % 2) === 1 } - return LocationIterator(elementCount, instanceCount, getLocation, isSecondary) + return LocationIterator(groupCount, instanceCount, getLocation, isSecondary) } function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: number) { - const { objectId, elementId } = pickingId + const { objectId, groupId } = pickingId if (id === objectId) { - const carb = structure.carbohydrates.elements[Math.floor(elementId / 2)] + const carb = structure.carbohydrates.elements[Math.floor(groupId / 2)] const { unit } = carb const index = OrderedSet.findPredecessorIndex(unit.elements, carb.anomericCarbon) const indices = OrderedSet.ofSingleton(index as StructureElement.UnitIndex) diff --git a/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts index de81e58df39a4d2da5573d99895442b6b651fbca..6bd885217c6132fbbdce6ed6ed481aeb68afda33 100644 --- a/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts @@ -8,12 +8,12 @@ import { Link, Structure, StructureElement } from 'mol-model/structure'; import { ComplexVisual, MeshUpdateState } from '..'; import { RuntimeContext } from 'mol-task' import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link'; -import { Mesh } from '../../../shape/mesh'; +import { Mesh } from '../../../mesh/mesh'; import { PickingId } from '../../../util/picking'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual'; -import { LocationIterator } from './util/location-iterator'; +import { LocationIterator } from '../../../util/location-iterator'; import { Interval } from 'mol-data/int'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; import { BitFlags } from 'mol-util'; @@ -73,24 +73,24 @@ export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintProp function CrossLinkRestraintIterator(structure: Structure): LocationIterator { const { pairs } = structure.crossLinkRestraints - const elementCount = pairs.length + const groupCount = pairs.length const instanceCount = 1 const location = Link.Location() - const getLocation = (elementIndex: number) => { - const pair = pairs[elementIndex] + const getLocation = (groupIndex: number) => { + const pair = pairs[groupIndex] location.aUnit = pair.unitA location.aIndex = pair.indexA location.bUnit = pair.unitB location.bIndex = pair.indexB return location } - return LocationIterator(elementCount, instanceCount, getLocation) + return LocationIterator(groupCount, instanceCount, getLocation) } function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { - const { objectId, elementId } = pickingId + const { objectId, groupId } = pickingId if (id === objectId) { - const pair = structure.crossLinkRestraints.pairs[elementId] + const pair = structure.crossLinkRestraints.pairs[groupId] if (pair) { return Link.Loci([ Link.Location(pair.unitA, pair.indexA, pair.unitB, pair.indexB) ]) } diff --git a/src/mol-geo/representation/structure/visual/element-point.ts b/src/mol-geo/representation/structure/visual/element-point.ts index 57306c4b9765092b471cead32cb6342c20023c26..e58f1bee17d71ac6a7605317fb6000a6ce448ca4 100644 --- a/src/mol-geo/representation/structure/visual/element-point.ts +++ b/src/mol-geo/representation/structure/visual/element-point.ts @@ -11,7 +11,7 @@ import { Unit } from 'mol-model/structure'; import { RuntimeContext } from 'mol-task' import { UnitsVisual, DefaultStructureProps } from '..'; -import { getElementLoci } from './util/element'; +import { getElementLoci, StructureElementIterator } from './util/element'; import { createTransforms, createColors, createSizes } from './util/common'; import { deepEqual, defaults } from 'mol-util'; import { SortedArray } from 'mol-data/int'; @@ -21,7 +21,6 @@ import { Loci } from 'mol-model/loci'; import { MarkerAction, createMarkers } from '../../../util/marker-data'; import { Vec3 } from 'mol-math/linear-algebra'; import { fillSerial } from 'mol-util/array'; -import { StructureElementIterator } from './util/location-iterator'; import { SizeThemeProps } from 'mol-view/theme/size'; export const DefaultPointProps = { @@ -79,16 +78,16 @@ export default function PointVisual(): UnitsVisual<PointProps> { const values: PointValues = { aPosition: ValueCell.create(vertices), - aElementId: ValueCell.create(fillSerial(new Float32Array(elementCount))), + aGroup: ValueCell.create(fillSerial(new Float32Array(elementCount))), aTransform: transforms, - aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + aInstance: ValueCell.create(fillSerial(new Float32Array(instanceCount))), ...color, ...marker, ...size, uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), uInstanceCount: ValueCell.create(instanceCount), - uElementCount: ValueCell.create(group.elements.length), + uGroupCount: ValueCell.create(group.elements.length), drawCount: ValueCell.create(vertices.length / 3), instanceCount: ValueCell.create(instanceCount), diff --git a/src/mol-geo/representation/structure/visual/element-sphere.ts b/src/mol-geo/representation/structure/visual/element-sphere.ts index 8f151ccf110b1511946edc83bb8c8f255dd701cc..523e19e1e3d62d8cc1a0c0ce6c3d1fdc4b699c14 100644 --- a/src/mol-geo/representation/structure/visual/element-sphere.ts +++ b/src/mol-geo/representation/structure/visual/element-sphere.ts @@ -6,8 +6,7 @@ */ import { UnitsVisual, MeshUpdateState } from '..'; -import { createElementSphereMesh, markElement, getElementLoci } from './util/element'; -import { StructureElementIterator } from './util/location-iterator'; +import { createElementSphereMesh, markElement, getElementLoci, StructureElementIterator } from './util/element'; import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; export const DefaultElementSphereProps = { diff --git a/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts b/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts index 40d6c5709e25357a57971fc5195683f53437671b..813da2a3b9ce6864298fe0e8424972e05ab97b7a 100644 --- a/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts @@ -7,12 +7,11 @@ import { Link, Structure, StructureElement } from 'mol-model/structure'; import { ComplexVisual, MeshUpdateState } from '..'; import { RuntimeContext } from 'mol-task' -import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link'; -import { Mesh } from '../../../shape/mesh'; +import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh, LinkIterator } from './util/link'; +import { Mesh } from '../../../mesh/mesh'; import { PickingId } from '../../../util/picking'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; -import { LinkIterator } from './util/location-iterator'; import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual'; import { Interval } from 'mol-data/int'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; @@ -70,9 +69,9 @@ export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkProps> { } function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { - const { objectId, elementId } = pickingId + const { objectId, groupId } = pickingId if (id === objectId) { - const bond = structure.links.bonds[elementId] + const bond = structure.links.bonds[groupId] return Link.Loci([ Link.Location( bond.unitA, bond.indexA as StructureElement.UnitIndex, diff --git a/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts b/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts index 12c1a7c0cc0734e417fc6cfabf1b9d5194e30a74..bf3e964bc6788f9b2f36e47324de31e147e6eb40 100644 --- a/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts @@ -8,12 +8,11 @@ import { Unit, Link, StructureElement } from 'mol-model/structure'; import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { DefaultLinkCylinderProps, LinkCylinderProps, createLinkCylinderMesh } from './util/link'; -import { Mesh } from '../../../shape/mesh'; +import { DefaultLinkCylinderProps, LinkCylinderProps, createLinkCylinderMesh, LinkIterator } from './util/link'; +import { Mesh } from '../../../mesh/mesh'; import { PickingId } from '../../../util/picking'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; -import { LinkIterator } from './util/location-iterator'; import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; import { Interval } from 'mol-data/int'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; @@ -82,13 +81,13 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> { } function getLinkLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { - const { objectId, instanceId, elementId } = pickingId + const { objectId, instanceId, groupId } = pickingId const unit = group.units[instanceId] if (id === objectId && Unit.isAtomic(unit)) { return Link.Loci([ Link.Location( - unit, unit.links.a[elementId] as StructureElement.UnitIndex, - unit, unit.links.b[elementId] as StructureElement.UnitIndex + unit, unit.links.a[groupId] as StructureElement.UnitIndex, + unit, unit.links.b[groupId] as StructureElement.UnitIndex ) ]) } diff --git a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts index eb4ffed1f450e0c598a74142f4fe8a5168c3f07b..0ace3c5262d2d6ad41fe037b03a982400857c89f 100644 --- a/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts +++ b/src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts @@ -7,15 +7,16 @@ import { Unit } from 'mol-model/structure'; import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { Mesh } from '../../../shape/mesh'; -import { MeshBuilder } from '../../../shape/mesh-builder'; -import { getElementLoci, markElement } from './util/element'; +import { Mesh } from '../../../mesh/mesh'; +import { MeshBuilder } from '../../../mesh/mesh-builder'; +import { getElementLoci, markElement, StructureElementIterator } from './util/element'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { Segmentation, SortedArray } from 'mol-data/int'; import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types'; import { getElementIndexForAtomId, getElementIndexForAtomRole } from 'mol-model/structure/util'; -import { StructureElementIterator } from './util/location-iterator'; import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; +import { addCylinder } from '../../../mesh/builder/cylinder'; +import { Box } from '../../../primitive/box'; const p1 = Vec3.zero() const p2 = Vec3.zero() @@ -29,7 +30,9 @@ const vC = Vec3.zero() const center = Vec3.zero() const t = Mat4.identity() const sVec = Vec3.zero() +const box = Box() +// TODO define props, should be scalable async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, props: {}, mesh?: Mesh) { if (!Unit.isAtomic(unit)) return Mesh.createEmpty(mesh) @@ -88,9 +91,9 @@ async function createNucleotideBlockMesh(ctx: RuntimeContext, unit: Unit, props: Vec3.scaleAndAdd(center, p1, v12, height / 2 - 0.2) Mat4.scale(t, t, Vec3.set(sVec, width, depth, height)) Mat4.setTranslation(t, center) - builder.setId(SortedArray.findPredecessorIndex(elements, idx6)) - builder.addBox(t) - builder.addCylinder(p5, p6, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) + builder.setGroup(SortedArray.findPredecessorIndex(elements, idx6)) + builder.add(t, box) + addCylinder(builder, p5, p6, 1, { radiusTop: 0.2, radiusBottom: 0.2 }) } } diff --git a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts index a80dae5b8a1882a6e93e797c749797873a1f8367..e3b1b00ae8c4923e157908bd9ecd404e10285b79 100644 --- a/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts @@ -7,16 +7,16 @@ import { Unit } from 'mol-model/structure'; import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { Mesh } from '../../../shape/mesh'; -import { MeshBuilder } from '../../../shape/mesh-builder'; +import { Mesh } from '../../../mesh/mesh'; +import { MeshBuilder } from '../../../mesh/mesh-builder'; import { getPolymerElementCount, PolymerBackboneIterator } from './util/polymer'; -import { getElementLoci, markElement } from './util/element'; +import { getElementLoci, markElement, StructureElementIterator } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; -import { StructureElementIterator } from './util/location-iterator'; import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; import { CylinderProps } from '../../../primitive/cylinder'; import { OrderedSet } from 'mol-data/int'; +import { addCylinder } from '../../../mesh/builder/cylinder'; export interface PolymerBackboneCylinderProps { sizeTheme: SizeThemeProps @@ -47,12 +47,12 @@ async function createPolymerBackboneCylinderMesh(ctx: RuntimeContext, unit: Unit pos(centerB.element, pB) cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerA) - builder.setId(OrderedSet.findPredecessorIndex(elements, centerA.element)) - builder.addCylinder(pA, pB, 0.5, cylinderProps) + builder.setGroup(OrderedSet.findPredecessorIndex(elements, centerA.element)) + addCylinder(builder, pA, pB, 0.5, cylinderProps) cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(centerB) - builder.setId(OrderedSet.findPredecessorIndex(elements, centerB.element)) - builder.addCylinder(pB, pA, 0.5, cylinderProps) + builder.setGroup(OrderedSet.findPredecessorIndex(elements, centerB.element)) + addCylinder(builder, pB, pA, 0.5, cylinderProps) if (i % 10000 === 0 && ctx.shouldUpdate) { await ctx.update({ message: 'Backbone mesh', current: i, max: polymerElementCount }); diff --git a/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts index b6eaf79647a2004288a76212be17ce0f6090618a..6ad043eba547f99896cfbc6e620c709b76dfcc7d 100644 --- a/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts +++ b/src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts @@ -7,16 +7,16 @@ import { Unit } from 'mol-model/structure'; import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { markElement, getElementLoci } from './util/element'; -import { Mesh } from '../../../shape/mesh'; -import { MeshBuilder } from '../../../shape/mesh-builder'; +import { markElement, getElementLoci, StructureElementIterator } from './util/element'; +import { Mesh } from '../../../mesh/mesh'; +import { MeshBuilder } from '../../../mesh/mesh-builder'; import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; -import { StructureElementIterator } from './util/location-iterator'; import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; import { OrderedSet } from 'mol-data/int'; +import { Wedge } from '../../../primitive/wedge'; const t = Mat4.identity() const sVec = Vec3.zero() @@ -28,6 +28,8 @@ const depthFactor = 4 const widthFactor = 4 const heightFactor = 6 +const wedge = Wedge() + export interface PolymerDirectionWedgeProps { sizeTheme: SizeThemeProps } @@ -49,7 +51,7 @@ async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, const polymerTraceIt = PolymerTraceIterator(unit) while (polymerTraceIt.hasNext) { const v = polymerTraceIt.move() - builder.setId(OrderedSet.findPredecessorIndex(unit.elements, v.center.element)) + builder.setGroup(OrderedSet.findPredecessorIndex(unit.elements, v.center.element)) const isNucleic = v.moleculeType === MoleculeType.DNA || v.moleculeType === MoleculeType.RNA const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) @@ -72,7 +74,7 @@ async function createPolymerDirectionWedgeMesh(ctx: RuntimeContext, unit: Unit, Mat4.mul(t, t, Mat4.rotY90Z180) Mat4.scale(t, t, Vec3.set(sVec, height, width, depth)) Mat4.setTranslation(t, v.p2) - builder.addWedge(t) + builder.add(t, wedge) } if (i % 10000 === 0 && ctx.shouldUpdate) { diff --git a/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts b/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts index f5a12fdc6673a805a0e2a2c252ac2dc3b54476a1..047850c67aae193be0cb0035aed18925e054bfcd 100644 --- a/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts +++ b/src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts @@ -7,15 +7,16 @@ import { Unit, StructureElement } from 'mol-model/structure'; import { UnitsVisual } from '..'; import { RuntimeContext } from 'mol-task' -import { Mesh } from '../../../shape/mesh'; -import { MeshBuilder } from '../../../shape/mesh-builder'; +import { Mesh } from '../../../mesh/mesh'; +import { MeshBuilder } from '../../../mesh/mesh-builder'; import { getPolymerGapCount, PolymerGapIterator } from './util/polymer'; -import { getElementLoci, markElement } from './util/element'; +import { getElementLoci, markElement, StructureElementIterator } from './util/element'; import { Vec3 } from 'mol-math/linear-algebra'; -import { StructureElementIterator } from './util/location-iterator'; import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; import { CylinderProps } from '../../../primitive/cylinder'; +import { addSphere } from '../../../mesh/builder/sphere'; +import { addFixedCountDashedCylinder } from '../../../mesh/builder/cylinder'; const segmentCount = 10 @@ -48,9 +49,9 @@ async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, pro while (polymerGapIt.hasNext) { const { centerA, centerB } = polymerGapIt.move() if (centerA.element === centerB.element) { - builder.setId(centerA.element) + builder.setGroup(centerA.element) pos(elements[centerA.element], pA) - builder.addSphere(pA, 0.6, 0) + addSphere(builder, pA, 0.6, 0) } else { const elmA = elements[centerA.element] const elmB = elements[centerB.element] @@ -59,13 +60,13 @@ async function createPolymerGapCylinderMesh(ctx: RuntimeContext, unit: Unit, pro l.element = elmA cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(l) - builder.setId(centerA.element) - builder.addFixedCountDashedCylinder(pA, pB, 0.5, segmentCount, cylinderProps) + builder.setGroup(centerA.element) + addFixedCountDashedCylinder(builder, pA, pB, 0.5, segmentCount, cylinderProps) l.element = elmB cylinderProps.radiusTop = cylinderProps.radiusBottom = sizeTheme.size(l) - builder.setId(centerB.element) - builder.addFixedCountDashedCylinder(pB, pA, 0.5, segmentCount, cylinderProps) + builder.setGroup(centerB.element) + addFixedCountDashedCylinder(builder, pB, pA, 0.5, segmentCount, cylinderProps) } if (i % 10000 === 0 && ctx.shouldUpdate) { diff --git a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts index da04a008c769a1214ee024875f64ee4dbe317e84..f65c7fb9cb36488df559bbe8a412d1ee03bd81f6 100644 --- a/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts +++ b/src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts @@ -7,15 +7,16 @@ import { Unit } from 'mol-model/structure'; import { UnitsVisual, MeshUpdateState } from '..'; import { RuntimeContext } from 'mol-task' -import { markElement, getElementLoci } from './util/element'; -import { Mesh } from '../../../shape/mesh'; -import { MeshBuilder } from '../../../shape/mesh-builder'; +import { markElement, getElementLoci, StructureElementIterator } from './util/element'; +import { Mesh } from '../../../mesh/mesh'; +import { MeshBuilder } from '../../../mesh/mesh-builder'; import { getPolymerElementCount, PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment } from './util/polymer'; -import { SecondaryStructureType, MoleculeType } from 'mol-model/structure/model/types'; -import { StructureElementIterator } from './util/location-iterator'; +import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types'; import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual'; import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size'; import { OrderedSet } from 'mol-data/int'; +import { addSheet } from '../../../mesh/builder/sheet'; +import { addTube } from '../../../mesh/builder/tube'; export interface PolymerTraceMeshProps { sizeTheme: SizeThemeProps @@ -44,12 +45,12 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, props: Po const polymerTraceIt = PolymerTraceIterator(unit) while (polymerTraceIt.hasNext) { const v = polymerTraceIt.move() - builder.setId(OrderedSet.findPredecessorIndex(unit.elements, v.center.element)) + builder.setGroup(OrderedSet.findPredecessorIndex(unit.elements, v.center.element)) - const isNucleic = v.moleculeType === MoleculeType.DNA || v.moleculeType === MoleculeType.RNA + const isNucleicType = isNucleic(v.moleculeType) const isSheet = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Beta) const isHelix = SecondaryStructureType.is(v.secStrucType, SecondaryStructureType.Flag.Helix) - const tension = (isNucleic || isSheet) ? 0.5 : 0.9 + const tension = (isNucleicType || isSheet) ? 0.5 : 0.9 interpolateCurveSegment(state, v, tension) @@ -58,18 +59,18 @@ async function createPolymerTraceMesh(ctx: RuntimeContext, unit: Unit, props: Po if (isSheet) { const height = width * aspectRatio const arrowHeight = v.secStrucChange ? height * arrowFactor : 0 - builder.addSheet(curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, true, true) + addSheet(builder, curvePoints, normalVectors, binormalVectors, linearSegments, width, height, arrowHeight, true, true) } else { let height: number if (isHelix) { height = width * aspectRatio - } else if (isNucleic) { + } else if (isNucleicType) { height = width * aspectRatio; [width, height] = [height, width] } else { height = width } - builder.addTube(curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true) + addTube(builder, curvePoints, normalVectors, binormalVectors, linearSegments, radialSegments, width, height, 1, true, true) } if (i % 10000 === 0 && ctx.shouldUpdate) { diff --git a/src/mol-geo/representation/structure/visual/util/common.ts b/src/mol-geo/representation/structure/visual/util/common.ts index fb7f11bf733b6055d8968d4c2dd7b5231608810a..e069563c8771d3a7d6281a4f91720be24a3b6c27 100644 --- a/src/mol-geo/representation/structure/visual/util/common.ts +++ b/src/mol-geo/representation/structure/visual/util/common.ts @@ -8,14 +8,14 @@ import { Unit, Structure } from 'mol-model/structure'; import { Mat4 } from 'mol-math/linear-algebra' -import { createUniformColor, ColorData, createElementColor, createElementInstanceColor, createInstanceColor } from '../../../../util/color-data'; -import { createUniformSize, SizeData, createElementSize, createElementInstanceSize, createInstanceSize } from '../../../../util/size-data'; +import { createUniformColor, ColorData, createGroupColor, createGroupInstanceColor, createInstanceColor } from '../../../../util/color-data'; +import { createUniformSize, SizeData, createGroupSize, createGroupInstanceSize, createInstanceSize } from '../../../../util/size-data'; import { ValueCell } from 'mol-util'; -import { LocationIterator } from './location-iterator'; -import { Mesh } from '../../../../shape/mesh'; +import { LocationIterator } from '../../../../util/location-iterator'; +import { Mesh } from '../../../../mesh/mesh'; import { MeshValues } from 'mol-gl/renderable'; import { getMeshData } from '../../../../util/mesh-data'; -import { MeshProps, createMeshValues, createRenderableState } from '../../../util'; +import { MeshProps, createMeshValues, createRenderableState, createIdentityTransform } from '../../../util'; import { StructureProps } from '../..'; import { createMarkers } from '../../../../util/marker-data'; import { createMeshRenderObject } from 'mol-gl/render-object'; @@ -32,18 +32,12 @@ export function createTransforms({ units }: Unit.SymmetryGroup, transforms?: Val return transforms ? ValueCell.update(transforms, array) : ValueCell.create(array) } -const identityTransform = new Float32Array(16) -Mat4.toArray(Mat4.identity(), identityTransform, 0) -export function createIdentityTransform(transforms?: ValueCell<Float32Array>) { - return transforms ? ValueCell.update(transforms, identityTransform) : ValueCell.create(identityTransform) -} - export function createColors(locationIt: LocationIterator, props: ColorThemeProps, colorData?: ColorData) { const colorTheme = ColorTheme(props) switch (colorTheme.kind) { case 'uniform': return createUniformColor(locationIt, colorTheme.color, colorData) - case 'element': return createElementColor(locationIt, colorTheme.color, colorData) - case 'elementInstance': return createElementInstanceColor(locationIt, colorTheme.color, colorData) + case 'group': return createGroupColor(locationIt, colorTheme.color, colorData) + case 'groupInstance': return createGroupInstanceColor(locationIt, colorTheme.color, colorData) case 'instance': return createInstanceColor(locationIt, colorTheme.color, colorData) } } @@ -52,8 +46,8 @@ export function createSizes(locationIt: LocationIterator, props: SizeThemeProps, const sizeTheme = SizeTheme(props) switch (sizeTheme.kind) { case 'uniform': return createUniformSize(locationIt, sizeTheme.size, sizeData) - case 'element': return createElementSize(locationIt, sizeTheme.size, sizeData) - case 'elementInstance': return createElementInstanceSize(locationIt, sizeTheme.size, sizeData) + case 'group': return createGroupSize(locationIt, sizeTheme.size, sizeData) + case 'groupInstance': return createGroupInstanceSize(locationIt, sizeTheme.size, sizeData) case 'instance': return createInstanceSize(locationIt, sizeTheme.size, sizeData) } } @@ -61,11 +55,11 @@ export function createSizes(locationIt: LocationIterator, props: SizeThemeProps, type StructureMeshProps = Required<MeshProps & StructureProps> function _createMeshValues(transforms: ValueCell<Float32Array>, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): MeshValues { - const { instanceCount, elementCount } = locationIt + const { instanceCount, groupCount } = locationIt const color = createColors(locationIt, props.colorTheme) - const marker = createMarkers(instanceCount * elementCount) + const marker = createMarkers(instanceCount * groupCount) - const counts = { drawCount: mesh.triangleCount * 3, elementCount, instanceCount } + const counts = { drawCount: mesh.triangleCount * 3, groupCount, instanceCount } return { ...getMeshData(mesh), diff --git a/src/mol-geo/representation/structure/visual/util/element.ts b/src/mol-geo/representation/structure/visual/util/element.ts index 89934754869f743e1321cadd11697e14e4296517..d469d6f2f53d63d0233fcf6c3defd0122c4483dc 100644 --- a/src/mol-geo/representation/structure/visual/util/element.ts +++ b/src/mol-geo/representation/structure/visual/util/element.ts @@ -8,12 +8,14 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { Unit, StructureElement } from 'mol-model/structure'; import { RuntimeContext } from 'mol-task'; import { sphereVertexCount } from '../../../../primitive/sphere'; -import { Mesh } from '../../../../shape/mesh'; -import { MeshBuilder } from '../../../../shape/mesh-builder'; +import { Mesh } from '../../../../mesh/mesh'; +import { MeshBuilder } from '../../../../mesh/mesh-builder'; import { Loci, EmptyLoci } from 'mol-model/loci'; import { Interval, OrderedSet } from 'mol-data/int'; import { PickingId } from '../../../../util/picking'; import { SizeTheme, SizeThemeProps } from 'mol-view/theme/size'; +import { LocationIterator } from '../../../../util/location-iterator'; +import { addSphere } from '../../../../mesh/builder/sphere'; export interface ElementSphereMeshProps { sizeTheme: SizeThemeProps, @@ -38,8 +40,8 @@ export async function createElementSphereMesh(ctx: RuntimeContext, unit: Unit, p l.element = elements[i] pos(elements[i], v) - meshBuilder.setId(i) - meshBuilder.addSphere(v, sizeTheme.size(l), detail) + meshBuilder.setGroup(i) + addSphere(meshBuilder, v, sizeTheme.size(l), detail) if (i % 10000 === 0 && ctx.shouldUpdate) { await ctx.update({ message: 'Sphere mesh', current: i, max: elementCount }); @@ -74,11 +76,25 @@ export function markElement(loci: Loci, group: Unit.SymmetryGroup, apply: (inter } export function getElementLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { - const { objectId, instanceId, elementId } = pickingId + const { objectId, instanceId, groupId } = pickingId if (id === objectId) { const unit = group.units[instanceId] - const indices = OrderedSet.ofSingleton(elementId as StructureElement.UnitIndex); + const indices = OrderedSet.ofSingleton(groupId as StructureElement.UnitIndex); return StructureElement.Loci([{ unit, indices }]) } return EmptyLoci +} + +export namespace StructureElementIterator { + export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { + const unit = group.units[0] + const groupCount = group.elements.length + const instanceCount = group.units.length + const location = StructureElement.create(unit) + const getLocation = (groupIndex: number) => { + location.element = unit.elements[groupIndex] + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } } \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/link.ts b/src/mol-geo/representation/structure/visual/util/link.ts index fa687917bbe58f663a6f17704de70c78d5a1341e..865e52d99668e5d38d9c950928953049444e2253 100644 --- a/src/mol-geo/representation/structure/visual/util/link.ts +++ b/src/mol-geo/representation/structure/visual/util/link.ts @@ -6,12 +6,15 @@ import { Vec3 } from 'mol-math/linear-algebra'; import { RuntimeContext } from 'mol-task'; -import { Mesh } from '../../../../shape/mesh'; -import { MeshBuilder } from '../../../../shape/mesh-builder'; +import { Mesh } from '../../../../mesh/mesh'; +import { MeshBuilder } from '../../../../mesh/mesh-builder'; import { LinkType } from 'mol-model/structure/model/types'; import { DefaultMeshProps } from '../../../util'; import { SizeThemeProps } from 'mol-view/theme/size'; import { CylinderProps } from '../../../../primitive/cylinder'; +import { LocationIterator } from '../../../../util/location-iterator'; +import { Unit, StructureElement, Structure, Link } from 'mol-model/structure'; +import { addFixedCountDashedCylinder, addCylinder, addDoubleCylinder } from '../../../../mesh/builder/cylinder'; export const DefaultLinkCylinderProps = { ...DefaultMeshProps, @@ -87,12 +90,12 @@ export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: L const linkRadius = radius(edgeIndex) const o = order(edgeIndex) const f = flags(edgeIndex) - meshBuilder.setId(edgeIndex) + meshBuilder.setGroup(edgeIndex) - if (LinkType.is(f, LinkType.Flag.MetallicCoordination)) { - // show metall coordinations with dashed cylinders + if (LinkType.is(f, LinkType.Flag.MetallicCoordination) || LinkType.is(f, LinkType.Flag.Hydrogen)) { + // show metall coordinations and hydrogen bonds with dashed cylinders cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius / 3 - meshBuilder.addFixedCountDashedCylinder(va, vb, 0.5, 7, cylinderProps) + addFixedCountDashedCylinder(meshBuilder, va, vb, 0.5, 7, cylinderProps) } else if (o === 2 || o === 3) { // show bonds with order 2 or 3 using 2 or 3 parallel cylinders const multiRadius = linkRadius * (linkScale / (0.5 * o)) @@ -103,11 +106,11 @@ export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: L cylinderProps.radiusTop = cylinderProps.radiusBottom = multiRadius - if (o === 3) meshBuilder.addCylinder(va, vb, 0.5, cylinderProps) - meshBuilder.addDoubleCylinder(va, vb, 0.5, vShift, cylinderProps) + if (o === 3) addCylinder(meshBuilder, va, vb, 0.5, cylinderProps) + addDoubleCylinder(meshBuilder, va, vb, 0.5, vShift, cylinderProps) } else { cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius - meshBuilder.addCylinder(va, vb, 0.5, cylinderProps) + addCylinder(meshBuilder, va, vb, 0.5, cylinderProps) } if (edgeIndex % 10000 === 0 && ctx.shouldUpdate) { @@ -116,4 +119,33 @@ export async function createLinkCylinderMesh(ctx: RuntimeContext, linkBuilder: L } return meshBuilder.getMesh() +} + +export namespace LinkIterator { + export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { + const unit = group.units[0] + const groupCount = Unit.isAtomic(unit) ? unit.links.edgeCount * 2 : 0 + const instanceCount = group.units.length + const location = StructureElement.create(unit) + const getLocation = (groupIndex: number) => { + location.element = unit.elements[(unit as Unit.Atomic).links.a[groupIndex]] + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } + + export function fromStructure(structure: Structure): LocationIterator { + const groupCount = structure.links.bondCount + const instanceCount = 1 + const location = Link.Location() + const getLocation = (groupIndex: number) => { + const bond = structure.links.bonds[groupIndex] + location.aUnit = bond.unitA + location.aIndex = bond.indexA as StructureElement.UnitIndex + location.bUnit = bond.unitB + location.bIndex = bond.indexB as StructureElement.UnitIndex + return location + } + return LocationIterator(groupCount, instanceCount, getLocation) + } } \ No newline at end of file diff --git a/src/mol-geo/representation/structure/visual/util/location-iterator.ts b/src/mol-geo/representation/structure/visual/util/location-iterator.ts deleted file mode 100644 index aad0da64abdedce9ec3d4221379b91f56e256255..0000000000000000000000000000000000000000 --- a/src/mol-geo/representation/structure/visual/util/location-iterator.ts +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { Iterator } from 'mol-data'; -import { Unit, StructureElement, Structure, Link } from 'mol-model/structure'; -import { NullLocation, Location } from 'mol-model/location'; - -export interface LocationValue { - location: Location - index: number - elementIndex: number - instanceIndex: number - isSecondary: boolean -} - -export const NullLocationValue: LocationValue = { - location: NullLocation, - index: 0, - elementIndex: 0, - instanceIndex: 0, - isSecondary: false -} - -export interface LocationIterator extends Iterator<LocationValue> { - readonly hasNext: boolean - readonly isNextNewInstance: boolean - readonly elementCount: number - readonly instanceCount: number - move(): LocationValue - reset(): void - skipInstance(): void -} - -type LocationGetter = (elementIndex: number, instanceIndex: number) => Location -type IsSecondaryGetter = (elementIndex: number, instanceIndex: number) => boolean - -export function LocationIterator(elementCount: number, instanceCount: number, getLocation: LocationGetter, isSecondary: IsSecondaryGetter = () => false): LocationIterator { - const value: LocationValue = { - location: NullLocation as Location, - index: 0, - elementIndex: 0, - instanceIndex: 0, - isSecondary: false - } - - let hasNext = value.elementIndex < elementCount - let isNextNewInstance = false - let elementIndex = 0 - let instanceIndex = 0 - - return { - get hasNext () { return hasNext }, - get isNextNewInstance () { return isNextNewInstance }, - get elementCount () { return elementCount }, - get instanceCount () { return instanceCount }, - move() { - if (hasNext) { - value.elementIndex = elementIndex - value.instanceIndex = instanceIndex - value.index = instanceIndex * elementCount + elementIndex - value.location = getLocation(elementIndex, instanceIndex) - value.isSecondary = isSecondary(elementIndex, instanceIndex) - ++elementIndex - if (elementIndex === elementCount) { - ++instanceIndex - isNextNewInstance = true - if (instanceIndex < instanceCount) elementIndex = 0 - } else { - isNextNewInstance = false - } - hasNext = elementIndex < elementCount - } - return value - }, - reset() { - value.location = NullLocation - value.index = 0 - value.elementIndex = 0 - value.instanceIndex = 0 - value.isSecondary = false - - hasNext = value.elementIndex < elementCount - isNextNewInstance = false - elementIndex = 0 - instanceIndex = 0 - }, - skipInstance() { - if (hasNext && value.instanceIndex === instanceIndex) { - ++instanceIndex - elementIndex = 0 - hasNext = instanceIndex < instanceCount - } - } - } -} - -export namespace StructureElementIterator { - export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { - const unit = group.units[0] - const elementCount = group.elements.length - const instanceCount = group.units.length - const location = StructureElement.create(unit) - const getLocation = (elementIndex: number) => { - location.element = unit.elements[elementIndex] - return location - } - return LocationIterator(elementCount, instanceCount, getLocation) - } -} - -export namespace LinkIterator { - export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { - const unit = group.units[0] - const elementCount = Unit.isAtomic(unit) ? unit.links.edgeCount * 2 : 0 - const instanceCount = group.units.length - const location = StructureElement.create(unit) - const getLocation = (elementIndex: number) => { - location.element = unit.elements[(unit as Unit.Atomic).links.a[elementIndex]] - return location - } - return LocationIterator(elementCount, instanceCount, getLocation) - } - - export function fromStructure(structure: Structure): LocationIterator { - const elementCount = structure.links.bondCount - const instanceCount = 1 - const location = Link.Location() - const getLocation = (elementIndex: number) => { - const bond = structure.links.bonds[elementIndex] - location.aUnit = bond.unitA - location.aIndex = bond.indexA as StructureElement.UnitIndex - location.bUnit = bond.unitB - location.bIndex = bond.indexB as StructureElement.UnitIndex - return location - } - return LocationIterator(elementCount, instanceCount, getLocation) - } -} \ No newline at end of file diff --git a/src/mol-geo/representation/util.ts b/src/mol-geo/representation/util.ts index 13d34ebeccba7dae263d2b78e32fd55dca4fc02c..4edca150e52f42e76d67a5b28fd3f76754d4ed19 100644 --- a/src/mol-geo/representation/util.ts +++ b/src/mol-geo/representation/util.ts @@ -10,6 +10,7 @@ import { MeshValues, RenderableState } from 'mol-gl/renderable'; import { defaults } from 'mol-util'; import { Structure } from 'mol-model/structure'; import { fillSerial } from 'mol-util/array'; +import { Mat4 } from 'mol-math/linear-algebra'; export const DefaultBaseProps = { alpha: 1, @@ -28,14 +29,20 @@ export const DefaultMeshProps = { } export type MeshProps = typeof DefaultMeshProps -type Counts = { drawCount: number, elementCount: number, instanceCount: number } +const identityTransform = new Float32Array(16) +Mat4.toArray(Mat4.identity(), identityTransform, 0) +export function createIdentityTransform(transforms?: ValueCell<Float32Array>) { + return transforms ? ValueCell.update(transforms, identityTransform) : ValueCell.create(identityTransform) +} + +type Counts = { drawCount: number, groupCount: number, instanceCount: number } export function createBaseValues(props: Required<BaseProps>, counts: Counts) { return { uAlpha: ValueCell.create(props.alpha), uInstanceCount: ValueCell.create(counts.instanceCount), - uElementCount: ValueCell.create(counts.elementCount), - aInstanceId: ValueCell.create(fillSerial(new Float32Array(counts.instanceCount))), + uGroupCount: ValueCell.create(counts.groupCount), + aInstance: ValueCell.create(fillSerial(new Float32Array(counts.instanceCount))), drawCount: ValueCell.create(counts.drawCount), instanceCount: ValueCell.create(counts.instanceCount), } diff --git a/src/mol-geo/representation/volume/surface.ts b/src/mol-geo/representation/volume/surface.ts index 82e1a5e25afe79e404090c57ccc08157740ebed8..1d289273d6e5783431b9185c98c8d09c3d1778ae 100644 --- a/src/mol-geo/representation/volume/surface.ts +++ b/src/mol-geo/representation/volume/surface.ts @@ -8,7 +8,7 @@ import { VolumeData, VolumeIsoValue } from 'mol-model/volume' import { Task, RuntimeContext } from 'mol-task' import { computeMarchingCubes } from '../../util/marching-cubes/algorithm'; -import { Mesh } from '../../shape/mesh'; +import { Mesh } from '../../mesh/mesh'; import { VolumeVisual } from '.'; import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object'; import { ValueCell, defaults } from 'mol-util'; @@ -72,13 +72,13 @@ export default function SurfaceVisual(): VolumeVisual<SurfaceProps> { const values: MeshValues = { ...getMeshData(mesh), aTransform: ValueCell.create(new Float32Array(Mat4.identity())), - aInstanceId: ValueCell.create(fillSerial(new Float32Array(instanceCount))), + aInstance: ValueCell.create(fillSerial(new Float32Array(instanceCount))), ...color, ...marker, uAlpha: ValueCell.create(defaults(props.alpha, 1.0)), uInstanceCount: ValueCell.create(instanceCount), - uElementCount: ValueCell.create(mesh.triangleCount), + uGroupCount: ValueCell.create(mesh.triangleCount), elements: mesh.indexBuffer, diff --git a/src/mol-geo/shape/mesh-builder.ts b/src/mol-geo/shape/mesh-builder.ts deleted file mode 100644 index f3dafe8a41d33153039a6af87bb1dee4bfd44e81..0000000000000000000000000000000000000000 --- a/src/mol-geo/shape/mesh-builder.ts +++ /dev/null @@ -1,279 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { ValueCell } from 'mol-util/value-cell' -import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra'; -import { ChunkedArray } from 'mol-data/util'; - -import { Plane, PlaneProps } from '../primitive/plane'; -import { Cylinder, CylinderProps } from '../primitive/cylinder'; -import { Sphere, SphereProps } from '../primitive/sphere'; -import { Mesh } from './mesh'; -import { getNormalMatrix } from '../util'; -import { addSheet } from '../primitive/sheet'; -import { addTube } from '../primitive/tube'; -import { StarProps, Star } from '../primitive/star'; -import { Octahedron, PerforatedOctahedron } from '../primitive/octahedron'; -import { Primitive } from '../primitive/primitive'; -import { DiamondPrism, PentagonalPrism, HexagonalPrism } from '../primitive/prism'; -import { OctagonalPyramide, PerforatedOctagonalPyramide } from '../primitive/pyramid'; -import { PerforatedBox, Box } from '../primitive/box'; -import { Wedge } from '../primitive/wedge'; - -export interface MeshBuilderState { - vertices: ChunkedArray<number, 3> - normals: ChunkedArray<number, 3> - indices: ChunkedArray<number, 3> -} - -export interface MeshBuilder { - add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices?: ArrayLike<number>): void - addBox(t: Mat4): void - addPerforatedBox(t: Mat4): void - addPlane(t: Mat4, props?: PlaneProps): void - addWedge(t: Mat4): void - addDiamondPrism(t: Mat4): void - addPentagonalPrism(t: Mat4): void - addHexagonalPrism(t: Mat4): void - addOctagonalPyramid(t: Mat4): void - addPerforatedOctagonalPyramid(t: Mat4): void - addStar(t: Mat4, props?: StarProps): void - addOctahedron(t: Mat4): void - addPerforatedOctahedron(t: Mat4): void - addCylinder(start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps): void - addDoubleCylinder(start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps): void - addFixedCountDashedCylinder(start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps): void - addSphere(center: Vec3, radius: number, detail: number): void - addTube(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean): void - addSheet(centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean): void - setId(id: number): void - getMesh(): Mesh -} - -const cylinderMap = new Map<string, Primitive>() -const sphereMap = new Map<string, Primitive>() - -const up = Vec3.create(0, 1, 0) -const tmpV = Vec3.zero() -const tmpMat3 = Mat3.zero() - -const tmpCylinderDir = Vec3.zero() -const tmpCylinderMatDir = Vec3.zero() -const tmpCylinderCenter = Vec3.zero() -const tmpCylinderMat = Mat4.zero() -// const tmpCylinderMatTrans = Mat4.zero() -const tmpCylinderStart = Vec3.zero() -const tmpUp = Vec3.zero() - -function setCylinderMat(m: Mat4, start: Vec3, dir: Vec3, length: number) { - Vec3.setMagnitude(tmpCylinderMatDir, dir, length / 2) - Vec3.add(tmpCylinderCenter, start, tmpCylinderMatDir) - // ensure the direction used to create the rotation is always pointing in the same - // direction so the triangles of adjacent cylinder will line up - Vec3.copy(tmpUp, up) - if (Vec3.dot(tmpCylinderMatDir, tmpUp) < 0) Vec3.scale(tmpUp, tmpUp, -1) - Vec3.makeRotation(m, tmpUp, tmpCylinderMatDir) - return Mat4.setTranslation(m, tmpCylinderCenter) -} - -function getCylinder(props: CylinderProps) { - const key = JSON.stringify(props) - let cylinder = cylinderMap.get(key) - if (cylinder === undefined) { - cylinder = Cylinder(props) - cylinderMap.set(key, cylinder) - } - return cylinder -} - -const tmpSphereMat = Mat4.identity() - -function setSphereMat(m: Mat4, center: Vec3) { - return Mat4.setTranslation(m, center) -} - -function getSphere(props: SphereProps) { - const key = JSON.stringify(props) - let sphere = sphereMap.get(key) - if (sphere === undefined) { - sphere = Sphere(props) - sphereMap.set(key, sphere) - } - return sphere -} - -// TODO cache primitives based on props - -export namespace MeshBuilder { - export function create(initialCount = 2048, chunkSize = 1024, mesh?: Mesh): MeshBuilder { - const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.vertexBuffer.ref.value : initialCount); - const normals = ChunkedArray.create(Float32Array, 3, chunkSize, mesh ? mesh.normalBuffer.ref.value : initialCount); - const indices = ChunkedArray.create(Uint32Array, 3, chunkSize * 3, mesh ? mesh.indexBuffer.ref.value : initialCount * 3); - const state: MeshBuilderState = { vertices, normals, indices }; - - const ids = ChunkedArray.create(Float32Array, 1, chunkSize, mesh ? mesh.idBuffer.ref.value : initialCount); - const offsets = ChunkedArray.create(Uint32Array, 1, chunkSize, mesh ? mesh.offsetBuffer.ref.value : initialCount); - - let currentId = -1 - - function add(t: Mat4, _vertices: ArrayLike<number>, _normals: ArrayLike<number>, _indices: ArrayLike<number>) { - const { elementCount } = vertices - const n = getNormalMatrix(tmpMat3, t) - for (let i = 0, il = _vertices.length; i < il; i += 3) { - // position - Vec3.fromArray(tmpV, _vertices, i) - Vec3.transformMat4(tmpV, tmpV, t) - ChunkedArray.add3(vertices, tmpV[0], tmpV[1], tmpV[2]); - // normal - Vec3.fromArray(tmpV, _normals, i) - Vec3.transformMat3(tmpV, tmpV, n) - ChunkedArray.add3(normals, tmpV[0], tmpV[1], tmpV[2]); - // id - ChunkedArray.add(ids, currentId); - } - for (let i = 0, il = _indices.length; i < il; i += 3) { - ChunkedArray.add3(indices, _indices[i] + elementCount, _indices[i + 1] + elementCount, _indices[i + 2] + elementCount); - } - } - - return { - add, - addBox: (t: Mat4) => { - const { vertices, normals, indices } = Box() - add(t, vertices, normals, indices) - }, - addPerforatedBox: (t: Mat4) => { - const { vertices, normals, indices } = PerforatedBox() - add(t, vertices, normals, indices) - }, - addPlane: (t: Mat4, props?: PlaneProps) => { - const { vertices, normals, indices } = Plane(props) - add(t, vertices, normals, indices) - }, - addWedge: (t: Mat4) => { - const { vertices, normals, indices } = Wedge() - add(t, vertices, normals, indices) - }, - addDiamondPrism: (t: Mat4) => { - const { vertices, normals, indices } = DiamondPrism() - add(t, vertices, normals, indices) - }, - addPentagonalPrism: (t: Mat4) => { - const { vertices, normals, indices } = PentagonalPrism() - add(t, vertices, normals, indices) - }, - addHexagonalPrism: (t: Mat4) => { - const { vertices, normals, indices } = HexagonalPrism() - add(t, vertices, normals, indices) - }, - addOctagonalPyramid: (t: Mat4) => { - const { vertices, normals, indices } = OctagonalPyramide() - add(t, vertices, normals, indices) - }, - addPerforatedOctagonalPyramid: (t: Mat4) => { - const { vertices, normals, indices } = PerforatedOctagonalPyramide() - add(t, vertices, normals, indices) - }, - addStar: (t: Mat4, props?: StarProps) => { - const { vertices, normals, indices } = Star(props) - add(t, vertices, normals, indices) - }, - addOctahedron: (t: Mat4) => { - const { vertices, normals, indices } = Octahedron() - add(t, vertices, normals, indices) - }, - addPerforatedOctahedron: (t: Mat4) => { - const { vertices, normals, indices } = PerforatedOctahedron() - add(t, vertices, normals, indices) - }, - addCylinder: (start: Vec3, end: Vec3, lengthScale: number, props: CylinderProps) => { - const d = Vec3.distance(start, end) * lengthScale - props.height = d - const { vertices, normals, indices } = getCylinder(props) - Vec3.sub(tmpCylinderDir, end, start) - setCylinderMat(tmpCylinderMat, start, tmpCylinderDir, d) - add(tmpCylinderMat, vertices, normals, indices) - }, - addDoubleCylinder: (start: Vec3, end: Vec3, lengthScale: number, shift: Vec3, props: CylinderProps) => { - const d = Vec3.distance(start, end) * lengthScale - props.height = d - const { vertices, normals, indices } = getCylinder(props) - Vec3.sub(tmpCylinderDir, end, start) - // positivly shifted cylinder - Vec3.add(tmpCylinderStart, start, shift) - setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) - add(tmpCylinderMat, vertices, normals, indices) - // negativly shifted cylinder - Vec3.sub(tmpCylinderStart, start, shift) - setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d) - add(tmpCylinderMat, vertices, normals, indices) - }, - addFixedCountDashedCylinder: (start: Vec3, end: Vec3, lengthScale: number, segmentCount: number, props: CylinderProps) => { - const s = Math.floor(segmentCount / 2) - const step = 1 / segmentCount - - // automatically adjust length so links/bonds that are rendered as two half cylinders - // have evenly spaced dashed cylinders - if (lengthScale < 1) { - const bias = lengthScale / 2 / segmentCount - lengthScale += segmentCount % 2 === 1 ? bias : -bias - } - - const d = Vec3.distance(start, end) * lengthScale - props.height = d * step - const { vertices, normals, indices } = getCylinder(props) - Vec3.sub(tmpCylinderDir, end, start) - - for (let j = 0; j < s; ++j) { - const f = step * (j * 2 + 1) - Vec3.setMagnitude(tmpCylinderDir, tmpCylinderDir, d * f) - Vec3.add(tmpCylinderStart, start, tmpCylinderDir) - setCylinderMat(tmpCylinderMat, tmpCylinderStart, tmpCylinderDir, d * step) - add(tmpCylinderMat, vertices, normals, indices) - } - }, - addSphere: (center: Vec3, radius: number, detail: number) => { - const { vertices, normals, indices } = getSphere({ radius, detail }) - setSphereMat(tmpSphereMat, center) - add(tmpSphereMat, vertices, normals, indices) - }, - addTube: (centers: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, radialSegments: number, width: number, height: number, waveFactor: number, startCap: boolean, endCap: boolean) => { - const addedVertexCount = addTube(centers, normals, binormals, linearSegments, radialSegments, width, height, waveFactor, startCap, endCap, state) - for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(ids, currentId); - }, - addSheet: (controls: ArrayLike<number>, normals: ArrayLike<number>, binormals: ArrayLike<number>, linearSegments: number, width: number, height: number, arrowHeight: number, startCap: boolean, endCap: boolean) => { - const addedVertexCount = addSheet(controls, normals, binormals, linearSegments, width, height, arrowHeight, startCap, endCap, state) - for (let i = 0, il = addedVertexCount; i < il; ++i) ChunkedArray.add(ids, currentId); - }, - setId: (id: number) => { - if (currentId !== id) { - currentId = id - ChunkedArray.add(offsets, vertices.elementCount) - } - }, - getMesh: () => { - ChunkedArray.add(offsets, vertices.elementCount) - const vb = ChunkedArray.compact(vertices, true) as Float32Array - const ib = ChunkedArray.compact(indices, true) as Uint32Array - const nb = ChunkedArray.compact(normals, true) as Float32Array - const idb = ChunkedArray.compact(ids, true) as Float32Array - const ob = ChunkedArray.compact(offsets, true) as Uint32Array - return { - vertexCount: vertices.elementCount, - triangleCount: indices.elementCount, - offsetCount: offsets.elementCount, - vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb), - indexBuffer: mesh ? ValueCell.update(mesh.indexBuffer, ib) : ValueCell.create(ib), - normalBuffer: mesh ? ValueCell.update(mesh.normalBuffer, nb) : ValueCell.create(nb), - idBuffer: mesh ? ValueCell.update(mesh.idBuffer, idb) : ValueCell.create(idb), - offsetBuffer: mesh ? ValueCell.update(mesh.offsetBuffer, ob) : ValueCell.create(ob), - normalsComputed: true, - offsetsComputed: true, - } - } - } - } -} \ No newline at end of file diff --git a/src/mol-geo/shape/vertex-map.ts b/src/mol-geo/shape/vertex-map.ts deleted file mode 100644 index 0211ed33334dc08b5a065d9dc7250d88fc156450..0000000000000000000000000000000000000000 --- a/src/mol-geo/shape/vertex-map.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { ChunkedArray } from 'mol-data/util'; -import { Mesh } from './mesh'; - -/** Mapping between vertices and ids */ -interface VertexMap { - idCount: number, - offsetCount: number, - ids: Helpers.NumberArray - offsets: Uint32Array, -} - -function createOffsets(idCount: number, ids: Helpers.NumberArray) { - const offsets = ChunkedArray.create(Uint32Array, 1, 1024, 2048); - let prevId = ids[0] - ChunkedArray.add(offsets, 0) - for (let i = 1; i < idCount; ++i) { - if (prevId !== ids[i]) { - prevId = ids[i] - ChunkedArray.add(offsets, i) - } - } - ChunkedArray.add(offsets, idCount) - return ChunkedArray.compact(offsets, false) as Uint32Array -} - -namespace VertexMap { - export function create(idCount: number, offsetCount: number, ids: Helpers.NumberArray, offsets: Uint32Array): VertexMap { - return { - idCount, - offsetCount, - ids, - offsets - } - } - - export function fromMesh(mesh: Mesh) { - const ids = mesh.idBuffer.ref.value - const offsets = createOffsets(mesh.vertexCount, ids) - return create(mesh.vertexCount, offsets.length, ids, offsets) - } - - export function rangeFromId (id: number, vertexMap: VertexMap) { - return [0, 0] - } -} - -export default VertexMap \ No newline at end of file diff --git a/src/mol-geo/util/color-data.ts b/src/mol-geo/util/color-data.ts index 47e7eaf1d2383bdcc81eebf46a45d6864b1fb913..d8f0c3d2e72397637ce8d6064e6d834e31dfeb8b 100644 --- a/src/mol-geo/util/color-data.ts +++ b/src/mol-geo/util/color-data.ts @@ -8,16 +8,16 @@ import { ValueCell } from 'mol-util'; import { TextureImage, createTextureImage } from 'mol-gl/renderable/util'; import { Color } from 'mol-util/color'; import { Vec2, Vec3 } from 'mol-math/linear-algebra'; -import { LocationIterator } from '../representation/structure/visual/util/location-iterator'; +import { LocationIterator } from './location-iterator'; import { Location, NullLocation } from 'mol-model/location'; -export type ColorType = 'uniform' | 'instance' | 'element' | 'elementInstance' +export type ColorType = 'uniform' | 'instance' | 'group' | 'groupInstance' export type ColorData = { uColor: ValueCell<Vec3>, aColor: ValueCell<Float32Array>, tColor: ValueCell<TextureImage>, - uColorTexSize: ValueCell<Vec2>, + uColorTexDim: ValueCell<Vec2>, dColorType: ValueCell<string>, } @@ -27,7 +27,7 @@ const emptyColorTexture = { array: new Uint8Array(3), width: 1, height: 1 } function createEmptyColorTexture() { return { tColor: ValueCell.create(emptyColorTexture), - uColorTexSize: ValueCell.create(Vec2.create(1, 1)) + uColorTexDim: ValueCell.create(Vec2.create(1, 1)) } } @@ -56,7 +56,7 @@ export function createUniformColor(locationIt: LocationIterator, colorFn: Locati export function createTextureColor(colors: TextureImage, type: ColorType, colorData?: ColorData): ColorData { if (colorData) { ValueCell.update(colorData.tColor, colors) - ValueCell.update(colorData.uColorTexSize, Vec2.create(colors.width, colors.height)) + ValueCell.update(colorData.uColorTexDim, Vec2.create(colors.width, colors.height)) if (colorData.dColorType.ref.value !== type) { ValueCell.update(colorData.dColorType, type) } @@ -66,7 +66,7 @@ export function createTextureColor(colors: TextureImage, type: ColorType, colorD uColor: ValueCell.create(Vec3.zero()), aColor: ValueCell.create(new Float32Array(0)), tColor: ValueCell.create(colors), - uColorTexSize: ValueCell.create(Vec2.create(colors.width, colors.height)), + uColorTexDim: ValueCell.create(Vec2.create(colors.width, colors.height)), dColorType: ValueCell.create(type), } } @@ -84,25 +84,25 @@ export function createInstanceColor(locationIt: LocationIterator, colorFn: Locat return createTextureColor(colors, 'instance', colorData) } -/** Creates color texture with color for each element (i.e. shared across instances/units) */ -export function createElementColor(locationIt: LocationIterator, colorFn: LocationColor, colorData?: ColorData): ColorData { - const { elementCount } = locationIt - const colors = colorData && colorData.tColor.ref.value.array.length >= elementCount * 3 ? colorData.tColor.ref.value : createTextureImage(elementCount, 3) +/** Creates color texture with color for each group (i.e. shared across instances/units) */ +export function createGroupColor(locationIt: LocationIterator, colorFn: LocationColor, colorData?: ColorData): ColorData { + const { groupCount } = locationIt + const colors = colorData && colorData.tColor.ref.value.array.length >= groupCount * 3 ? colorData.tColor.ref.value : createTextureImage(groupCount, 3) while (locationIt.hasNext && !locationIt.isNextNewInstance) { - const { location, isSecondary, elementIndex } = locationIt.move() - Color.toArray(colorFn(location, isSecondary), colors.array, elementIndex * 3) + const { location, isSecondary, groupIndex } = locationIt.move() + Color.toArray(colorFn(location, isSecondary), colors.array, groupIndex * 3) } - return createTextureColor(colors, 'element', colorData) + return createTextureColor(colors, 'group', colorData) } -/** Creates color texture with color for each element instance (i.e. for each unit) */ -export function createElementInstanceColor(locationIt: LocationIterator, colorFn: LocationColor, colorData?: ColorData): ColorData { - const { elementCount, instanceCount } = locationIt - const count = instanceCount * elementCount +/** Creates color texture with color for each group in each instance (i.e. for each unit) */ +export function createGroupInstanceColor(locationIt: LocationIterator, colorFn: LocationColor, colorData?: ColorData): ColorData { + const { groupCount, instanceCount } = locationIt + const count = instanceCount * groupCount const colors = colorData && colorData.tColor.ref.value.array.length >= count * 3 ? colorData.tColor.ref.value : createTextureImage(count, 3) while (locationIt.hasNext && !locationIt.isNextNewInstance) { const { location, isSecondary, index } = locationIt.move() Color.toArray(colorFn(location, isSecondary), colors.array, index * 3) } - return createTextureColor(colors, 'elementInstance', colorData) + return createTextureColor(colors, 'groupInstance', colorData) } \ No newline at end of file diff --git a/src/mol-geo/util/location-iterator.ts b/src/mol-geo/util/location-iterator.ts new file mode 100644 index 0000000000000000000000000000000000000000..435d0c45c3be8181456098ec99331c4cf7f579d5 --- /dev/null +++ b/src/mol-geo/util/location-iterator.ts @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Iterator } from 'mol-data'; +import { NullLocation, Location } from 'mol-model/location'; + +export interface LocationValue { + location: Location + index: number + groupIndex: number + instanceIndex: number + isSecondary: boolean +} + +export const NullLocationValue: LocationValue = { + location: NullLocation, + index: 0, + groupIndex: 0, + instanceIndex: 0, + isSecondary: false +} + +export interface LocationIterator extends Iterator<LocationValue> { + readonly hasNext: boolean + readonly isNextNewInstance: boolean + readonly groupCount: number + readonly instanceCount: number + move(): LocationValue + reset(): void + skipInstance(): void +} + +type LocationGetter = (groupIndex: number, instanceIndex: number) => Location +type IsSecondaryGetter = (groupIndex: number, instanceIndex: number) => boolean + +export function LocationIterator(groupCount: number, instanceCount: number, getLocation: LocationGetter, isSecondary: IsSecondaryGetter = () => false): LocationIterator { + const value: LocationValue = { + location: NullLocation as Location, + index: 0, + groupIndex: 0, + instanceIndex: 0, + isSecondary: false + } + + let hasNext = value.groupIndex < groupCount + let isNextNewInstance = false + let groupIndex = 0 + let instanceIndex = 0 + + return { + get hasNext () { return hasNext }, + get isNextNewInstance () { return isNextNewInstance }, + get groupCount () { return groupCount }, + get instanceCount () { return instanceCount }, + move() { + if (hasNext) { + value.groupIndex = groupIndex + value.instanceIndex = instanceIndex + value.index = instanceIndex * groupCount + groupIndex + value.location = getLocation(groupIndex, instanceIndex) + value.isSecondary = isSecondary(groupIndex, instanceIndex) + ++groupIndex + if (groupIndex === groupCount) { + ++instanceIndex + isNextNewInstance = true + if (instanceIndex < instanceCount) groupIndex = 0 + } else { + isNextNewInstance = false + } + hasNext = groupIndex < groupCount + } + return value + }, + reset() { + value.location = NullLocation + value.index = 0 + value.groupIndex = 0 + value.instanceIndex = 0 + value.isSecondary = false + + hasNext = value.groupIndex < groupCount + isNextNewInstance = false + groupIndex = 0 + instanceIndex = 0 + }, + skipInstance() { + if (hasNext && value.instanceIndex === instanceIndex) { + ++instanceIndex + groupIndex = 0 + hasNext = instanceIndex < instanceCount + } + } + } +} \ No newline at end of file diff --git a/src/mol-geo/util/marching-cubes/algorithm.ts b/src/mol-geo/util/marching-cubes/algorithm.ts index 4b2eaf964996164cd06ccdebd141e8a57b8a20ce..f636ff582c8160ce384eea92873779f726301a0f 100644 --- a/src/mol-geo/util/marching-cubes/algorithm.ts +++ b/src/mol-geo/util/marching-cubes/algorithm.ts @@ -7,7 +7,7 @@ import { Task, RuntimeContext } from 'mol-task' import { ChunkedArray } from 'mol-data/util' import { Tensor } from 'mol-math/linear-algebra' -import { Mesh } from '../../shape/mesh' +import { Mesh } from '../../mesh/mesh' import { Index, EdgeIdInfo, CubeEdges, EdgeTable, TriTable } from './tables' import { ValueCell } from 'mol-util' @@ -76,18 +76,15 @@ class MarchingCubesComputation { const ret: Mesh = { vertexCount: this.state.vertexCount, triangleCount: this.state.triangleCount, - offsetCount: 0, vertexBuffer: os ? ValueCell.update(os.vertexBuffer, vb) : ValueCell.create(vb), indexBuffer: os ? ValueCell.update(os.indexBuffer, ib) : ValueCell.create(ib), normalBuffer: os ? os.normalBuffer : ValueCell.create(new Float32Array(0)), - idBuffer: this.state.assignIds - ? os && os.idBuffer - ? ValueCell.update(os.idBuffer, ChunkedArray.compact(this.state.idBuffer) as Float32Array) + groupBuffer: this.state.assignIds + ? os && os.groupBuffer + ? ValueCell.update(os.groupBuffer, ChunkedArray.compact(this.state.idBuffer) as Float32Array) : ValueCell.create(ChunkedArray.compact(this.state.idBuffer) as Float32Array) : ValueCell.create(new Float32Array(0)), - offsetBuffer: os ? os.offsetBuffer : ValueCell.create(new Uint32Array(0)), - normalsComputed: false, - offsetsComputed: false + normalsComputed: false } return ret; diff --git a/src/mol-geo/util/marker-data.ts b/src/mol-geo/util/marker-data.ts index 93fa6b5c21fd5684735d1784d6602d9239e30756..55dc2494560d9bc734dba5a1a11f73f835f797b7 100644 --- a/src/mol-geo/util/marker-data.ts +++ b/src/mol-geo/util/marker-data.ts @@ -10,7 +10,7 @@ import { TextureImage, createTextureImage } from 'mol-gl/renderable/util'; export type MarkerData = { tMarker: ValueCell<TextureImage> - uMarkerTexSize: ValueCell<Vec2> + uMarkerTexDim: ValueCell<Vec2> } export enum MarkerAction { @@ -77,26 +77,26 @@ export function createMarkers(count: number, markerData?: MarkerData): MarkerDat : createTextureImage(count, 1) if (markerData) { ValueCell.update(markerData.tMarker, markers) - ValueCell.update(markerData.uMarkerTexSize, Vec2.create(markers.width, markers.height)) + ValueCell.update(markerData.uMarkerTexDim, Vec2.create(markers.width, markers.height)) return markerData } else { return { tMarker: ValueCell.create(markers), - uMarkerTexSize: ValueCell.create(Vec2.create(markers.width, markers.height)), + uMarkerTexDim: ValueCell.create(Vec2.create(markers.width, markers.height)), } } } const emptyMarkerTexture = { array: new Uint8Array(1), width: 1, height: 1 } -export function createEmptyMarkers(markerData?: MarkerData) { +export function createEmptyMarkers(markerData?: MarkerData): MarkerData { if (markerData) { ValueCell.update(markerData.tMarker, emptyMarkerTexture) - ValueCell.update(markerData.uMarkerTexSize, Vec2.create(1, 1)) + ValueCell.update(markerData.uMarkerTexDim, Vec2.create(1, 1)) return markerData } else { return { tMarker: ValueCell.create(emptyMarkerTexture), - uMarkerTexSize: ValueCell.create(Vec2.create(1, 1)), + uMarkerTexDim: ValueCell.create(Vec2.create(1, 1)), } } } \ No newline at end of file diff --git a/src/mol-geo/util/mesh-data.ts b/src/mol-geo/util/mesh-data.ts index 9fd9add8ec596c4dc8bd917b777adcaf4a9d2784..0451ee98a8bfee2d7e2790c69a40a3144ca6ba69 100644 --- a/src/mol-geo/util/mesh-data.ts +++ b/src/mol-geo/util/mesh-data.ts @@ -5,18 +5,18 @@ */ import { ValueCell } from 'mol-util/value-cell' -import { Mesh } from '../shape/mesh'; +import { Mesh } from '../mesh/mesh'; type MeshData = { aPosition: ValueCell<Float32Array>, aNormal: ValueCell<Float32Array>, - aElementId: ValueCell<Float32Array>, + aGroup: ValueCell<Float32Array>, } export function getMeshData(mesh: Mesh): MeshData { return { aPosition: mesh.vertexBuffer, aNormal: mesh.normalBuffer, - aElementId: mesh.idBuffer, + aGroup: mesh.groupBuffer, } } \ No newline at end of file diff --git a/src/mol-geo/util/picking.ts b/src/mol-geo/util/picking.ts index 00d12d6fd6d297ad232fb81720eb0dc8dd63f252..07f2bf743ea1d5b18717a002910ce1a246684cb0 100644 --- a/src/mol-geo/util/picking.ts +++ b/src/mol-geo/util/picking.ts @@ -18,7 +18,7 @@ export function decodeIdRGBA(r: number, g: number, b: number) { export interface PickingId { objectId: number instanceId: number - elementId: number + groupId: number } export interface PickingInfo { diff --git a/src/mol-geo/util/size-data.ts b/src/mol-geo/util/size-data.ts index 25573107e59c5a52ba3541af8b41e649207c6a3a..f1a59a8fa6448b1931576d5d8c3b3b2f4e0af48c 100644 --- a/src/mol-geo/util/size-data.ts +++ b/src/mol-geo/util/size-data.ts @@ -7,16 +7,16 @@ import { ValueCell } from 'mol-util'; import { Vec2 } from 'mol-math/linear-algebra'; import { TextureImage, createTextureImage } from 'mol-gl/renderable/util'; -import { LocationIterator } from '../representation/structure/visual/util/location-iterator'; +import { LocationIterator } from './location-iterator'; import { Location, NullLocation } from 'mol-model/location'; -export type SizeType = 'uniform' | 'instance' | 'element' | 'elementInstance' +export type SizeType = 'uniform' | 'instance' | 'group' | 'groupInstance' export type SizeData = { uSize: ValueCell<number>, aSize: ValueCell<Float32Array>, tSize: ValueCell<TextureImage>, - uSizeTexSize: ValueCell<Vec2>, + uSizeTexDim: ValueCell<Vec2>, dSizeType: ValueCell<string>, } @@ -26,7 +26,7 @@ const emptySizeTexture = { array: new Uint8Array(1), width: 1, height: 1 } function createEmptySizeTexture() { return { tSize: ValueCell.create(emptySizeTexture), - uSizeTexSize: ValueCell.create(Vec2.create(1, 1)) + uSizeTexDim: ValueCell.create(Vec2.create(1, 1)) } } @@ -55,7 +55,7 @@ export function createUniformSize(locationIt: LocationIterator, sizeFn: Location export function createTextureSize(sizes: TextureImage, type: SizeType, sizeData?: SizeData): SizeData { if (sizeData) { ValueCell.update(sizeData.tSize, sizes) - ValueCell.update(sizeData.uSizeTexSize, Vec2.create(sizes.width, sizes.height)) + ValueCell.update(sizeData.uSizeTexDim, Vec2.create(sizes.width, sizes.height)) if (sizeData.dSizeType.ref.value !== type) { ValueCell.update(sizeData.dSizeType, type) } @@ -65,7 +65,7 @@ export function createTextureSize(sizes: TextureImage, type: SizeType, sizeData? uSize: ValueCell.create(0), aSize: ValueCell.create(new Float32Array(0)), tSize: ValueCell.create(sizes), - uSizeTexSize: ValueCell.create(Vec2.create(sizes.width, sizes.height)), + uSizeTexDim: ValueCell.create(Vec2.create(sizes.width, sizes.height)), dSizeType: ValueCell.create(type), } } @@ -83,25 +83,25 @@ export function createInstanceSize(locationIt: LocationIterator, sizeFn: Locatio return createTextureSize(sizes, 'instance', sizeData) } -/** Creates size texture with size for each element (i.e. shared across instances/units) */ -export function createElementSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData { - const { elementCount } = locationIt - const sizes = sizeData && sizeData.tSize.ref.value.array.length >= elementCount ? sizeData.tSize.ref.value : createTextureImage(elementCount, 1) +/** Creates size texture with size for each group (i.e. shared across instances/units) */ +export function createGroupSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData { + const { groupCount } = locationIt + const sizes = sizeData && sizeData.tSize.ref.value.array.length >= groupCount ? sizeData.tSize.ref.value : createTextureImage(groupCount, 1) while (locationIt.hasNext && !locationIt.isNextNewInstance) { const v = locationIt.move() - sizes.array[v.elementIndex] = sizeFn(v.location) + sizes.array[v.groupIndex] = sizeFn(v.location) } - return createTextureSize(sizes, 'element', sizeData) + return createTextureSize(sizes, 'group', sizeData) } -/** Creates size texture with size for each element instance (i.e. for each unit) */ -export function createElementInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData { - const { elementCount, instanceCount } = locationIt - const count = instanceCount * elementCount +/** Creates size texture with size for each group in each instance (i.e. for each unit) */ +export function createGroupInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData { + const { groupCount, instanceCount } = locationIt + const count = instanceCount * groupCount const sizes = sizeData && sizeData.tSize.ref.value.array.length >= count ? sizeData.tSize.ref.value : createTextureImage(count, 1) while (locationIt.hasNext && !locationIt.isNextNewInstance) { const v = locationIt.move() sizes.array[v.index] = sizeFn(v.location) } - return createTextureSize(sizes, 'elementInstance', sizeData) + return createTextureSize(sizes, 'groupInstance', sizeData) } \ No newline at end of file diff --git a/src/mol-gl/_spec/renderer.spec.ts b/src/mol-gl/_spec/renderer.spec.ts index f6474217fbdd9a30d4a59a4e184843b37192a348..e4d5b6c6cbf4230d2d8618c3a47fbd4dd9a5fe3f 100644 --- a/src/mol-gl/_spec/renderer.spec.ts +++ b/src/mol-gl/_spec/renderer.spec.ts @@ -46,8 +46,8 @@ function createRenderer(gl: WebGLRenderingContext) { function createPoints() { const aPosition = ValueCell.create(new Float32Array([0, -1, 0, -1, 0, 0, 1, 1, 0])) - const aElementId = ValueCell.create(fillSerial(new Float32Array(3))) - const aInstanceId = ValueCell.create(fillSerial(new Float32Array(1))) + const aGroup = ValueCell.create(fillSerial(new Float32Array(3))) + const aInstance = ValueCell.create(fillSerial(new Float32Array(1))) const color = createValueColor(Color(0xFF0000)) const size = createValueSize(1) const marker = createEmptyMarkers() @@ -58,16 +58,16 @@ function createPoints() { const values: PointValues = { aPosition, - aElementId, + aGroup, aTransform, - aInstanceId, + aInstance, ...color, ...marker, ...size, uAlpha: ValueCell.create(1.0), uInstanceCount: ValueCell.create(1), - uElementCount: ValueCell.create(3), + uGroupCount: ValueCell.create(3), drawCount: ValueCell.create(3), instanceCount: ValueCell.create(1), diff --git a/src/mol-gl/renderable/point.ts b/src/mol-gl/renderable/point.ts index 155c3f2069d12c341cd12f3db63412e33daf3fa4..f229413889610ccd4ff9a160476debd2fcc33b9b 100644 --- a/src/mol-gl/renderable/point.ts +++ b/src/mol-gl/renderable/point.ts @@ -15,7 +15,7 @@ export const PointSchema = { ...BaseSchema, aSize: AttributeSpec('float32', 1, 0), uSize: UniformSpec('f'), - uSizeTexSize: UniformSpec('v2'), + uSizeTexDim: UniformSpec('v2'), tSize: TextureSpec('alpha', 'ubyte'), dSizeType: DefineSpec('string', ['uniform', 'attribute']), dPointSizeAttenuation: DefineSpec('boolean'), diff --git a/src/mol-gl/renderable/schema.ts b/src/mol-gl/renderable/schema.ts index adfa5985b56104dc556ab8938b7d672fdc9a8ab7..7364e731b384e90cfe0224981c202a60e232f4ee 100644 --- a/src/mol-gl/renderable/schema.ts +++ b/src/mol-gl/renderable/schema.ts @@ -142,18 +142,18 @@ export const InternalSchema = { } export const BaseSchema = { - aInstanceId: AttributeSpec('float32', 1, 1), + aInstance: AttributeSpec('float32', 1, 1), aPosition: AttributeSpec('float32', 3, 0), - aElementId: AttributeSpec('float32', 1, 0), + aGroup: AttributeSpec('float32', 1, 0), aTransform: AttributeSpec('float32', 16, 1), aColor: AttributeSpec('float32', 3, 0), uAlpha: UniformSpec('f'), uInstanceCount: UniformSpec('i'), - uElementCount: UniformSpec('i'), + uGroupCount: UniformSpec('i'), uColor: UniformSpec('v3'), - uColorTexSize: UniformSpec('v2'), - uMarkerTexSize: UniformSpec('v2'), + uColorTexDim: UniformSpec('v2'), + uMarkerTexDim: UniformSpec('v2'), tColor: TextureSpec('rgb', 'ubyte'), tMarker: TextureSpec('alpha', 'ubyte'), @@ -161,7 +161,7 @@ export const BaseSchema = { drawCount: ValueSpec('number'), instanceCount: ValueSpec('number'), - dColorType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'element', 'element_instance']), + dColorType: DefineSpec('string', ['uniform', 'attribute', 'instance', 'group', 'group_instance']), dUseFog: DefineSpec('boolean'), } export type BaseSchema = typeof BaseSchema diff --git a/src/mol-gl/shader/chunks/assign-color-varying.glsl b/src/mol-gl/shader/chunks/assign-color-varying.glsl index b5848197a89b908cb5664869d1206f90eb222042..f4f5dad7358e2e52f052023500745156e891bd75 100644 --- a/src/mol-gl/shader/chunks/assign-color-varying.glsl +++ b/src/mol-gl/shader/chunks/assign-color-varying.glsl @@ -1,15 +1,15 @@ #if defined(dColorType_attribute) vColor.rgb = aColor; #elif defined(dColorType_instance) - vColor.rgb = readFromTexture(tColor, aInstanceId, uColorTexSize).rgb; -#elif defined(dColorType_element) - vColor.rgb = readFromTexture(tColor, aElementId, uColorTexSize).rgb; -#elif defined(dColorType_elementInstance) - vColor.rgb = readFromTexture(tColor, aInstanceId * float(uElementCount) + aElementId, uColorTexSize).rgb; + vColor.rgb = readFromTexture(tColor, aInstance, uColorTexDim).rgb; +#elif defined(dColorType_group) + vColor.rgb = readFromTexture(tColor, aGroup, uColorTexDim).rgb; +#elif defined(dColorType_groupInstance) + vColor.rgb = readFromTexture(tColor, aGroup * float(uGroupCount) + aGroup, uColorTexDim).rgb; #elif defined(dColorType_objectPicking) vColor = encodeIdRGBA(float(uObjectId)); #elif defined(dColorType_instancePicking) - vColor = encodeIdRGBA(aInstanceId); -#elif defined(dColorType_elementPicking) - vColor = encodeIdRGBA(aElementId); + vColor = encodeIdRGBA(aInstance); +#elif defined(dColorType_groupPicking) + vColor = encodeIdRGBA(aGroup); #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/assign-marker-varying.glsl b/src/mol-gl/shader/chunks/assign-marker-varying.glsl index 1afbdd7cfbeca72ebeb83a4bcaef4c91063874cd..38c3e0a474debc92226378e42368c7b42362f693 100644 --- a/src/mol-gl/shader/chunks/assign-marker-varying.glsl +++ b/src/mol-gl/shader/chunks/assign-marker-varying.glsl @@ -1 +1 @@ -vMarker = readFromTexture(tMarker, aInstanceId * float(uElementCount) + aElementId, uMarkerTexSize).a; \ No newline at end of file +vMarker = readFromTexture(tMarker, aInstance * float(uGroupCount) + aGroup, uMarkerTexDim).a; \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/assign-material-color.glsl b/src/mol-gl/shader/chunks/assign-material-color.glsl index fa0ecfad09dbbcc4ce57d156b4e488381407b690..5969c88c34b534a0556d2da9f30e6b22f41a557e 100644 --- a/src/mol-gl/shader/chunks/assign-material-color.glsl +++ b/src/mol-gl/shader/chunks/assign-material-color.glsl @@ -1,5 +1,5 @@ #if defined(dColorType_uniform) vec4 material = vec4(uColor, 1.0); -#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_element) || defined(dColorType_elementInstance) || defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_elementPicking) +#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance) || defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking) vec4 material = vColor; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-frag-params.glsl b/src/mol-gl/shader/chunks/color-frag-params.glsl index 55731de96863282a6d664f51276b3e19d335dc87..caa12c98d9c2eea2a48767fcea185a419b761fe0 100644 --- a/src/mol-gl/shader/chunks/color-frag-params.glsl +++ b/src/mol-gl/shader/chunks/color-frag-params.glsl @@ -1,5 +1,5 @@ #if defined(dColorType_uniform) uniform vec3 uColor; -#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_element) || defined(dColorType_elementInstance) || defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_elementPicking) +#elif defined(dColorType_attribute) || defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance) || defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking) varying vec4 vColor; #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/color-vert-params.glsl b/src/mol-gl/shader/chunks/color-vert-params.glsl index 8f49becee4630b39320a3660dcae7adc8a6aafcd..63318ea3c6c4caac90718bae39ae37267a77b860 100644 --- a/src/mol-gl/shader/chunks/color-vert-params.glsl +++ b/src/mol-gl/shader/chunks/color-vert-params.glsl @@ -3,11 +3,11 @@ #elif defined(dColorType_attribute) varying vec4 vColor; attribute vec3 aColor; -#elif defined(dColorType_instance) || defined(dColorType_element) || defined(dColorType_elementInstance) +#elif defined(dColorType_instance) || defined(dColorType_group) || defined(dColorType_groupInstance) varying vec4 vColor; - uniform vec2 uColorTexSize; + uniform vec2 uColorTexDim; uniform sampler2D tColor; -#elif defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_elementPicking) +#elif defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking) varying vec4 vColor; #pragma glslify: encodeIdRGBA = require(../utils/encode-id-rgba.glsl) #endif \ No newline at end of file diff --git a/src/mol-gl/shader/chunks/common-frag-params.glsl b/src/mol-gl/shader/chunks/common-frag-params.glsl index 7470f1041311568d7010e15b2f73c67d09651585..a1b1b64d8eb9b2a560e4de1b101bb5cc331748ab 100644 --- a/src/mol-gl/shader/chunks/common-frag-params.glsl +++ b/src/mol-gl/shader/chunks/common-frag-params.glsl @@ -1,6 +1,6 @@ uniform int uObjectId; uniform int uInstanceCount; -uniform int uElementCount; +uniform int uGroupCount; uniform vec3 uHighlightColor; uniform vec3 uSelectColor; diff --git a/src/mol-gl/shader/chunks/common-vert-params.glsl b/src/mol-gl/shader/chunks/common-vert-params.glsl index 27d1dd0b338b166efc5479233cd2670fc489f62c..30bc2caea18865056975654eeccac9b43348ba66 100644 --- a/src/mol-gl/shader/chunks/common-vert-params.glsl +++ b/src/mol-gl/shader/chunks/common-vert-params.glsl @@ -2,9 +2,9 @@ uniform mat4 uProjection, uModel, uView; uniform int uObjectId; uniform int uInstanceCount; -uniform int uElementCount; +uniform int uGroupCount; -uniform vec2 uMarkerTexSize; +uniform vec2 uMarkerTexDim; uniform sampler2D tMarker; varying float vMarker; #pragma glslify: readFromTexture = require(../utils/read-from-texture.glsl) \ No newline at end of file diff --git a/src/mol-gl/shader/mesh.frag b/src/mol-gl/shader/mesh.frag index cc387cb22b293464889921d6f48c91bdd9b1a7f2..ce282933ea1281f35e1699e3d0acc373ec3a814f 100644 --- a/src/mol-gl/shader/mesh.frag +++ b/src/mol-gl/shader/mesh.frag @@ -38,7 +38,7 @@ void main() { // material color #pragma glslify: import('./chunks/assign-material-color.glsl') - #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_elementPicking) + #if defined(dColorType_objectPicking) || defined(dColorType_instancePicking) || defined(dColorType_groupPicking) // gl_FragColor = vec4(material.r, material.g, material.a, 1.0); gl_FragColor = material; #else diff --git a/src/mol-gl/shader/mesh.vert b/src/mol-gl/shader/mesh.vert index 0f7b837d2cd7569c1997ff057ca32cc4fc2f4e5a..af38be41e65a3be4d05412a1cadd618ce5d38438 100644 --- a/src/mol-gl/shader/mesh.vert +++ b/src/mol-gl/shader/mesh.vert @@ -12,8 +12,8 @@ precision highp int; attribute vec3 aPosition; attribute mat4 aTransform; -attribute float aInstanceId; -attribute float aElementId; +attribute float aInstance; +attribute float aGroup; #ifndef dFlatShaded attribute vec3 aNormal; diff --git a/src/mol-gl/shader/point.vert b/src/mol-gl/shader/point.vert index f8061d9587c4139f22e8cc723c604152e3387658..950ba3db17bef0d249d56e2ebac4e63a0222d3fb 100644 --- a/src/mol-gl/shader/point.vert +++ b/src/mol-gl/shader/point.vert @@ -21,8 +21,8 @@ uniform float uViewportHeight; attribute vec3 aPosition; attribute mat4 aTransform; -attribute float aInstanceId; -attribute float aElementId; +attribute float aInstance; +attribute float aGroup; void main(){ #pragma glslify: import('./chunks/assign-color-varying.glsl') @@ -33,11 +33,11 @@ void main(){ #elif defined(dSizeType_attribute) float size = aSize; #elif defined(dSizeType_instance) - float size = readFromTexture(tSize, aInstanceId, uSizeTexSize).r; - #elif defined(dSizeType_element) - float size = readFromTexture(tSize, aElementId, uSizeTexSize).r; - #elif defined(dSizeType_elementInstance) - float size = readFromTexture(tSize, aInstanceId * float(uElementCount) + aElementId, uSizeTexSize).r; + float size = readFromTexture(tSize, aInstance, uSizeTexDim).r; + #elif defined(dSizeType_group) + float size = readFromTexture(tSize, aGroup, uSizeTexDim).r; + #elif defined(dSizeType_groupInstance) + float size = readFromTexture(tSize, aInstance * float(uGroupCount) + aGroup, uSizeTexDim).r; #endif #ifdef dPointSizeAttenuation diff --git a/src/mol-gl/shader/utils/read-from-texture.glsl b/src/mol-gl/shader/utils/read-from-texture.glsl index 10b4e9d60c09519c17cd0b5a3fe60e27a8bb7fe6..a43c9d528af35cd1a2be41dfb2d18d3b2c240bf1 100644 --- a/src/mol-gl/shader/utils/read-from-texture.glsl +++ b/src/mol-gl/shader/utils/read-from-texture.glsl @@ -4,10 +4,10 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -vec4 readFromTexture (const in sampler2D tex, const in float i, const in vec2 size) { - float x = mod(i, size.x); - float y = floor(i / size.x); - vec2 uv = (vec2(x, y) + 0.5) / size; +vec4 readFromTexture (const in sampler2D tex, const in float i, const in vec2 dim) { + float x = mod(i, dim.x); + float y = floor(i / dim.x); + vec2 uv = (vec2(x, y) + 0.5) / dim; return texture2D(tex, uv); } #pragma glslify: export(readFromTexture) \ No newline at end of file diff --git a/src/mol-gl/webgl/render-item.ts b/src/mol-gl/webgl/render-item.ts index a9a8244b0571a8877afbb116b711e18902fcbe36..284591374c09de8e144518f3bff698b72036fc20 100644 --- a/src/mol-gl/webgl/render-item.ts +++ b/src/mol-gl/webgl/render-item.ts @@ -45,7 +45,7 @@ const RenderVariantDefines = { 'draw': {}, 'pickObject': { dColorType: ValueCell.create('objectPicking') }, 'pickInstance': { dColorType: ValueCell.create('instancePicking') }, - 'pickElement': { dColorType: ValueCell.create('elementPicking') } + 'pickGroup': { dColorType: ValueCell.create('groupPicking') } } export type RenderVariant = keyof typeof RenderVariantDefines diff --git a/src/mol-io/reader/cif/schema/bird.ts b/src/mol-io/reader/cif/schema/bird.ts index e50ae25be452619e817f76e65107f94badc49a58..0614e84107ffc60182a213c6c27fcc01df209493 100644 --- a/src/mol-io/reader/cif/schema/bird.ts +++ b/src/mol-io/reader/cif/schema/bird.ts @@ -11,16 +11,15 @@ import { Database, Column } from 'mol-data/db' import Schema = Column.Schema const str = Schema.str; -const int = Schema.int; const float = Schema.float; -// const coord = Schema.coord; - const Aliased = Schema.Aliased; -// const Matrix = Schema.Matrix; -// const Vector = Schema.Vector; -// const List = Schema.List; +const int = Schema.int; export const BIRD_Schema = { + /** + * Data items in the PDBX_REFERENCE_MOLECULE category record + * reference information about small polymer molecules. + */ pdbx_reference_molecule: { /** * The value of _pdbx_reference_molecule.prd_id is the unique identifier @@ -108,6 +107,10 @@ export const BIRD_Schema = { */ replaced_by: str, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_LIST category record + * the list of entities within each reference molecule. + */ pdbx_reference_entity_list: { /** * The value of _pdbx_reference_entity_list.prd_id is a reference @@ -132,6 +135,10 @@ export const BIRD_Schema = { */ component_id: int, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_NONPOLY category record + * the list of entities within each reference molecule. + */ pdbx_reference_entity_nonpoly: { /** * The value of _pdbx_reference_entity_nonpoly.prd_id is a reference @@ -153,6 +160,10 @@ export const BIRD_Schema = { */ chem_comp_id: str, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_LINK category give details about + * the linkages between entities within reference molecules. + */ pdbx_reference_entity_link: { /** * The value of _pdbx_reference_entity_link.link_id uniquely identifies @@ -248,6 +259,11 @@ export const BIRD_Schema = { */ link_class: Aliased<'PP' | 'PN' | 'NP' | 'NN'>(str), }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_POLY_LINK category give details about + * polymer linkages including both standard and non-standard linkages between + * polymer componnents. + */ pdbx_reference_entity_poly_link: { /** * The value of _pdbx_reference_entity_poly_link.link_id uniquely identifies @@ -317,6 +333,11 @@ export const BIRD_Schema = { */ value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str), }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_POLY category record details about + * the polymer, such as the type of the polymer, the number of + * monomers and whether it has nonstandard features. + */ pdbx_reference_entity_poly: { /** * The value of _pdbx_reference_entity_poly.prd_id is a reference @@ -341,6 +362,10 @@ export const BIRD_Schema = { */ db_name: str, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_POLY_SEQ category specify the sequence + * of monomers in a polymer. + */ pdbx_reference_entity_poly_seq: { /** * The value of _pdbx_reference_entity_poly_seq.prd_id is a reference @@ -377,6 +402,9 @@ export const BIRD_Schema = { */ hetero: Aliased<'Y' | 'N'>(str), }, + /** + * Additional features associated with the reference entity. + */ pdbx_reference_entity_sequence: { /** * The value of _pdbx_reference_entity_sequence.prd_id is a reference @@ -401,6 +429,10 @@ export const BIRD_Schema = { */ one_letter_codes: str, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_SRC_NAT category record + * details of the source from which the entity was obtained. + */ pdbx_reference_entity_src_nat: { /** * The value of _pdbx_reference_entity_src_nat.prd_id is a reference @@ -434,6 +466,10 @@ export const BIRD_Schema = { */ db_name: str, }, + /** + * Data items in the PDBX_PRD_AUDIT category records + * the status and tracking information for this molecule. + */ pdbx_prd_audit: { /** * This data item is a pointer to _pdbx_reference_molecule.prd_id in the diff --git a/src/mol-io/reader/cif/schema/ccd.ts b/src/mol-io/reader/cif/schema/ccd.ts index 0149ed58fa59be1b992e6eda99343fe3823b566d..3a5e0d2c0987fb983c92c8ae555634513e5a4fab 100644 --- a/src/mol-io/reader/cif/schema/ccd.ts +++ b/src/mol-io/reader/cif/schema/ccd.ts @@ -11,16 +11,22 @@ import { Database, Column } from 'mol-data/db' import Schema = Column.Schema const str = Schema.str; -const int = Schema.int; const float = Schema.float; -const coord = Schema.coord; - -const Aliased = Schema.Aliased; -// const Matrix = Schema.Matrix; -// const Vector = Schema.Vector; const List = Schema.List; +const Aliased = Schema.Aliased; +const int = Schema.int; +const coord = Schema.coord; export const CCD_Schema = { + /** + * Data items in the CHEM_COMP category give details about each + * of the chemical components from which the relevant chemical + * structures can be constructed, such as name, mass or charge. + * + * The related categories CHEM_COMP_ATOM, CHEM_COMP_BOND, + * CHEM_COMP_ANGLE etc. describe the detailed geometry of these + * chemical components. + */ chem_comp: { /** * The formula for the chemical component. Formulae are written @@ -167,6 +173,14 @@ export const CCD_Schema = { */ pdbx_processing_site: Aliased<'PDBE' | 'EBI' | 'PDBJ' | 'RCSB'>(str), }, + /** + * Data items in the CHEM_COMP_ATOM category record details about + * the atoms in a chemical component. Specifying the atomic + * coordinates for the components in this category is an + * alternative to specifying the structure of the component + * via bonds, angles, planes etc. in the appropriate + * CHEM_COMP subcategories. + */ chem_comp_atom: { /** * An alternative identifier for the atom. This data item would be @@ -271,6 +285,12 @@ export const CCD_Schema = { */ pdbx_leaving_atom_flag: Aliased<'Y' | 'N'>(str), }, + /** + * Data items in the CHEM_COMP_BOND category record details about + * the bonds between atoms in a chemical component. Target values + * may be specified as bond orders, as a distance between the two + * atoms, or both. + */ chem_comp_bond: { /** * The ID of the first of the two atoms that define the bond. @@ -310,6 +330,10 @@ export const CCD_Schema = { */ pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str), }, + /** + * Data items in the CHEM_COMP_DESCRIPTOR category provide + * string descriptors of component chemical structure. + */ pdbx_chem_comp_descriptor: { /** * This data item is a pointer to _chem_comp.id in the CHEM_COMP @@ -336,6 +360,10 @@ export const CCD_Schema = { */ program_version: str, }, + /** + * Data items in the CHEM_COMP_IDENTIFIER category provide + * identifiers for chemical components. + */ pdbx_chem_comp_identifier: { /** * This data item is a pointer to _chem_comp.id in the CHEM_COMP diff --git a/src/mol-io/reader/cif/schema/mmcif.ts b/src/mol-io/reader/cif/schema/mmcif.ts index f395639e8ab4e68823fdd37087f4195dbd56aac0..526cb248bf6d32e7953eb55055e8673db48d9931 100644 --- a/src/mol-io/reader/cif/schema/mmcif.ts +++ b/src/mol-io/reader/cif/schema/mmcif.ts @@ -14,13 +14,22 @@ const str = Schema.str; const int = Schema.int; const float = Schema.float; const coord = Schema.coord; - const Aliased = Schema.Aliased; const Matrix = Schema.Matrix; const Vector = Schema.Vector; const List = Schema.List; export const mmCIF_Schema = { + /** + * Data items in the ATOM_SITE category record details about + * the atom sites in a macromolecular crystal structure, such as + * the positional coordinates, atomic displacement parameters, + * magnetic moments and directions. + * + * The data items for describing anisotropic atomic + * displacement factors are only used if the corresponding items + * are not given in the ATOM_SITE_ANISOTROP category. + */ atom_site: { /** * An alternative identifier for _atom_site.label_asym_id that @@ -204,6 +213,11 @@ export const mmCIF_Schema = { */ ihm_model_id: int, }, + /** + * Data items in the ATOM_SITES category record details about + * the crystallographic cell and cell transformations, which are + * common to all atom sites. + */ atom_sites: { /** * This data item is a pointer to _entry.id in the ENTRY category. @@ -236,6 +250,10 @@ export const mmCIF_Schema = { */ fract_transf_vector: Vector(3), }, + /** + * Data items in the CELL category record details about the + * crystallographic cell parameters. + */ cell: { /** * Unit-cell angle alpha of the reported structure in degrees. @@ -283,6 +301,15 @@ export const mmCIF_Schema = { */ pdbx_unique_axis: str, }, + /** + * Data items in the CHEM_COMP category give details about each + * of the chemical components from which the relevant chemical + * structures can be constructed, such as name, mass or charge. + * + * The related categories CHEM_COMP_ATOM, CHEM_COMP_BOND, + * CHEM_COMP_ANGLE etc. describe the detailed geometry of these + * chemical components. + */ chem_comp: { /** * The formula for the chemical component. Formulae are written @@ -344,6 +371,12 @@ export const mmCIF_Schema = { */ pdbx_synonyms: List(';', x => x), }, + /** + * Data items in the CHEM_COMP_BOND category record details about + * the bonds between atoms in a chemical component. Target values + * may be specified as bond orders, as a distance between the two + * atoms, or both. + */ chem_comp_bond: { /** * The ID of the first of the two atoms that define the bond. @@ -383,6 +416,37 @@ export const mmCIF_Schema = { */ pdbx_aromatic_flag: Aliased<'Y' | 'N'>(str), }, + /** + * Data items in the ENTITY category record details (such as + * chemical composition, name and source) about the molecular + * entities that are present in the crystallographic structure. + * + * Items in the various ENTITY subcategories provide a full + * chemical description of these molecular entities. + * + * Entities are of three types: polymer, non-polymer and water. + * Note that the water category includes only water; ordered + * solvent such as sulfate ion or acetone would be described as + * individual non-polymer entities. + * + * The ENTITY category is specific to macromolecular CIF + * applications and replaces the function of the CHEMICAL category + * in the CIF core. + * + * It is important to remember that the ENTITY data are not the + * result of the crystallographic experiment; those results are + * represented by the ATOM_SITE data items. ENTITY data items + * describe the chemistry of the molecules under investigation + * and can most usefully be thought of as the ideal groups to which + * the structure is restrained or constrained during refinement. + * + * It is also important to remember that entities do not correspond + * directly to the enumeration of the contents of the asymmetric + * unit. Entities are described only once, even in those structures + * that contain multiple observations of an entity. The + * STRUCT_ASYM data items, which reference the entity list, + * describe and label the contents of the asymmetric unit. + */ entity: { /** * A description of special aspects of the entity. @@ -446,6 +510,11 @@ export const mmCIF_Schema = { */ pdbx_ec: List(',', x => x), }, + /** + * Data items in the ENTITY_POLY category record details about the + * polymer, such as the type of the polymer, the number of + * monomers and whether it has nonstandard features. + */ entity_poly: { /** * This data item is a pointer to _entity.id in the ENTITY category. @@ -511,6 +580,14 @@ export const mmCIF_Schema = { */ pdbx_target_identifier: str, }, + /** + * Data items in the ENTITY_POLY_SEQ category specify the sequence + * of monomers in a polymer. Allowance is made for the possibility + * of microheterogeneity in a sample by allowing a given sequence + * number to be correlated with more than one monomer ID. The + * corresponding ATOM_SITE entries should reflect this + * heterogeneity. + */ entity_poly_seq: { /** * This data item is a pointer to _entity.id in the ENTITY category. @@ -535,6 +612,12 @@ export const mmCIF_Schema = { */ num: int, }, + /** + * There is only one item in the ENTRY category, _entry.id. This + * data item gives a name to this entry and is indirectly a key to + * the categories (such as CELL, GEOM, EXPTL) that describe + * information pertinent to the entire data block. + */ entry: { /** * The value of _entry.id identifies the data block. @@ -544,6 +627,11 @@ export const mmCIF_Schema = { */ id: str, }, + /** + * Data items in the EXPTL category record details about the + * experimental work prior to the intensity measurements and + * details about the absorption-correction technique employed. + */ exptl: { /** * This data item is a pointer to _entry.id in the ENTRY category. @@ -554,6 +642,10 @@ export const mmCIF_Schema = { */ method: Aliased<'X-RAY DIFFRACTION' | 'NEUTRON DIFFRACTION' | 'FIBER DIFFRACTION' | 'ELECTRON CRYSTALLOGRAPHY' | 'ELECTRON MICROSCOPY' | 'SOLUTION NMR' | 'SOLID-STATE NMR' | 'SOLUTION SCATTERING' | 'POWDER DIFFRACTION' | 'INFRARED SPECTROSCOPY' | 'EPR' | 'FLUORESCENCE TRANSFER' | 'THEORETICAL MODEL'>(str), }, + /** + * Data items in the STRUCT category record details about the + * description of the crystallographic structure. + */ struct: { /** * This data item is a pointer to _entry.id in the ENTRY category. @@ -566,6 +658,10 @@ export const mmCIF_Schema = { */ title: str, }, + /** + * Data items in the STRUCT_ASYM category record details about the + * structural elements in the asymmetric unit. + */ struct_asym: { /** * A description of special aspects of this portion of the contents @@ -594,6 +690,13 @@ export const mmCIF_Schema = { */ pdbx_blank_PDB_chainid_flag: Aliased<'Y' | 'N'>(str), }, + /** + * Data items in the STRUCT_CONF category record details about + * the backbone conformation of a segment of polymer. + * + * Data items in the STRUCT_CONF_TYPE category define the + * criteria used to identify the backbone conformations. + */ struct_conf: { /** * A component of the identifier for the residue at which the @@ -734,6 +837,14 @@ export const mmCIF_Schema = { */ pdbx_PDB_helix_id: str, }, + /** + * Data items in the STRUCT_CONN category record details about + * the connections between portions of the structure. These can be + * hydrogen bonds, salt bridges, disulfide bridges and so on. + * + * The STRUCT_CONN_TYPE records define the criteria used to + * identify these connections. + */ struct_conn: { /** * This data item is a pointer to _struct_conn_type.id in the @@ -961,6 +1072,11 @@ export const mmCIF_Schema = { */ pdbx_value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad'>(str), }, + /** + * Data items in the STRUCT_CONN_TYPE category record details + * about the criteria used to identify interactions between + * portions of the structure. + */ struct_conn_type: { /** * The criteria used to define the interaction. @@ -976,6 +1092,10 @@ export const mmCIF_Schema = { */ reference: str, }, + /** + * Data items in the STRUCT_KEYWORDS category specify keywords + * that describe the chemical structure in this entry. + */ struct_keywords: { /** * This data item is a pointer to _entry.id in the ENTRY category. @@ -990,6 +1110,14 @@ export const mmCIF_Schema = { */ pdbx_keywords: str, }, + /** + * Data items in the STRUCT_NCS_OPER category describe the + * noncrystallographic symmetry operations. + * + * Each operator is specified as a matrix and a subsequent + * translation vector. Operators need not represent proper + * rotations. + */ struct_ncs_oper: { /** * A code to indicate whether this operator describes a @@ -1024,6 +1152,13 @@ export const mmCIF_Schema = { */ vector: Vector(3), }, + /** + * Data items in the STRUCT_SHEET_RANGE category record details + * about the residue ranges that form a beta-sheet. Residues are + * included in a range if they made beta-sheet-type hydrogen-bonding + * interactions with at least one adjacent strand and if there are + * at least two residues in the range. + */ struct_sheet_range: { /** * A component of the identifier for the residue at which the @@ -1145,6 +1280,12 @@ export const mmCIF_Schema = { */ pdbx_end_PDB_ins_code: str, }, + /** + * Data items in the STRUCT_SITE category record details about + * portions of the structure that contribute to structurally + * relevant sites (e.g. active sites, substrate-binding subsites, + * metal-coordination sites). + */ struct_site: { /** * A description of special aspects of the site. @@ -1192,6 +1333,11 @@ export const mmCIF_Schema = { */ pdbx_auth_ins_code: str, }, + /** + * Data items in the STRUCT_SITE_GEN category record details about + * the generation of portions of the structure that contribute to + * structurally relevant sites. + */ struct_site_gen: { /** * A description of special aspects of the symmetry generation of @@ -1282,6 +1428,10 @@ export const mmCIF_Schema = { */ pdbx_num_res: int, }, + /** + * Data items in the SYMMETRY category record details about the + * space-group symmetry. + */ symmetry: { /** * This data item is a pointer to _entry.id in the ENTRY category. @@ -1320,30 +1470,11 @@ export const mmCIF_Schema = { */ 'space_group_name_H-M': str, }, - pdbx_struct_assembly: { - /** - * Provides details of the method used to determine or - * compute the assembly. - */ - method_details: str, - /** - * Provides the details of the oligomeric state of the assembly. - */ - oligomeric_details: str, - /** - * The number of polymer molecules in the assembly. - */ - oligomeric_count: int, - /** - * A description of special aspects of the macromolecular assembly. - */ - details: str, - /** - * The value of _pdbx_struct_assembly.id must uniquely identify a record in - * the PDBX_STRUCT_ASSEMBLY list. - */ - id: str, - }, + /** + * Data items in the PDBX_STRUCT_MOD_RESIDUE category list the + * modified polymer components in the entry and provide some + * details describing the nature of the modification. + */ pdbx_struct_mod_residue: { /** * The value of _pdbx_struct_mod_residue.id must uniquely identify @@ -1410,6 +1541,11 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Data items in the PDBX_STRUCT_OPER_LIST category describe + * Cartesian rotation and translation operations required to + * generate or transform the coordinates deposited with this entry. + */ pdbx_struct_oper_list: { /** * This identifier code must uniquely identify a @@ -1439,6 +1575,40 @@ export const mmCIF_Schema = { */ vector: Vector(3), }, + /** + * Data items in the PDBX_STRUCT_ASSEMBLY category record details about + * the structural elements that form macromolecular assemblies. + */ + pdbx_struct_assembly: { + /** + * Provides details of the method used to determine or + * compute the assembly. + */ + method_details: str, + /** + * Provides the details of the oligomeric state of the assembly. + */ + oligomeric_details: str, + /** + * The number of polymer molecules in the assembly. + */ + oligomeric_count: int, + /** + * A description of special aspects of the macromolecular assembly. + */ + details: str, + /** + * The value of _pdbx_struct_assembly.id must uniquely identify a record in + * the PDBX_STRUCT_ASSEMBLY list. + */ + id: str, + }, + /** + * Data items in the PDBX_STRUCT_ASSEMBLY_GEN category record details about + * the generation of each macromolecular assemblies. The PDBX_STRUCT_ASSEMBLY_GEN + * data items provide the specifications of the components that + * constitute that assembly in terms of cartesian transformations. + */ pdbx_struct_assembly_gen: { /** * This data item is a pointer to _struct_asym.id in @@ -1468,6 +1638,10 @@ export const mmCIF_Schema = { */ oper_expression: str, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_LIST category record + * the list of entities within each reference molecule. + */ pdbx_reference_entity_list: { /** * The value of _pdbx_reference_entity_list.prd_id is a reference @@ -1492,6 +1666,10 @@ export const mmCIF_Schema = { */ component_id: int, }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_LINK category give details about + * the linkages between entities within reference molecules. + */ pdbx_reference_entity_link: { /** * The value of _pdbx_reference_entity_link.link_id uniquely identifies @@ -1587,6 +1765,11 @@ export const mmCIF_Schema = { */ link_class: Aliased<'PP' | 'PN' | 'NP' | 'NN'>(str), }, + /** + * Data items in the PDBX_REFERENCE_ENTITY_POLY_LINK category give details about + * polymer linkages including both standard and non-standard linkages between + * polymer componnents. + */ pdbx_reference_entity_poly_link: { /** * The value of _pdbx_reference_entity_poly_link.link_id uniquely identifies @@ -1656,6 +1839,10 @@ export const mmCIF_Schema = { */ value_order: Aliased<'sing' | 'doub' | 'trip' | 'quad' | 'arom' | 'poly' | 'delo' | 'pi'>(str), }, + /** + * Data items in the PDBX_MOLECULE category identify reference molecules + * within a PDB entry. + */ pdbx_molecule: { /** * The value of _pdbx_molecule.prd_id is the PDB accession code for this @@ -1672,6 +1859,10 @@ export const mmCIF_Schema = { */ asym_id: str, }, + /** + * Data items in the PDBX_MOLECULE_FEATURES category record features of molecules + * within a PDB entry. + */ pdbx_molecule_features: { /** * The value of _pdbx_molecule_features.prd_id is the PDB accession code for this @@ -1695,6 +1886,11 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Data items in the IHM_STARTING_MODEL_DETAILS category records the + * details about structural models used as starting inputs in + * the integrative model building process. + */ ihm_starting_model_details: { /** * A unique identifier for the starting structural model. @@ -1750,6 +1946,11 @@ export const mmCIF_Schema = { */ dataset_list_id: int, }, + /** + * Data items in the IHM_STARTING_COMPARATIVE_MODELS category records + * additional details about comparative models used as starting inputs in + * the integrative model building process. + */ ihm_starting_comparative_models: { /** * A unique identifier for the starting comparative model. @@ -1805,6 +2006,15 @@ export const mmCIF_Schema = { */ alignment_file_id: int, }, + /** + * Data items in the IHM_STARTING_MODEL_SEQ_DIF category provide a + * mechanism for indicating and annotating point differences + * between the sequence of the entity or biological unit described + * in the data block and the sequence of the starting model used in + * the integrative modeling referenced from a database. The point + * differences may be due to point mutations introduced in the + * starting model or the presence of modified amino acid residues. + */ ihm_starting_model_seq_dif: { /** * A unique identifier for the entry. @@ -1857,6 +2067,12 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Data items in the IHM_MODEL_REPRESENTATION category records the + * details about the architecture and representation of structural + * models created by the integrative model building tasks. This + * category handles the multi-scale model representation, if employed. + */ ihm_model_representation: { /** * A unique identifier for the model details record. @@ -1918,6 +2134,11 @@ export const mmCIF_Schema = { */ model_object_count: int, }, + /** + * Data items in the IHM_STRUCT_ASSEMBLY category records the + * details of the structural assemblies and used in the + * IHM modeling. + */ ihm_struct_assembly: { /** * A unique identifier for the structural assembly description. @@ -1968,6 +2189,10 @@ export const mmCIF_Schema = { */ seq_id_end: int, }, + /** + * Data items in the IHM_STRUCT_ASSEMBLY_DETAILS category provides + * additional details regarding the structure assembly. + */ ihm_struct_assembly_details: { /** * A unique identifier for the structural assembly. @@ -1982,6 +2207,10 @@ export const mmCIF_Schema = { */ assembly_description: str, }, + /** + * Data items in the IHM_MODELING_PROTOCOL category records the + * step-wise details of the integrative modeling workflow. + */ ihm_modeling_protocol: { /** * A unique identifier for the modeling protocol/step combination. @@ -2049,6 +2278,10 @@ export const mmCIF_Schema = { */ ordered_flag: Aliased<'YES' | 'NO'>(str), }, + /** + * Data items in the IHM_MULTI_STATE_MODELING category records the + * details of the multi-state modeling protocol, if applicable. + */ ihm_multi_state_modeling: { /** * A unique identifier for the multiple states being described. @@ -2094,6 +2327,11 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Data items in the IHM_MODELING_POST_PROCESS category records + * the details of the post processing of the models/results of + * the modeling protocol. + */ ihm_modeling_post_process: { /** * A unique identifier for the post modeling analysis/step combination. @@ -2133,6 +2371,11 @@ export const mmCIF_Schema = { */ num_models_end: int, }, + /** + * Data items in the IHM_ENSEMBLE_INFO category records the + * details of the model clusters or ensembles obtained after + * sampling. + */ ihm_ensemble_info: { /** * A unique id for the ensemble. @@ -2193,6 +2436,10 @@ export const mmCIF_Schema = { */ ensemble_file_id: int, }, + /** + * Data items in the IHM_MODEL_LIST category record the + * details of the models being deposited. + */ ihm_model_list: { /** * A unique identifier for the model / model group combination. @@ -2246,6 +2493,10 @@ export const mmCIF_Schema = { */ representation_id: int, }, + /** + * Data items in the IHM_MODEL_REPRESENTATIVE category record the + * details of the representative model in an ensemble or cluster. + */ ihm_model_representative: { /** * A unique identifier for the representative of the model group. @@ -2268,6 +2519,15 @@ export const mmCIF_Schema = { */ selection_criteria: Aliased<'medoid' | 'closest to the average' | 'lowest energy' | 'target function' | 'fewest violations' | 'minimized average structure' | 'best scoring model' | 'centroid' | 'other selction criteria'>(str), }, + /** + * Category holds the list of all datasets used in the IHM modeling. + * These can be datasets archived in other related databases such as + * BMRB, EMDB, EMPIAR, SASBDB, PRIDE etc., or can be hosted in other + * places such as the authors website, github etc. These datasets are + * elaborated in detail in the IHM_DATASET_RELATED_DB_REFERENCE and/or + * the IHM_DATASET_EXTERNAL_REFERENCE categories. This category + * holds the list of all datasets used. + */ ihm_dataset_list: { /** * A unique identifier for the dataset. @@ -2283,6 +2543,9 @@ export const mmCIF_Schema = { */ database_hosted: Aliased<'YES' | 'NO'>(str), }, + /** + * Category provides a mechanism to group datasets. + */ ihm_dataset_group: { /** * A unique identifier for the entry. @@ -2298,6 +2561,9 @@ export const mmCIF_Schema = { */ dataset_list_id: int, }, + /** + * Category holds information about related datasets, where one is derived from the other. + */ ihm_related_datasets: { /** * A unique identifier for the entry. @@ -2316,6 +2582,11 @@ export const mmCIF_Schema = { */ dataset_list_id_primary: int, }, + /** + * Category holds information related to data sources for the entry. + * These can be datasets archived in other related databases such as + * BMRB, EMDB, EMPIAR, SASBDB, PRIDE etc. + */ ihm_dataset_related_db_reference: { /** * A unique identifier for the related database entry. @@ -2344,6 +2615,18 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Category holds links to other external data sources for the I/H model entry. + * Input datasets held in other databases such as EMDB, BMRB, SASBDB etc. + * are referenced in the IHM_DATASET_RELATED_DB_REFERENCE category. + * This data category, along with IHM_EXTERNAL_FILES category, holds information + * regarding other non-database external data sources, such as DOIs (digital + * object identifiers) or supplementary files stored locally. The DOIs can either + * lead to the external data file(s) directly (as in case of DOIs provided by the PDB) + * or might lead to an HTML landing page (as provided by Zenodo). In the latter case, + * additional URL (Uniform Resource Locator) information is required to retrieve + * the external data file(s). + */ ihm_external_reference_info: { /** * A unique identifier for the external reference. @@ -2376,6 +2659,12 @@ export const mmCIF_Schema = { */ associated_url: str, }, + /** + * Category provides details regarding external files. The IHM_EXTERNAL_REFERENCE_INFO + * category captures the top-level details regarding external data sources. + * This category captures the specific details regarding externally stored files + * related to the particular I/H model entry. + */ ihm_external_files: { /** * A unique identifier for each external file. @@ -2409,6 +2698,10 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Category provides additional details regarding input data hosted externally + * at other resources. + */ ihm_dataset_external_reference: { /** * A unique identifier for the external data. @@ -2427,6 +2720,13 @@ export const mmCIF_Schema = { */ file_id: int, }, + /** + * Data items in the IHM_LOCALIZATION_DENSITY_FILES category records the + * details of files that provide information regarding localization densities + * of ensembles. These may be stored externally as local files or linked via + * DOI and can be in any accepted format that provides volume information + * (CCP4, MRC, etc.). + */ ihm_localization_density_files: { /** * A unique identifier. @@ -2464,6 +2764,14 @@ export const mmCIF_Schema = { */ asym_id: str, }, + /** + * Data items in the IHM_PREDICTED_CONTACT_RESTRAINT category records the + * list of predicted contacts used in the integrative modeling experiment. + * This has been adapted from the widely used CASP RR format + * (http://www.predictioncenter.org/casp8/index.cgi?page=format#RR). + * These contacts may be derived from various computational tools. + * The software information can be provided in the SOFTWARE category. + */ ihm_predicted_contact_restraint: { /** * A unique identifier for the predicted contact restraint. @@ -2563,6 +2871,11 @@ export const mmCIF_Schema = { */ software_id: int, }, + /** + * Data items in the IHM_CROSS_LINK_LIST category records the + * list of spatial restraints derived from chemical crosslinking + * experiment. + */ ihm_cross_link_list: { /** * A unique identifier for the cross link restraint. @@ -2628,6 +2941,12 @@ export const mmCIF_Schema = { */ dataset_list_id: int, }, + /** + * Data items in the IHM_CROSS_LINK_RESTRAINT category enumerates the + * implementation details of the chemical crosslinking restraints in + * the integrative modeling. This category holds the details of how + * the experimentally derived crosslinks are applied in the modeling. + */ ihm_cross_link_restraint: { /** * A unique identifier for the cross link record. @@ -2740,6 +3059,10 @@ export const mmCIF_Schema = { */ sigma_2: float, }, + /** + * Data items in the IHM_CROSS_LINK_RESULT_PARAMETERS category records the + * results of the crosslinking restraint parameters in the IHM modeling. + */ ihm_cross_link_result_parameters: { /** * A unique identifier for the restraint/model combination. @@ -2773,6 +3096,10 @@ export const mmCIF_Schema = { */ sigma_2: float, }, + /** + * Data items in the IHM_2DEM_CLASS_AVERAGE_RESTRAINT category records the + * details of the 2DEM class averages used in the IHM modeling. + */ ihm_2dem_class_average_restraint: { /** * A unique identifier for the 2dem class average. @@ -2829,6 +3156,24 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Data items in the IHM_2DEM_CLASS_AVERAGE_FITTING category records the + * details of the fitting of the model to the 2DEM class averages + * used in the IHM modeling. The following conventions are recommended + * while generating the rotation matrix and translation vector for + * transformation. + * + * - The model is rotated and translated to fit to the 2DEM image. + * - The 2DEM image should be in the XY plane. + * - The lower left image corner (image pixel index 0,0) should be at x,y,z = (0,0,0). + * - The 2D image is scaled by the _ihm_2dem_class_average_restraint.pixel_size_width + * and _ihm_2dem_class_average_restraint.pixel_size_height from the + * IHM_2DEM_CLASS_AVERAGE_RESTRAINT table. + * - The transformation is applied after the scaling and hence the translation vector + * should account for the scaling. + * - There are no specifications for Z translations i.e., how far the image should be + * from the model while projecting. It may be set to zero. + */ ihm_2dem_class_average_fitting: { /** * A unique identifier for the 2dem class average fitting data. @@ -2859,6 +3204,11 @@ export const mmCIF_Schema = { */ tr_vector: Vector(3), }, + /** + * Data items in the IHM_3DEM_RESTRAINT category records the + * details of the 3DEM maps used as restraints in the + * IHM modeling. + */ ihm_3dem_restraint: { /** * A unique identifier for the 3DEM restraint description. @@ -2902,6 +3252,11 @@ export const mmCIF_Schema = { */ cross_correlation_coefficient: float, }, + /** + * Data items in the IHM_SAS_RESTRAINT category records the + * details of the SAS data used as restraints in the + * IHM modeling. + */ ihm_sas_restraint: { /** * A unique identifier for the SAS restraint description. @@ -2960,6 +3315,11 @@ export const mmCIF_Schema = { */ details: str, }, + /** + * Data items in the IHM_STARTING_MODEL_COORD category records the coordinates + * for structural templates used as starting inputs in the integrative model + * building tasks. + */ ihm_starting_model_coord: { /** * A unique identifier for this coordinate position. @@ -3030,6 +3390,10 @@ export const mmCIF_Schema = { */ B_iso_or_equiv: float, }, + /** + * Data items in the IHM_SPHERE_OBJ_SITE category records the details + * of the spherical objects modeled in the integrative structural model. + */ ihm_sphere_obj_site: { /** * A unique identifier for this pseudo atom / sphere object. @@ -3083,6 +3447,10 @@ export const mmCIF_Schema = { */ model_id: int, }, + /** + * Data items in the IHM_GAUSSIAN_OBJ_SITE category records the details + * of the gaussian objects modeled in the integrative structural model. + */ ihm_gaussian_obj_site: { /** * A unique identifier for this gaussian object in the model. @@ -3135,6 +3503,10 @@ export const mmCIF_Schema = { */ model_id: int, }, + /** + * Data items in the IHM_GAUSSIAN_OBJ_ENSEMBLE category records the details + * of the gaussian objects representing an ensemble or cluster of models. + */ ihm_gaussian_obj_ensemble: { /** * A unique identifier for this gaussian object. @@ -3187,6 +3559,10 @@ export const mmCIF_Schema = { */ ensemble_id: int, }, + /** + * IHM_FEATURE_LIST is the high level category that provides defintions + * to select atoms/residues from polymeric and non-polymeric entities. + */ ihm_feature_list: { /** * A unique identifier for the feature. @@ -3202,6 +3578,11 @@ export const mmCIF_Schema = { */ entity_type: Aliased<'polymer' | 'non-polymer' | 'macrolide' | 'water'>(str), }, + /** + * Data items in the IHM_POLY_RESIDUE_FEATURE category provides the defintions + * required to select a specific residue or a set of residues that may or may not be + * in a contiguous range. + */ ihm_poly_residue_feature: { /** * A unique identifier for the category. @@ -3246,6 +3627,11 @@ export const mmCIF_Schema = { */ seq_id_end: int, }, + /** + * Data items in the IHM_DERIVED_DISTANCE_RESTRAINT category records the + * list of distance restraints used in the integrative modeling experiment. + * These distance redistance restraints may be derived from various kinds of experiments. + */ ihm_derived_distance_restraint: { /** * A unique identifier for the derived distance restraint. diff --git a/src/mol-io/reader/obj/parser.ts b/src/mol-io/reader/obj/parser.ts new file mode 100644 index 0000000000000000000000000000000000000000..46cd16ccb151b1fb0ab69afa873c83f33a09e0b8 --- /dev/null +++ b/src/mol-io/reader/obj/parser.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import Result from '../result' +import { Task, RuntimeContext } from 'mol-task' +import { Mesh } from 'mol-geo/mesh/mesh'; + +async function parseInternal(data: string, ctx: RuntimeContext): Promise<Result<Mesh>> { + // TODO + const mesh: Mesh = Mesh.createEmpty(); + // Mesh.computeNormalsImmediate(mesh) + return Result.success(mesh); +} + +export function parse(data: string) { + return Task.create<Result<Mesh>>('Parse OBJ', async ctx => { + return await parseInternal(data, ctx); + }); +} + +export default parse; \ No newline at end of file diff --git a/src/mol-math/linear-algebra/3d/vec3.ts b/src/mol-math/linear-algebra/3d/vec3.ts index 2527ca8724068857a12562845ee7895800901c72..f2f0e1427e87cd980e42d676a5a3d1f62db091a7 100644 --- a/src/mol-math/linear-algebra/3d/vec3.ts +++ b/src/mol-math/linear-algebra/3d/vec3.ts @@ -50,13 +50,13 @@ namespace Vec3 { v[0] = array[offset + 0] v[1] = array[offset + 1] v[2] = array[offset + 2] + return v } export function toArray(v: Vec3, out: Helpers.NumberArray, offset: number) { out[offset + 0] = v[0] out[offset + 1] = v[1] out[offset + 2] = v[2] - return v } export function create(x: number, y: number, z: number): Vec3 { diff --git a/src/mol-model-props/rcsb/graphql/types.ts b/src/mol-model-props/rcsb/graphql/types.ts index a5c7ebb3ed520bff17eafc1e4d8cd075c49f1202..b97fd46b849b6f387f4ce5c3bb9c68f6d44a7e21 100644 --- a/src/mol-model-props/rcsb/graphql/types.ts +++ b/src/mol-model-props/rcsb/graphql/types.ts @@ -1,5 +1,5 @@ /* tslint:disable */ -/** Generated in 2018-08-20T10:50:59-07:00 */ +/** Generated in 2018-08-22T17:02:01-07:00 */ export enum PdbxLeavingAtomFlag { N = "N", @@ -42,7 +42,7 @@ export enum UnpublishedFlag { Y = "Y" } -export enum PdbxMonochromaticOrLaueML { +export enum PdbxMonochromaticOrLaueMl { L = "L", M = "M" } diff --git a/src/mol-model/location.ts b/src/mol-model/location.ts index c3361122aa7839d48c84b000aaf3cc13bb1608d7..39546ddac69d0642e20e7f5d232b824d798e2c90 100644 --- a/src/mol-model/location.ts +++ b/src/mol-model/location.ts @@ -6,6 +6,7 @@ import { StructureElement } from './structure' import { Link } from './structure/structure/unit/links' +import { Shape } from './shape/shape'; /** A null value Location */ export const NullLocation = { kind: 'null-location' as 'null-location' } @@ -14,4 +15,4 @@ export function isNullLocation(x: any): x is NullLocation { return !!x && x.kind === 'null-location'; } -export type Location = StructureElement | Link.Location | NullLocation \ No newline at end of file +export type Location = StructureElement | Link.Location | Shape.Location | NullLocation \ No newline at end of file diff --git a/src/mol-model/loci.ts b/src/mol-model/loci.ts index 37a679c9c9ef3f856f0b40d8e246714f83dadd25..d84498e133ae0e709429c81c6b57a5a715f981b2 100644 --- a/src/mol-model/loci.ts +++ b/src/mol-model/loci.ts @@ -6,6 +6,7 @@ import { StructureElement } from './structure' import { Link } from './structure/structure/unit/links' +import { Shape } from './shape'; /** A Loci that includes every loci */ export const EveryLoci = { kind: 'every-loci' as 'every-loci' } @@ -21,4 +22,4 @@ export function isEmptyLoci(x: any): x is EmptyLoci { return !!x && x.kind === 'empty-loci'; } -export type Loci = StructureElement.Loci | Link.Loci | EveryLoci | EmptyLoci \ No newline at end of file +export type Loci = StructureElement.Loci | Link.Loci | EveryLoci | EmptyLoci | Shape.Loci \ No newline at end of file diff --git a/src/mol-model/shape.ts b/src/mol-model/shape.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc1125ad411cce5f45eef76efc8f423fbeb09512 --- /dev/null +++ b/src/mol-model/shape.ts @@ -0,0 +1,7 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +export * from './shape/shape' \ No newline at end of file diff --git a/src/mol-model/shape/shape.ts b/src/mol-model/shape/shape.ts new file mode 100644 index 0000000000000000000000000000000000000000..58f930b6ed8e685b4038c2be3f06ff4a9d417691 --- /dev/null +++ b/src/mol-model/shape/shape.ts @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { Mesh } from 'mol-geo/mesh/mesh'; +import { Color } from 'mol-util/color'; +import { UUID, ValueCell } from 'mol-util'; +import { OrderedSet } from 'mol-data/int'; +import { arrayMax } from 'mol-util/array'; + +export interface Shape { + readonly id: UUID + readonly name: string + readonly mesh: Mesh + readonly colors: ValueCell<Color[]> + readonly labels: ValueCell<string[]> + readonly groupCount: number +} + +export namespace Shape { + export function create(name: string, mesh: Mesh, colors: Color[], labels: string[]): Shape { + let currentGroupBufferVersion = -1 + let currentGroupCount = -1 + + return { + id: UUID.create(), + name, + mesh, + get groupCount() { + if (mesh.groupBuffer.ref.version !== currentGroupBufferVersion) { + currentGroupCount = arrayMax(mesh.groupBuffer.ref.value) + 1 + } + return currentGroupCount + }, + colors: ValueCell.create(colors), + labels: ValueCell.create(labels), + } + } + + export interface Location { + readonly kind: 'group-location' + shape: Shape + group: number + } + + export function Location(shape?: Shape, group?: number): Location { + return { kind: 'group-location', shape: shape!, group: group || 0 }; + } + + export function isLocation(x: any): x is Location { + return !!x && x.kind === 'group-location'; + } + + export interface Loci { + readonly kind: 'group-loci', + readonly groups: ReadonlyArray<{ + shape: Shape, + ids: OrderedSet<number> + }> + } + + export function Loci(groups: ArrayLike<{ shape: Shape, ids: OrderedSet<number> }>): Loci { + return { kind: 'group-loci', groups: groups as Loci['groups'] }; + } + + export function isLoci(x: any): x is Loci { + return !!x && x.kind === 'group-loci'; + } +} \ No newline at end of file diff --git a/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts b/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts index 371ac04a16b8410f2b256703813aa044e9a4d0a8..e3b16f7729a38301ca803f8d187d3818150ec6b3 100644 --- a/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts +++ b/src/mol-model/structure/model/formats/mmcif/bonds/struct_conn.ts @@ -11,7 +11,7 @@ import { LinkType } from '../../../types' import { findEntityIdByAsymId, findAtomIndexByLabelName } from '../util' import { Column } from 'mol-data/db' import { ModelPropertyDescriptor } from '../../../properties/custom'; -import { mmCIF_Database } from 'mol-io/reader/cif/schema/mmcif'; +import { mmCIF_Database, mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif'; import { SortedArray } from 'mol-data/int'; import { CifWriter } from 'mol-io/writer/cif' import { ElementIndex } from '../../../indexing'; @@ -137,17 +137,7 @@ export namespace StructConn { partners: { residueIndex: number, atomIndex: ElementIndex, symmetry: string }[] } - type StructConnType = - | 'covale' - | 'covale_base' - | 'covale_phosphate' - | 'covale_sugar' - | 'disulf' - | 'hydrog' - | 'metalc' - | 'mismat' - | 'modres' - | 'saltbr' + type StructConnType = typeof mmCIF_Schema.struct_conn.conn_type_id.T export function attachFromMmCif(model: Model): boolean { if (model.customProperties.has(Descriptor)) return true; @@ -248,7 +238,7 @@ export namespace StructConn { case 'disulf': flags = LinkType.Flag.Covalent | LinkType.Flag.Sulfide; break; case 'hydrog': flags = LinkType.Flag.Hydrogen; break; case 'metalc': flags = LinkType.Flag.MetallicCoordination; break; - case 'saltbr': flags = LinkType.Flag.Ion; break; + case 'saltbr': flags = LinkType.Flag.Ionic; break; } entries.push({ rowIndex: i, flags, order, distance: pdbx_dist_value.value(i), partners }); diff --git a/src/mol-model/structure/model/types.ts b/src/mol-model/structure/model/types.ts index 58a8989b5462d2ed9ffc3ae56756fe95143bbe34..ed5cb504da50424c273793f68551282e1bfa1202 100644 --- a/src/mol-model/structure/model/types.ts +++ b/src/mol-model/structure/model/types.ts @@ -50,6 +50,8 @@ export const enum MoleculeType { RNA, /** DNA, e.g. component type included in `DNAComponentTypeNames` */ DNA, + /** PNA, peptide nucleic acid, comp id included in `PeptideBaseNames` */ + PNA, /** sacharide, e.g. component type included in `SaccharideComponentTypeNames` */ saccharide } @@ -77,6 +79,12 @@ export const MoleculeTypeAtomRoleId: { [k: number]: { [k in AtomRole]: string } direction: 'C1\'', // TODO 'C1*' backboneStart: 'P', backboneEnd: 'O3\'' // TODO 'O3*' + }, + [MoleculeType.PNA]: { + trace: 'N4\'', // TODO 'N4*' + direction: 'C7\'', // TODO 'C7*' + backboneStart: 'N1\'', // TODO 'N1*' + backboneEnd: 'C1\'' // TODO 'C1*' } } @@ -153,9 +161,10 @@ export const ExtraSaccharideNames = [ export const RnaBaseNames = [ 'A', 'C', 'T', 'G', 'I', 'U' ] export const DnaBaseNames = [ 'DA', 'DC', 'DT', 'DG', 'DI', 'DU' ] -export const PurinBaseNames = [ 'A', 'G', 'DA', 'DG', 'DI' ] -export const PyrimidineBaseNames = [ 'C', 'T', 'U', 'DC', 'DT', 'DU' ] -export const BaseNames = RnaBaseNames.concat(DnaBaseNames) +export const PeptideBaseNames = [ 'APN', 'CPN', 'TPN', 'GPN' ] +export const PurinBaseNames = [ 'A', 'G', 'DA', 'DG', 'DI', 'APN', 'GPN' ] +export const PyrimidineBaseNames = [ 'C', 'T', 'U', 'DC', 'DT', 'DU', 'CPN', 'TPN' ] +export const BaseNames = RnaBaseNames.concat(DnaBaseNames, PeptideBaseNames) export const isPurinBase = (compId: string) => PurinBaseNames.includes(compId.toUpperCase()) export const isPyrimidineBase = (compId: string) => PyrimidineBaseNames.includes(compId.toUpperCase()) @@ -164,7 +173,9 @@ export const isPyrimidineBase = (compId: string) => PyrimidineBaseNames.includes export function getMoleculeType(compType: string, compId: string) { compType = compType.toUpperCase() compId = compId.toUpperCase() - if (ProteinComponentTypeNames.includes(compType)) { + if (PeptideBaseNames.includes(compId)) { + return MoleculeType.PNA + } else if (ProteinComponentTypeNames.includes(compType)) { return MoleculeType.protein } else if (RNAComponentTypeNames.includes(compType)) { return MoleculeType.RNA @@ -182,11 +193,11 @@ export function getMoleculeType(compType: string, compId: string) { } export function isPolymer(moleculeType: MoleculeType) { - return moleculeType === MoleculeType.protein || moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA + return moleculeType === MoleculeType.protein || moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA || moleculeType === MoleculeType.PNA } export function isNucleic(moleculeType: MoleculeType) { - return moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA + return moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA || moleculeType === MoleculeType.PNA } /** @@ -484,7 +495,7 @@ export namespace LinkType { Covalent = 0x1, MetallicCoordination = 0x2, Hydrogen = 0x4, - Ion = 0x8, + Ionic = 0x8, Sulfide = 0x10, Aromatic = 0x20, Computed = 0x40 diff --git a/src/mol-model/structure/query/queries/generators.ts b/src/mol-model/structure/query/queries/generators.ts index 9a75838c987f3fedcf344235ddf05570f044fd4c..34ce3fd620119edf4ce852b80bd19e146f205489 100644 --- a/src/mol-model/structure/query/queries/generators.ts +++ b/src/mol-model/structure/query/queries/generators.ts @@ -20,9 +20,13 @@ export const none: StructureQuery = ctx => StructureSelection.Sequence(ctx.input export const all: StructureQuery = ctx => StructureSelection.Singletons(ctx.inputStructure, ctx.inputStructure); export interface AtomsQueryParams { + /** Query to be executed for each entity once */ entityTest: QueryPredicate, + /** Query to be executed for each chain once */ chainTest: QueryPredicate, + /** Query to be executed for each residue once */ residueTest: QueryPredicate, + /** Query to be executed for each atom */ atomTest: QueryPredicate, groupBy: QueryFn } diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index 6c31ccd7483b52d341fea903aedbccf6df848d34..0c83fbcd981cba97b08393086738f339d080aa4b 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/src/mol-model/structure/structure/element.ts @@ -18,7 +18,7 @@ interface StructureElement<U = Unit> { namespace StructureElement { export function create(unit?: Unit, element?: ElementIndex): StructureElement { - return { kind: 'element-location', unit: unit as any, element: element || (0 as ElementIndex) }; + return { kind: 'element-location', unit: unit!, element: element || (0 as ElementIndex) }; } // TODO: when nominal types are available, make this indexed by UnitIndex diff --git a/src/mol-util/array.ts b/src/mol-util/array.ts index d3dfa14a95f7bc2e030ef609e5effaf8a8f1ff08..11998ff2d6d9391ca612620e34f2e5d5706bb641 100644 --- a/src/mol-util/array.ts +++ b/src/mol-util/array.ts @@ -4,6 +4,9 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ +// TODO move to mol-math as Vector??? + +/** Get the maximum value in an array */ export function arrayMax(array: Helpers.NumberArray) { let max = -Infinity for (let i = 0, il = array.length; i < il; ++i) { @@ -12,6 +15,7 @@ export function arrayMax(array: Helpers.NumberArray) { return max } +/** Get the minimum value in an array */ export function arrayMin(array: Helpers.NumberArray) { let min = Infinity for (let i = 0, il = array.length; i < il; ++i) { @@ -20,6 +24,7 @@ export function arrayMin(array: Helpers.NumberArray) { return min } +/** Get the sum of values in an array */ export function arraySum(array: Helpers.NumberArray, stride = 1, offset = 0) { const n = array.length let sum = 0 @@ -29,10 +34,12 @@ export function arraySum(array: Helpers.NumberArray, stride = 1, offset = 0) { return sum } +/** Get the mean of values in an array */ export function arrayMean(array: Helpers.NumberArray, stride = 1, offset = 0) { return arraySum(array, stride, offset) / (array.length / stride) } +/** Get the root mean square of values in an array */ export function arrayRms(array: Helpers.NumberArray) { const n = array.length let sumSq = 0 @@ -43,6 +50,7 @@ export function arrayRms(array: Helpers.NumberArray) { return Math.sqrt(sumSq / n) } +/** Fill an array with serial numbers starting from 0 */ export function fillSerial<T extends Helpers.NumberArray> (array: T) { const n = array.length for (let i = 0; i < n; ++i) array[ i ] = i diff --git a/src/mol-view/label.ts b/src/mol-view/label.ts index 288eae4673297a388605118adc133dfe5ae1830f..fe766334660d7072333af05996eebe43e4685d4b 100644 --- a/src/mol-view/label.ts +++ b/src/mol-view/label.ts @@ -12,7 +12,7 @@ import { OrderedSet } from 'mol-data/int'; const elementLocA = StructureElement.create() const elementLocB = StructureElement.create() -function setElementLocation(loc: StructureElement, unit: Unit, index: number) { +function setElementLocation(loc: StructureElement, unit: Unit, index: StructureElement.UnitIndex) { loc.unit = unit loc.element = unit.elements[index] } @@ -36,6 +36,13 @@ export function labelFirst(loci: Loci): string { } else { return 'Unknown' } + case 'group-loci': + const g = loci.groups[0] + if (g) { + return g.shape.labels.ref.value[OrderedSet.getAt(g.ids, 0)] + } else { + return 'Unknown' + } case 'every-loci': return 'Everything' case 'empty-loci': diff --git a/src/mol-view/stage.ts b/src/mol-view/stage.ts index 910b8b39b7cd981c8ea50eab5c65d0bb8e3de9f8..6ecac7aa58dcde699b76c542eb2d80852050fb27 100644 --- a/src/mol-view/stage.ts +++ b/src/mol-view/stage.ts @@ -121,9 +121,11 @@ export class Stage { // this.loadMmcifUrl(`../../examples/1cbs_updated.cif`) // this.loadMmcifUrl(`../../examples/1crn.cif`) // this.loadPdbid('5u0q') // mixed dna/rna in same polymer - // this.loadPdbid('5u0q') // temp + // this.loadPdbid('1xj9') // PNA (peptide nucleic acid) + this.loadPdbid('5eme') // PNA (peptide nucleic acid) and RNA + // this.loadPdbid('5eme') // temp - this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) // ok + // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000001.cif`) // ok // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000002.cif`) // ok // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000003.cif`) // ok // this.loadMmcifUrl(`../../../test/pdb-dev/PDBDEV_00000004.cif`) // TODO issue with cross-link extraction, not shown diff --git a/src/mol-view/theme/color.ts b/src/mol-view/theme/color.ts index ba8fec56a0fa4883ffe7e4121f73fdb974b20154..f02f54b3a11d757f1d636d71a99a12f8d414ee1f 100644 --- a/src/mol-view/theme/color.ts +++ b/src/mol-view/theme/color.ts @@ -15,6 +15,7 @@ import { ElementSymbolColorTheme } from './color/element-symbol'; import { UnitIndexColorTheme } from './color/unit-index'; import { UniformColorTheme } from './color/uniform'; import { CrossLinkColorTheme } from './color/cross-link'; +import { ShapeGroupColorTheme } from './color/shape-group'; export interface ColorTheme { kind: ColorType @@ -30,6 +31,7 @@ export function ColorTheme(props: ColorThemeProps): ColorTheme { case 'element-symbol': return ElementSymbolColorTheme(props) case 'unit-index': return UnitIndexColorTheme(props) case 'uniform': return UniformColorTheme(props) + case 'shape-group': return ShapeGroupColorTheme(props) } } @@ -47,7 +49,8 @@ export const ColorThemeInfo = { 'chain-id': {}, 'element-symbol': {}, 'unit-index': {}, - 'uniform': {} + 'uniform': {}, + 'shape-group': {} } export type ColorThemeName = keyof typeof ColorThemeInfo export const ColorThemeNames = Object.keys(ColorThemeInfo) \ No newline at end of file diff --git a/src/mol-view/theme/color/carbohydrate-symbol.ts b/src/mol-view/theme/color/carbohydrate-symbol.ts index 8ccdf51d91b9dde4fb39bc7fead5f459f687a65e..7c3093a0b2ffce1e3e8ac4e865516bf8976f1ce7 100644 --- a/src/mol-view/theme/color/carbohydrate-symbol.ts +++ b/src/mol-view/theme/color/carbohydrate-symbol.ts @@ -47,7 +47,7 @@ export function CarbohydrateSymbolColorTheme(props: ColorThemeProps): ColorTheme } return { - kind: 'element', + kind: 'group', color: colorFn } } \ No newline at end of file diff --git a/src/mol-view/theme/color/chain-id.ts b/src/mol-view/theme/color/chain-id.ts index 8a40badbf5188c939212c49153421b2ec58ecfc9..9e15eec0f430d12805b680c155c03033cc7223e8 100644 --- a/src/mol-view/theme/color/chain-id.ts +++ b/src/mol-view/theme/color/chain-id.ts @@ -43,7 +43,7 @@ export function ChainIdColorTheme(props: ColorThemeProps): ColorTheme { } return { - kind: 'element', + kind: 'group', color: colorFn } } \ No newline at end of file diff --git a/src/mol-view/theme/color/cross-link.ts b/src/mol-view/theme/color/cross-link.ts index aa80d8b26557a24d0f5951dc6160f45dfe7ac95f..5a4709dc550531cafeb512eef140987399612dfd 100644 --- a/src/mol-view/theme/color/cross-link.ts +++ b/src/mol-view/theme/color/cross-link.ts @@ -42,7 +42,7 @@ export function CrossLinkColorTheme(props: ColorThemeProps): ColorTheme { } return { - kind: 'element', + kind: 'group', color: colorFn } } \ No newline at end of file diff --git a/src/mol-view/theme/color/element-index.ts b/src/mol-view/theme/color/element-index.ts index 78daf537ace4e0efd16eec0641c374c7c4d4b367..f6abd54f3cdee2a02e2531e660a9b93449d831ba 100644 --- a/src/mol-view/theme/color/element-index.ts +++ b/src/mol-view/theme/color/element-index.ts @@ -44,7 +44,7 @@ export function ElementIndexColorTheme(props: ColorThemeProps): ColorTheme { } return { - kind: 'elementInstance', + kind: 'groupInstance', color: colorFn } } \ No newline at end of file diff --git a/src/mol-view/theme/color/element-symbol.ts b/src/mol-view/theme/color/element-symbol.ts index 0a8be64caea01c68611df96b29ce9c10d5fdd743..eaa64ebb687eff4b8b8d2d9888ff5215a298eba6 100644 --- a/src/mol-view/theme/color/element-symbol.ts +++ b/src/mol-view/theme/color/element-symbol.ts @@ -39,7 +39,7 @@ export function ElementSymbolColorTheme(props: ColorThemeProps): ColorTheme { } return { - kind: 'element', + kind: 'group', color: colorFn } } \ No newline at end of file diff --git a/src/mol-view/theme/color/shape-group.ts b/src/mol-view/theme/color/shape-group.ts new file mode 100644 index 0000000000000000000000000000000000000000..f7be8107b23ea16e631fb08bd567e8af292b42e7 --- /dev/null +++ b/src/mol-view/theme/color/shape-group.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { ColorTheme, ColorThemeProps } from '../color'; +import { Color } from 'mol-util/color'; +import { Location } from 'mol-model/location'; +import { Shape } from 'mol-model/shape'; + +const DefaultColor = 0xCCCCCC as Color + +export function ShapeGroupColorTheme(props: ColorThemeProps): ColorTheme { + return { + kind: 'group', + color: (location: Location): Color => { + if (Shape.isLocation(location)) { + return location.shape.colors.ref.value[location.group] + } + return DefaultColor + } + } +} \ No newline at end of file diff --git a/src/mol-view/theme/size/physical.ts b/src/mol-view/theme/size/physical.ts index e034b5c2c0670bc7641e2d26102e7d500d91066a..87c7ccefe0c8ebe717d9269bf032fa077d7b7668 100644 --- a/src/mol-view/theme/size/physical.ts +++ b/src/mol-view/theme/size/physical.ts @@ -42,7 +42,7 @@ export function PhysicalSizeTheme(props: SizeThemeProps): SizeTheme { } return { - kind: 'element', + kind: 'group', size: sizeFn } } \ No newline at end of file diff --git a/src/mol-view/viewer.ts b/src/mol-view/viewer.ts index addf444decb7f26f324fa726c3cfa1f306e8a0f4..d3eb6d3d22ebb55237a9c35a776fe7b698307bde 100644 --- a/src/mol-view/viewer.ts +++ b/src/mol-view/viewer.ts @@ -109,7 +109,7 @@ namespace Viewer { const pickHeight = Math.round(canvas.height * pickScale) const objectPickTarget = createRenderTarget(ctx, pickWidth, pickHeight) const instancePickTarget = createRenderTarget(ctx, pickWidth, pickHeight) - const elementPickTarget = createRenderTarget(ctx, pickWidth, pickHeight) + const groupPickTarget = createRenderTarget(ctx, pickWidth, pickHeight) let pickDirty = true let drawPending = false @@ -165,7 +165,7 @@ namespace Viewer { switch (variant) { case 'pickObject': objectPickTarget.bind(); break; case 'pickInstance': instancePickTarget.bind(); break; - case 'pickElement': elementPickTarget.bind(); break; + case 'pickGroup': groupPickTarget.bind(); break; case 'draw': ctx.unbindFramebuffer(); renderer.setViewport(0, 0, canvas.width, canvas.height); @@ -210,7 +210,7 @@ namespace Viewer { function pick() { render('pickObject', pickDirty) render('pickInstance', pickDirty) - render('pickElement', pickDirty) + render('pickGroup', pickDirty) pickDirty = false } @@ -232,11 +232,11 @@ namespace Viewer { ctx.readPixels(xp, yp, 1, 1, buffer) const instanceId = decodeIdRGBA(buffer[0], buffer[1], buffer[2]) - elementPickTarget.bind() + groupPickTarget.bind() ctx.readPixels(xp, yp, 1, 1, buffer) - const elementId = decodeIdRGBA(buffer[0], buffer[1], buffer[2]) + const groupId = decodeIdRGBA(buffer[0], buffer[1], buffer[2]) - return { objectId, instanceId, elementId } + return { objectId, instanceId, groupId } } handleResize() @@ -303,7 +303,7 @@ namespace Viewer { case 'draw': return renderer.getImageData() case 'pickObject': return objectPickTarget.getImageData() case 'pickInstance': return instancePickTarget.getImageData() - case 'pickElement': return elementPickTarget.getImageData() + case 'pickGroup': return groupPickTarget.getImageData() } }, reprCount, @@ -334,7 +334,7 @@ namespace Viewer { const pickHeight = Math.round(canvas.height * pickScale) objectPickTarget.setSize(pickWidth, pickHeight) instancePickTarget.setSize(pickWidth, pickHeight) - elementPickTarget.setSize(pickWidth, pickHeight) + groupPickTarget.setSize(pickWidth, pickHeight) } } }