mirror of
https://github.com/molstar/molstar.git
synced 2026-06-04 21:34:23 +08:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee8cae16d2 | ||
|
|
feaf6f7fd4 | ||
|
|
04775a2e44 | ||
|
|
bec9fec755 | ||
|
|
c7edf40afe | ||
|
|
b44962eb2f | ||
|
|
c64851492c | ||
|
|
4a2e93e265 | ||
|
|
55de0aba69 | ||
|
|
ecfa7b5a99 | ||
|
|
bee3dc4595 | ||
|
|
787ca47825 | ||
|
|
6fab6ce1f2 | ||
|
|
9fd95f1a11 | ||
|
|
69fe0901e2 | ||
|
|
8c417ef35c | ||
|
|
01691f3050 | ||
|
|
128abf3090 | ||
|
|
0c0e995256 | ||
|
|
4090498f92 | ||
|
|
24677d6931 | ||
|
|
908fff8041 | ||
|
|
aa1eb90f66 | ||
|
|
1d21787e7e | ||
|
|
42409a2bc7 | ||
|
|
b31302ba3a | ||
|
|
3840b0041b | ||
|
|
cc68f8311d | ||
|
|
3400c8e94a | ||
|
|
61c47c517b | ||
|
|
76674917ca | ||
|
|
b835eb8de7 | ||
|
|
3f0d476e94 | ||
|
|
9423d56d36 | ||
|
|
0f03fe99d6 | ||
|
|
556d5bb003 | ||
|
|
8e3ea6943f | ||
|
|
599cfc1b1c | ||
|
|
84eccb5019 | ||
|
|
2dd07bb0e3 | ||
|
|
f404d23280 | ||
|
|
8b7333b470 | ||
|
|
7d26567d40 | ||
|
|
8f6dbf2192 | ||
|
|
db350ddfd3 | ||
|
|
c0144d826c | ||
|
|
de3e819b80 | ||
|
|
bbf96567b1 | ||
|
|
c9a3254bd6 | ||
|
|
bad6d030f1 | ||
|
|
e1ad67a059 | ||
|
|
c62f19623c |
@@ -38,7 +38,24 @@
|
||||
"selector": "ExportDefaultDeclaration",
|
||||
"message": "Default exports are not allowed"
|
||||
}
|
||||
]
|
||||
],
|
||||
"no-throw-literal": "error",
|
||||
"key-spacing": "error",
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"array-bracket-spacing": "error",
|
||||
"space-in-parens": "error",
|
||||
"computed-property-spacing": "error",
|
||||
"prefer-const": ["error", {
|
||||
"destructuring": "all",
|
||||
"ignoreReadBeforeAssign": false
|
||||
}],
|
||||
"space-before-function-paren": "off",
|
||||
"func-call-spacing": "off",
|
||||
"no-multi-spaces": "error",
|
||||
"block-spacing": "error",
|
||||
"keyword-spacing": "off",
|
||||
"space-before-blocks": "error",
|
||||
"semi-spacing": "error"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
@@ -89,7 +106,14 @@
|
||||
"error",
|
||||
"1tbs", { "allowSingleLine": true }
|
||||
],
|
||||
"@typescript-eslint/comma-spacing": "error"
|
||||
"@typescript-eslint/comma-spacing": "error",
|
||||
"@typescript-eslint/space-before-function-paren": ["error", {
|
||||
"anonymous": "always",
|
||||
"named": "never",
|
||||
"asyncArrow": "always"
|
||||
}],
|
||||
"@typescript-eslint/func-call-spacing": ["error"],
|
||||
"@typescript-eslint/keyword-spacing": ["error"]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
32
CHANGELOG.md
32
CHANGELOG.md
@@ -6,6 +6,38 @@ Note that since we don't clearly distinguish between a public and private interf
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v2.3.2] - 2021-10-01
|
||||
|
||||
- Prefer WebGL1 on iOS devices until WebGL2 support has stabilized.
|
||||
|
||||
|
||||
## [v2.3.1] - 2021-09-28
|
||||
|
||||
- Add Charmm saccharide names
|
||||
- Treat missing occupancy column as occupany of 1
|
||||
- Fix line shader not accounting for aspect ratio
|
||||
- [Breaking] Fix point repr & shader
|
||||
- Was unusable with ``wboit``
|
||||
- Replaced ``pointFilledCircle`` & ``pointEdgeBleach`` params by ``pointStyle`` (square, circle, fuzzy)
|
||||
- Set ``pointSizeAttenuation`` to false by default
|
||||
- Set ``sizeTheme`` to ``uniform`` by default
|
||||
- Add ``markerPriority`` option to Renderer (useful in combination with edges of marking pass)
|
||||
- Add support support for ``chem_comp_bond`` and ``struct_conn`` categories (fixes ModelServer behavior where these categories should have been present)
|
||||
- Model and VolumeServer: fix argparse config
|
||||
|
||||
## [v2.3.0] - 2021-09-06
|
||||
|
||||
- Take include/exclude flags into account when displaying aromatic bonds
|
||||
- Improve marking performance
|
||||
- Avoid unnecessary draw calls/ui updates when marking
|
||||
- Check if loci is superset of visual
|
||||
- Check if loci overlaps with unit visual
|
||||
- Ensure ``Interval`` is used for ranges instead of ``SortedArray``
|
||||
- Add uniform marker type
|
||||
- Special case for reversing previous mark
|
||||
- Add optional marking pass
|
||||
- Outlines visible and hidden parts of highlighted/selected groups
|
||||
- Add highlightStrength/selectStrength renderer params
|
||||
|
||||
## [v2.2.3] - 2021-08-25
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@ audit.block_doi
|
||||
|
||||
database_code.depnum_ccdc_archive
|
||||
database_code.depnum_ccdc_fiz
|
||||
database_code.ICSD
|
||||
database_code.MDF
|
||||
database_code.NBS
|
||||
database_code.CSD
|
||||
database_code.COD
|
||||
database_code.icsd
|
||||
database_code.mdf
|
||||
database_code.nbs
|
||||
database_code.csd
|
||||
database_code.cod
|
||||
|
||||
chemical.name_systematic
|
||||
chemical.name_common
|
||||
@@ -24,8 +24,8 @@ atom_type_scat.dispersion_imag
|
||||
atom_type_scat.source
|
||||
|
||||
space_group.crystal_system
|
||||
space_group.name_H-M_full
|
||||
space_group.IT_number
|
||||
space_group.name_h-m_full
|
||||
space_group.it_number
|
||||
space_group_symop.operation_xyz
|
||||
|
||||
cell.length_a
|
||||
@@ -35,14 +35,14 @@ cell.angle_alpha
|
||||
cell.angle_beta
|
||||
cell.angle_gamma
|
||||
cell.volume
|
||||
cell.formula_units_Z
|
||||
cell.formula_units_z
|
||||
|
||||
atom_site.label
|
||||
atom_site.type_symbol
|
||||
atom_site.fract_x
|
||||
atom_site.fract_y
|
||||
atom_site.fract_z
|
||||
atom_site.U_iso_or_equiv
|
||||
atom_site.u_iso_or_equiv
|
||||
atom_site.adp_type
|
||||
atom_site.occupancy
|
||||
atom_site.calc_flag
|
||||
@@ -52,20 +52,13 @@ atom_site.disorder_group
|
||||
atom_site.site_symmetry_multiplicity
|
||||
|
||||
atom_site_aniso.label
|
||||
atom_site_aniso.U
|
||||
atom_site_aniso.U_11
|
||||
atom_site_aniso.U_22
|
||||
atom_site_aniso.U_33
|
||||
atom_site_aniso.U_23
|
||||
atom_site_aniso.U_13
|
||||
atom_site_aniso.U_12
|
||||
atom_site_aniso.U_su
|
||||
atom_site_aniso.U_11_su
|
||||
atom_site_aniso.U_22_su
|
||||
atom_site_aniso.U_33_su
|
||||
atom_site_aniso.U_23_su
|
||||
atom_site_aniso.U_13_su
|
||||
atom_site_aniso.U_12_su
|
||||
atom_site_aniso.u
|
||||
atom_site_aniso.u_11
|
||||
atom_site_aniso.u_22
|
||||
atom_site_aniso.u_33
|
||||
atom_site_aniso.u_23
|
||||
atom_site_aniso.u_13
|
||||
atom_site_aniso.u_12
|
||||
|
||||
geom_bond.atom_site_label_1
|
||||
geom_bond.atom_site_label_2
|
||||
|
||||
|
13829
package-lock.json
generated
13829
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
96
package.json
96
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "molstar",
|
||||
"version": "2.2.3",
|
||||
"version": "2.3.2",
|
||||
"description": "A comprehensive macromolecular library.",
|
||||
"homepage": "https://github.com/molstar/molstar#readme",
|
||||
"repository": {
|
||||
@@ -88,68 +88,68 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/add": "^2.0.2",
|
||||
"@graphql-codegen/cli": "^1.19.4",
|
||||
"@graphql-codegen/time": "^2.0.2",
|
||||
"@graphql-codegen/typescript": "^1.19.0",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^1.18.1",
|
||||
"@graphql-codegen/typescript-graphql-request": "^2.0.3",
|
||||
"@graphql-codegen/typescript-operations": "^1.17.12",
|
||||
"@types/cors": "^2.8.8",
|
||||
"@typescript-eslint/eslint-plugin": "^4.9.1",
|
||||
"@typescript-eslint/parser": "^4.9.1",
|
||||
"@graphql-codegen/add": "^3.1.0",
|
||||
"@graphql-codegen/cli": "^2.2.0",
|
||||
"@graphql-codegen/time": "^3.1.0",
|
||||
"@graphql-codegen/typescript": "^2.2.2",
|
||||
"@graphql-codegen/typescript-graphql-files-modules": "^2.1.0",
|
||||
"@graphql-codegen/typescript-graphql-request": "^4.1.4",
|
||||
"@graphql-codegen/typescript-operations": "^2.1.4",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@typescript-eslint/eslint-plugin": "^4.31.0",
|
||||
"@typescript-eslint/parser": "^4.31.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"concurrently": "^5.3.0",
|
||||
"cpx2": "^3.0.0",
|
||||
"concurrently": "^6.2.1",
|
||||
"cpx2": "^3.0.2",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"css-loader": "^5.0.1",
|
||||
"eslint": "^7.15.0",
|
||||
"css-loader": "^6.2.0",
|
||||
"eslint": "^7.32.0",
|
||||
"extra-watch-webpack-plugin": "^1.0.3",
|
||||
"file-loader": "^6.2.0",
|
||||
"fs-extra": "^9.0.1",
|
||||
"graphql": "^15.4.0",
|
||||
"http-server": "^0.12.3",
|
||||
"jest": "^26.6.3",
|
||||
"mini-css-extract-plugin": "^1.3.2",
|
||||
"node-sass": "^6.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"graphql": "^15.5.3",
|
||||
"http-server": "^13.0.1",
|
||||
"jest": "^27.1.1",
|
||||
"mini-css-extract-plugin": "^2.3.0",
|
||||
"node-sass": "^6.0.1",
|
||||
"path-browserify": "^1.0.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass-loader": "^11.1.1",
|
||||
"simple-git": "^2.25.0",
|
||||
"sass-loader": "^12.1.0",
|
||||
"simple-git": "^2.45.1",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"ts-jest": "^26.4.4",
|
||||
"typescript": "^4.2.4",
|
||||
"webpack": "^5.37.1",
|
||||
"webpack-cli": "^4.7.0",
|
||||
"style-loader": "^3.2.1",
|
||||
"ts-jest": "^27.0.5",
|
||||
"typescript": "^4.4.3",
|
||||
"webpack": "^5.52.1",
|
||||
"webpack-cli": "^4.8.0",
|
||||
"webpack-version-file-plugin": "^0.4.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/argparse": "^1.0.38",
|
||||
"@types/benchmark": "^2.1.0",
|
||||
"@types/compression": "1.7.0",
|
||||
"@types/express": "^4.17.9",
|
||||
"@types/jest": "^26.0.18",
|
||||
"@types/node": "^14.14.11",
|
||||
"@types/node-fetch": "^2.5.7",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/swagger-ui-dist": "3.30.0",
|
||||
"argparse": "^1.0.10",
|
||||
"@types/argparse": "^2.0.10",
|
||||
"@types/benchmark": "^2.1.1",
|
||||
"@types/compression": "1.7.2",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "^27.0.1",
|
||||
"@types/node": "^16.9.1",
|
||||
"@types/node-fetch": "^2.5.12",
|
||||
"@types/react": "^17.0.20",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/swagger-ui-dist": "3.30.1",
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.19.0",
|
||||
"compression": "^1.7.4",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^4.17.1",
|
||||
"h264-mp4-encoder": "^1.0.12",
|
||||
"immer": "^8.0.1",
|
||||
"immer": "^9.0.6",
|
||||
"immutable": "^3.8.2",
|
||||
"node-fetch": "^2.6.1",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"rxjs": "^6.6.6",
|
||||
"swagger-ui-dist": "^3.37.2",
|
||||
"tslib": "^2.1.0",
|
||||
"util.promisify": "^1.0.1",
|
||||
"xhr2": "^0.2.0"
|
||||
"node-fetch": "^2.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"rxjs": "^7.3.0",
|
||||
"swagger-ui-dist": "^3.52.1",
|
||||
"tslib": "^2.3.1",
|
||||
"util.promisify": "^1.1.1",
|
||||
"xhr2": "^0.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ export class ViewportComponent extends PluginUIComponent {
|
||||
pocketPreset = () => this.set(PocketPreset);
|
||||
interactionsPreset = () => this.set(InteractionsPreset);
|
||||
|
||||
get showButtons () {
|
||||
get showButtons() {
|
||||
return this.plugin.config.get(ShowButtons);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,12 +52,16 @@
|
||||
var collapseLeftPanel = getParam('collapse-left-panel', '[^&]+').trim() === '1';
|
||||
var pdbProvider = getParam('pdb-provider', '[^&]+').trim().toLowerCase();
|
||||
var emdbProvider = getParam('emdb-provider', '[^&]+').trim().toLowerCase();
|
||||
var mapProvider = getParam('map-provider', '[^&]+').trim().toLowerCase();
|
||||
var viewer = new molstar.Viewer('app', {
|
||||
layoutShowControls: !hideControls,
|
||||
viewportShowExpand: false,
|
||||
collapseLeftPanel: collapseLeftPanel,
|
||||
pdbProvider: pdbProvider || 'pdbe',
|
||||
emdbProvider: emdbProvider || 'pdbe',
|
||||
volumeStreamingServer: (mapProvider || 'pdbe') === 'rcsb'
|
||||
? 'https://maps.rcsb.org'
|
||||
: 'https://www.ebi.ac.uk/pdbe/densities'
|
||||
});
|
||||
|
||||
var snapshotId = getParam('snapshot-id', '[^&]+').trim();
|
||||
|
||||
@@ -325,7 +325,7 @@ export class Viewer {
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
this.plugin.layout.events.updated.next();
|
||||
this.plugin.layout.events.updated.next(void 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ import { ensureDataAvailable, readCCD } from './util';
|
||||
function extractIonNames(ccd: DatabaseCollection<CCD_Schema>) {
|
||||
const ionNames: string[] = [];
|
||||
for (const k in ccd) {
|
||||
const {chem_comp} = ccd[k];
|
||||
const { chem_comp } = ccd[k];
|
||||
if (chem_comp.name.value(0).toUpperCase().includes(' ION')) {
|
||||
ionNames.push(chem_comp.id.value(0));
|
||||
}
|
||||
@@ -54,20 +54,20 @@ async function run(out: string, forceDownload = false) {
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Extract and save IonNames from CCD.'
|
||||
});
|
||||
parser.addArgument('out', {
|
||||
parser.add_argument('out', {
|
||||
help: 'Generated file output path.'
|
||||
});
|
||||
parser.addArgument([ '--forceDownload', '-f' ], {
|
||||
action: 'storeTrue',
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of CCD and PVCD.'
|
||||
});
|
||||
interface Args {
|
||||
out: string,
|
||||
forceDownload?: boolean,
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(args.out, args.forceDownload);
|
||||
|
||||
@@ -171,7 +171,7 @@ async function createBonds(
|
||||
pdbx_aromatic_flag, pdbx_stereo_config, molstar_protonation_variant
|
||||
});
|
||||
|
||||
const bondDatabase = Database.ofTables(
|
||||
const bondDatabase = Database.ofTables(
|
||||
CCB_TABLE_NAME,
|
||||
{ chem_comp_bond: mmCIF_chemCompBond_schema },
|
||||
{ chem_comp_bond: bondTable }
|
||||
@@ -265,21 +265,21 @@ const CCB_TABLE_NAME = 'CHEM_COMP_BONDS';
|
||||
const CCA_TABLE_NAME = 'CHEM_COMP_ATOMS';
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Create a cif file with one big table of all chem_comp_bond entries from the CCD and PVCD.'
|
||||
});
|
||||
parser.addArgument('out', {
|
||||
parser.add_argument('out', {
|
||||
help: 'Generated file output path.'
|
||||
});
|
||||
parser.addArgument([ '--forceDownload', '-f' ], {
|
||||
action: 'storeTrue',
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of CCD and PVCD.'
|
||||
});
|
||||
parser.addArgument([ '--binary', '-b' ], {
|
||||
action: 'storeTrue',
|
||||
parser.add_argument('--binary', '-b', {
|
||||
action: 'store_true',
|
||||
help: 'Output as BinaryCIF.'
|
||||
});
|
||||
parser.addArgument(['--ccaOut', '-a'], {
|
||||
parser.add_argument('--ccaOut', '-a', {
|
||||
help: 'Optional generated file output path for chem_comp_atom data.',
|
||||
required: false
|
||||
});
|
||||
@@ -289,6 +289,6 @@ interface Args {
|
||||
binary?: boolean,
|
||||
ccaOut?: string
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(args.out, args.binary, args.forceDownload, args.ccaOut);
|
||||
|
||||
@@ -37,20 +37,20 @@ function run(args: Args) {
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Convert any CIF file to a BCIF file'
|
||||
});
|
||||
parser.addArgument([ 'src' ], {
|
||||
parser.add_argument('src', {
|
||||
help: 'Source CIF path'
|
||||
});
|
||||
parser.addArgument([ 'out' ], {
|
||||
parser.add_argument('out', {
|
||||
help: 'Output BCIF path'
|
||||
});
|
||||
parser.addArgument([ '-c', '--config' ], {
|
||||
parser.add_argument('-c', '--config', {
|
||||
help: 'Optional encoding strategy/precision config path',
|
||||
required: false
|
||||
});
|
||||
parser.addArgument([ '-f', '--filter' ], {
|
||||
parser.add_argument('-f', '--filter', {
|
||||
help: 'Optional filter whitelist/blacklist path',
|
||||
required: false
|
||||
});
|
||||
@@ -61,7 +61,7 @@ interface Args {
|
||||
config?: string
|
||||
filter?: string
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
if (args) {
|
||||
run(args);
|
||||
|
||||
@@ -124,15 +124,15 @@ async function getFieldNamesFilter(fieldNamesPath: string): Promise<Filter> {
|
||||
const csvFile = parsed.result;
|
||||
|
||||
const fieldNamesCol = csvFile.table.getColumn('0');
|
||||
if (!fieldNamesCol) throw 'error getting fields columns';
|
||||
if (!fieldNamesCol) throw new Error('error getting fields columns');
|
||||
const fieldNames = fieldNamesCol.toStringArray();
|
||||
|
||||
const filter: Filter = {};
|
||||
fieldNames.forEach((name, i) => {
|
||||
const [ category, field ] = name.split('.');
|
||||
const [category, field] = name.split('.');
|
||||
// console.log(category, field)
|
||||
if (!filter[ category ]) filter[ category ] = {};
|
||||
filter[ category ][ field ] = true;
|
||||
if (!filter[category]) filter[category] = {};
|
||||
filter[category][field] = true;
|
||||
});
|
||||
return filter;
|
||||
}
|
||||
@@ -178,44 +178,44 @@ const CIF_CORE_ATTR_PATH = `${DIC_DIR}/templ_attr.cif`;
|
||||
const CIF_CORE_ATTR_URL = 'https://raw.githubusercontent.com/COMCIFS/cif_core/master/templ_attr.cif';
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Create schema from mmcif dictionary (v50 plus IHM and entity_branch extensions, downloaded from wwPDB)'
|
||||
});
|
||||
parser.addArgument([ '--preset', '-p' ], {
|
||||
defaultValue: '',
|
||||
parser.add_argument('--preset', '-p', {
|
||||
default: '',
|
||||
choices: ['', 'mmCIF', 'CCD', 'BIRD', 'CifCore'],
|
||||
help: 'Preset name'
|
||||
});
|
||||
parser.addArgument([ '--name', '-n' ], {
|
||||
defaultValue: '',
|
||||
parser.add_argument('--name', '-n', {
|
||||
default: '',
|
||||
help: 'Schema name'
|
||||
});
|
||||
parser.addArgument([ '--out', '-o' ], {
|
||||
parser.add_argument('--out', '-o', {
|
||||
help: 'Generated schema output path, if not given printed to stdout'
|
||||
});
|
||||
parser.addArgument([ '--targetFormat', '-tf' ], {
|
||||
defaultValue: 'typescript-molstar',
|
||||
parser.add_argument('--targetFormat', '-tf', {
|
||||
default: 'typescript-molstar',
|
||||
choices: ['typescript-molstar', 'json-internal'],
|
||||
help: 'Target format'
|
||||
});
|
||||
parser.addArgument([ '--dicPath', '-d' ], {
|
||||
defaultValue: '',
|
||||
parser.add_argument('--dicPath', '-d', {
|
||||
default: '',
|
||||
help: 'Path to dictionary'
|
||||
});
|
||||
parser.addArgument([ '--fieldNamesPath', '-fn' ], {
|
||||
defaultValue: '',
|
||||
parser.add_argument('--fieldNamesPath', '-fn', {
|
||||
default: '',
|
||||
help: 'Field names to include'
|
||||
});
|
||||
parser.addArgument([ '--forceDicDownload', '-f' ], {
|
||||
action: 'storeTrue',
|
||||
parser.add_argument('--forceDicDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of dictionaries'
|
||||
});
|
||||
parser.addArgument([ '--moldataImportPath', '-mip' ], {
|
||||
defaultValue: 'molstar/lib/mol-data',
|
||||
parser.add_argument('--moldataImportPath', '-mip', {
|
||||
default: 'molstar/lib/mol-data',
|
||||
help: 'mol-data import path (for typescript target only)'
|
||||
});
|
||||
parser.addArgument([ '--addAliases', '-aa' ], {
|
||||
action: 'storeTrue',
|
||||
parser.add_argument('--addAliases', '-aa', {
|
||||
action: 'store_true',
|
||||
help: 'Add field name/path aliases'
|
||||
});
|
||||
interface Args {
|
||||
@@ -230,7 +230,7 @@ interface Args {
|
||||
moldataImportPath: string
|
||||
addAliases: boolean
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
const FORCE_DIC_DOWNLOAD = args.forceDicDownload;
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ export function getFieldType(type: string, description: string, values?: string[
|
||||
case 'seq-one-letter-code':
|
||||
case 'author':
|
||||
case 'orcid_id':
|
||||
case 'pdbx_PDB_obsoleted_db_id':
|
||||
case 'pdbx_related_db_id':
|
||||
case 'sequence_dep':
|
||||
case 'pdb_id':
|
||||
case 'emd_id':
|
||||
@@ -79,7 +81,7 @@ export function getFieldType(type: string, description: string, values?: string[
|
||||
case 'List(Real,Real)':
|
||||
case 'List(Real,Real,Real,Real)':
|
||||
case 'Date':
|
||||
case 'Datetime':
|
||||
case 'DateTime':
|
||||
case 'Tag':
|
||||
case 'Implied':
|
||||
return wrapContainer('str', ',', description, container);
|
||||
@@ -187,7 +189,7 @@ function getContainer(d: Data.CifFrame, imports: Imports, ctx: FrameData) {
|
||||
function getCode(d: Data.CifFrame, imports: Imports, ctx: FrameData): [string, string[] | undefined, string | undefined ] | undefined {
|
||||
const code = getField('item_type', 'code', d, imports, ctx) || getField('type', 'contents', d, imports, ctx);
|
||||
if (code) {
|
||||
return [ code.str(0), getEnums(d, imports, ctx), getContainer(d, imports, ctx) ];
|
||||
return [code.str(0), getEnums(d, imports, ctx), getContainer(d, imports, ctx)];
|
||||
} else {
|
||||
console.log(`item_type.code or type.contents not found for '${d.header}'`);
|
||||
}
|
||||
@@ -232,29 +234,26 @@ const FORCE_INT_FIELDS = [
|
||||
'_struct_sheet_range.end_auth_seq_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Note that name and mapped name must share a prefix. This is not always the case in
|
||||
* the cifCore dictionary, but for downstream code to work a container field with the
|
||||
* same prefix as the member fields must be given here and in the field names filter
|
||||
* list.
|
||||
*/
|
||||
const FORCE_MATRIX_FIELDS_MAP: { [k: string]: string } = {
|
||||
'atom_site_aniso.U_11': 'U',
|
||||
'atom_site_aniso.U_22': 'U',
|
||||
'atom_site_aniso.U_33': 'U',
|
||||
'atom_site_aniso.U_23': 'U',
|
||||
'atom_site_aniso.U_13': 'U',
|
||||
'atom_site_aniso.U_12': 'U',
|
||||
'atom_site_aniso.U_11_su': 'U_su',
|
||||
'atom_site_aniso.U_22_su': 'U_su',
|
||||
'atom_site_aniso.U_33_su': 'U_su',
|
||||
'atom_site_aniso.U_23_su': 'U_su',
|
||||
'atom_site_aniso.U_13_su': 'U_su',
|
||||
'atom_site_aniso.U_12_su': 'U_su',
|
||||
'atom_site_aniso.u_11': 'u', // is matrix_u in the the dic
|
||||
'atom_site_aniso.u_22': 'u',
|
||||
'atom_site_aniso.u_33': 'u',
|
||||
'atom_site_aniso.u_23': 'u',
|
||||
'atom_site_aniso.u_13': 'u',
|
||||
'atom_site_aniso.u_12': 'u',
|
||||
};
|
||||
const FORCE_MATRIX_FIELDS = Object.keys(FORCE_MATRIX_FIELDS_MAP);
|
||||
|
||||
const EXTRA_ALIASES: Database['aliases'] = {
|
||||
'atom_site_aniso.U': [
|
||||
'atom_site_anisotrop_U'
|
||||
],
|
||||
'atom_site_aniso.U_su': [
|
||||
'atom_site_aniso_U_esd',
|
||||
'atom_site_anisotrop_U_esd',
|
||||
'atom_site_aniso.matrix_u': [
|
||||
'atom_site_anisotrop_U',
|
||||
'atom_site_aniso.U'
|
||||
],
|
||||
};
|
||||
|
||||
@@ -317,7 +316,7 @@ export function generateSchema(frames: CifFrame[], imports: Imports = new Map())
|
||||
frames.forEach(d => {
|
||||
// category definitions in mmCIF start with '_' and don't include a '.'
|
||||
// category definitions in cifCore don't include a '.'
|
||||
if (d.header[0] === '_' || d.header.includes('.')) return;
|
||||
if (d.header[0] === '_' || d.header.includes('.')) return;
|
||||
const categoryName = d.header.toLowerCase();
|
||||
// console.log(d.header, d.categoryNames, d.categories)
|
||||
let descriptionField: Data.CifField | undefined;
|
||||
@@ -372,7 +371,7 @@ export function generateSchema(frames: CifFrame[], imports: Imports = new Map())
|
||||
const parent_name = item_linked.getField('parent_name');
|
||||
if (child_name && parent_name) {
|
||||
for (let i = 0; i < item_linked.rowCount; ++i) {
|
||||
const childName = child_name.str(i);
|
||||
const childName: string = child_name.str(i);
|
||||
const parentName = parent_name.str(i);
|
||||
if (childName in links && links[childName] !== parentName) {
|
||||
console.log(`${childName} linked to ${links[childName]}, ignoring link to ${parentName}`);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Database, Filter, Column } from './schema';
|
||||
import { indentString } from '../../../mol-util/string';
|
||||
import { FieldPath } from '../../../mol-io/reader/cif/schema';
|
||||
|
||||
function header (name: string, info: string, moldataImportPath: string) {
|
||||
function header(name: string, info: string, moldataImportPath: string) {
|
||||
return `/**
|
||||
* Copyright (c) 2017-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
@@ -22,7 +22,7 @@ import { Database, Column } from '${moldataImportPath}/db';
|
||||
import Schema = Column.Schema;`;
|
||||
}
|
||||
|
||||
function footer (name: string) {
|
||||
function footer(name: string) {
|
||||
return `
|
||||
export type ${name}_Schema = typeof ${name}_Schema;
|
||||
export interface ${name}_Database extends Database<${name}_Schema> {};`;
|
||||
@@ -89,7 +89,7 @@ function doc(description: string, spacesCount: number) {
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
export function generate (name: string, info: string, schema: Database, fields: Filter | undefined, moldataImportPath: string, addAliases: boolean) {
|
||||
export function generate(name: string, info: string, schema: Database, fields: Filter | undefined, moldataImportPath: string, addAliases: boolean) {
|
||||
const codeLines: string[] = [];
|
||||
|
||||
if (fields) {
|
||||
@@ -128,7 +128,7 @@ export function generate (name: string, info: string, schema: Database, fields:
|
||||
codeLines.push('');
|
||||
codeLines.push(`export const ${name}_Aliases = {`);
|
||||
Object.keys(schema.aliases).forEach(path => {
|
||||
const [ table, columnName ] = path.split('.');
|
||||
const [table, columnName] = path.split('.');
|
||||
if (fields && !fields[table]) return;
|
||||
if (fields && !fields[table][columnName]) return;
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@ export function parseImportGet(s: string): Import[] {
|
||||
// [{'save':hi_ang_Fox_coeffs 'file':templ_attr.cif} {'save':hi_ang_Fox_c0 'file':templ_enum.cif}]
|
||||
// [{"file":'templ_enum.cif' "save":'H_M_ref'}]
|
||||
return s.trim().substring(2, s.length - 2).split(/}[ \n\t]*{/g).map(s => {
|
||||
const save = s.match(/('save'|"save"):([^ \t\n]+)/);
|
||||
const file = s.match(/('file'|"file"):([^ \t\n]+)/);
|
||||
const save = s.match(/('save'|"save"):([^ \t\n{}]+)/);
|
||||
const file = s.match(/('file'|"file"):([^ \t\n{}]+)/);
|
||||
return {
|
||||
save: save ? save[0].substr(7).replace(/['"]/g, '') : undefined,
|
||||
file: file ? file[0].substr(7).replace(/['"]/g, '') : undefined
|
||||
|
||||
@@ -51,13 +51,13 @@ export function ListCol(subType: 'int' | 'str' | 'float' | 'coord', separator: s
|
||||
|
||||
export type Filter = { [ table: string ]: { [ column: string ]: true } }
|
||||
|
||||
export function mergeFilters (...filters: Filter[]) {
|
||||
export function mergeFilters(...filters: Filter[]) {
|
||||
const n = filters.length;
|
||||
const mergedFilter: Filter = {};
|
||||
const fields: Map<string, number> = new Map();
|
||||
filters.forEach(filter => {
|
||||
Object.keys(filter).forEach(category => {
|
||||
Object.keys(filter[ category ]).forEach(field => {
|
||||
Object.keys(filter[category]).forEach(field => {
|
||||
const key = `${category}.${field}`;
|
||||
const value = fields.get(key) || 0;
|
||||
fields.set(key, value + 1);
|
||||
|
||||
@@ -70,21 +70,21 @@ export const LipidNames = new Set(${lipidNames.replace(/"/g, "'").replace(/,/g,
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Create lipid params (from martini lipids itp)'
|
||||
});
|
||||
parser.addArgument([ '--out', '-o' ], {
|
||||
parser.add_argument('--out', '-o', {
|
||||
help: 'Generated lipid params output path, if not given printed to stdout'
|
||||
});
|
||||
parser.addArgument([ '--forceDownload', '-f' ], {
|
||||
action: 'storeTrue',
|
||||
parser.add_argument('--forceDownload', '-f', {
|
||||
action: 'store_true',
|
||||
help: 'Force download of martini lipids itp'
|
||||
});
|
||||
interface Args {
|
||||
out: string
|
||||
forceDownload: boolean
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
const FORCE_DOWNLOAD = args.forceDownload;
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ export function printSecStructure(model: Model) {
|
||||
const count = residues._rowCount;
|
||||
let rI = 0;
|
||||
while (rI < count) {
|
||||
let start = rI;
|
||||
const start = rI;
|
||||
while (rI < count && key[start] === key[rI]) rI++;
|
||||
rI--;
|
||||
|
||||
@@ -230,21 +230,21 @@ async function runFile(filename: string, args: Args) {
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Print info about a structure, mainly to test and showcase the mol-model module'
|
||||
});
|
||||
parser.addArgument(['--download', '-d'], { help: 'Pdb entry id' });
|
||||
parser.addArgument(['--file', '-f'], { help: 'filename' });
|
||||
parser.add_argument('--download', '-d', { help: 'Pdb entry id' });
|
||||
parser.add_argument('--file', '-f', { help: 'filename' });
|
||||
|
||||
parser.addArgument(['--models'], { help: 'print models info', action: 'storeTrue' });
|
||||
parser.addArgument(['--seq'], { help: 'print sequence', action: 'storeTrue' });
|
||||
parser.addArgument(['--units'], { help: 'print units', action: 'storeTrue' });
|
||||
parser.addArgument(['--sym'], { help: 'print symmetry', action: 'storeTrue' });
|
||||
parser.addArgument(['--rings'], { help: 'print rings', action: 'storeTrue' });
|
||||
parser.addArgument(['--intraBonds'], { help: 'print intra unit bonds', action: 'storeTrue' });
|
||||
parser.addArgument(['--interBonds'], { help: 'print inter unit bonds', action: 'storeTrue' });
|
||||
parser.addArgument(['--mod'], { help: 'print modified residues', action: 'storeTrue' });
|
||||
parser.addArgument(['--sec'], { help: 'print secoundary structure', action: 'storeTrue' });
|
||||
parser.add_argument('--models', { help: 'print models info', action: 'store_true' });
|
||||
parser.add_argument('--seq', { help: 'print sequence', action: 'store_true' });
|
||||
parser.add_argument('--units', { help: 'print units', action: 'store_true' });
|
||||
parser.add_argument('--sym', { help: 'print symmetry', action: 'store_true' });
|
||||
parser.add_argument('--rings', { help: 'print rings', action: 'store_true' });
|
||||
parser.add_argument('--intraBonds', { help: 'print intra unit bonds', action: 'store_true' });
|
||||
parser.add_argument('--interBonds', { help: 'print inter unit bonds', action: 'store_true' });
|
||||
parser.add_argument('--mod', { help: 'print modified residues', action: 'store_true' });
|
||||
parser.add_argument('--sec', { help: 'print secoundary structure', action: 'store_true' });
|
||||
interface Args {
|
||||
download?: string,
|
||||
file?: string,
|
||||
@@ -260,7 +260,7 @@ interface Args {
|
||||
mod?: boolean,
|
||||
sec?: boolean,
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
if (args.download) runDL(args.download, args);
|
||||
else if (args.file) runFile(args.file, args);
|
||||
|
||||
@@ -38,7 +38,7 @@ function print(volume: Volume) {
|
||||
}
|
||||
|
||||
async function doMesh(volume: Volume, filename: string) {
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) } )).run();
|
||||
const mesh = await Task.create('', runtime => createVolumeIsosurfaceMesh({ runtime }, volume, Theme.createEmpty(), { isoValue: Volume.IsoValue.absolute(1.5) })).run();
|
||||
console.log({ vc: mesh.vertexCount, tc: mesh.triangleCount });
|
||||
|
||||
// Export the mesh in OBJ format.
|
||||
@@ -75,13 +75,13 @@ async function run(url: string, meshFilename: string) {
|
||||
}
|
||||
|
||||
const parser = new argparse.ArgumentParser({
|
||||
addHelp: true,
|
||||
add_help: true,
|
||||
description: 'Info about VolumeData from mol-model module'
|
||||
});
|
||||
parser.addArgument([ '--emdb', '-e' ], {
|
||||
parser.add_argument('--emdb', '-e', {
|
||||
help: 'EMDB id, for example 8116',
|
||||
});
|
||||
parser.addArgument([ '--mesh' ], {
|
||||
parser.add_argument('--mesh', {
|
||||
help: 'Mesh filename',
|
||||
required: true
|
||||
});
|
||||
@@ -89,6 +89,6 @@ interface Args {
|
||||
emdb?: string,
|
||||
mesh: string
|
||||
}
|
||||
const args: Args = parser.parseArgs();
|
||||
const args: Args = parser.parse_args();
|
||||
|
||||
run(`https://ds.litemol.org/em/emd-${args.emdb}/cell?detail=4`, args.mesh);
|
||||
@@ -38,7 +38,7 @@ type MappingRow = Table.Row<S.mapping>;
|
||||
|
||||
function writeDomain(enc: CifWriter.Encoder, domain: DomainAnnotation | undefined) {
|
||||
if (!domain) return;
|
||||
enc.writeCategory({ name: `pdbx_${domain.name}_domain_annotation`, instance: () => CifWriter.Category.ofTable(domain.domains) });
|
||||
enc.writeCategory({ name: `pdbx_${domain.name}_domain_annotation`, instance: () => CifWriter.Category.ofTable(domain.domains) });
|
||||
enc.writeCategory({ name: `pdbx_${domain.name}_domain_mapping`, instance: () => CifWriter.Category.ofTable(domain.mappings) });
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ async function getMappings(id: string) {
|
||||
};
|
||||
|
||||
|
||||
let PORT = process.env.port || 1338;
|
||||
const PORT = process.env.port || 1338;
|
||||
|
||||
const app = express();
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ class LightingDemo {
|
||||
...this.plugin.canvas3d!.props.postprocessing,
|
||||
...props.postprocessing
|
||||
},
|
||||
}});
|
||||
} });
|
||||
}
|
||||
|
||||
async load({ url, format = 'mmcif', isBinary = true, assemblyId = '' }: LoadParams, radius: number, bias: number) {
|
||||
|
||||
@@ -250,7 +250,7 @@ class MolStarProteopediaWrapper {
|
||||
setBackground(color: number) {
|
||||
if (!this.plugin.canvas3d) return;
|
||||
const renderer = this.plugin.canvas3d.props.renderer;
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
|
||||
PluginCommands.Canvas3D.SetSettings(this.plugin, { settings: { renderer: { ...renderer, backgroundColor: Color(color) } } });
|
||||
}
|
||||
|
||||
toggleSpin() {
|
||||
|
||||
@@ -41,20 +41,32 @@ interface ANVILContext {
|
||||
export const ANVILParams = {
|
||||
numberOfSpherePoints: PD.Numeric(175, { min: 35, max: 700, step: 1 }, { description: 'Number of spheres/directions to test for membrane placement. Original value is 350.' }),
|
||||
stepSize: PD.Numeric(1, { min: 0.25, max: 4, step: 0.25 }, { description: 'Thickness of membrane slices that will be tested' }),
|
||||
minThickness: PD.Numeric(20, { min: 10, max: 30, step: 1}, { description: 'Minimum membrane thickness used during refinement' }),
|
||||
maxThickness: PD.Numeric(40, { min: 30, max: 50, step: 1}, { description: 'Maximum membrane thickness used during refinement' }),
|
||||
minThickness: PD.Numeric(20, { min: 10, max: 30, step: 1 }, { description: 'Minimum membrane thickness used during refinement' }),
|
||||
maxThickness: PD.Numeric(40, { min: 30, max: 50, step: 1 }, { description: 'Maximum membrane thickness used during refinement' }),
|
||||
asaCutoff: PD.Numeric(40, { min: 10, max: 100, step: 1 }, { description: 'Relative ASA cutoff above which residues will be considered' }),
|
||||
adjust: PD.Numeric(14, { min: 0, max: 30, step: 1 }, { description: 'Minimum length of membrane-spanning regions (original values: 14 for alpha-helices and 5 for beta sheets). Set to 0 to not optimize membrane thickness.' })
|
||||
adjust: PD.Numeric(14, { min: 0, max: 30, step: 1 }, { description: 'Minimum length of membrane-spanning regions (original values: 14 for alpha-helices and 5 for beta sheets). Set to 0 to not optimize membrane thickness.' }),
|
||||
tmdetDefinition: PD.Boolean(false, { description: `Use TMDET's classification of membrane-favoring amino acids. TMDET's classification shows better performance on porins and other beta-barrel structures.` })
|
||||
};
|
||||
export type ANVILParams = typeof ANVILParams
|
||||
export type ANVILProps = PD.Values<ANVILParams>
|
||||
|
||||
/** ANVIL-specific (not general) definition of membrane-favoring amino acids */
|
||||
const ANVIL_DEFINITION = new Set(['ALA', 'CYS', 'GLY', 'HIS', 'ILE', 'LEU', 'MET', 'PHE', 'SER', 'TRP', 'VAL']);
|
||||
/** TMDET-specific (not general) definition of membrane-favoring amino acids */
|
||||
const TMDET_DEFINITION = new Set(['LEU', 'ILE', 'VAL', 'PHE', 'MET', 'GLY', 'TRP', 'TYR']);
|
||||
|
||||
/**
|
||||
* Implements:
|
||||
* Membrane positioning for high- and low-resolution protein structures through a binary classification approach
|
||||
* Guillaume Postic, Yassine Ghouzam, Vincent Guiraud, and Jean-Christophe Gelly
|
||||
* Protein Engineering, Design & Selection, 2015, 1–5
|
||||
* doi: 10.1093/protein/gzv063
|
||||
*
|
||||
* ANVIL is derived from TMDET, the corresponding classification of hydrophobic amino acids is provided as optional parameter:
|
||||
* Gabor E. Tusnady, Zsuzsanna Dosztanyi and Istvan Simon
|
||||
* Transmembrane proteins in the Protein Data Bank: identification and classification
|
||||
* Bioinformatics, 2004, 2964-2972
|
||||
* doi: 10.1093/bioinformatics/bth340
|
||||
*/
|
||||
export function computeANVIL(structure: Structure, props: ANVILProps) {
|
||||
return Task.create('Compute Membrane Orientation', async runtime => {
|
||||
@@ -87,6 +99,11 @@ async function initialize(structure: Structure, props: ANVILProps, accessibleSur
|
||||
const offsets = new Array<number>();
|
||||
const exposed = new Array<number>();
|
||||
const hydrophobic = new Array<boolean>();
|
||||
const definition = props.tmdetDefinition ? TMDET_DEFINITION : ANVIL_DEFINITION;
|
||||
|
||||
function isPartOfEntity(l: StructureElement.Location): boolean {
|
||||
return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.model.atomicHierarchy.residues.label_seq_id.valueKind(l.unit.residueIndex[l.element]) === 0;
|
||||
}
|
||||
|
||||
const vec = v3zero();
|
||||
for (let i = 0, il = structure.units.length; i < il; ++i) {
|
||||
@@ -98,8 +115,8 @@ async function initialize(structure: Structure, props: ANVILProps, accessibleSur
|
||||
const eI = elements[j];
|
||||
l.element = eI;
|
||||
|
||||
// consider only amino acids
|
||||
if (getElementMoleculeType(unit, eI) !== MoleculeType.Protein) {
|
||||
// consider only amino acids in chains
|
||||
if (getElementMoleculeType(unit, eI) !== MoleculeType.Protein || !isPartOfEntity(l)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -121,7 +138,7 @@ async function initialize(structure: Structure, props: ANVILProps, accessibleSur
|
||||
offsets.push(structure.serialMapping.getSerialIndex(l.unit, l.element));
|
||||
if (AccessibleSurfaceArea.getValue(l, accessibleSurfaceArea) / MaxAsa[label_comp_id(l)] > asaCutoff) {
|
||||
exposed.push(structure.serialMapping.getSerialIndex(l.unit, l.element));
|
||||
hydrophobic.push(isHydrophobic(label_comp_id(l)));
|
||||
hydrophobic.push(isHydrophobic(definition, label_comp_id(l)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +183,7 @@ export async function calculate(runtime: RuntimeContext, structure: Structure, p
|
||||
}
|
||||
|
||||
const normalVector = v3zero();
|
||||
const center = v3zero();
|
||||
const center = v3zero();
|
||||
v3sub(normalVector, membrane.planePoint1, membrane.planePoint2);
|
||||
v3normalize(normalVector, normalVector);
|
||||
|
||||
@@ -344,7 +361,7 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
||||
// collect all residues in membrane layer
|
||||
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
||||
const unit = units[unitIndices[offsets[k]]];
|
||||
if (!Unit.isAtomic(unit)) throw 'Property only available for atomic models.';
|
||||
if (!Unit.isAtomic(unit)) notAtomic();
|
||||
const elementIndex = elementIndices[offsets[k]];
|
||||
|
||||
authAsymId = unit.model.atomicHierarchy.chains.auth_asym_id.value(unit.chainIndex[elementIndex]);
|
||||
@@ -365,7 +382,7 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
||||
|
||||
for (let k = 0, kl = offsets.length; k < kl; k++) {
|
||||
const unit = units[unitIndices[offsets[k]]];
|
||||
if (!Unit.isAtomic(unit)) throw 'Property only available for atomic models.';
|
||||
if (!Unit.isAtomic(unit)) notAtomic();
|
||||
const elementIndex = elementIndices[offsets[k]];
|
||||
|
||||
authAsymId = unit.model.atomicHierarchy.chains.auth_asym_id.value(unit.chainIndex[elementIndex]);
|
||||
@@ -387,7 +404,7 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
||||
}
|
||||
lastAuthSeqId = authSeqId;
|
||||
endOffset = k;
|
||||
} else {
|
||||
} else {
|
||||
lastAuthSeqId++;
|
||||
endOffset++;
|
||||
}
|
||||
@@ -428,6 +445,10 @@ function membraneSegments(ctx: ANVILContext, membrane: MembraneCandidate): Array
|
||||
return refinedSegments;
|
||||
}
|
||||
|
||||
function notAtomic(): never {
|
||||
throw new Error('Property only available for atomic models.');
|
||||
}
|
||||
|
||||
/** Filter for membrane residues and calculate the final extent of the membrane layer */
|
||||
function adjustExtent(ctx: ANVILContext, membrane: MembraneCandidate, centroid: Vec3): number {
|
||||
const { offsets, structure } = ctx;
|
||||
@@ -455,11 +476,11 @@ function adjustExtent(ctx: ANVILContext, membrane: MembraneCandidate, centroid:
|
||||
}
|
||||
|
||||
function qValue(currentStats: HphobHphil, initialStats: HphobHphil): number {
|
||||
if(initialStats.hphob < 1) {
|
||||
if (initialStats.hphob < 1) {
|
||||
initialStats.hphob = 0.1;
|
||||
}
|
||||
|
||||
if(initialStats.hphil < 1) {
|
||||
if (initialStats.hphil < 1) {
|
||||
initialStats.hphil += 1;
|
||||
}
|
||||
|
||||
@@ -484,7 +505,7 @@ function generateSpherePoints(ctx: ANVILContext, numberOfSpherePoints: number):
|
||||
const { centroid, extent } = ctx;
|
||||
const points = [];
|
||||
let oldPhi = 0, h, theta, phi;
|
||||
for(let k = 1, kl = numberOfSpherePoints + 1; k < kl; k++) {
|
||||
for (let k = 1, kl = numberOfSpherePoints + 1; k < kl; k++) {
|
||||
h = -1 + 2 * (k - 1) / (2 * numberOfSpherePoints - 1);
|
||||
theta = Math.acos(h);
|
||||
phi = (k === 1 || k === numberOfSpherePoints) ? 0 : (oldPhi + 3.6 / Math.sqrt(2 * numberOfSpherePoints * (1 - h * h))) % (2 * Math.PI);
|
||||
@@ -566,11 +587,9 @@ namespace HphobHphil {
|
||||
}
|
||||
}
|
||||
|
||||
/** ANVIL-specific (not general) definition of membrane-favoring amino acids */
|
||||
const HYDROPHOBIC_AMINO_ACIDS = new Set(['ALA', 'CYS', 'GLY', 'HIS', 'ILE', 'LEU', 'MET', 'PHE', 'SER', 'TRP', 'VAL']);
|
||||
/** Returns true if ANVIL considers this as amino acid that favors being embedded in a membrane */
|
||||
export function isHydrophobic(label_comp_id: string): boolean {
|
||||
return HYDROPHOBIC_AMINO_ACIDS.has(label_comp_id);
|
||||
/** Returns true if the definition considers this as membrane-favoring amino acid */
|
||||
export function isHydrophobic(definition: Set<string>, label_comp_id: string): boolean {
|
||||
return definition.has(label_comp_id);
|
||||
}
|
||||
|
||||
/** Accessible surface area used for normalization. ANVIL uses 'Total-Side REL' values from NACCESS, from: Hubbard, S. J., & Thornton, J. M. (1993). naccess. Computer Program, Department of Biochemistry and Molecular Biology, University College London, 2(1). */
|
||||
|
||||
@@ -52,7 +52,7 @@ export const ANVILMembraneOrientation = PluginBehavior.create<{ autoAttach: bool
|
||||
}
|
||||
|
||||
update(p: { autoAttach: boolean }) {
|
||||
let updated = this.params.autoAttach !== p.autoAttach;
|
||||
const updated = this.params.autoAttach !== p.autoAttach;
|
||||
this.params.autoAttach = p.autoAttach;
|
||||
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
|
||||
return updated;
|
||||
@@ -150,7 +150,7 @@ export const MembraneOrientationPreset = StructureRepresentationPresetProvider({
|
||||
params: () => StructureRepresentationPresetProvider.CommonParams,
|
||||
async apply(ref, params, plugin) {
|
||||
const structureCell = StateObjectRef.resolveAndCheck(plugin.state.data, ref);
|
||||
const structure = structureCell?.obj?.data;
|
||||
const structure = structureCell?.obj?.data;
|
||||
if (!structureCell || !structure) return {};
|
||||
|
||||
if (!MembraneOrientationProvider.get(structure).value) {
|
||||
|
||||
@@ -33,7 +33,7 @@ export function CellPackGenerateColorTheme(ctx: ThemeDataContext, props: PD.Valu
|
||||
|
||||
if (ctx.structure && info) {
|
||||
const colors = distinctColors(info.packingsCount);
|
||||
let hcl = Hcl.fromColor(Hcl(), colors[info.packingIndex]);
|
||||
const hcl = Hcl.fromColor(Hcl(), colors[info.packingIndex]);
|
||||
|
||||
const hue = [Math.max(0, hcl[0] - 35), Math.min(360, hcl[0] + 35)] as [number, number];
|
||||
|
||||
@@ -48,7 +48,7 @@ export function CellPackGenerateColorTheme(ctx: ThemeDataContext, props: PD.Valu
|
||||
hue, chroma: [30, 80], luminance: [15, 85],
|
||||
clusteringStepCount: 50, minSampleCount: 800, maxCount: 75
|
||||
}
|
||||
}}, { minLabel: 'Min', maxLabel: 'Max' });
|
||||
} }, { minLabel: 'Min', maxLabel: 'Max' });
|
||||
legend = palette.legend;
|
||||
const modelColor = new Map<number, Color>();
|
||||
for (let i = 0, il = models.length; i < il; ++i) {
|
||||
|
||||
@@ -49,7 +49,7 @@ function ResampleControlPoints(points: NumberArray, segmentLength: number) {
|
||||
// controlPoints.Insert(0, controlPoints[0] + (controlPoints[0] - controlPoints[1]) / 2.0f);
|
||||
// controlPoints.Add(controlPoints[nP - 1] + (controlPoints[nP - 1] - controlPoints[nP - 2]) / 2.0f);
|
||||
|
||||
let resampledControlPoints: Vec3[] = [];
|
||||
const resampledControlPoints: Vec3[] = [];
|
||||
// resampledControlPoints.Add(controlPoints[0]);
|
||||
// resampledControlPoints.Add(controlPoints[1]);
|
||||
|
||||
@@ -111,7 +111,7 @@ function GetSmoothNormals(points: Vec3[]) {
|
||||
let p1 = points[1];
|
||||
let p2 = points[2];
|
||||
const p21 = Vec3.sub(tmpV1, p2, p1);
|
||||
const p01 = Vec3.sub(tmpV2, p0, p1);
|
||||
const p01 = Vec3.sub(tmpV2, p0, p1);
|
||||
const p0121 = Vec3.cross(tmpV3, p01, p21);
|
||||
Vec3.normalize(prevV, p0121);
|
||||
smoothNormals.push(Vec3.clone(prevV));
|
||||
@@ -179,7 +179,7 @@ function GetMiniFrame(points: Vec3[], normals: Vec3[]) {
|
||||
const v1t = Vec3.scale(mfTmpV5, v1, (2.0 / c1) * Vec3.dot(v1, frames[i].t));
|
||||
const tan_L_i = Vec3.sub(mfTmpV6, frames[i].t, v1t);
|
||||
// # compute reflection vector of R_2
|
||||
const v2 = Vec3.sub(mfTmpV7, t2, tan_L_i);
|
||||
const v2 = Vec3.sub(mfTmpV7, t2, tan_L_i);
|
||||
const c2 = Vec3.dot(v2, v2);
|
||||
// compute r_(i+1) = R_2 * r_i^L
|
||||
const v2l = Vec3.scale(mfTmpV8, v1, (2.0 / c2) * Vec3.dot(v2, ref_L_i));
|
||||
@@ -195,7 +195,7 @@ export function getMatFromResamplePoints(points: NumberArray, segmentLength: num
|
||||
let new_points: Vec3[] = [];
|
||||
if (resample) new_points = ResampleControlPoints(points, segmentLength);
|
||||
else {
|
||||
for (let idx = 0; idx < points.length / 3; ++idx){
|
||||
for (let idx = 0; idx < points.length / 3; ++idx) {
|
||||
new_points.push(Vec3.fromArray(Vec3.zero(), points, idx * 3));
|
||||
}
|
||||
}
|
||||
@@ -211,7 +211,7 @@ export function getMatFromResamplePoints(points: NumberArray, segmentLength: num
|
||||
if (d >= segmentLength) {
|
||||
// use twist or random?
|
||||
const quat = Quat.rotationTo(Quat.zero(), Vec3.create(0, 0, 1), frames[i].t); // Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),new_normal[i]);//Quat.rotationTo(Quat.zero(), Vec3.create(0,0,1),direction);new_normal
|
||||
const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random() * 3.60 ); // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
|
||||
const rq = Quat.setAxisAngle(Quat.zero(), frames[i].t, Math.random() * 3.60); // Quat.setAxisAngle(Quat.zero(),direction, Math.random()*3.60 );//Quat.identity();//
|
||||
const m = Mat4.fromQuat(Mat4.zero(), Quat.multiply(Quat.zero(), rq, quat)); // Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),quat1,quat2));//Mat4.fromQuat(Mat4.zero(),quat);//Mat4.identity();//Mat4.fromQuat(Mat4.zero(),Quat.multiply(Quat.zero(),rq,quat));
|
||||
// let pos:Vec3 = Vec3.add(Vec3.zero(),pti1,pti)
|
||||
// pos = Vec3.scale(pos,pos,1.0/2.0);
|
||||
|
||||
@@ -73,9 +73,9 @@ export interface Ingredient {
|
||||
|
||||
export interface IngredientSource {
|
||||
pdb: string;
|
||||
bu?: string; /** biological unit e.g AU,BU1,etc.. */
|
||||
bu?: string; /** biological unit e.g AU,BU1,etc.. */
|
||||
selection?: string; /** NGL selection or :A or :B etc.. */
|
||||
model?: string; /** model number e.g 0,1,2... */
|
||||
model?: string; /** model number e.g 0,1,2... */
|
||||
transform: {
|
||||
center: boolean;
|
||||
translate?: Vec3;
|
||||
|
||||
@@ -46,7 +46,7 @@ async function getModel(plugin: PluginContext, id: string, ingredient: Ingredien
|
||||
const modelIndex = (ingredient.source.model) ? parseInt(ingredient.source.model) : 0;
|
||||
const surface = (ingredient.ingtype) ? (ingredient.ingtype === 'transmembrane') : false;
|
||||
let trajectory = trajCache.get(id);
|
||||
let assets: Asset.Wrapper[] = [];
|
||||
const assets: Asset.Wrapper[] = [];
|
||||
if (!trajectory) {
|
||||
if (file) {
|
||||
if (file.name.endsWith('.cif')) {
|
||||
@@ -68,7 +68,7 @@ async function getModel(plugin: PluginContext, id: string, ingredient: Ingredien
|
||||
throw new Error(`unsupported file type '${file.name}'`);
|
||||
}
|
||||
} else if (id.match(/^[1-9][a-zA-Z0-9]{3,3}$/i)) {
|
||||
if (surface){
|
||||
if (surface) {
|
||||
try {
|
||||
const data = await getFromOPM(plugin, id, assetManager);
|
||||
assets.push(data.asset);
|
||||
@@ -108,7 +108,7 @@ async function getStructure(plugin: PluginContext, model: Model, source: Ingredi
|
||||
structure = await plugin.runTask(StructureSymmetry.buildAssembly(structure, assembly));
|
||||
}
|
||||
let query;
|
||||
if (source.selection){
|
||||
if (source.selection) {
|
||||
const asymIds: string[] = source.selection.replace(' ', '').replace(':', '').split('or');
|
||||
query = MS.struct.modifier.union([
|
||||
MS.struct.generator.atomGroups({
|
||||
@@ -157,9 +157,9 @@ function getCurveTransforms(ingredient: Ingredient) {
|
||||
const n = ingredient.nbCurve || 0;
|
||||
const instances: Mat4[] = [];
|
||||
let segmentLength = 3.4;
|
||||
if (ingredient.uLength){
|
||||
if (ingredient.uLength) {
|
||||
segmentLength = ingredient.uLength;
|
||||
} else if (ingredient.radii){
|
||||
} else if (ingredient.radii) {
|
||||
segmentLength = ingredient.radii[0].radii
|
||||
? ingredient.radii[0].radii[0] * 2.0
|
||||
: 3.4;
|
||||
@@ -177,7 +177,7 @@ function getCurveTransforms(ingredient: Ingredient) {
|
||||
continue;
|
||||
}
|
||||
// test for resampling
|
||||
let distance: number = Vec3.distance(_points[0], _points[1]);
|
||||
const distance: number = Vec3.distance(_points[0], _points[1]);
|
||||
if (distance >= segmentLength + 2.0) {
|
||||
console.info(distance);
|
||||
resampling = true;
|
||||
@@ -196,7 +196,7 @@ function getAssembly(transforms: Mat4[], structure: Structure) {
|
||||
|
||||
for (let i = 0, il = transforms.length; i < il; ++i) {
|
||||
const id = `${i + 1}`;
|
||||
const op = SymmetryOperator.create(id, transforms[i], { assembly: { id, operId: i, operList: [ id ] } });
|
||||
const op = SymmetryOperator.create(id, transforms[i], { assembly: { id, operId: i, operList: [id] } });
|
||||
for (const unit of units) {
|
||||
builder.addWithOperator(unit, op);
|
||||
}
|
||||
@@ -333,7 +333,7 @@ async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredi
|
||||
structure = await getCurve(plugin, name, ingredient, getCurveTransforms(ingredient), model);
|
||||
} else {
|
||||
let bu: string|undefined = source.bu ? source.bu : undefined;
|
||||
if (bu){
|
||||
if (bu) {
|
||||
if (bu === 'AU') {
|
||||
bu = undefined;
|
||||
} else {
|
||||
@@ -343,22 +343,22 @@ async function getIngredientStructure(plugin: PluginContext, ingredient: Ingredi
|
||||
structure = await getStructure(plugin, model, source, { assembly: bu });
|
||||
// transform with offset and pcp
|
||||
let legacy: boolean = true;
|
||||
if (ingredient.offset || ingredient.principalAxis){
|
||||
if (ingredient.offset || ingredient.principalAxis) {
|
||||
legacy = false;
|
||||
const structureMean = getStructureMean(structure);
|
||||
Vec3.negate(structureMean, structureMean);
|
||||
const m1: Mat4 = Mat4.identity();
|
||||
Mat4.setTranslation(m1, structureMean);
|
||||
structure = Structure.transform(structure, m1);
|
||||
if (ingredient.offset){
|
||||
if (!Vec3.exactEquals(ingredient.offset, Vec3.zero())){
|
||||
if (ingredient.offset) {
|
||||
if (!Vec3.exactEquals(ingredient.offset, Vec3.zero())) {
|
||||
const m: Mat4 = Mat4.identity();
|
||||
Mat4.setTranslation(m, ingredient.offset);
|
||||
structure = Structure.transform(structure, m);
|
||||
}
|
||||
}
|
||||
if (ingredient.principalAxis){
|
||||
if (!Vec3.exactEquals(ingredient.principalAxis, Vec3.unitZ)){
|
||||
if (ingredient.principalAxis) {
|
||||
if (!Vec3.exactEquals(ingredient.principalAxis, Vec3.unitZ)) {
|
||||
const q: Quat = Quat.identity();
|
||||
Quat.rotationTo(q, ingredient.principalAxis, Vec3.unitZ);
|
||||
const m: Mat4 = Mat4.fromQuat(Mat4.zero(), q);
|
||||
@@ -387,7 +387,7 @@ export function createStructureFromCellPack(plugin: PluginContext, packing: Cell
|
||||
structures.push(ingredientStructure.structure);
|
||||
assets.push(...ingredientStructure.assets);
|
||||
const c = ingredients[iName].color;
|
||||
if (c){
|
||||
if (c) {
|
||||
colors.push(Color.fromNormalizedRgb(c[0], c[1], c[2]));
|
||||
} else {
|
||||
skipColors = true;
|
||||
@@ -402,7 +402,7 @@ export function createStructureFromCellPack(plugin: PluginContext, packing: Cell
|
||||
for (const s of structures) {
|
||||
if (ctx.shouldUpdate) await ctx.update(`${s.label}`);
|
||||
let maxInvariantId = 0;
|
||||
let maxChainGroupId = 0;
|
||||
const maxChainGroupId = 0;
|
||||
for (const u of s.units) {
|
||||
const invariantId = u.invariantId + offsetInvariantId;
|
||||
const chainGroupId = u.chainGroupId + offsetChainGroupId;
|
||||
@@ -415,7 +415,7 @@ export function createStructureFromCellPack(plugin: PluginContext, packing: Cell
|
||||
|
||||
if (ctx.shouldUpdate) await ctx.update(`${name} - structure`);
|
||||
const structure = Structure.create(units);
|
||||
for( let i = 0, il = structure.models.length; i < il; ++i) {
|
||||
for (let i = 0, il = structure.models.length; i < il; ++i) {
|
||||
Model.TrajectoryInfo.set(structure.models[i], { size: il, index: i });
|
||||
}
|
||||
return { structure, assets, colors: skipColors ? undefined : colors };
|
||||
@@ -454,7 +454,7 @@ async function loadMembrane(plugin: PluginContext, name: string, state: State, p
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!file){
|
||||
if (!file) {
|
||||
// check for cif directly
|
||||
const cifileName = `${name}.cif`;
|
||||
for (const f of params.ingredients) {
|
||||
@@ -544,7 +544,7 @@ async function loadPackings(plugin: PluginContext, runtime: RuntimeContext, stat
|
||||
representation: params.preset.representation,
|
||||
};
|
||||
await CellpackPackingPreset.apply(packing, packingParams, plugin);
|
||||
if ( packings[i].location === 'surface' && params.membrane){
|
||||
if (packings[i].location === 'surface' && params.membrane) {
|
||||
await loadMembrane(plugin, packings[i].name, state, params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ const StructureFromCellpack = PluginStateTransform.BuiltIn({
|
||||
},
|
||||
dispose({ b, cache }) {
|
||||
const assets = (cache as any).assets as Asset.Wrapper[];
|
||||
if(assets) {
|
||||
if (assets) {
|
||||
for (const a of assets) a.dispose();
|
||||
}
|
||||
|
||||
@@ -115,12 +115,12 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({
|
||||
// TODO: optimze
|
||||
// TODO: think of ways how to fast-track changes to this for animations
|
||||
const model = a.data;
|
||||
let initial_structure = Structure.ofModel(model);
|
||||
const initial_structure = Structure.ofModel(model);
|
||||
const structures: Structure[] = [];
|
||||
let structure: Structure = initial_structure;
|
||||
// the list of asambly *?
|
||||
const symmetry = ModelSymmetry.Provider.get(model);
|
||||
if (symmetry && symmetry.assemblies.length !== 0){
|
||||
if (symmetry && symmetry.assemblies.length !== 0) {
|
||||
for (const a of symmetry.assemblies) {
|
||||
const s = await StructureSymmetry.buildAssembly(initial_structure, a.id).runInContext(ctx);
|
||||
structures.push(s);
|
||||
@@ -137,7 +137,7 @@ const StructureFromAssemblies = PluginStateTransform.BuiltIn({
|
||||
offsetInvariantId += maxInvariantId + 1;
|
||||
}
|
||||
structure = builder.getStructure();
|
||||
for( let i = 0, il = structure.models.length; i < il; ++i) {
|
||||
for (let i = 0, il = structure.models.length; i < il; ++i) {
|
||||
Model.TrajectoryInfo.set(structure.models[i], { size: il, index: i });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ export async function getFromPdb(plugin: PluginContext, pdbId: string, assetMana
|
||||
return { mmcif: cif.blocks[0], asset };
|
||||
}
|
||||
|
||||
export async function getFromOPM(plugin: PluginContext, pdbId: string, assetManager: AssetManager){
|
||||
export async function getFromOPM(plugin: PluginContext, pdbId: string, assetManager: AssetManager) {
|
||||
const asset = await plugin.runTask(assetManager.resolve(Asset.getUrlAsset(assetManager, `https://opm-assets.storage.googleapis.com/pdb/${pdbId.toLowerCase()}.pdb`), 'string'));
|
||||
return { pdb: await parsePDBfile(plugin, asset.data, pdbId), asset };
|
||||
}
|
||||
|
||||
@@ -41,10 +41,10 @@ export const DnatcoConfalPyramidsPreset = StructureRepresentationPresetProvider(
|
||||
|
||||
let pyramidsRepr;
|
||||
if (representations)
|
||||
pyramidsRepr = builder.buildRepresentation(update, pyramids, { type: ConfalPyramidsRepresentationProvider, typeParams, color: ConfalPyramidsColorThemeProvider }, { tag: 'confal-pyramdis' } );
|
||||
pyramidsRepr = builder.buildRepresentation(update, pyramids, { type: ConfalPyramidsRepresentationProvider, typeParams, color: ConfalPyramidsColorThemeProvider }, { tag: 'confal-pyramdis' });
|
||||
|
||||
await update.commit({ revertOnError: true });
|
||||
return { components: { ...components, pyramids }, representations: { ...representations, pyramidsRepr } };
|
||||
return { components: { ...components, pyramids }, representations: { ...representations, pyramidsRepr } };
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ const ColorMapping: ReadonlyMap<ConformerClasses, Color> = new Map([
|
||||
['B', Color(0xC8CFFF)],
|
||||
['BII', Color(0x0059DA)],
|
||||
['miB', Color(0x3BE8FB)],
|
||||
['Z', Color(0x01F60E)],
|
||||
['Z', Color(0x01F60E)],
|
||||
['IC', Color(0xFA5CFB)],
|
||||
['OPN', Color(0xE90000)],
|
||||
['SYN', Color(0xFFFF01)],
|
||||
@@ -165,8 +165,8 @@ export function ConfalPyramidsColorTheme(ctx: ThemeDataContext, props: PD.Values
|
||||
legend: TableLegend(iterableToArray(ColorMapping.entries()).map(([conformer, color]) => {
|
||||
return [conformer, color] as [string, Color];
|
||||
}).concat([
|
||||
[ 'Error', ErrorColor ],
|
||||
[ 'Unknown', DefaultColor ]
|
||||
['Error', ErrorColor],
|
||||
['Unknown', DefaultColor]
|
||||
]))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ export namespace ConfalPyramidsUtil {
|
||||
const first = residueInfoFromLocation(locFirst);
|
||||
const second = residueInfoFromLocation(locSecond);
|
||||
const model_id = this.hasMultipleModels ? `-m${modelNum}` : '';
|
||||
const alt_id_1 = fakeAltId_1 !== '' ? `.${fakeAltId_1}` : (first.alt_id.length ? `.${first.alt_id}` : '');
|
||||
const alt_id_1 = fakeAltId_1 !== '' ? `.${fakeAltId_1}` : (first.alt_id.length ? `.${first.alt_id}` : '');
|
||||
const alt_id_2 = fakeAltId_2 !== '' ? `.${fakeAltId_2}` : (second.alt_id.length ? `.${second.alt_id}` : '');
|
||||
const ins_code_1 = first.ins_code.length ? `.${first.ins_code}` : '';
|
||||
const ins_code_2 = second.ins_code.length ? `.${second.ins_code}` : '';
|
||||
|
||||
@@ -61,7 +61,7 @@ function getColumns(block: G3dDataBlock) {
|
||||
objectForEach(data, (hs, h) => {
|
||||
objectForEach(hs, (chs, ch) => {
|
||||
const entity_id = `${ch}-${h}`;
|
||||
const l = chs.start.length;
|
||||
const l = chs.start.length;
|
||||
if (l === 0) return;
|
||||
|
||||
let x = chs.x[0];
|
||||
|
||||
@@ -53,7 +53,7 @@ export class GlbExporter extends MeshExporter<GlbData> {
|
||||
max[j] = Math.max(a[i + j], max[j]);
|
||||
}
|
||||
}
|
||||
return [ min, max ];
|
||||
return [min, max];
|
||||
}
|
||||
|
||||
private addBuffer(buffer: ArrayBuffer, componentType: number, type: string, count: number, target: number, min?: any, max?: any, normalized?: boolean) {
|
||||
@@ -108,7 +108,7 @@ export class GlbExporter extends MeshExporter<GlbData> {
|
||||
indexArray = indices!.slice(0, drawCount);
|
||||
}
|
||||
|
||||
const [ vertexMin, vertexMax ] = GlbExporter.vec3MinMax(vertexArray);
|
||||
const [vertexMin, vertexMax] = GlbExporter.vec3MinMax(vertexArray);
|
||||
|
||||
let vertexBuffer = vertexArray.buffer;
|
||||
let normalBuffer = normalArray.buffer;
|
||||
@@ -273,14 +273,14 @@ export class GlbExporter extends MeshExporter<GlbData> {
|
||||
if (padding) {
|
||||
chunk.push(padding.buffer);
|
||||
}
|
||||
return [ chunk, 8 + byteLength ];
|
||||
return [chunk, 8 + byteLength];
|
||||
};
|
||||
const jsonString = JSON.stringify(gltf);
|
||||
const jsonBuffer = new Uint8Array(jsonString.length);
|
||||
asciiWrite(jsonBuffer, jsonString);
|
||||
|
||||
const [ jsonChunk, jsonChunkLength ] = createChunk(0x4E4F534A, [jsonBuffer.buffer], jsonBuffer.length, 0x20);
|
||||
const [ binaryChunk, binaryChunkLength ] = createChunk(0x004E4942, this.binaryBuffer, binaryBufferLength, 0x00);
|
||||
const [jsonChunk, jsonChunkLength] = createChunk(0x4E4F534A, [jsonBuffer.buffer], jsonBuffer.length, 0x20);
|
||||
const [binaryChunk, binaryChunkLength] = createChunk(0x004E4942, this.binaryBuffer, binaryBufferLength, 0x00);
|
||||
|
||||
const glbBufferLength = 12 + jsonChunkLength + binaryChunkLength;
|
||||
const header = new ArrayBuffer(12);
|
||||
|
||||
@@ -102,7 +102,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements
|
||||
}
|
||||
const framebuffer = webgl.namedFramebuffers[GeoExportName];
|
||||
|
||||
const [ width, height ] = colorTexDim;
|
||||
const [width, height] = colorTexDim;
|
||||
const colorGrid = new Uint8Array(width * height * 4);
|
||||
|
||||
framebuffer.bind();
|
||||
@@ -357,7 +357,7 @@ export abstract class MeshExporter<D extends RenderObjectExportData> implements
|
||||
}
|
||||
const framebuffer = webgl.namedFramebuffers[GeoExportName];
|
||||
|
||||
const [ width, height ] = values.uGeoTexDim.ref.value;
|
||||
const [width, height] = values.uGeoTexDim.ref.value;
|
||||
const vertices = new Float32Array(width * height * 4);
|
||||
const normals = new Float32Array(width * height * 4);
|
||||
const groups = webgl.isWebGL2 ? new Uint8Array(width * height * 4) : new Float32Array(width * height * 4);
|
||||
|
||||
@@ -62,7 +62,7 @@ export namespace PDBePreferredAssembly {
|
||||
if (model.customProperties.has(Descriptor)) return true;
|
||||
|
||||
let asmName: string | undefined = fromCifData(model);
|
||||
if (asmName === void 0 && params.PDBe_apiSourceJson) {
|
||||
if (asmName === void 0 && params.PDBe_apiSourceJson) {
|
||||
const data = await params.PDBe_apiSourceJson(model);
|
||||
if (!data) return false;
|
||||
asmName = asmNameFromJson(model, data);
|
||||
|
||||
@@ -52,7 +52,7 @@ export const PDBeStructureQualityReport = PluginBehavior.create<{ autoAttach: bo
|
||||
}
|
||||
|
||||
update(p: { autoAttach: boolean, showTooltip: boolean }) {
|
||||
let updated = this.params.autoAttach !== p.autoAttach;
|
||||
const updated = this.params.autoAttach !== p.autoAttach;
|
||||
this.params.autoAttach = p.autoAttach;
|
||||
this.params.showTooltip = p.showTooltip;
|
||||
this.ctx.customModelProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
|
||||
|
||||
@@ -87,7 +87,7 @@ export function StructureQualityReportColorTheme(ctx: ThemeDataContext, props: P
|
||||
};
|
||||
}
|
||||
|
||||
export const StructureQualityReportColorThemeProvider: ColorTheme.Provider<Params, 'pdbe-structure-quality-report'> = {
|
||||
export const StructureQualityReportColorThemeProvider: ColorTheme.Provider<Params, 'pdbe-structure-quality-report'> = {
|
||||
name: 'pdbe-structure-quality-report',
|
||||
label: 'Structure Quality Report',
|
||||
category: ColorTheme.Category.Validation,
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace StructureQualityReport {
|
||||
}
|
||||
|
||||
export function fromCif(ctx: CustomProperty.Context, model: Model, props: StructureQualityReportProps): StructureQualityReport | undefined {
|
||||
let info = PropertyWrapper.tryGetInfoFromCif('pdbe_structure_quality_report', model);
|
||||
const info = PropertyWrapper.tryGetInfoFromCif('pdbe_structure_quality_report', model);
|
||||
if (!info) return;
|
||||
const data = getCifData(model);
|
||||
const issueMap = createIssueMapFromCif(model, data.residues, data.groups);
|
||||
|
||||
@@ -47,7 +47,7 @@ export const RCSBAssemblySymmetry = PluginBehavior.create<{ autoAttach: boolean
|
||||
}
|
||||
|
||||
update(p: { autoAttach: boolean }) {
|
||||
let updated = this.params.autoAttach !== p.autoAttach;
|
||||
const updated = this.params.autoAttach !== p.autoAttach;
|
||||
this.params.autoAttach = p.autoAttach;
|
||||
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
|
||||
return updated;
|
||||
@@ -85,7 +85,7 @@ export const InitAssemblySymmetry3D = StateAction.build({
|
||||
const assemblySymmetryData = AssemblySymmetryDataProvider.get(a.data).value;
|
||||
const symmetryIndex = assemblySymmetryData ? AssemblySymmetry.firstNonC1(assemblySymmetryData) : -1;
|
||||
await AssemblySymmetryProvider.attach(propCtx, a.data, { symmetryIndex });
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
plugin.log.error(`Assembly Symmetry: ${e}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ export function getSymmetrySelectParam(structure?: Structure) {
|
||||
for (let i = 0, il = assemblySymmetryData.length; i < il; ++i) {
|
||||
const { symbol, kind } = assemblySymmetryData[i];
|
||||
if (symbol !== 'C1') {
|
||||
options.push([ i, `${i + 1}: ${symbol} ${kind}` ]);
|
||||
options.push([i, `${i + 1}: ${symbol} ${kind}`]);
|
||||
}
|
||||
}
|
||||
if (options.length > 1) {
|
||||
|
||||
@@ -310,7 +310,7 @@ function setSymbolTransform(t: Mat4, symbol: string, axes: AssemblySymmetry.Rota
|
||||
}
|
||||
}
|
||||
|
||||
const unitCircleDirections = (function() {
|
||||
const unitCircleDirections = (function () {
|
||||
const dirs: Vec3[] = [];
|
||||
const circle = polygon(12, false, 1);
|
||||
for (let i = 0, il = circle.length; i < il; i += 3) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { CollapsableState, CollapsableControls } from '../../../mol-plugin-ui/base';
|
||||
import { ApplyActionControl } from '../../../mol-plugin-ui/state/apply-action';
|
||||
import { InitAssemblySymmetry3D, AssemblySymmetry3D, AssemblySymmetryPreset, tryCreateAssemblySymmetry } from './behavior';
|
||||
import { AssemblySymmetryProvider, AssemblySymmetryProps, AssemblySymmetryDataProvider, AssemblySymmetry } from './prop';
|
||||
import { AssemblySymmetryProvider, AssemblySymmetryProps, AssemblySymmetryDataProvider, AssemblySymmetry } from './prop';
|
||||
import { ParameterControls } from '../../../mol-plugin-ui/controls/parameters';
|
||||
import { ParamDefinition as PD } from '../../../mol-util/param-definition';
|
||||
import { StructureHierarchyManager } from '../../../mol-plugin-state/manager/structure/hierarchy';
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
schema: https://data.rcsb.org/graphql
|
||||
documents: './src/extensions/rcsb/graphql/symmetry.gql.ts'
|
||||
generates:
|
||||
'./src/extensions/rcsb/graphql/types.ts':
|
||||
plugins:
|
||||
- add: '/* eslint-disable */'
|
||||
- time
|
||||
- typescript
|
||||
- typescript-operations
|
||||
config:
|
||||
immutableTypes: true
|
||||
skipTypename: true
|
||||
'./src/extensions/rcsb/graphql/types.ts':
|
||||
plugins:
|
||||
- add:
|
||||
content: '/* eslint-disable */'
|
||||
- time
|
||||
- typescript
|
||||
- typescript-operations
|
||||
config:
|
||||
immutableTypes: true
|
||||
skipTypename: true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -63,7 +63,7 @@ export const RCSBValidationReport = PluginBehavior.create<{ autoAttach: boolean,
|
||||
}
|
||||
|
||||
update(p: { autoAttach: boolean, showTooltip: boolean }) {
|
||||
let updated = this.params.autoAttach !== p.autoAttach;
|
||||
const updated = this.params.autoAttach !== p.autoAttach;
|
||||
this.params.autoAttach = p.autoAttach;
|
||||
this.params.showTooltip = p.showTooltip;
|
||||
this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace ValidationReport {
|
||||
}
|
||||
|
||||
export async function obtain(ctx: CustomProperty.Context, model: Model, props: ValidationReportProps): Promise<CustomProperty.Data<ValidationReport>> {
|
||||
switch(props.source.name) {
|
||||
switch (props.source.name) {
|
||||
case 'file': return open(ctx, model, props.source.params);
|
||||
case 'server': return fetch(ctx, model, props.source.params);
|
||||
}
|
||||
@@ -208,8 +208,8 @@ function createInterUnitClashes(structure: Structure, clashes: ValidationReport[
|
||||
|
||||
for (let i = 0, il = clashes.edgeCount * 2; i < il; ++i) {
|
||||
// TODO create lookup
|
||||
let indexA = SortedArray.indexOf(elementsA, a[i]);
|
||||
let indexB = SortedArray.indexOf(elementsB, b[i]);
|
||||
const indexA = SortedArray.indexOf(elementsA, a[i]);
|
||||
const indexB = SortedArray.indexOf(elementsB, b[i]);
|
||||
|
||||
if (indexA !== -1 && indexB !== -1) {
|
||||
unitA.conformation.position(a[i], pA);
|
||||
@@ -250,8 +250,8 @@ function createIntraUnitClashes(unit: Unit.Atomic, clashes: ValidationReport['cl
|
||||
|
||||
for (let i = 0, il = edgeCount * 2; i < il; ++i) {
|
||||
// TODO create lookup
|
||||
let indexA = SortedArray.indexOf(elements, a[i]);
|
||||
let indexB = SortedArray.indexOf(elements, b[i]);
|
||||
const indexA = SortedArray.indexOf(elements, a[i]);
|
||||
const indexB = SortedArray.indexOf(elements, b[i]);
|
||||
|
||||
if (indexA !== -1 && indexB !== -1) {
|
||||
unit.conformation.position(a[i], pA);
|
||||
@@ -431,7 +431,7 @@ function parseValidationReportXml(xml: XMLDocument, model: Model): ValidationRep
|
||||
|
||||
const groups = xml.getElementsByTagName('ModelledSubgroup');
|
||||
for (let i = 0, il = groups.length; i < il; ++i) {
|
||||
const g = groups[ i ];
|
||||
const g = groups[i];
|
||||
const ga = g.attributes;
|
||||
|
||||
const pdbx_PDB_model_num = parseInt(getItem(ga, 'model'));
|
||||
|
||||
@@ -107,7 +107,7 @@ function getIntraClashLabel(structure: Structure, unit: Unit.Atomic, clashes: In
|
||||
|
||||
function IntraClashLoci(structure: Structure, unit: Unit.Atomic, clashes: IntraUnitClashes, elements: number[]) {
|
||||
return DataLoci('intra-clashes', { unit, clashes }, elements,
|
||||
(boundingSphere: Sphere3D) => getIntraClashBoundingSphere(unit, clashes, elements, boundingSphere),
|
||||
(boundingSphere: Sphere3D) => getIntraClashBoundingSphere(unit, clashes, elements, boundingSphere),
|
||||
() => getIntraClashLabel(structure, unit, clashes, elements));
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ function getIntraClashLoci(pickingId: PickingId, structureGroup: StructureGroup,
|
||||
}
|
||||
|
||||
function eachIntraClash(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
|
||||
let changed = false;
|
||||
const changed = false;
|
||||
// TODO
|
||||
return changed;
|
||||
}
|
||||
@@ -226,7 +226,7 @@ function getInterClashLabel(structure: Structure, clashes: InterUnitClashes, ele
|
||||
|
||||
function InterClashLoci(structure: Structure, clashes: InterUnitClashes, elements: number[]) {
|
||||
return DataLoci('inter-clashes', clashes, elements,
|
||||
(boundingSphere: Sphere3D) => getInterClashBoundingSphere(structure, clashes, elements, boundingSphere),
|
||||
(boundingSphere: Sphere3D) => getInterClashBoundingSphere(structure, clashes, elements, boundingSphere),
|
||||
() => getInterClashLabel(structure, clashes, elements));
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ function getInterClashLoci(pickingId: PickingId, structure: Structure, id: numbe
|
||||
}
|
||||
|
||||
function eachInterClash(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
|
||||
let changed = false;
|
||||
const changed = false;
|
||||
// TODO
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class Camera implements ICamera {
|
||||
readonly inverseProjectionView: Mat4 = Mat4.identity();
|
||||
|
||||
private pixelScale: number
|
||||
get pixelRatio () {
|
||||
get pixelRatio() {
|
||||
const dpr = (typeof window !== 'undefined') ? window.devicePixelRatio : 1;
|
||||
return dpr * this.pixelScale;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ const FAR_RANGE = 1;
|
||||
const tmpVec4 = Vec4();
|
||||
|
||||
/** Transform point into 2D window coordinates. */
|
||||
export function cameraProject (out: Vec4, point: Vec3, viewport: Viewport, projectionView: Mat4) {
|
||||
export function cameraProject(out: Vec4, point: Vec3, viewport: Viewport, projectionView: Mat4) {
|
||||
const { x: vX, y: vY, width: vWidth, height: vHeight } = viewport;
|
||||
|
||||
// clip space -> NDC -> window coordinates, implicit 1.0 for w component
|
||||
@@ -90,7 +90,7 @@ export function cameraProject (out: Vec4, point: Vec3, viewport: Viewport, proje
|
||||
* Transform point from screen space to 3D coordinates.
|
||||
* The point must have x and y set to 2D window coordinates and z between 0 (near) and 1 (far).
|
||||
*/
|
||||
export function cameraUnproject (out: Vec3, point: Vec3, viewport: Viewport, inverseProjectionView: Mat4) {
|
||||
export function cameraUnproject(out: Vec3, point: Vec3, viewport: Viewport, inverseProjectionView: Mat4) {
|
||||
const { x: vX, y: vY, width: vWidth, height: vHeight } = viewport;
|
||||
|
||||
const x = point[0] - vX;
|
||||
|
||||
@@ -38,6 +38,7 @@ import { StereoCamera, StereoCameraParams } from './camera/stereo';
|
||||
import { Helper } from './helper/helper';
|
||||
import { Passes } from './passes/passes';
|
||||
import { shallowEqual } from '../mol-util';
|
||||
import { MarkingParams } from './passes/marking';
|
||||
|
||||
export const Canvas3DParams = {
|
||||
camera: PD.Group({
|
||||
@@ -80,6 +81,7 @@ export const Canvas3DParams = {
|
||||
|
||||
multiSample: PD.Group(MultiSampleParams),
|
||||
postprocessing: PD.Group(PostprocessingParams),
|
||||
marking: PD.Group(MarkingParams),
|
||||
renderer: PD.Group(RendererParams),
|
||||
trackball: PD.Group(TrackballControlsParams),
|
||||
debug: PD.Group(DebugHelperParams),
|
||||
@@ -113,19 +115,21 @@ namespace Canvas3DContext {
|
||||
preserveDrawingBuffer: true,
|
||||
pixelScale: 1,
|
||||
pickScale: 0.25,
|
||||
enableWboit: true
|
||||
enableWboit: true,
|
||||
preferWebGl1: false
|
||||
};
|
||||
export type Attribs = typeof DefaultAttribs
|
||||
|
||||
export function fromCanvas(canvas: HTMLCanvasElement, attribs: Partial<Attribs> = {}): Canvas3DContext {
|
||||
const a = { ...DefaultAttribs, ...attribs };
|
||||
const { antialias, preserveDrawingBuffer, pixelScale } = a;
|
||||
const { antialias, preserveDrawingBuffer, pixelScale, preferWebGl1 } = a;
|
||||
const gl = getGLContext(canvas, {
|
||||
antialias,
|
||||
preserveDrawingBuffer,
|
||||
alpha: true, // the renderer requires an alpha channel
|
||||
depth: true, // the renderer requires a depth buffer
|
||||
premultipliedAlpha: true, // the renderer outputs PMA
|
||||
preferWebGl1
|
||||
});
|
||||
if (gl === null) throw new Error('Could not create a WebGL rendering context');
|
||||
|
||||
@@ -228,7 +232,7 @@ interface Canvas3D {
|
||||
/** Sets drawPaused = false without starting the built in animation loop */
|
||||
resume(): void
|
||||
identify(x: number, y: number): PickData | undefined
|
||||
mark(loci: Representation.Loci, action: MarkerAction): void
|
||||
mark(loci: Representation.Loci, action: MarkerAction, noDraw?: boolean): void
|
||||
getLoci(pickingId: PickingId | undefined): Representation.Loci
|
||||
|
||||
notifyDidDraw: boolean,
|
||||
@@ -337,7 +341,7 @@ namespace Canvas3D {
|
||||
return { loci, repr };
|
||||
}
|
||||
|
||||
function mark(reprLoci: Representation.Loci, action: MarkerAction) {
|
||||
function mark(reprLoci: Representation.Loci, action: MarkerAction, noDraw = false) {
|
||||
const { repr, loci } = reprLoci;
|
||||
let changed = false;
|
||||
if (repr) {
|
||||
@@ -347,7 +351,7 @@ namespace Canvas3D {
|
||||
changed = helper.camera.mark(loci, action) || changed;
|
||||
reprRenderObjects.forEach((_, _repr) => { changed = _repr.mark(loci, action) || changed; });
|
||||
}
|
||||
if (changed) {
|
||||
if (changed && !noDraw) {
|
||||
scene.update(void 0, true);
|
||||
helper.handle.scene.update(void 0, true);
|
||||
helper.camera.scene.update(void 0, true);
|
||||
@@ -390,7 +394,7 @@ namespace Canvas3D {
|
||||
if (MultiSamplePass.isEnabled(p.multiSample)) {
|
||||
multiSampleHelper.render(renderer, cam, scene, helper, true, p.transparentBackground, p);
|
||||
} else {
|
||||
passes.draw.render(renderer, cam, scene, helper, true, p.transparentBackground, p.postprocessing);
|
||||
passes.draw.render(renderer, cam, scene, helper, true, p.transparentBackground, p.postprocessing, p.marking);
|
||||
}
|
||||
pickHelper.dirty = true;
|
||||
didRender = true;
|
||||
@@ -636,6 +640,7 @@ namespace Canvas3D {
|
||||
viewport: p.viewport,
|
||||
|
||||
postprocessing: { ...p.postprocessing },
|
||||
marking: { ...p.marking },
|
||||
multiSample: { ...p.multiSample },
|
||||
renderer: { ...renderer.props },
|
||||
trackball: { ...controls.props },
|
||||
@@ -729,7 +734,7 @@ namespace Canvas3D {
|
||||
resized,
|
||||
setProps: (properties, doNotRequestDraw = false) => {
|
||||
const props: PartialCanvas3DProps = typeof properties === 'function'
|
||||
? produce(getProps(), properties)
|
||||
? produce(getProps(), properties as any)
|
||||
: properties;
|
||||
|
||||
const cameraState: Partial<Camera.Snapshot> = Object.create(null);
|
||||
@@ -771,6 +776,7 @@ namespace Canvas3D {
|
||||
}
|
||||
|
||||
if (props.postprocessing) Object.assign(p.postprocessing, props.postprocessing);
|
||||
if (props.marking) Object.assign(p.marking, props.marking);
|
||||
if (props.multiSample) Object.assign(p.multiSample, props.multiSample);
|
||||
if (props.renderer) renderer.setProps(props.renderer);
|
||||
if (props.trackball) controls.setProps(props.trackball);
|
||||
@@ -835,9 +841,6 @@ namespace Canvas3D {
|
||||
height = Math.round(p.viewport.params.height * gl.drawingBufferHeight);
|
||||
y = Math.round(gl.drawingBufferHeight - height - p.viewport.params.y * gl.drawingBufferHeight);
|
||||
width = Math.round(p.viewport.params.width * gl.drawingBufferWidth);
|
||||
// if (x + width >= gl.drawingBufferWidth) width = gl.drawingBufferWidth - x;
|
||||
// if (y + height >= gl.drawingBufferHeight) height = gl.drawingBufferHeight - y - 1;
|
||||
// console.log({ x, y, width, height });
|
||||
}
|
||||
|
||||
if (oldX !== x || oldY !== y || oldWidth !== width || oldHeight !== height) {
|
||||
|
||||
@@ -121,7 +121,7 @@ export class BoundingSphereHelper {
|
||||
}
|
||||
get props() { return this._props as Readonly<DebugHelperProps>; }
|
||||
|
||||
setProps (props: Partial<DebugHelperProps>) {
|
||||
setProps(props: Partial<DebugHelperProps>) {
|
||||
Object.assign(this._props, props);
|
||||
if (this.isEnabled) this.update();
|
||||
}
|
||||
|
||||
@@ -149,13 +149,13 @@ export class Canvas3dInteractionHelper {
|
||||
}
|
||||
|
||||
constructor(private canvasIdentify: Canvas3D['identify'], private getLoci: Canvas3D['getLoci'], private input: InputObserver, private camera: Camera, private maxFps: number = 30) {
|
||||
input.drag.subscribe(({x, y, buttons, button, modifiers }) => {
|
||||
input.drag.subscribe(({ x, y, buttons, button, modifiers }) => {
|
||||
this.isInteracting = true;
|
||||
// console.log('drag');
|
||||
this.drag(x, y, buttons, button, modifiers);
|
||||
});
|
||||
|
||||
input.move.subscribe(({x, y, inside, buttons, button, modifiers }) => {
|
||||
input.move.subscribe(({ x, y, inside, buttons, button, modifiers }) => {
|
||||
if (!inside || this.isInteracting) return;
|
||||
// console.log('move');
|
||||
this.move(x, y, buttons, button, modifiers);
|
||||
@@ -166,7 +166,7 @@ export class Canvas3dInteractionHelper {
|
||||
this.leave();
|
||||
});
|
||||
|
||||
input.click.subscribe(({x, y, buttons, button, modifiers }) => {
|
||||
input.click.subscribe(({ x, y, buttons, button, modifiers }) => {
|
||||
if (this.outsideViewport(x, y)) return;
|
||||
// console.log('click');
|
||||
this.click(x, y, buttons, button, modifiers);
|
||||
|
||||
@@ -26,6 +26,7 @@ import { copy_frag } from '../../mol-gl/shader/copy.frag';
|
||||
import { StereoCamera } from '../camera/stereo';
|
||||
import { WboitPass } from './wboit';
|
||||
import { AntialiasingPass, PostprocessingPass, PostprocessingProps } from './postprocessing';
|
||||
import { MarkingPass, MarkingProps } from './marking';
|
||||
|
||||
const DepthMergeSchema = {
|
||||
...QuadSchema,
|
||||
@@ -57,8 +58,8 @@ const CopySchema = {
|
||||
tColor: TextureSpec('texture', 'rgba', 'ubyte', 'nearest'),
|
||||
uTexSize: UniformSpec('v2'),
|
||||
};
|
||||
const CopyShaderCode = ShaderCode('copy', quad_vert, copy_frag);
|
||||
type CopyRenderable = ComputeRenderable<Values<typeof CopySchema>>
|
||||
const CopyShaderCode = ShaderCode('copy', quad_vert, copy_frag);
|
||||
type CopyRenderable = ComputeRenderable<Values<typeof CopySchema>>
|
||||
|
||||
function getCopyRenderable(ctx: WebGLContext, colorTexture: Texture): CopyRenderable {
|
||||
const values: Values<typeof CopySchema> = {
|
||||
@@ -92,6 +93,7 @@ export class DrawPass {
|
||||
private copyFboPostprocessing: CopyRenderable
|
||||
|
||||
private wboit: WboitPass | undefined
|
||||
private readonly marking: MarkingPass
|
||||
readonly postprocessing: PostprocessingPass
|
||||
private readonly antialiasing: AntialiasingPass
|
||||
|
||||
@@ -122,6 +124,7 @@ export class DrawPass {
|
||||
this.depthMerge = getDepthMergeRenderable(webgl, this.depthTexturePrimitives, this.depthTextureVolumes, this.packedDepth);
|
||||
|
||||
this.wboit = enableWboit ? new WboitPass(webgl, width, height) : undefined;
|
||||
this.marking = new MarkingPass(webgl, width, height);
|
||||
this.postprocessing = new PostprocessingPass(webgl, this);
|
||||
this.antialiasing = new AntialiasingPass(webgl, this);
|
||||
|
||||
@@ -162,6 +165,7 @@ export class DrawPass {
|
||||
this.wboit.setSize(width, height);
|
||||
}
|
||||
|
||||
this.marking.setSize(width, height);
|
||||
this.postprocessing.setSize(width, height);
|
||||
this.antialiasing.setSize(width, height);
|
||||
}
|
||||
@@ -281,10 +285,11 @@ export class DrawPass {
|
||||
renderer.renderBlendedTransparent(scene.primitives, camera, null);
|
||||
}
|
||||
|
||||
private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
|
||||
private _render(renderer: Renderer, camera: ICamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps, markingProps: MarkingProps) {
|
||||
const volumeRendering = scene.volumes.renderables.length > 0;
|
||||
const postprocessingEnabled = PostprocessingPass.isEnabled(postprocessingProps);
|
||||
const antialiasingEnabled = AntialiasingPass.isEnabled(postprocessingProps);
|
||||
const markingEnabled = MarkingPass.isEnabled(markingProps);
|
||||
|
||||
const { x, y, width, height } = camera.viewport;
|
||||
renderer.setViewport(x, y, width, height);
|
||||
@@ -309,6 +314,22 @@ export class DrawPass {
|
||||
this.drawTarget.bind();
|
||||
}
|
||||
|
||||
if (markingEnabled) {
|
||||
const markingDepthTest = markingProps.ghostEdgeStrength < 1;
|
||||
if (markingDepthTest) {
|
||||
this.marking.depthTarget.bind();
|
||||
renderer.clear(false);
|
||||
renderer.renderMarkingDepth(scene.primitives, camera, null);
|
||||
}
|
||||
|
||||
this.marking.maskTarget.bind();
|
||||
renderer.clear(false);
|
||||
renderer.renderMarkingMask(scene.primitives, camera, markingDepthTest ? this.marking.depthTarget.texture : null);
|
||||
|
||||
this.marking.update(markingProps);
|
||||
this.marking.render(camera.viewport, postprocessingEnabled ? this.postprocessing.target : this.colorTarget);
|
||||
}
|
||||
|
||||
if (helper.debug.isEnabled) {
|
||||
helper.debug.syncVisibility();
|
||||
renderer.renderBlended(helper.debug.scene, camera, null);
|
||||
@@ -338,15 +359,15 @@ export class DrawPass {
|
||||
this.webgl.gl.flush();
|
||||
}
|
||||
|
||||
render(renderer: Renderer, camera: Camera | StereoCamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps) {
|
||||
render(renderer: Renderer, camera: Camera | StereoCamera, scene: Scene, helper: Helper, toDrawingBuffer: boolean, transparentBackground: boolean, postprocessingProps: PostprocessingProps, markingProps: MarkingProps) {
|
||||
renderer.setTransparentBackground(transparentBackground);
|
||||
renderer.setDrawingBufferSize(this.colorTarget.getWidth(), this.colorTarget.getHeight());
|
||||
|
||||
if (StereoCamera.is(camera)) {
|
||||
this._render(renderer, camera.left, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps);
|
||||
this._render(renderer, camera.right, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps);
|
||||
this._render(renderer, camera.left, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps, markingProps);
|
||||
this._render(renderer, camera.right, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps, markingProps);
|
||||
} else {
|
||||
this._render(renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps);
|
||||
this._render(renderer, camera, scene, helper, toDrawingBuffer, transparentBackground, postprocessingProps, markingProps);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,13 @@ import { Viewport } from '../camera/util';
|
||||
import { PixelData } from '../../mol-util/image';
|
||||
import { Helper } from '../helper/helper';
|
||||
import { CameraHelper, CameraHelperParams } from '../helper/camera-helper';
|
||||
import { MarkingParams } from './marking';
|
||||
|
||||
export const ImageParams = {
|
||||
transparentBackground: PD.Boolean(false),
|
||||
multiSample: PD.Group(MultiSampleParams),
|
||||
postprocessing: PD.Group(PostprocessingParams),
|
||||
marking: PD.Group(MarkingParams),
|
||||
|
||||
cameraHelper: PD.Group(CameraHelperParams),
|
||||
};
|
||||
@@ -85,7 +87,7 @@ export class ImagePass {
|
||||
this.multiSampleHelper.render(this.renderer, this._camera, this.scene, this.helper, false, this.props.transparentBackground, this.props);
|
||||
this._colorTarget = this.multiSamplePass.colorTarget;
|
||||
} else {
|
||||
this.drawPass.render(this.renderer, this._camera, this.scene, this.helper, false, this.props.transparentBackground, this.props.postprocessing);
|
||||
this.drawPass.render(this.renderer, this._camera, this.scene, this.helper, false, this.props.transparentBackground, this.props.postprocessing, this.props.marking);
|
||||
this._colorTarget = this.drawPass.getColorTarget(this.props.postprocessing);
|
||||
}
|
||||
}
|
||||
|
||||
194
src/mol-canvas3d/passes/marking.ts
Normal file
194
src/mol-canvas3d/passes/marking.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { QuadSchema, QuadValues } from '../../mol-gl/compute/util';
|
||||
import { ComputeRenderable, createComputeRenderable } from '../../mol-gl/renderable';
|
||||
import { DefineSpec, TextureSpec, UniformSpec, Values } from '../../mol-gl/renderable/schema';
|
||||
import { ShaderCode } from '../../mol-gl/shader-code';
|
||||
import { WebGLContext } from '../../mol-gl/webgl/context';
|
||||
import { createComputeRenderItem } from '../../mol-gl/webgl/render-item';
|
||||
import { Texture } from '../../mol-gl/webgl/texture';
|
||||
import { Vec2, Vec3 } from '../../mol-math/linear-algebra';
|
||||
import { ValueCell } from '../../mol-util';
|
||||
import { ParamDefinition as PD } from '../../mol-util/param-definition';
|
||||
import { quad_vert } from '../../mol-gl/shader/quad.vert';
|
||||
import { overlay_frag } from '../../mol-gl/shader/marking/overlay.frag';
|
||||
import { Viewport } from '../camera/util';
|
||||
import { RenderTarget } from '../../mol-gl/webgl/render-target';
|
||||
import { Color } from '../../mol-util/color';
|
||||
import { edge_frag } from '../../mol-gl/shader/marking/edge.frag';
|
||||
|
||||
export const MarkingParams = {
|
||||
enabled: PD.Boolean(false),
|
||||
highlightEdgeColor: PD.Color(Color.darken(Color.fromNormalizedRgb(1.0, 0.4, 0.6), 1.0)),
|
||||
selectEdgeColor: PD.Color(Color.darken(Color.fromNormalizedRgb(0.2, 1.0, 0.1), 1.0)),
|
||||
edgeScale: PD.Numeric(1, { min: 1, max: 3, step: 1 }, { description: 'Thickness of the edge.' }),
|
||||
ghostEdgeStrength: PD.Numeric(0.3, { min: 0, max: 1, step: 0.1 }, { description: 'Opacity of the hidden edges that are covered by other geometry. When set to 1, one less geometry render pass is done.' }),
|
||||
innerEdgeFactor: PD.Numeric(1.5, { min: 0, max: 3, step: 0.1 }, { description: 'Factor to multiply the inner edge color with - for added contrast.' }),
|
||||
};
|
||||
export type MarkingProps = PD.Values<typeof MarkingParams>
|
||||
|
||||
export class MarkingPass {
|
||||
static isEnabled(props: MarkingProps) {
|
||||
return props.enabled;
|
||||
}
|
||||
|
||||
readonly depthTarget: RenderTarget
|
||||
readonly maskTarget: RenderTarget
|
||||
private readonly edgesTarget: RenderTarget
|
||||
|
||||
private readonly edge: EdgeRenderable
|
||||
private readonly overlay: OverlayRenderable
|
||||
|
||||
constructor(private webgl: WebGLContext, width: number, height: number) {
|
||||
this.depthTarget = webgl.createRenderTarget(width, height);
|
||||
this.maskTarget = webgl.createRenderTarget(width, height);
|
||||
this.edgesTarget = webgl.createRenderTarget(width, height);
|
||||
|
||||
this.edge = getEdgeRenderable(webgl, this.maskTarget.texture);
|
||||
this.overlay = getOverlayRenderable(webgl, this.edgesTarget.texture);
|
||||
}
|
||||
|
||||
private setEdgeState(viewport: Viewport) {
|
||||
const { gl, state } = this.webgl;
|
||||
|
||||
state.enable(gl.SCISSOR_TEST);
|
||||
state.enable(gl.BLEND);
|
||||
state.blendFunc(gl.ONE, gl.ONE);
|
||||
state.blendEquation(gl.FUNC_ADD);
|
||||
state.disable(gl.DEPTH_TEST);
|
||||
state.depthMask(false);
|
||||
|
||||
const { x, y, width, height } = viewport;
|
||||
gl.viewport(x, y, width, height);
|
||||
gl.scissor(x, y, width, height);
|
||||
|
||||
state.clearColor(0, 0, 0, 0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
}
|
||||
|
||||
private setOverlayState(viewport: Viewport) {
|
||||
const { gl, state } = this.webgl;
|
||||
|
||||
state.enable(gl.SCISSOR_TEST);
|
||||
state.enable(gl.BLEND);
|
||||
state.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||
state.blendEquation(gl.FUNC_ADD);
|
||||
state.disable(gl.DEPTH_TEST);
|
||||
state.depthMask(false);
|
||||
|
||||
const { x, y, width, height } = viewport;
|
||||
gl.viewport(x, y, width, height);
|
||||
gl.scissor(x, y, width, height);
|
||||
}
|
||||
|
||||
setSize(width: number, height: number) {
|
||||
const w = this.depthTarget.getWidth();
|
||||
const h = this.depthTarget.getHeight();
|
||||
|
||||
if (width !== w || height !== h) {
|
||||
this.depthTarget.setSize(width, height);
|
||||
this.maskTarget.setSize(width, height);
|
||||
this.edgesTarget.setSize(width, height);
|
||||
|
||||
ValueCell.update(this.edge.values.uTexSizeInv, Vec2.set(this.edge.values.uTexSizeInv.ref.value, 1 / width, 1 / height));
|
||||
ValueCell.update(this.overlay.values.uTexSizeInv, Vec2.set(this.overlay.values.uTexSizeInv.ref.value, 1 / width, 1 / height));
|
||||
}
|
||||
}
|
||||
|
||||
update(props: MarkingProps) {
|
||||
const { highlightEdgeColor, selectEdgeColor, edgeScale, innerEdgeFactor, ghostEdgeStrength } = props;
|
||||
|
||||
const { values: edgeValues } = this.edge;
|
||||
const _edgeScale = Math.round(edgeScale * this.webgl.pixelRatio);
|
||||
if (edgeValues.dEdgeScale.ref.value !== _edgeScale) {
|
||||
ValueCell.update(edgeValues.dEdgeScale, _edgeScale);
|
||||
this.edge.update();
|
||||
}
|
||||
|
||||
const { values: overlayValues } = this.overlay;
|
||||
ValueCell.update(overlayValues.uHighlightEdgeColor, Color.toVec3Normalized(overlayValues.uHighlightEdgeColor.ref.value, highlightEdgeColor));
|
||||
ValueCell.update(overlayValues.uSelectEdgeColor, Color.toVec3Normalized(overlayValues.uSelectEdgeColor.ref.value, selectEdgeColor));
|
||||
ValueCell.update(overlayValues.uInnerEdgeFactor, innerEdgeFactor);
|
||||
ValueCell.update(overlayValues.uGhostEdgeStrength, ghostEdgeStrength);
|
||||
}
|
||||
|
||||
render(viewport: Viewport, target: RenderTarget | undefined) {
|
||||
this.edgesTarget.bind();
|
||||
this.setEdgeState(viewport);
|
||||
this.edge.render();
|
||||
|
||||
if (target) {
|
||||
target.bind();
|
||||
} else {
|
||||
this.webgl.unbindFramebuffer();
|
||||
}
|
||||
this.setOverlayState(viewport);
|
||||
this.overlay.render();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const EdgeSchema = {
|
||||
...QuadSchema,
|
||||
tMaskTexture: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
uTexSizeInv: UniformSpec('v2'),
|
||||
dEdgeScale: DefineSpec('number'),
|
||||
};
|
||||
const EdgeShaderCode = ShaderCode('edge', quad_vert, edge_frag);
|
||||
type EdgeRenderable = ComputeRenderable<Values<typeof EdgeSchema>>
|
||||
|
||||
function getEdgeRenderable(ctx: WebGLContext, maskTexture: Texture): EdgeRenderable {
|
||||
const width = maskTexture.getWidth();
|
||||
const height = maskTexture.getHeight();
|
||||
|
||||
const values: Values<typeof EdgeSchema> = {
|
||||
...QuadValues,
|
||||
tMaskTexture: ValueCell.create(maskTexture),
|
||||
uTexSizeInv: ValueCell.create(Vec2.create(1 / width, 1 / height)),
|
||||
dEdgeScale: ValueCell.create(1),
|
||||
};
|
||||
|
||||
const schema = { ...EdgeSchema };
|
||||
const renderItem = createComputeRenderItem(ctx, 'triangles', EdgeShaderCode, schema, values);
|
||||
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const OverlaySchema = {
|
||||
...QuadSchema,
|
||||
tEdgeTexture: TextureSpec('texture', 'rgba', 'ubyte', 'linear'),
|
||||
uTexSizeInv: UniformSpec('v2'),
|
||||
uHighlightEdgeColor: UniformSpec('v3'),
|
||||
uSelectEdgeColor: UniformSpec('v3'),
|
||||
uGhostEdgeStrength: UniformSpec('f'),
|
||||
uInnerEdgeFactor: UniformSpec('f'),
|
||||
};
|
||||
const OverlayShaderCode = ShaderCode('overlay', quad_vert, overlay_frag);
|
||||
type OverlayRenderable = ComputeRenderable<Values<typeof OverlaySchema>>
|
||||
|
||||
function getOverlayRenderable(ctx: WebGLContext, edgeTexture: Texture): OverlayRenderable {
|
||||
const width = edgeTexture.getWidth();
|
||||
const height = edgeTexture.getHeight();
|
||||
|
||||
const values: Values<typeof OverlaySchema> = {
|
||||
...QuadValues,
|
||||
tEdgeTexture: ValueCell.create(edgeTexture),
|
||||
uTexSizeInv: ValueCell.create(Vec2.create(1 / width, 1 / height)),
|
||||
uHighlightEdgeColor: ValueCell.create(Vec3()),
|
||||
uSelectEdgeColor: ValueCell.create(Vec3()),
|
||||
uGhostEdgeStrength: ValueCell.create(0),
|
||||
uInnerEdgeFactor: ValueCell.create(0),
|
||||
};
|
||||
|
||||
const schema = { ...OverlaySchema };
|
||||
const renderItem = createComputeRenderItem(ctx, 'triangles', OverlayShaderCode, schema, values);
|
||||
|
||||
return createComputeRenderable(renderItem, values);
|
||||
}
|
||||
@@ -22,9 +22,9 @@ import { Renderer } from '../../mol-gl/renderer';
|
||||
import { Scene } from '../../mol-gl/scene';
|
||||
import { Helper } from '../helper/helper';
|
||||
import { StereoCamera } from '../camera/stereo';
|
||||
|
||||
import { quad_vert } from '../../mol-gl/shader/quad.vert';
|
||||
import { compose_frag } from '../../mol-gl/shader/compose.frag';
|
||||
import { MarkingProps } from './marking';
|
||||
|
||||
const ComposeSchema = {
|
||||
...QuadSchema,
|
||||
@@ -55,7 +55,11 @@ export const MultiSampleParams = {
|
||||
};
|
||||
export type MultiSampleProps = PD.Values<typeof MultiSampleParams>
|
||||
|
||||
type Props = { multiSample: MultiSampleProps, postprocessing: PostprocessingProps }
|
||||
type Props = {
|
||||
multiSample: MultiSampleProps
|
||||
postprocessing: PostprocessingProps
|
||||
marking: MarkingProps
|
||||
}
|
||||
|
||||
export class MultiSamplePass {
|
||||
static isEnabled(props: MultiSampleProps) {
|
||||
@@ -119,7 +123,7 @@ export class MultiSamplePass {
|
||||
//
|
||||
// This manual approach to MSAA re-renders the scene once for
|
||||
// each sample with camera jitter and accumulates the results.
|
||||
const offsetList = JitterVectors[ Math.max(0, Math.min(props.multiSample.sampleLevel, 5)) ];
|
||||
const offsetList = JitterVectors[Math.max(0, Math.min(props.multiSample.sampleLevel, 5))];
|
||||
|
||||
const { x, y, width, height } = camera.viewport;
|
||||
const baseSampleWeight = 1.0 / offsetList.length;
|
||||
@@ -144,7 +148,7 @@ export class MultiSamplePass {
|
||||
ValueCell.update(compose.values.uWeight, sampleWeight);
|
||||
|
||||
// render scene
|
||||
drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing);
|
||||
drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing, props.marking);
|
||||
|
||||
// compose rendered scene with compose target
|
||||
composeTarget.bind();
|
||||
@@ -186,7 +190,7 @@ export class MultiSamplePass {
|
||||
//
|
||||
// This manual approach to MSAA re-renders the scene once for
|
||||
// each sample with camera jitter and accumulates the results.
|
||||
const offsetList = JitterVectors[ Math.max(0, Math.min(props.multiSample.sampleLevel, 5)) ];
|
||||
const offsetList = JitterVectors[Math.max(0, Math.min(props.multiSample.sampleLevel, 5))];
|
||||
|
||||
if (sampleIndex === -2 || sampleIndex >= offsetList.length) return -2;
|
||||
|
||||
@@ -194,7 +198,7 @@ export class MultiSamplePass {
|
||||
const sampleWeight = 1.0 / offsetList.length;
|
||||
|
||||
if (sampleIndex === -1) {
|
||||
drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing);
|
||||
drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing, props.marking);
|
||||
ValueCell.update(compose.values.uWeight, 1.0);
|
||||
ValueCell.update(compose.values.tColor, drawPass.getColorTarget(props.postprocessing).texture);
|
||||
compose.update();
|
||||
@@ -222,7 +226,7 @@ export class MultiSamplePass {
|
||||
camera.update();
|
||||
|
||||
// render scene
|
||||
drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing);
|
||||
drawPass.render(renderer, camera, scene, helper, false, transparentBackground, props.postprocessing, props.marking);
|
||||
|
||||
// compose rendered scene with compose target
|
||||
composeTarget.bind();
|
||||
@@ -240,7 +244,7 @@ export class MultiSamplePass {
|
||||
compose.render();
|
||||
|
||||
sampleIndex += 1;
|
||||
if (sampleIndex >= offsetList.length ) break;
|
||||
if (sampleIndex >= offsetList.length) break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,33 +278,33 @@ export class MultiSamplePass {
|
||||
|
||||
const JitterVectors = [
|
||||
[
|
||||
[ 0, 0 ]
|
||||
[0, 0]
|
||||
],
|
||||
[
|
||||
[ 4, 4 ], [ -4, -4 ]
|
||||
[4, 4], [-4, -4]
|
||||
],
|
||||
[
|
||||
[ -2, -6 ], [ 6, -2 ], [ -6, 2 ], [ 2, 6 ]
|
||||
[-2, -6], [6, -2], [-6, 2], [2, 6]
|
||||
],
|
||||
[
|
||||
[ 1, -3 ], [ -1, 3 ], [ 5, 1 ], [ -3, -5 ],
|
||||
[ -5, 5 ], [ -7, -1 ], [ 3, 7 ], [ 7, -7 ]
|
||||
[1, -3], [-1, 3], [5, 1], [-3, -5],
|
||||
[-5, 5], [-7, -1], [3, 7], [7, -7]
|
||||
],
|
||||
[
|
||||
[ 1, 1 ], [ -1, -3 ], [ -3, 2 ], [ 4, -1 ],
|
||||
[ -5, -2 ], [ 2, 5 ], [ 5, 3 ], [ 3, -5 ],
|
||||
[ -2, 6 ], [ 0, -7 ], [ -4, -6 ], [ -6, 4 ],
|
||||
[ -8, 0 ], [ 7, -4 ], [ 6, 7 ], [ -7, -8 ]
|
||||
[1, 1], [-1, -3], [-3, 2], [4, -1],
|
||||
[-5, -2], [2, 5], [5, 3], [3, -5],
|
||||
[-2, 6], [0, -7], [-4, -6], [-6, 4],
|
||||
[-8, 0], [7, -4], [6, 7], [-7, -8]
|
||||
],
|
||||
[
|
||||
[ -4, -7 ], [ -7, -5 ], [ -3, -5 ], [ -5, -4 ],
|
||||
[ -1, -4 ], [ -2, -2 ], [ -6, -1 ], [ -4, 0 ],
|
||||
[ -7, 1 ], [ -1, 2 ], [ -6, 3 ], [ -3, 3 ],
|
||||
[ -7, 6 ], [ -3, 6 ], [ -5, 7 ], [ -1, 7 ],
|
||||
[ 5, -7 ], [ 1, -6 ], [ 6, -5 ], [ 4, -4 ],
|
||||
[ 2, -3 ], [ 7, -2 ], [ 1, -1 ], [ 4, -1 ],
|
||||
[ 2, 1 ], [ 6, 2 ], [ 0, 4 ], [ 4, 4 ],
|
||||
[ 2, 5 ], [ 7, 5 ], [ 5, 6 ], [ 3, 7 ]
|
||||
[-4, -7], [-7, -5], [-3, -5], [-5, -4],
|
||||
[-1, -4], [-2, -2], [-6, -1], [-4, 0],
|
||||
[-7, 1], [-1, 2], [-6, 3], [-3, 3],
|
||||
[-7, 6], [-3, 6], [-5, 7], [-1, 7],
|
||||
[5, -7], [1, -6], [6, -5], [4, -4],
|
||||
[2, -3], [7, -2], [1, -1], [4, -1],
|
||||
[2, 1], [6, 2], [0, 4], [4, 4],
|
||||
[2, 5], [7, 5], [5, 6], [3, 7]
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@@ -154,10 +154,10 @@ function getSsaoBlurRenderable(ctx: WebGLContext, ssaoDepthTexture: Texture, dir
|
||||
}
|
||||
|
||||
function getBlurKernel(kernelSize: number): number[] {
|
||||
let sigma = kernelSize / 3.0;
|
||||
let halfKernelSize = Math.floor((kernelSize + 1) / 2);
|
||||
const sigma = kernelSize / 3.0;
|
||||
const halfKernelSize = Math.floor((kernelSize + 1) / 2);
|
||||
|
||||
let kernel = [];
|
||||
const kernel = [];
|
||||
for (let x = 0; x < halfKernelSize; x++) {
|
||||
kernel.push((1.0 / ((Math.sqrt(2 * Math.PI)) * sigma)) * Math.exp(-x * x / (2 * sigma * sigma)));
|
||||
}
|
||||
@@ -166,7 +166,7 @@ function getBlurKernel(kernelSize: number): number[] {
|
||||
}
|
||||
|
||||
function getSamples(vectorSamples: Vec3[], nSamples: number): number[] {
|
||||
let samples = [];
|
||||
const samples = [];
|
||||
for (let i = 0; i < nSamples; i++) {
|
||||
let scale = (i * i + 2.0 * i + 1) / (nSamples * nSamples);
|
||||
scale = 0.1 + scale * (1.0 - 0.1);
|
||||
@@ -241,7 +241,7 @@ function getPostprocessingRenderable(ctx: WebGLContext, colorTexture: Texture, d
|
||||
export const PostprocessingParams = {
|
||||
occlusion: PD.MappedStatic('on', {
|
||||
on: PD.Group({
|
||||
samples: PD.Numeric(32, {min: 1, max: 256, step: 1}),
|
||||
samples: PD.Numeric(32, { min: 1, max: 256, step: 1 }),
|
||||
radius: PD.Numeric(5, { min: 0, max: 10, step: 0.1 }, { description: 'Final radius is 2^x.' }),
|
||||
bias: PD.Numeric(0.8, { min: 0, max: 3, step: 0.1 }),
|
||||
blurKernelSize: PD.Numeric(15, { min: 1, max: 25, step: 2 }),
|
||||
@@ -314,7 +314,7 @@ export class PostprocessingPass {
|
||||
|
||||
this.randomHemisphereVector = [];
|
||||
for (let i = 0; i < 256; i++) {
|
||||
let v = Vec3();
|
||||
const v = Vec3();
|
||||
v[0] = Math.random() * 2.0 - 1.0;
|
||||
v[1] = Math.random() * 2.0 - 1.0;
|
||||
v[2] = Math.random();
|
||||
@@ -376,7 +376,7 @@ export class PostprocessingPass {
|
||||
const outlinesEnabled = props.outline.name === 'on';
|
||||
const occlusionEnabled = props.occlusion.name === 'on';
|
||||
|
||||
let invProjection = Mat4.identity();
|
||||
const invProjection = Mat4.identity();
|
||||
Mat4.invert(invProjection, camera.projection);
|
||||
|
||||
if (props.occlusion.name === 'on') {
|
||||
|
||||
@@ -25,8 +25,8 @@ import { Viewport } from '../camera/util';
|
||||
import { isDebugMode } from '../../mol-util/debug';
|
||||
|
||||
export const SmaaParams = {
|
||||
edgeThreshold:PD.Numeric(0.1, { min: 0.05, max: 0.15, step: 0.01 }),
|
||||
maxSearchSteps:PD.Numeric(16, { min: 0, max: 32, step: 1 }),
|
||||
edgeThreshold: PD.Numeric(0.1, { min: 0.05, max: 0.15, step: 0.01 }),
|
||||
maxSearchSteps: PD.Numeric(16, { min: 0, max: 32, step: 1 }),
|
||||
};
|
||||
export type SmaaProps = PD.Values<typeof SmaaParams>
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export function setCanvasSize(canvas: HTMLCanvasElement, width: number, height:
|
||||
}
|
||||
|
||||
/** Resize canvas to container element taking `devicePixelRatio` into account */
|
||||
export function resizeCanvas (canvas: HTMLCanvasElement, container: HTMLElement, scale = 1) {
|
||||
export function resizeCanvas(canvas: HTMLCanvasElement, container: HTMLElement, scale = 1) {
|
||||
let width = window.innerWidth;
|
||||
let height = window.innerHeight;
|
||||
if (container !== document.body) {
|
||||
|
||||
@@ -100,7 +100,7 @@ describe('table', () => {
|
||||
n: Column.ofArray({ array: ['row1', 'row2'], schema: Column.Schema.str }),
|
||||
});
|
||||
const s = { x: Column.Schema.int, y: Column.Schema.int };
|
||||
const picked = Table.pickColumns(s, t, { y: Column.ofArray({ array: [3, 4], schema: Column.Schema.int })});
|
||||
const picked = Table.pickColumns(s, t, { y: Column.ofArray({ array: [3, 4], schema: Column.Schema.int }) });
|
||||
expect(picked._columns).toEqual(['x', 'y']);
|
||||
expect(picked._rowCount).toEqual(2);
|
||||
expect(picked.x.toArray()).toEqual([10, -1]);
|
||||
|
||||
@@ -33,21 +33,21 @@ describe('linked list', () => {
|
||||
expect(list.count).toBe(5);
|
||||
});
|
||||
|
||||
it ('remove', () => {
|
||||
it('remove', () => {
|
||||
const list = create([1, 2, 3, 4]);
|
||||
let fst = list.removeFirst();
|
||||
const fst = list.removeFirst();
|
||||
expect(fst).toBe(1);
|
||||
expect(list.last!.value).toBe(4);
|
||||
expect(list.count).toBe(3);
|
||||
expect(toArray(list)).toEqual([2, 3, 4]);
|
||||
|
||||
let last = list.removeLast();
|
||||
const last = list.removeLast();
|
||||
expect(last).toBe(4);
|
||||
expect(list.last!.value).toBe(3);
|
||||
expect(list.count).toBe(2);
|
||||
expect(toArray(list)).toEqual([2, 3]);
|
||||
|
||||
let n3 = list.find(3)!;
|
||||
const n3 = list.find(3)!;
|
||||
list.remove(n3);
|
||||
expect(list.first!.value).toBe(2);
|
||||
expect(list.last!.value).toBe(2);
|
||||
|
||||
@@ -19,7 +19,7 @@ export const ofBounds = I.ofBounds;
|
||||
export function ofSortedArray(xs: Nums): OrderedSetImpl {
|
||||
if (!xs.length) return Empty;
|
||||
// check if the array is just a range
|
||||
if (xs[xs.length - 1] - xs[0] + 1 === xs.length) return I.ofRange(xs[0], xs[xs.length - 1]);
|
||||
if (S.isRange(xs)) return I.ofRange(xs[0], xs[xs.length - 1]);
|
||||
return xs as any;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,9 +22,10 @@ export function ofRange(min: number, max: number) {
|
||||
return ret;
|
||||
}
|
||||
export function is(xs: any): xs is Nums { return xs && (Array.isArray(xs) || !!xs.buffer); }
|
||||
export function isRange(xs: Nums) { return xs[xs.length - 1] - xs[0] + 1 === xs.length; }
|
||||
|
||||
export function start(xs: Nums) { return xs[0]; }
|
||||
export function end(xs: Nums) { return xs[xs.length - 1] + 1; }
|
||||
export function end(xs: Nums) { return xs[xs.length - 1] + 1; }
|
||||
export function min(xs: Nums) { return xs[0]; }
|
||||
export function max(xs: Nums) { return xs[xs.length - 1]; }
|
||||
export function size(xs: Nums) { return xs.length; }
|
||||
@@ -59,9 +60,11 @@ export function getAt(xs: Nums, i: number) { return xs[i]; }
|
||||
|
||||
export function areEqual(a: Nums, b: Nums) {
|
||||
if (a === b) return true;
|
||||
const aSize = a.length;
|
||||
let aSize = a.length;
|
||||
if (aSize !== b.length || a[0] !== b[0] || a[aSize - 1] !== b[aSize - 1]) return false;
|
||||
for (let i = 0; i < aSize; i++) {
|
||||
if (isRange(a)) return true;
|
||||
aSize--;
|
||||
for (let i = 1; i < aSize; i++) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -340,7 +343,7 @@ export function deduplicate(xs: Nums) {
|
||||
}
|
||||
|
||||
export function indicesOf(a: Nums, b: Nums): Nums {
|
||||
if (a === b) return ofSortedArray(createRangeArray(0, a.length - 1));
|
||||
if (areEqual(a, b)) return ofSortedArray(createRangeArray(0, a.length - 1));
|
||||
|
||||
const { startI: sI, startJ: sJ, endI, endJ } = getSuitableIntersectionRange(a, b);
|
||||
let i = sI, j = sJ;
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace SortedArray {
|
||||
/** create sorted array [min, max) (it does NOT contain the max value) */
|
||||
export const ofBounds: <T extends number = number>(min: T, max: T) => SortedArray<T> = (min, max) => Impl.ofRange(min, max - 1) as any;
|
||||
export const is: <T extends number = number>(v: any) => v is SortedArray<T> = Impl.is as any;
|
||||
export const isRange: <T extends number = number>(array: ArrayLike<number>) => boolean = Impl.isRange as any;
|
||||
|
||||
export const has: <T extends number = number>(array: SortedArray<T>, x: T) => boolean = Impl.has as any;
|
||||
/** Returns the index of `x` in `set` or -1 if not found. */
|
||||
|
||||
@@ -15,7 +15,7 @@ interface IntTuple { '@type': 'int-tuple' }
|
||||
namespace IntTuple {
|
||||
export const Zero: IntTuple = 0 as any;
|
||||
|
||||
const { _int32, _float64, _int32_1, _float64_1 } = (function() {
|
||||
const { _int32, _float64, _int32_1, _float64_1 } = (function () {
|
||||
const data = new ArrayBuffer(8);
|
||||
const data_1 = new ArrayBuffer(8);
|
||||
return {
|
||||
|
||||
@@ -8,14 +8,14 @@ import { ChunkedArray } from '../chunked-array';
|
||||
|
||||
describe('Chunked Array', () => {
|
||||
it('creation', () => {
|
||||
const arr = ChunkedArray.create<number, 2>(Array, 2, 2);
|
||||
const arr = ChunkedArray.create<number, 2>(Array, 2, 2);
|
||||
ChunkedArray.add2(arr, 1, 2);
|
||||
ChunkedArray.add2(arr, 3, 4);
|
||||
expect(ChunkedArray.compact(arr)).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
it('initial', () => {
|
||||
const arr = ChunkedArray.create(Int32Array, 2, 6, new Int32Array([1, 2, 3, 4]));
|
||||
const arr = ChunkedArray.create(Int32Array, 2, 6, new Int32Array([1, 2, 3, 4]));
|
||||
ChunkedArray.add2(arr, 4, 3);
|
||||
ChunkedArray.add2(arr, 2, 1);
|
||||
ChunkedArray.add2(arr, 5, 6);
|
||||
@@ -23,13 +23,13 @@ describe('Chunked Array', () => {
|
||||
});
|
||||
|
||||
it('add many', () => {
|
||||
const arr = ChunkedArray.create<number, 2>(Array, 2, 2);
|
||||
const arr = ChunkedArray.create<number, 2>(Array, 2, 2);
|
||||
ChunkedArray.addMany(arr, [1, 2, 3, 4]);
|
||||
expect(ChunkedArray.compact(arr)).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
it('resize', () => {
|
||||
const arr = ChunkedArray.create<number, 2>(Int32Array, 2, 2);
|
||||
const arr = ChunkedArray.create<number, 2>(Int32Array, 2, 2);
|
||||
ChunkedArray.add2(arr, 1, 2);
|
||||
ChunkedArray.add2(arr, 3, 4);
|
||||
ChunkedArray.add2(arr, 5, 6);
|
||||
@@ -39,7 +39,7 @@ describe('Chunked Array', () => {
|
||||
});
|
||||
|
||||
it('resize-fraction', () => {
|
||||
const arr = ChunkedArray.create<number, 2>(Int32Array, 2, 2.5);
|
||||
const arr = ChunkedArray.create<number, 2>(Int32Array, 2, 2.5);
|
||||
ChunkedArray.add2(arr, 1, 2);
|
||||
ChunkedArray.add2(arr, 3, 4);
|
||||
ChunkedArray.add2(arr, 5, 6);
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace ChunkedArray {
|
||||
}
|
||||
|
||||
function allocateNext(array: ChunkedArray<any, any>) {
|
||||
let nextSize = array.growBy * array.elementSize;
|
||||
const nextSize = array.growBy * array.elementSize;
|
||||
array.currentSize = nextSize;
|
||||
array.currentIndex = 0;
|
||||
array.currentChunk = new array.ctor(nextSize);
|
||||
|
||||
@@ -52,8 +52,8 @@ export namespace BaseGeometry {
|
||||
if (!transform) transform = createIdentityTransform();
|
||||
const locationIterator = LocationIterator(1, transform.instanceCount.ref.value, 1, () => NullLocation, false, () => false);
|
||||
const theme: Theme = {
|
||||
color: UniformColorTheme({}, { value: colorValue}),
|
||||
size: UniformSizeTheme({}, { value: sizeValue})
|
||||
color: UniformColorTheme({}, { value: colorValue }),
|
||||
size: UniformSizeTheme({}, { value: sizeValue })
|
||||
};
|
||||
return { transform, locationIterator, theme };
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { Mat4, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { transformPositionArray, GroupMapping, createGroupMapping} from '../../util';
|
||||
import { transformPositionArray, GroupMapping, createGroupMapping } from '../../util';
|
||||
import { GeometryUtils } from '../geometry';
|
||||
import { createColors } from '../color-data';
|
||||
import { createMarkers } from '../marker-data';
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { Mat4, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { transformPositionArray, GroupMapping, createGroupMapping} from '../../util';
|
||||
import { transformPositionArray, GroupMapping, createGroupMapping } from '../../util';
|
||||
import { GeometryUtils } from '../geometry';
|
||||
import { createColors } from '../color-data';
|
||||
import { createMarkers } from '../marker-data';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -9,20 +9,75 @@ import { Vec2 } from '../../mol-math/linear-algebra';
|
||||
import { TextureImage, createTextureImage } from '../../mol-gl/renderable/util';
|
||||
|
||||
export type MarkerData = {
|
||||
uMarker: ValueCell<number>,
|
||||
tMarker: ValueCell<TextureImage<Uint8Array>>
|
||||
uMarkerTexDim: ValueCell<Vec2>
|
||||
dMarkerType: ValueCell<string>,
|
||||
markerAverage: ValueCell<number>
|
||||
markerStatus: ValueCell<number>
|
||||
}
|
||||
|
||||
const MarkerCountLut = new Uint8Array(0x0303 + 1);
|
||||
MarkerCountLut[0x0001] = 1;
|
||||
MarkerCountLut[0x0002] = 1;
|
||||
MarkerCountLut[0x0003] = 1;
|
||||
MarkerCountLut[0x0100] = 1;
|
||||
MarkerCountLut[0x0200] = 1;
|
||||
MarkerCountLut[0x0300] = 1;
|
||||
MarkerCountLut[0x0101] = 2;
|
||||
MarkerCountLut[0x0201] = 2;
|
||||
MarkerCountLut[0x0301] = 2;
|
||||
MarkerCountLut[0x0102] = 2;
|
||||
MarkerCountLut[0x0202] = 2;
|
||||
MarkerCountLut[0x0302] = 2;
|
||||
MarkerCountLut[0x0103] = 2;
|
||||
MarkerCountLut[0x0203] = 2;
|
||||
MarkerCountLut[0x0303] = 2;
|
||||
|
||||
/**
|
||||
* Calculates the average number of entries that have any marker flag set.
|
||||
*
|
||||
* For alternative implementations and performance tests see
|
||||
* `src\perf-tests\markers-average.ts`.
|
||||
*/
|
||||
export function getMarkersAverage(array: Uint8Array, count: number): number {
|
||||
if (count === 0) return 0;
|
||||
|
||||
const view = new Uint32Array(array.buffer, 0, array.buffer.byteLength >> 2);
|
||||
const viewEnd = (count - 4) >> 2;
|
||||
const backStart = 4 * viewEnd;
|
||||
|
||||
let sum = 0;
|
||||
for (let i = 0; i < viewEnd; ++i) {
|
||||
const v = view[i];
|
||||
sum += MarkerCountLut[v & 0xFFFF] + MarkerCountLut[v >> 16];
|
||||
}
|
||||
for (let i = backStart; i < count; ++i) {
|
||||
sum += array[i] && 1;
|
||||
}
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
export function createMarkers(count: number, markerData?: MarkerData): MarkerData {
|
||||
const markers = createTextureImage(Math.max(1, count), 1, Uint8Array, markerData && markerData.tMarker.ref.value.array);
|
||||
const average = getMarkersAverage(markers.array, count);
|
||||
const status = average === 0 ? 0 : -1;
|
||||
if (markerData) {
|
||||
ValueCell.updateIfChanged(markerData.uMarker, 0);
|
||||
ValueCell.update(markerData.tMarker, markers);
|
||||
ValueCell.update(markerData.uMarkerTexDim, Vec2.create(markers.width, markers.height));
|
||||
ValueCell.updateIfChanged(markerData.dMarkerType, status === -1 ? 'groupInstance' : 'uniform');
|
||||
ValueCell.updateIfChanged(markerData.markerAverage, average);
|
||||
ValueCell.updateIfChanged(markerData.markerStatus, status);
|
||||
return markerData;
|
||||
} else {
|
||||
return {
|
||||
uMarker: ValueCell.create(0),
|
||||
tMarker: ValueCell.create(markers),
|
||||
uMarkerTexDim: ValueCell.create(Vec2.create(markers.width, markers.height)),
|
||||
markerAverage: ValueCell.create(average),
|
||||
markerStatus: ValueCell.create(status),
|
||||
dMarkerType: ValueCell.create('uniform'),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -30,13 +85,21 @@ export function createMarkers(count: number, markerData?: MarkerData): MarkerDat
|
||||
const emptyMarkerTexture = { array: new Uint8Array(1), width: 1, height: 1 };
|
||||
export function createEmptyMarkers(markerData?: MarkerData): MarkerData {
|
||||
if (markerData) {
|
||||
ValueCell.updateIfChanged(markerData.uMarker, 0);
|
||||
ValueCell.update(markerData.tMarker, emptyMarkerTexture);
|
||||
ValueCell.update(markerData.uMarkerTexDim, Vec2.create(1, 1));
|
||||
ValueCell.updateIfChanged(markerData.dMarkerType, 'uniform');
|
||||
ValueCell.updateIfChanged(markerData.markerAverage, 0);
|
||||
ValueCell.updateIfChanged(markerData.markerStatus, 0);
|
||||
return markerData;
|
||||
} else {
|
||||
return {
|
||||
uMarker: ValueCell.create(0),
|
||||
tMarker: ValueCell.create(emptyMarkerTexture),
|
||||
uMarkerTexDim: ValueCell.create(Vec2.create(1, 1)),
|
||||
markerAverage: ValueCell.create(0),
|
||||
markerStatus: ValueCell.create(0),
|
||||
dMarkerType: ValueCell.create('uniform'),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@ const torsionVector = Vec3();
|
||||
export function addRibbon(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, widthValues: ArrayLike<number>, heightValues: ArrayLike<number>, arrowHeight: number) {
|
||||
const { currentGroup, vertices, normals, indices, groups } = state;
|
||||
|
||||
let vertexCount = vertices.elementCount;
|
||||
const vertexCount = vertices.elementCount;
|
||||
let offsetLength = 0;
|
||||
|
||||
if (arrowHeight > 0) {
|
||||
|
||||
@@ -85,7 +85,7 @@ function addCap(offset: number, state: MeshBuilder.State, controlPoints: ArrayLi
|
||||
export function addSheet(state: MeshBuilder.State, controlPoints: ArrayLike<number>, normalVectors: ArrayLike<number>, binormalVectors: ArrayLike<number>, linearSegments: number, widthValues: ArrayLike<number>, heightValues: ArrayLike<number>, arrowHeight: number, startCap: boolean, endCap: boolean) {
|
||||
const { currentGroup, vertices, normals, indices, groups } = state;
|
||||
|
||||
let vertexCount = vertices.elementCount;
|
||||
const vertexCount = vertices.elementCount;
|
||||
let offsetLength = 0;
|
||||
|
||||
if (arrowHeight > 0) {
|
||||
|
||||
@@ -39,7 +39,7 @@ export function calcMeshColorSmoothing(input: ColorSmoothingInput, resolution: n
|
||||
Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2));
|
||||
const { min } = box;
|
||||
|
||||
const [ xn, yn ] = gridDim;
|
||||
const [xn, yn] = gridDim;
|
||||
const { width, height } = getVolumeTexture2dLayout(gridDim);
|
||||
// console.log({ width, height, dim });
|
||||
|
||||
@@ -104,7 +104,7 @@ export function calcMeshColorSmoothing(input: ColorSmoothingInput, resolution: n
|
||||
const d = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
if (d > p) continue;
|
||||
|
||||
let s = p - d;
|
||||
const s = p - d;
|
||||
const index = getIndex(xi, yi, zi);
|
||||
data[index] += r * s;
|
||||
data[index + 1] += g * s;
|
||||
|
||||
@@ -61,8 +61,8 @@ export namespace MeshBuilder {
|
||||
|
||||
v3triangleNormal(tmpV, a, b, c);
|
||||
for (let i = 0; i < 3; ++i) {
|
||||
caAdd3(normals, tmpV[0], tmpV[1], tmpV[2]); // normal
|
||||
caAdd(groups, currentGroup); // group
|
||||
caAdd3(normals, tmpV[0], tmpV[1], tmpV[2]); // normal
|
||||
caAdd(groups, currentGroup); // group
|
||||
}
|
||||
caAdd3(indices, offset, offset + 1, offset + 2);
|
||||
}
|
||||
@@ -152,7 +152,7 @@ export namespace MeshBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
export function getMesh (state: State): Mesh {
|
||||
export function getMesh(state: State): Mesh {
|
||||
const { vertices, normals, indices, groups, mesh } = state;
|
||||
const vb = ChunkedArray.compact(vertices, true) as Float32Array;
|
||||
const ib = ChunkedArray.compact(indices, true) as Uint32Array;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
|
||||
import { ValueCell } from '../../../mol-util';
|
||||
import { Mat4, Vec3, Vec4 } from '../../../mol-math/linear-algebra';
|
||||
import { transformPositionArray, GroupMapping, createGroupMapping} from '../../util';
|
||||
import { transformPositionArray, GroupMapping, createGroupMapping } from '../../util';
|
||||
import { GeometryUtils } from '../geometry';
|
||||
import { createColors } from '../color-data';
|
||||
import { createMarkers } from '../marker-data';
|
||||
@@ -117,12 +117,19 @@ export namespace Points {
|
||||
|
||||
//
|
||||
|
||||
export const StyleTypes = {
|
||||
'square': 'Square',
|
||||
'circle': 'Circle',
|
||||
'fuzzy': 'Fuzzy',
|
||||
};
|
||||
export type StyleTypes = keyof typeof StyleTypes;
|
||||
export const StyleTypeNames = Object.keys(StyleTypes) as StyleTypes[];
|
||||
|
||||
export const Params = {
|
||||
...BaseGeometry.Params,
|
||||
sizeFactor: PD.Numeric(1.5, { min: 0, max: 10, step: 0.1 }),
|
||||
pointSizeAttenuation: PD.Boolean(false),
|
||||
pointFilledCircle: PD.Boolean(false),
|
||||
pointEdgeBleach: PD.Numeric(0.2, { min: 0, max: 1, step: 0.05 }),
|
||||
pointStyle: PD.Select('square', PD.objectToOptions(StyleTypes)),
|
||||
};
|
||||
export type Params = typeof Params
|
||||
|
||||
@@ -189,8 +196,7 @@ export namespace Points {
|
||||
...BaseGeometry.createValues(props, counts),
|
||||
uSizeFactor: ValueCell.create(props.sizeFactor),
|
||||
dPointSizeAttenuation: ValueCell.create(props.pointSizeAttenuation),
|
||||
dPointFilledCircle: ValueCell.create(props.pointFilledCircle),
|
||||
uPointEdgeBleach: ValueCell.create(props.pointEdgeBleach),
|
||||
dPointStyle: ValueCell.create(props.pointStyle),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -204,8 +210,7 @@ export namespace Points {
|
||||
BaseGeometry.updateValues(values, props);
|
||||
ValueCell.updateIfChanged(values.uSizeFactor, props.sizeFactor);
|
||||
ValueCell.updateIfChanged(values.dPointSizeAttenuation, props.pointSizeAttenuation);
|
||||
ValueCell.updateIfChanged(values.dPointFilledCircle, props.pointFilledCircle);
|
||||
ValueCell.updateIfChanged(values.uPointEdgeBleach, props.pointEdgeBleach);
|
||||
ValueCell.updateIfChanged(values.dPointStyle, props.pointStyle);
|
||||
}
|
||||
|
||||
function updateBoundingSphere(values: PointsValues, points: Points) {
|
||||
@@ -229,10 +234,7 @@ export namespace Points {
|
||||
|
||||
function updateRenderableState(state: RenderableState, props: PD.Values<Params>) {
|
||||
BaseGeometry.updateRenderableState(state, props);
|
||||
state.opaque = state.opaque && (
|
||||
!props.pointFilledCircle ||
|
||||
(props.pointFilledCircle && props.pointEdgeBleach === 0)
|
||||
);
|
||||
state.opaque = state.opaque && props.pointStyle !== 'fuzzy';
|
||||
state.writeDepth = state.opaque;
|
||||
}
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export function createTextureSize(sizes: TextureImage<Uint8Array>, type: SizeTyp
|
||||
|
||||
/** Creates size texture with size for each instance/unit */
|
||||
export function createInstanceSize(locationIt: LocationIterator, sizeFn: LocationSize, sizeData?: SizeData): SizeData {
|
||||
const { instanceCount} = locationIt;
|
||||
const { instanceCount } = locationIt;
|
||||
const sizes = createTextureImage(Math.max(1, instanceCount), 3, Uint8Array, sizeData && sizeData.tSize.ref.value.array);
|
||||
locationIt.reset();
|
||||
while (locationIt.hasNext && !locationIt.isNextNewInstance) {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { createTextureImage, TextureImage } from '../../../mol-gl/renderable/uti
|
||||
|
||||
const TextAtlasCache: { [k: string]: FontAtlas } = {};
|
||||
|
||||
export function getFontAtlas (props: Partial<FontAtlasProps>) {
|
||||
export function getFontAtlas(props: Partial<FontAtlasProps>) {
|
||||
const hash = JSON.stringify(props);
|
||||
if (TextAtlasCache[hash] === undefined) {
|
||||
TextAtlasCache[hash] = new FontAtlas(props);
|
||||
@@ -69,7 +69,7 @@ export class FontAtlas {
|
||||
private readonly maxWidth: number
|
||||
private readonly middle: number
|
||||
|
||||
constructor (props: Partial<FontAtlasProps> = {}) {
|
||||
constructor(props: Partial<FontAtlasProps> = {}) {
|
||||
const p = { ...PD.getDefaultValues(FontAtlasParams), ...props };
|
||||
this.props = p;
|
||||
|
||||
@@ -110,7 +110,7 @@ export class FontAtlas {
|
||||
this.placeholder = this.get(String.fromCharCode(0xFFFD));
|
||||
}
|
||||
|
||||
get (char: string) {
|
||||
get(char: string) {
|
||||
if (this.mapped[char] === undefined) {
|
||||
this.draw(char);
|
||||
|
||||
@@ -144,7 +144,7 @@ export class FontAtlas {
|
||||
return this.mapped[char];
|
||||
}
|
||||
|
||||
draw (char: string) {
|
||||
draw(char: string) {
|
||||
const h = this.lineHeight;
|
||||
const ctx = this.scratchContext;
|
||||
const data = this.scratchData;
|
||||
|
||||
@@ -69,7 +69,7 @@ export namespace TextBuilder {
|
||||
} else if (attachment.startsWith('middle')) {
|
||||
yShift = bHeight / 2;
|
||||
} else {
|
||||
yShift = 0; // "bottom"
|
||||
yShift = 0; // "bottom"
|
||||
}
|
||||
// horizontal
|
||||
if (attachment.endsWith('right')) {
|
||||
@@ -77,7 +77,7 @@ export namespace TextBuilder {
|
||||
} else if (attachment.endsWith('center')) {
|
||||
xShift = bWidth / 2;
|
||||
} else {
|
||||
xShift = 0; // "left"
|
||||
xShift = 0; // "left"
|
||||
}
|
||||
|
||||
if (tether) {
|
||||
|
||||
@@ -259,7 +259,7 @@ export function calcTextureMeshColorSmoothing(input: ColorSmoothingInput, resolu
|
||||
Vec3.add(gridDim, gridDim, Vec3.create(2, 2, 2));
|
||||
const { min } = box;
|
||||
|
||||
const [ dx, dy, dz ] = gridDim;
|
||||
const [dx, dy, dz] = gridDim;
|
||||
const { texDimX: width, texDimY: height, texCols } = getTexture2dSize(gridDim);
|
||||
// console.log({ width, height, texCols, dim, resolution });
|
||||
|
||||
|
||||
@@ -73,18 +73,18 @@ let boxCage: Cage;
|
||||
export function BoxCage() {
|
||||
if (!boxCage) {
|
||||
boxCage = createCage([
|
||||
0.5, 0.5, -0.5, // bottom
|
||||
-0.5, 0.5, -0.5,
|
||||
0.5, 0.5, -0.5, // bottom
|
||||
-0.5, 0.5, -0.5,
|
||||
-0.5, -0.5, -0.5,
|
||||
0.5, -0.5, -0.5,
|
||||
0.5, 0.5, 0.5, // top
|
||||
-0.5, 0.5, 0.5,
|
||||
0.5, 0.5, 0.5, // top
|
||||
-0.5, 0.5, 0.5,
|
||||
-0.5, -0.5, 0.5,
|
||||
0.5, -0.5, 0.5
|
||||
], [
|
||||
0, 4, 1, 5, 2, 6, 3, 7, // sides
|
||||
0, 1, 1, 2, 2, 3, 3, 0, // bottom base
|
||||
4, 5, 5, 6, 6, 7, 7, 4 // top base
|
||||
0, 4, 1, 5, 2, 6, 3, 7, // sides
|
||||
0, 1, 1, 2, 2, 3, 3, 0, // bottom base
|
||||
4, 5, 5, 6, 6, 7, 7, 4 // top base
|
||||
]);
|
||||
}
|
||||
return boxCage;
|
||||
|
||||
@@ -89,10 +89,10 @@ export function Cylinder(props?: CylinderProps): Primitive {
|
||||
|
||||
for (let y = 0; y < heightSegments; ++y) {
|
||||
// we use the index array to access the correct indices
|
||||
const a = indexArray[ y ][ x ];
|
||||
const b = indexArray[ y + 1 ][ x ];
|
||||
const c = indexArray[ y + 1 ][ x + 1 ];
|
||||
const d = indexArray[ y ][ x + 1 ];
|
||||
const a = indexArray[y][x];
|
||||
const b = indexArray[y + 1][x];
|
||||
const c = indexArray[y + 1][x + 1];
|
||||
const d = indexArray[y][x + 1];
|
||||
|
||||
// faces
|
||||
indices.push(a, b, d);
|
||||
@@ -107,7 +107,7 @@ export function Cylinder(props?: CylinderProps): Primitive {
|
||||
const sign = (top === true) ? 1 : - 1;
|
||||
|
||||
// save the index of the first center vertex
|
||||
let centerIndexStart = index;
|
||||
const centerIndexStart = index;
|
||||
|
||||
// first we generate the center vertex data of the cap.
|
||||
// because the geometry needs one set of uvs per face,
|
||||
@@ -125,7 +125,7 @@ export function Cylinder(props?: CylinderProps): Primitive {
|
||||
}
|
||||
|
||||
// save the index of the last center vertex
|
||||
let centerIndexEnd = index;
|
||||
const centerIndexEnd = index;
|
||||
|
||||
// now we generate the surrounding vertices, normals and uvs
|
||||
for (let x = 0; x <= radialSegments; ++x) {
|
||||
|
||||
@@ -14,10 +14,10 @@ const b = 1 / t;
|
||||
const c = 2 - t;
|
||||
|
||||
export const dodecahedronVertices: ReadonlyArray<number> = [
|
||||
c, 0, a, -c, 0, a, -b, b, b, 0, a, c, b, b, b,
|
||||
b, -b, b, 0, -a, c, -b, -b, b, c, 0, -a, -c, 0, -a,
|
||||
-b, -b, -b, 0, -a, -c, b, -b, -b, b, b, -b, 0, a, -c,
|
||||
-b, b, -b, a, c, 0, -a, c, 0, -a, -c, 0, a, -c, 0
|
||||
c, 0, a, -c, 0, a, -b, b, b, 0, a, c, b, b, b,
|
||||
b, -b, b, 0, -a, c, -b, -b, b, c, 0, -a, -c, 0, -a,
|
||||
-b, -b, -b, 0, -a, -c, b, -b, -b, b, b, -b, 0, a, -c,
|
||||
-b, b, -b, a, c, 0, -a, c, 0, -a, -c, 0, a, -c, 0
|
||||
];
|
||||
|
||||
/** indices of pentagonal faces, groups of five */
|
||||
@@ -36,25 +36,25 @@ export const dodecahedronFaces: ReadonlyArray<number> = [
|
||||
7, 1, 2, 17, 18
|
||||
];
|
||||
|
||||
const dodecahedronIndices: ReadonlyArray<number> = [ // pentagonal faces
|
||||
4, 3, 2, 2, 1, 0, 4, 2, 0, // 4, 3, 2, 1, 0
|
||||
7, 6, 5, 5, 0, 1, 7, 5, 1, // 7, 6, 5, 0, 1
|
||||
12, 11, 10, 10, 9, 8, 12, 10, 8, // 12, 11, 10, 9, 8
|
||||
15, 14, 13, 13, 8, 9, 15, 13, 9, // 15, 14, 13, 8, 9
|
||||
14, 3, 4, 4, 16, 13, 14, 4, 13, // 14, 3, 4, 16, 13
|
||||
3, 14, 15, 15, 17, 2, 3, 15, 2, // 3, 14, 15, 17, 2
|
||||
11, 6, 7, 7, 18, 10, 11, 7, 10, // 11, 6, 7, 18, 10
|
||||
6, 11, 12, 12, 19, 5, 6, 12, 5, // 6, 11, 12, 19, 5
|
||||
4, 0, 5, 5, 19, 16, 4, 5, 16, // 4, 0, 5, 19, 16
|
||||
12, 8, 13, 13, 16, 19, 12, 13, 19, // 12, 8, 13, 16, 19
|
||||
15, 9, 10, 10, 18, 17, 15, 10, 17, // 15, 9, 10, 18, 17
|
||||
7, 1, 2, 2, 17, 18, 7, 2, 18, // 7, 1, 2, 17, 18
|
||||
const dodecahedronIndices: ReadonlyArray<number> = [ // pentagonal faces
|
||||
4, 3, 2, 2, 1, 0, 4, 2, 0, // 4, 3, 2, 1, 0
|
||||
7, 6, 5, 5, 0, 1, 7, 5, 1, // 7, 6, 5, 0, 1
|
||||
12, 11, 10, 10, 9, 8, 12, 10, 8, // 12, 11, 10, 9, 8
|
||||
15, 14, 13, 13, 8, 9, 15, 13, 9, // 15, 14, 13, 8, 9
|
||||
14, 3, 4, 4, 16, 13, 14, 4, 13, // 14, 3, 4, 16, 13
|
||||
3, 14, 15, 15, 17, 2, 3, 15, 2, // 3, 14, 15, 17, 2
|
||||
11, 6, 7, 7, 18, 10, 11, 7, 10, // 11, 6, 7, 18, 10
|
||||
6, 11, 12, 12, 19, 5, 6, 12, 5, // 6, 11, 12, 19, 5
|
||||
4, 0, 5, 5, 19, 16, 4, 5, 16, // 4, 0, 5, 19, 16
|
||||
12, 8, 13, 13, 16, 19, 12, 13, 19, // 12, 8, 13, 16, 19
|
||||
15, 9, 10, 10, 18, 17, 15, 10, 17, // 15, 9, 10, 18, 17
|
||||
7, 1, 2, 2, 17, 18, 7, 2, 18, // 7, 1, 2, 17, 18
|
||||
];
|
||||
|
||||
const dodecahedronEdges: ReadonlyArray<number> = [
|
||||
0, 1, 0, 4, 0, 5, 1, 2, 1, 7, 2, 3, 2, 17, 3, 4, 3, 14, 4, 16,
|
||||
5, 6, 5, 19, 6, 7, 6, 11, 7, 18, 8, 9, 8, 12, 8, 13, 9, 10, 9, 15,
|
||||
10, 11, 10, 18, 11, 12, 12, 19, 13, 14, 13, 16, 14, 15, 15, 17, 16, 19, 17, 18,
|
||||
0, 1, 0, 4, 0, 5, 1, 2, 1, 7, 2, 3, 2, 17, 3, 4, 3, 14, 4, 16,
|
||||
5, 6, 5, 19, 6, 7, 6, 11, 7, 18, 8, 9, 8, 12, 8, 13, 9, 10, 9, 15,
|
||||
10, 11, 10, 18, 11, 12, 12, 19, 13, 14, 13, 16, 14, 15, 15, 17, 16, 19, 17, 18,
|
||||
];
|
||||
|
||||
let dodecahedron: Primitive;
|
||||
|
||||
@@ -10,22 +10,22 @@ import { Cage, createCage } from './cage';
|
||||
const t = (1 + Math.sqrt(5)) / 2;
|
||||
|
||||
const icosahedronVertices: ReadonlyArray<number> = [
|
||||
-1, t, 0, 1, t, 0, -1, -t, 0, 1, -t, 0,
|
||||
0, -1, t, 0, 1, t, 0, -1, -t, 0, 1, -t,
|
||||
t, 0, -1, t, 0, 1, -t, 0, -1, -t, 0, 1
|
||||
-1, t, 0, 1, t, 0, -1, -t, 0, 1, -t, 0,
|
||||
0, -1, t, 0, 1, t, 0, -1, -t, 0, 1, -t,
|
||||
t, 0, -1, t, 0, 1, -t, 0, -1, -t, 0, 1
|
||||
];
|
||||
|
||||
const icosahedronIndices: ReadonlyArray<number> = [
|
||||
0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
|
||||
1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
|
||||
3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
|
||||
4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
|
||||
0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
|
||||
1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
|
||||
3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
|
||||
4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
|
||||
];
|
||||
|
||||
const icosahedronEdges: ReadonlyArray<number> = [
|
||||
0, 11, 5, 11, 0, 5, 1, 5, 0, 1, 1, 7, 0, 7, 7, 10, 0, 10, 10, 11,
|
||||
5, 9, 4, 11, 2, 10, 6, 7, 1, 8, 3, 9, 4, 9, 3, 4, 2, 4, 2, 3,
|
||||
2, 6, 3, 6, 6, 8, 3, 8, 8, 9, 4, 5, 2, 11, 6, 10, 7, 8, 1, 9
|
||||
0, 11, 5, 11, 0, 5, 1, 5, 0, 1, 1, 7, 0, 7, 7, 10, 0, 10, 10, 11,
|
||||
5, 9, 4, 11, 2, 10, 6, 7, 1, 8, 3, 9, 4, 9, 3, 4, 2, 4, 2, 3,
|
||||
2, 6, 3, 6, 6, 8, 3, 8, 8, 9, 4, 5, 2, 11, 6, 10, 7, 8, 1, 9
|
||||
];
|
||||
|
||||
let icosahedron: Primitive;
|
||||
|
||||
@@ -8,27 +8,27 @@ import { createPrimitive, Primitive } from './primitive';
|
||||
import { createCage, Cage } from './cage';
|
||||
|
||||
export const octahedronVertices: ReadonlyArray<number> = [
|
||||
0.5, 0, 0, -0.5, 0, 0, 0, 0.5, 0,
|
||||
0, -0.5, 0, 0, 0, 0.5, 0, 0, -0.5
|
||||
0.5, 0, 0, -0.5, 0, 0, 0, 0.5, 0,
|
||||
0, -0.5, 0, 0, 0, 0.5, 0, 0, -0.5
|
||||
];
|
||||
|
||||
export const octahedronIndices: ReadonlyArray<number> = [
|
||||
0, 2, 4, 0, 4, 3, 0, 3, 5,
|
||||
0, 5, 2, 1, 2, 5, 1, 5, 3,
|
||||
1, 3, 4, 1, 4, 2
|
||||
0, 2, 4, 0, 4, 3, 0, 3, 5,
|
||||
0, 5, 2, 1, 2, 5, 1, 5, 3,
|
||||
1, 3, 4, 1, 4, 2
|
||||
];
|
||||
|
||||
export const perforatedOctahedronIndices: ReadonlyArray<number> = [
|
||||
0, 2, 4, 0, 4, 3,
|
||||
0, 2, 4, 0, 4, 3,
|
||||
// 0, 3, 5, 0, 5, 2,
|
||||
1, 2, 5, 1, 5, 3,
|
||||
1, 2, 5, 1, 5, 3,
|
||||
// 1, 3, 4, 1, 4, 2
|
||||
];
|
||||
|
||||
const octahedronEdges: ReadonlyArray<number> = [
|
||||
0, 2, 1, 3, 2, 1, 3, 0,
|
||||
0, 4, 1, 4, 2, 4, 3, 4,
|
||||
0, 5, 1, 5, 2, 5, 3, 5,
|
||||
0, 2, 1, 3, 2, 1, 3, 0,
|
||||
0, 4, 1, 4, 2, 4, 3, 4,
|
||||
0, 5, 1, 5, 2, 5, 3, 5,
|
||||
];
|
||||
|
||||
let octahedron: Primitive;
|
||||
|
||||
@@ -28,7 +28,7 @@ const plane: Primitive = {
|
||||
|
||||
const planeCage: Cage = {
|
||||
vertices: plane.vertices,
|
||||
edges: new Uint32Array([ 0, 1, 2, 3, 3, 1, 2, 0 ])
|
||||
edges: new Uint32Array([0, 1, 2, 3, 3, 1, 2, 0])
|
||||
};
|
||||
|
||||
export function Plane(): Primitive {
|
||||
|
||||
@@ -46,9 +46,9 @@ export function Polyhedron(_vertices: ArrayLike<number>, _indices: ArrayLike<num
|
||||
// iterate over all faces and apply a subdivison with the given detail value
|
||||
for (let i = 0; i < _indices.length; i += 3) {
|
||||
// get the vertices of the face
|
||||
Vec3.fromArray(a, _vertices, _indices[ i + 0 ] * 3);
|
||||
Vec3.fromArray(b, _vertices, _indices[ i + 1 ] * 3);
|
||||
Vec3.fromArray(c, _vertices, _indices[ i + 2 ] * 3);
|
||||
Vec3.fromArray(a, _vertices, _indices[i + 0] * 3);
|
||||
Vec3.fromArray(b, _vertices, _indices[i + 1] * 3);
|
||||
Vec3.fromArray(c, _vertices, _indices[i + 2] * 3);
|
||||
|
||||
// perform subdivision
|
||||
subdivideFace(a, b, c, detail);
|
||||
|
||||
@@ -83,8 +83,8 @@ export function PerforatedOctagonalPyramid() {
|
||||
vertices[8 * 3 + 4] = 0;
|
||||
vertices[8 * 3 + 5] = 0.5;
|
||||
const indices: ReadonlyArray<number> = [
|
||||
0, 1, 8, 1, 2, 8, 4, 5, 8, 5, 6, 8,
|
||||
2, 3, 9, 3, 4, 9, 6, 7, 9, 7, 0, 9
|
||||
0, 1, 8, 1, 2, 8, 4, 5, 8, 5, 6, 8,
|
||||
2, 3, 9, 3, 4, 9, 6, 7, 9, 7, 0, 9
|
||||
];
|
||||
perforatedOctagonalPyramid = createPrimitive(vertices, indices);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { Polyhedron } from './polyhedron';
|
||||
import { Icosahedron } from './icosahedron';
|
||||
import { Icosahedron } from './icosahedron';
|
||||
import { Primitive } from './primitive';
|
||||
|
||||
const { vertices, indices } = Icosahedron();
|
||||
|
||||
@@ -8,16 +8,16 @@ import { createPrimitive, Primitive } from './primitive';
|
||||
import { createCage, Cage } from './cage';
|
||||
|
||||
export const tetrahedronVertices: ReadonlyArray<number> = [
|
||||
0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5
|
||||
0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5, -0.5, 0.5, -0.5, -0.5
|
||||
];
|
||||
|
||||
export const tetrahedronIndices: ReadonlyArray<number> = [
|
||||
2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
|
||||
2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
|
||||
];
|
||||
|
||||
const tetrahedronEdges: ReadonlyArray<number> = [
|
||||
0, 1, 1, 2, 2, 0,
|
||||
0, 3, 1, 3, 2, 3,
|
||||
0, 1, 1, 2, 2, 0,
|
||||
0, 3, 1, 3, 2, 3,
|
||||
];
|
||||
|
||||
let tetrahedron: Primitive;
|
||||
|
||||
@@ -47,7 +47,7 @@ export function Torus(props?: TorusProps): Primitive {
|
||||
vertices.push(...vertex);
|
||||
|
||||
// normal
|
||||
Vec3.set(center, radius * Math.cos(u), radius * Math.sin(u), 0 );
|
||||
Vec3.set(center, radius * Math.cos(u), radius * Math.sin(u), 0);
|
||||
Vec3.sub(normal, vertex, center);
|
||||
Vec3.normalize(normal, normal);
|
||||
normals.push(...normal);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Vec3, Mat4, Mat3 } from '../mol-math/linear-algebra';
|
||||
import { NumberArray } from '../mol-util/type-helpers';
|
||||
import { arrayMax } from '../mol-util/array';
|
||||
|
||||
export function normalizeVec3Array<T extends NumberArray> (a: T, count: number) {
|
||||
export function normalizeVec3Array<T extends NumberArray>(a: T, count: number) {
|
||||
for (let i = 0, il = count * 3; i < il; i += 3) {
|
||||
const x = a[i];
|
||||
const y = a[i + 1];
|
||||
@@ -23,7 +23,7 @@ export function normalizeVec3Array<T extends NumberArray> (a: T, count: number)
|
||||
|
||||
const tmpV3 = Vec3();
|
||||
|
||||
export function transformPositionArray (t: Mat4, array: NumberArray, offset: number, count: number) {
|
||||
export function transformPositionArray(t: Mat4, array: NumberArray, offset: number, count: number) {
|
||||
for (let i = 0, il = count * 3; i < il; i += 3) {
|
||||
Vec3.fromArray(tmpV3, array, offset + i);
|
||||
Vec3.transformMat4(tmpV3, tmpV3, t);
|
||||
@@ -31,7 +31,7 @@ export function transformPositionArray (t: Mat4, array: NumberArray, offset: num
|
||||
}
|
||||
}
|
||||
|
||||
export function transformDirectionArray (n: Mat3, array: NumberArray, offset: number, count: number) {
|
||||
export function transformDirectionArray(n: Mat3, array: NumberArray, offset: number, count: number) {
|
||||
for (let i = 0, il = count * 3; i < il; i += 3) {
|
||||
Vec3.fromArray(tmpV3, array, offset + i);
|
||||
Vec3.transformMat3(tmpV3, tmpV3, n);
|
||||
@@ -60,7 +60,7 @@ const ab = Vec3();
|
||||
* http://www.iquilezles.org/www/articles/normals/normals.htm
|
||||
* - normals array must contain only zeros
|
||||
*/
|
||||
export function computeIndexedVertexNormals<T extends NumberArray> (vertices: NumberArray, indices: NumberArray, normals: T, vertexCount: number, triangleCount: number) {
|
||||
export function computeIndexedVertexNormals<T extends NumberArray>(vertices: NumberArray, indices: NumberArray, normals: T, vertexCount: number, triangleCount: number) {
|
||||
|
||||
for (let i = 0, il = triangleCount * 3; i < il; i += 3) {
|
||||
const ai = indices[i] * 3;
|
||||
@@ -95,7 +95,7 @@ export function computeIndexedVertexNormals<T extends NumberArray> (vertices: Nu
|
||||
* vertex normals for unindexed triangle soup
|
||||
* - normals array must contain only zeros
|
||||
*/
|
||||
export function computeVertexNormals<T extends NumberArray> (vertices: NumberArray, normals: T, vertexCount: number) {
|
||||
export function computeVertexNormals<T extends NumberArray>(vertices: NumberArray, normals: T, vertexCount: number) {
|
||||
for (let i = 0, il = vertexCount * 3; i < il; i += 9) {
|
||||
Vec3.fromArray(a, vertices, i);
|
||||
Vec3.fromArray(b, vertices, i + 3);
|
||||
|
||||
@@ -53,8 +53,8 @@ export function LocationIterator(groupCount: number, instanceCount: number, stri
|
||||
let voidInstances = false;
|
||||
|
||||
return {
|
||||
get hasNext () { return hasNext; },
|
||||
get isNextNewInstance () { return isNextNewInstance; },
|
||||
get hasNext() { return hasNext; },
|
||||
get isNextNewInstance() { return isNextNewInstance; },
|
||||
groupCount,
|
||||
instanceCount,
|
||||
count: groupCount * instanceCount,
|
||||
|
||||
@@ -35,10 +35,10 @@ export function MarchinCubesMeshBuilder(vertexChunkSize: number, mesh?: Mesh): M
|
||||
return {
|
||||
addVertex: (x: number, y: number, z: number) => {
|
||||
++vertexCount;
|
||||
return ChunkedArray.add3(vertices, x, y, z );
|
||||
return ChunkedArray.add3(vertices, x, y, z);
|
||||
},
|
||||
addNormal: (x: number, y: number, z: number) => {
|
||||
ChunkedArray.add3(normals, x, y, z );
|
||||
ChunkedArray.add3(normals, x, y, z);
|
||||
},
|
||||
addGroup: (group: number) => {
|
||||
ChunkedArray.add(groups, group);
|
||||
|
||||
@@ -440,16 +440,16 @@ export const TriTable = [
|
||||
* The line between edge 1 and 5 is always drawn as it's on the leading edge
|
||||
*/
|
||||
export const AllowedContours = [
|
||||
[ 0, 4, 4, 4, 2, 0, 0, 0, 2, 2, 0, 0 ], // 1 2 3 4 8 9
|
||||
[ 4, 0, 4, 4, 0, 8, 0, 0, 0, 8, 8, 0 ], // 0 2 3 5 9 10
|
||||
[ 4, 4, 0, 4, 0, 0, 8, 0, 0, 0, 8, 8 ], // 0 1 3 6 10 11
|
||||
[ 4, 4, 4, 0, 0, 0, 0, 1, 1, 0, 0, 1 ], // 0 1 2 7 8 11
|
||||
[ 2, 0, 0, 0, 0, 8, 8, 8, 2, 2, 0, 0 ], // 0 5 6 7 8 9
|
||||
[ 0, 8, 0, 0, 8, 0, 8, 8, 0, 8, 8, 0 ], // And rotate it
|
||||
[ 0, 0, 8, 0, 8, 8, 0, 8, 0, 0, 8, 8 ],
|
||||
[ 0, 0, 0, 1, 8, 8, 8, 0, 1, 0, 0, 1 ],
|
||||
[ 2, 0, 0, 1, 2, 0, 0, 1, 0, 2, 0, 1 ], // 0 3 4 7 9 11
|
||||
[ 2, 8, 0, 0, 2, 8, 0, 0, 2, 0, 8, 0 ], // And rotate some more
|
||||
[ 0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8 ],
|
||||
[ 0, 0, 8, 1, 0, 0, 8, 1, 1, 0, 8, 0 ]
|
||||
[0, 4, 4, 4, 2, 0, 0, 0, 2, 2, 0, 0], // 1 2 3 4 8 9
|
||||
[4, 0, 4, 4, 0, 8, 0, 0, 0, 8, 8, 0], // 0 2 3 5 9 10
|
||||
[4, 4, 0, 4, 0, 0, 8, 0, 0, 0, 8, 8], // 0 1 3 6 10 11
|
||||
[4, 4, 4, 0, 0, 0, 0, 1, 1, 0, 0, 1], // 0 1 2 7 8 11
|
||||
[2, 0, 0, 0, 0, 8, 8, 8, 2, 2, 0, 0], // 0 5 6 7 8 9
|
||||
[0, 8, 0, 0, 8, 0, 8, 8, 0, 8, 8, 0], // And rotate it
|
||||
[0, 0, 8, 0, 8, 8, 0, 8, 0, 0, 8, 8],
|
||||
[0, 0, 0, 1, 8, 8, 8, 0, 1, 0, 0, 1],
|
||||
[2, 0, 0, 1, 2, 0, 0, 1, 0, 2, 0, 1], // 0 3 4 7 9 11
|
||||
[2, 8, 0, 0, 2, 8, 0, 0, 2, 0, 8, 0], // And rotate some more
|
||||
[0, 8, 8, 0, 0, 8, 8, 0, 0, 8, 0, 8],
|
||||
[0, 0, 8, 1, 0, 0, 8, 1, 1, 0, 8, 0]
|
||||
];
|
||||
@@ -335,37 +335,37 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
canvas: {
|
||||
width, height
|
||||
} as HTMLCanvasElement,
|
||||
getAttachedShaders: function(program: WebGLProgram) {
|
||||
getAttachedShaders: function (program: WebGLProgram) {
|
||||
return [] as WebGLShader[];
|
||||
},
|
||||
getBufferParameter: function(target: number, pname: number) {
|
||||
getBufferParameter: function (target: number, pname: number) {
|
||||
return 0;
|
||||
},
|
||||
getContextAttributes: function() { return contextAttributes; },
|
||||
getFramebufferAttachmentParameter: function() {},
|
||||
getProgramInfoLog: function() { return ''; },
|
||||
getShaderInfoLog: function() { return ''; },
|
||||
getRenderbufferParameter: function() {},
|
||||
getShaderPrecisionFormat: function(shadertype: number, precisiontype: number) {
|
||||
getContextAttributes: function () { return contextAttributes; },
|
||||
getFramebufferAttachmentParameter: function () {},
|
||||
getProgramInfoLog: function () { return ''; },
|
||||
getShaderInfoLog: function () { return ''; },
|
||||
getRenderbufferParameter: function () {},
|
||||
getShaderPrecisionFormat: function (shadertype: number, precisiontype: number) {
|
||||
return {
|
||||
precision: 0,
|
||||
rangeMax: 0,
|
||||
rangeMin: 0
|
||||
};
|
||||
},
|
||||
getShaderSource: function(shader: WebGLShader | null) { return ''; },
|
||||
getTexParameter: function() {},
|
||||
getUniform: function() {},
|
||||
getVertexAttrib: function() {},
|
||||
getVertexAttribOffset: function(index: number, pname: number) { return 0; },
|
||||
hint: function(target: number, mode: number) {},
|
||||
isBuffer: function(buffer: WebGLBuffer | null) { return true; },
|
||||
isEnabled: function(cap: number) { return true; },
|
||||
isFramebuffer: function(framebuffer: WebGLFramebuffer | null) { return true; },
|
||||
isProgram: function(program: WebGLProgram | null) { return true; },
|
||||
isRenderbuffer: function(renderbuffer: WebGLRenderbuffer | null) { return true; },
|
||||
isShader: function(shader: WebGLShader | null) { return true; },
|
||||
isTexture: function(texture: WebGLTexture | null) { return true; },
|
||||
getShaderSource: function (shader: WebGLShader | null) { return ''; },
|
||||
getTexParameter: function () {},
|
||||
getUniform: function () {},
|
||||
getVertexAttrib: function () {},
|
||||
getVertexAttribOffset: function (index: number, pname: number) { return 0; },
|
||||
hint: function (target: number, mode: number) {},
|
||||
isBuffer: function (buffer: WebGLBuffer | null) { return true; },
|
||||
isEnabled: function (cap: number) { return true; },
|
||||
isFramebuffer: function (framebuffer: WebGLFramebuffer | null) { return true; },
|
||||
isProgram: function (program: WebGLProgram | null) { return true; },
|
||||
isRenderbuffer: function (renderbuffer: WebGLRenderbuffer | null) { return true; },
|
||||
isShader: function (shader: WebGLShader | null) { return true; },
|
||||
isTexture: function (texture: WebGLTexture | null) { return true; },
|
||||
getExtension: function (extensionName: string): any {
|
||||
switch (extensionName) {
|
||||
case 'EXT_blend_minmax': return {
|
||||
@@ -386,10 +386,10 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
} as EXT_sRGB;
|
||||
case 'OES_vertex_array_object': return {
|
||||
VERTEX_ARRAY_BINDING_OES: 0,
|
||||
bindVertexArrayOES: function(arrayObject: WebGLVertexArrayObjectOES) { },
|
||||
createVertexArrayOES: function(): WebGLVertexArrayObjectOES { return {}; },
|
||||
deleteVertexArrayOES: function(arrayObject: WebGLVertexArrayObjectOES) { },
|
||||
isVertexArrayOES: function(value: any) { return true; }
|
||||
bindVertexArrayOES: function (arrayObject: WebGLVertexArrayObjectOES) { },
|
||||
createVertexArrayOES: function (): WebGLVertexArrayObjectOES { return {}; },
|
||||
deleteVertexArrayOES: function (arrayObject: WebGLVertexArrayObjectOES) { },
|
||||
isVertexArrayOES: function (value: any) { return true; }
|
||||
} as OES_vertex_array_object;
|
||||
case 'WEBGL_color_buffer_float': return {
|
||||
FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT: 0,
|
||||
@@ -404,8 +404,8 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
} as WEBGL_debug_shaders;
|
||||
case 'WEBGL_draw_buffers': return null;
|
||||
case 'WEBGL_lose_context': return {
|
||||
loseContext: function() { },
|
||||
restoreContext: function() { },
|
||||
loseContext: function () { },
|
||||
restoreContext: function () { },
|
||||
} as WEBGL_lose_context;
|
||||
case 'WEBGL_depth_texture': return {
|
||||
UNSIGNED_INT_24_8_WEBGL: 0
|
||||
@@ -426,9 +426,9 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
} as OES_standard_derivatives;
|
||||
case 'OES_element_index_uint': return {} as OES_element_index_uint;
|
||||
case 'ANGLE_instanced_arrays': return {
|
||||
drawArraysInstancedANGLE: function(mode: number, first: number, count: number, primcount: number) {},
|
||||
drawElementsInstancedANGLE: function(mode: number, count: number, type: number, offset: number, primcount: number) {},
|
||||
vertexAttribDivisorANGLE: function(index: number, divisor: number) {},
|
||||
drawArraysInstancedANGLE: function (mode: number, first: number, count: number, primcount: number) {},
|
||||
drawElementsInstancedANGLE: function (mode: number, count: number, type: number, offset: number, primcount: number) {},
|
||||
vertexAttribDivisorANGLE: function (index: number, divisor: number) {},
|
||||
VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE: 0
|
||||
} as ANGLE_instanced_arrays;
|
||||
}
|
||||
@@ -476,10 +476,10 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
// Int arrays
|
||||
case gl.MAX_VIEWPORT_DIMS:
|
||||
case gl.SCISSOR_BOX:
|
||||
return new Int32Array([ 0, 0, 4096, 4096 ]);
|
||||
return new Int32Array([0, 0, 4096, 4096]);
|
||||
case gl.VIEWPORT:
|
||||
const { x, y, width, height } = viewport;
|
||||
return new Int32Array([ x, y, width, height ]);
|
||||
return new Int32Array([x, y, width, height]);
|
||||
|
||||
// Float arrays
|
||||
case gl.ALIASED_LINE_WIDTH_RANGE:
|
||||
@@ -487,12 +487,12 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
case gl.ALIASED_POINT_SIZE_RANGE:
|
||||
return new Float32Array([0, 255]);
|
||||
case gl.DEPTH_RANGE:
|
||||
return new Float32Array([ depthRange.zNear, depthRange.zFar ]);
|
||||
return new Float32Array([depthRange.zNear, depthRange.zFar]);
|
||||
case gl.BLEND_COLOR:
|
||||
return new Float32Array([0, 0, 0, 0]);
|
||||
case gl.COLOR_CLEAR_VALUE:
|
||||
const { r, g, b, a } = colorClearValue;
|
||||
return new Float32Array([ r, g, b, a ]);
|
||||
return new Float32Array([r, g, b, a]);
|
||||
|
||||
case gl.COLOR_WRITEMASK:
|
||||
return 0;
|
||||
@@ -601,7 +601,7 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
switch (pname) {
|
||||
case gl.SHADER_TYPE: return items[shader as number].type;
|
||||
case gl.COMPILE_STATUS: return true;
|
||||
default: throw `getShaderParameter ${pname}`;
|
||||
default: throw new Error(`getShaderParameter ${pname}`);
|
||||
}
|
||||
},
|
||||
shaderSource: function () { },
|
||||
@@ -628,7 +628,7 @@ export function createGl(width: number, height: number, contextAttributes: WebGL
|
||||
case gl.DELETE_STATUS: return false;
|
||||
case gl.VALIDATE_STATUS: return true;
|
||||
case gl.ATTACHED_SHADERS: return 2;
|
||||
default: throw `getProgramParameter ${pname}`;
|
||||
default: throw new Error(`getProgramParameter ${pname}`);
|
||||
}
|
||||
},
|
||||
deleteShader: function () { },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
* Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
||||
*
|
||||
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
||||
*/
|
||||
@@ -85,8 +85,7 @@ function createPoints() {
|
||||
|
||||
uSizeFactor: ValueCell.create(1),
|
||||
dPointSizeAttenuation: ValueCell.create(true),
|
||||
dPointFilledCircle: ValueCell.create(false),
|
||||
uPointEdgeBleach: ValueCell.create(0.5),
|
||||
dPointStyle: ValueCell.create('square'),
|
||||
};
|
||||
const state: RenderableState = {
|
||||
disposed: false,
|
||||
@@ -104,7 +103,7 @@ function createPoints() {
|
||||
|
||||
describe('renderer', () => {
|
||||
it('basic', () => {
|
||||
const [ width, height ] = [ 32, 32 ];
|
||||
const [width, height] = [32, 32];
|
||||
const gl = createGl(width, height, { preserveDrawingBuffer: true });
|
||||
const { ctx, renderer } = createRenderer(gl);
|
||||
|
||||
@@ -123,7 +122,7 @@ describe('renderer', () => {
|
||||
});
|
||||
|
||||
it('points', async () => {
|
||||
const [ width, height ] = [ 32, 32 ];
|
||||
const [width, height] = [32, 32];
|
||||
const gl = createGl(width, height, { preserveDrawingBuffer: true });
|
||||
const { ctx } = createRenderer(gl);
|
||||
const scene = Scene.create(ctx);
|
||||
@@ -134,17 +133,17 @@ describe('renderer', () => {
|
||||
scene.commit();
|
||||
expect(ctx.stats.resourceCounts.attribute).toBe(ctx.isWebGL2 ? 4 : 5);
|
||||
expect(ctx.stats.resourceCounts.texture).toBe(7);
|
||||
expect(ctx.stats.resourceCounts.vertexArray).toBe(6);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(6);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(12);
|
||||
expect(ctx.stats.resourceCounts.vertexArray).toBe(8);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(8);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(16);
|
||||
|
||||
scene.remove(points);
|
||||
scene.commit();
|
||||
expect(ctx.stats.resourceCounts.attribute).toBe(0);
|
||||
expect(ctx.stats.resourceCounts.texture).toBe(0);
|
||||
expect(ctx.stats.resourceCounts.vertexArray).toBe(0);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(6);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(12);
|
||||
expect(ctx.stats.resourceCounts.program).toBe(8);
|
||||
expect(ctx.stats.resourceCounts.shader).toBe(16);
|
||||
|
||||
ctx.resources.destroy();
|
||||
expect(ctx.stats.resourceCounts.program).toBe(0);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user