From 515aaaeb7c2af9769bd28153682acbbebf1c67a1 Mon Sep 17 00:00:00 2001 From: MarcoSchaeferT <schaefer.marco.ms@web.de> Date: Wed, 13 Feb 2019 16:38:42 +0100 Subject: [PATCH] Added file-selection for PLY-files and create initial ply-parser (working on...) --- package-lock.json | Bin 501957 -> 502363 bytes src/apps/structure-info/volume.ts | 1 + src/mol-io/common/ascii.ts | 90 ++++++ src/mol-io/reader/cif/text/parser.ts | 1 + src/mol-io/reader/common/text/tokenizer.ts | 1 + .../reader/ply/parse_data/data-model.ts | 39 +++ src/mol-io/reader/ply/parse_data/field.ts | 9 + .../reader/ply/parse_data/ply_parser.ts | 263 ++++++++++++++++++ .../reader/ply/read_data/data-source.ts | 58 ++++ src/mol-io/reader/ply/read_data/data.ts | 60 ++++ src/mol-plugin/index.ts | 3 +- src/mol-plugin/state/actions/basic.ts | 20 +- src/mol-plugin/state/objects.ts | 2 + src/mol-plugin/state/transforms/data.ts | 2 +- src/tests/browser/index.html | 1 + src/tests/browser/render-shape.ts | 12 +- 16 files changed, 554 insertions(+), 8 deletions(-) create mode 100644 src/mol-io/common/ascii.ts create mode 100644 src/mol-io/reader/ply/parse_data/data-model.ts create mode 100644 src/mol-io/reader/ply/parse_data/field.ts create mode 100644 src/mol-io/reader/ply/parse_data/ply_parser.ts create mode 100644 src/mol-io/reader/ply/read_data/data-source.ts create mode 100644 src/mol-io/reader/ply/read_data/data.ts diff --git a/package-lock.json b/package-lock.json index 10b4c8cd33289895aaf69b9f50e5a17428299ae3..7325a17319942dc6a86e2fd01de0740a393c55cd 100644 GIT binary patch delta 294 zcmX?lQSSB?xrP?TElg``rd2VSO#iT-m38`_`7FHCuhlRmP5Z#eKRsX`ljh`~4^^fc zXfm>Huc>9yW}Gfi$7DABKpj&Ygk@gOlnr66xyi)4{X{*}Qf`oO+grMsI2hrkOy4zw zNnrX4bw-`(S|`}JroZiB`ht*DU||MZEjwMVkEv?9LobuXbh}kd?9*R2F-cCJKZ}`v zy7XEm?dc!-ncOBf+~A+SVHK15_MCpEY$O}@&ST=){%-=4JO|i2Ijt-L)Ahcxa8CD~ q$@C0i*ZnRggY9**n4WUO#oFtZF#$0%5VHU=D-g47uUp3M&IADR=5Sd6 delta 255 zcmcb8MegWDxrP?TElg``CI?ItpT0qzopt)lJ|^DjTdJ6(r}Nb^xlcd9$s)78ua+s8 z5vW9Bx>!9^JeX1QnMHE?w>(Cv$qA)=(;MR1S*AazVp0dmZTD_q+RP0yal26u69?nu z1*fH_@7uy;Gkskz(?76@)1US+%?7EM9<Yp!W%`bOri|$iqS&;iFL=ztx;<wCQ!nH6 z51H&T)1{WNac{Ss#3auFRy|=B(|@pW1>H;r+rQ6dddfZhfCl5H$pSa6rhlksa-N>B nnn`nV!wr$?{LySulWq#M_pf9EVrC#_0b*7lW}Du>lKl(-eCKB! diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index 2faaf7086..f74a5440e 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -35,6 +35,7 @@ function print(data: Volume) { console.log(data.volume.cell); console.log(data.volume.dataStats); console.log(data.volume.fractionalBox); + console.log("\n\n Hello 12156421231 \n\n"); } async function doMesh(data: Volume, filename: string) { diff --git a/src/mol-io/common/ascii.ts b/src/mol-io/common/ascii.ts new file mode 100644 index 000000000..4a9b2edfa --- /dev/null +++ b/src/mol-io/common/ascii.ts @@ -0,0 +1,90 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * Adapted from https://github.com/rcsb/mmtf-javascript + * @author Alexander Rose <alexander.rose@weirdbyte.de> + * @author David Sehnal <david.sehnal@gmail.com> + */ +// NOT IN USE ELSEWEHERE !!!!! +export function asciiWrite(data: Uint8Array, offset: number, str: string) { + for (let i = 0, l = str.length; i < l; i++) { + let codePoint = str.charCodeAt(i); + + // One byte of UTF-8 + if (codePoint < 0x80) { + data[offset++] = codePoint >>> 0 & 0x7f | 0x00; + continue; + } + + // Two bytes of UTF-8 + if (codePoint < 0x800) { + data[offset++] = codePoint >>> 6 & 0x1f | 0xc0; + data[offset++] = codePoint >>> 0 & 0x3f | 0x80; + continue; + } + + // Three bytes of UTF-8. + if (codePoint < 0x10000) { + data[offset++] = codePoint >>> 12 & 0x0f | 0xe0; + data[offset++] = codePoint >>> 6 & 0x3f | 0x80; + data[offset++] = codePoint >>> 0 & 0x3f | 0x80; + continue; + } + + // Four bytes of UTF-8 + if (codePoint < 0x110000) { + data[offset++] = codePoint >>> 18 & 0x07 | 0xf0; + data[offset++] = codePoint >>> 12 & 0x3f | 0x80; + data[offset++] = codePoint >>> 6 & 0x3f | 0x80; + data[offset++] = codePoint >>> 0 & 0x3f | 0x80; + continue; + } + throw new Error('bad codepoint ' + codePoint); + } +} + +const __chars = function () { + let data: string[] = []; + for (let i = 0; i < 1024; i++) data[i] = String.fromCharCode(i); + return data; +}(); + +function throwError(err: string) { + throw new Error(err); +} + +export function asciiRead(data: number, offset: number, length: number) { + let chars = __chars; + let str: string | undefined = void 0; + + let byte = data; + // One byte character + if ((byte & 0x80) !== 0x00) throwError('Invalid byte ' + byte.toString(16)); + str = chars[byte]; + return str; +} + +export function asciiByteCount(str: string) { + let count = 0; + for (let i = 0, l = str.length; i < l; i++) { + let codePoint = str.charCodeAt(i); + if (codePoint < 0x80) { + count += 1; + continue; + } + if (codePoint < 0x800) { + count += 2; + continue; + } + if (codePoint < 0x10000) { + count += 3; + continue; + } + if (codePoint < 0x110000) { + count += 4; + continue; + } + throwError('bad codepoint ' + codePoint); + } + return count; +} \ No newline at end of file diff --git a/src/mol-io/reader/cif/text/parser.ts b/src/mol-io/reader/cif/text/parser.ts index 3ee75e270..4fa0605e8 100644 --- a/src/mol-io/reader/cif/text/parser.ts +++ b/src/mol-io/reader/cif/text/parser.ts @@ -60,6 +60,7 @@ interface TokenizerState { * Eat everything until a whitespace/newline occurs. */ function eatValue(state: TokenizerState) { + console.log("hello"); while (state.position < state.length) { switch (state.data.charCodeAt(state.position)) { case 9: // \t diff --git a/src/mol-io/reader/common/text/tokenizer.ts b/src/mol-io/reader/common/text/tokenizer.ts index 60f14c1b1..601309348 100644 --- a/src/mol-io/reader/common/text/tokenizer.ts +++ b/src/mol-io/reader/common/text/tokenizer.ts @@ -85,6 +85,7 @@ export namespace Tokenizer { /** Sets the current token start to current position and moves to the next line. */ export function markLine(state: Tokenizer) { state.tokenStart = state.position; + console.log("hello"); eatLine(state); } diff --git a/src/mol-io/reader/ply/parse_data/data-model.ts b/src/mol-io/reader/ply/parse_data/data-model.ts new file mode 100644 index 000000000..293f4b762 --- /dev/null +++ b/src/mol-io/reader/ply/parse_data/data-model.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import { CifField as CsvColumn } from '../../cif/data-model' + +export { CsvColumn } + +export interface PlyFile { + readonly name?: string, + readonly PLY_File: ply_form +} + +export function CsvFile(PLY_File: ply_form, name?: string): PlyFile { + return { name, PLY_File }; +} + +export interface ply_form { + readonly rowCount: number, + readonly vertexCount: number, + readonly faceCount: number, + readonly propertyCount: number, + readonly initialHead: ReadonlyArray<string>, + getColumn(name: string): CsvColumn | undefined +} + +export function CsvTable(rowCount: number, vertexCount: number, faceCount: number, propertyCount: number, initialHead: string[], columns: CsvColumns): ply_form { + return { rowCount, vertexCount, faceCount, propertyCount, initialHead: [...initialHead], getColumn(name) { return columns[name]; } }; +} + +export type CsvColumns = { [name: string]: CsvColumn } + +// export namespace CsvTable { +// export function empty(name: string): Table { +// return { rowCount: 0, name, fieldNames: [], getColumn(name: string) { return void 0; } }; +// }; +// } \ No newline at end of file diff --git a/src/mol-io/reader/ply/parse_data/field.ts b/src/mol-io/reader/ply/parse_data/field.ts new file mode 100644 index 000000000..a86e45353 --- /dev/null +++ b/src/mol-io/reader/ply/parse_data/field.ts @@ -0,0 +1,9 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +import Field from '../../cif/text/field' + +export default Field \ No newline at end of file diff --git a/src/mol-io/reader/ply/parse_data/ply_parser.ts b/src/mol-io/reader/ply/parse_data/ply_parser.ts new file mode 100644 index 000000000..31a91deb0 --- /dev/null +++ b/src/mol-io/reader/ply/parse_data/ply_parser.ts @@ -0,0 +1,263 @@ +/** + * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author Alexander Rose <alexander.rose@weirdbyte.de> + */ + +// import { Column } from 'mol-data/db' +import { Tokens, TokenBuilder, Tokenizer } from '../../common/text/tokenizer' +import * as Data from './data-model' +import Field from './field' +import Result from '../../result' +import { Task, RuntimeContext, chunkedSubtask, } from 'mol-task' + + +const enum PlyTokenType { + Value = 0, + Comment = 1, + End = 2, + property = 3 +} + +interface State { + data: string; + tokenizer: Tokenizer, + + tokenType: PlyTokenType; + runtimeCtx: RuntimeContext, + tokens: Tokens[], + + fieldCount: number, + recordCount: number, + + columnCount: number, + initialHead: string[], + propertyNames: string[], + + commentCharCode: number, + propertyCharCode: number +} + +function State(data: string, runtimeCtx: RuntimeContext, opts: PlyOptions): State { + + const tokenizer = Tokenizer(data) + return { + data, + tokenizer, + + tokenType: PlyTokenType.End, + runtimeCtx, + tokens: [], + + fieldCount: 0, + recordCount: 0, + + columnCount: 0, + initialHead: [], + propertyNames: [], + + commentCharCode: opts.comment.charCodeAt(0), + propertyCharCode: opts.property.charCodeAt(0) + }; +} + +/** + * Eat everything until a delimiter (whitespace) or newline occurs. + * Ignores whitespace at the end of the value, i.e. trim right. + * Returns true when a newline occurs after the value. + */ +function eatValue(state: Tokenizer) { + while (state.position < state.length) { + const c = state.data.charCodeAt(state.position); + ++state.position + switch (c) { + case 10: // \n + case 13: // \r + return true; + case 32: // ' ' Delimeter of ply is space (Unicode 32) + return; + case 9: // \t + case 32: // ' ' + break; + default: + ++state.tokenEnd; + break; + } + } +} + + + +function skipWhitespace(state: Tokenizer) { + let prev = -1; + while (state.position < state.length) { + const c = state.data.charCodeAt(state.position); + switch (c) { + case 9: // '\t' + //case 32: // ' ' + prev = c; + ++state.position; + break; + case 10: // \n + // handle \r\n + if (prev !== 13) { + ++state.lineNumber; + } + prev = c; + ++state.position; + break; + case 13: // \r + prev = c; + ++state.position; + ++state.lineNumber; + break; + default: + return; + } + } +} + +function skipLine(state: Tokenizer) { + while (state.position < state.length) { + const c = state.data.charCodeAt(state.position); + if (c === 10 || c === 13) return // \n or \r + ++state.position + } +} + +/** + * Move to the next token. + * Returns true when the current char is a newline, i.e. indicating a full record. + */ +function moveNextInternal(state: State) { + const tokenizer = state.tokenizer + //skipWhitespace(tokenizer); + + if (tokenizer.position >= tokenizer.length) { + state.tokenType = PlyTokenType.End; + return true; + } + + tokenizer.tokenStart = tokenizer.position; + tokenizer.tokenEnd = tokenizer.position; + const c = state.data.charCodeAt(tokenizer.position); + switch (c) { + case state.commentCharCode: + state.tokenType = PlyTokenType.Comment; + skipLine(tokenizer); + break; + case state.propertyCharCode: + state.tokenType = PlyTokenType.property; + //return eatProperty(tokenizer); + default: + state.tokenType = PlyTokenType.Value; + return eatValue(tokenizer); + } +} + +/** + * Moves to the next non-comment token/line. + * Returns true when the current char is a newline, i.e. indicating a full record. + */ +function moveNext(state: State) { + let newRecord = moveNextInternal(state); + while (state.tokenType === PlyTokenType.Comment) { // skip comment lines (marco + newRecord = moveNextInternal(state); + } + return newRecord +} + +function readRecordsChunk(chunkSize: number, state: State) { + if (state.tokenType === PlyTokenType.End) return 0 + + let newRecord = moveNext(state); + if (newRecord) ++state.recordCount + + const { tokens, tokenizer } = state; + let counter = 0; + while (state.tokenType === PlyTokenType.Value && counter < chunkSize) { + TokenBuilder.add(tokens[state.fieldCount % state.columnCount], tokenizer.tokenStart, tokenizer.tokenEnd); + ++state.fieldCount + newRecord = moveNext(state); + if (newRecord) ++state.recordCount + ++counter; + } + return counter; +} + +function readRecordsChunks(state: State) { + return chunkedSubtask(state.runtimeCtx, 100000, state, readRecordsChunk, + (ctx, state) => ctx.update({ message: 'Parsing...', current: state.tokenizer.position, max: state.data.length })); +} + +function addColumn (state: State) { + state.initialHead.push(Tokenizer.getTokenString(state.tokenizer)) + state.tokens.push(TokenBuilder.create(state.tokenizer, state.data.length / 80)) +} + +function init(state: State) { // only for first line to get the columns! (marco) + let newRecord = moveNext(state) + while (!newRecord) { // newRecord is only true when a newline occurs (marco) + addColumn(state) + newRecord = moveNext(state); + } + addColumn(state) + newRecord = moveNext(state); + while (!newRecord) { + addColumn(state) + newRecord = moveNext(state); + } + addColumn(state) + if(state.initialHead[0] !== 'ply'){ + console.log("ERROR: this is not a .ply file!") + throw new Error("this is not a .ply file!"); + return 0; + } + if(state.initialHead[2] !== 'ascii'){ + console.log("ERROR: only ASCII-DECODING is supported!"); + throw new Error("only ASCII-DECODING is supported!"); + return 0; + } + state.columnCount = state.initialHead.length + return 1; +} + +async function handleRecords(state: State): Promise<Data.ply_form> { + if(!init(state)){ + console.log("ERROR: parsing file (PLY) failed!") + throw new Error("parsing file (PLY) failed!"); + } + await readRecordsChunks(state) + + const columns: Data.CsvColumns = Object.create(null); + for (let i = 0; i < state.columnCount; ++i) { + columns[state.initialHead[i]] = Field(state.tokens[i], state.recordCount); + } + + + return Data.CsvTable(state.recordCount,0,0,0, state.initialHead, columns) +} + +async function parseInternal(data: string, ctx: RuntimeContext, opts: PlyOptions): Promise<Result<Data.PlyFile>> { + const state = State(data, ctx, opts); + + ctx.update({ message: 'Parsing...', current: 0, max: data.length }); + const table = await handleRecords(state) + const result = Data.CsvFile(table) + console.log(result); + return Result.success(result); +} + +interface PlyOptions { + comment: string; + property: string; +} + +export function parse(data: string, opts?: Partial<PlyOptions>) { + const completeOpts = Object.assign({}, { comment: 'c', property: 'p' }, opts) + return Task.create<Result<Data.PlyFile>>('Parse PLY', async ctx => { + return await parseInternal(data, ctx, completeOpts); + }); +} + +export default parse; \ No newline at end of file diff --git a/src/mol-io/reader/ply/read_data/data-source.ts b/src/mol-io/reader/ply/read_data/data-source.ts new file mode 100644 index 000000000..9a80b9364 --- /dev/null +++ b/src/mol-io/reader/ply/read_data/data-source.ts @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + * + * Adapted from LiteMol + */ + +import { Task, RuntimeContext } from 'mol-task'; + +export function readFromFile(file: File) { + return <Task<number | string>>readFromFileInternal(file); +} + + +async function processFile(ctx: RuntimeContext, e: any) { + const data = (e.target as FileReader).result; + return data as string; +} + +function readData(ctx: RuntimeContext, action: string, data: XMLHttpRequest | FileReader): Promise<any> { + return new Promise<any>((resolve, reject) => { + data.onerror = (e: any) => { + const error = (<FileReader>e.target).error; + reject(error ? error : 'Failed.'); + }; + + data.onabort = () => reject(Task.Aborted('')); + + data.onprogress = (e: ProgressEvent) => { + if (e.lengthComputable) { + ctx.update({ message: action, isIndeterminate: false, current: e.loaded, max: e.total }); + } else { + ctx.update({ message: `${action} ${(e.loaded / 1024 / 1024).toFixed(2)} MB`, isIndeterminate: true }); + } + } + data.onload = (e: any) => resolve(e); + }); +} + +function readFromFileInternal(file: File): Task<string | number> { + let reader: FileReader | undefined = void 0; + return Task.create('Read File', async ctx => { + try { + reader = new FileReader(); + reader.readAsBinaryString(file); + + ctx.update({ message: 'Opening file...', canAbort: true }); + const e = await readData(ctx, 'Reading...', reader); + const result = processFile(ctx, e); + return result; + } finally { + reader = void 0; + } + }, () => { + if (reader) reader.abort(); + }); +} diff --git a/src/mol-io/reader/ply/read_data/data.ts b/src/mol-io/reader/ply/read_data/data.ts new file mode 100644 index 000000000..699353a18 --- /dev/null +++ b/src/mol-io/reader/ply/read_data/data.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { PluginStateTransform } from '../../../../mol-plugin/state/objects'; +import { PluginStateObject as SO } from '../../../../mol-plugin/state/objects'; +import { Task } from 'mol-task'; +import PLY from 'mol-io/reader/ply/parse_data/ply_parser' +import { ParamDefinition as PD } from 'mol-util/param-definition'; +import { Transformer } from 'mol-state'; +import { readFromFile } from './data-source'; + +export { ReadFile_ascii } +type ReadFile_ascii = typeof ReadFile_ascii +const ReadFile_ascii = PluginStateTransform.BuiltIn({ + name: 'ReadFile_ascii', + display: { name: 'ReadFile_ascii', description: 'Read string data from the specified file' }, + from: SO.Root, + to: [SO.Data.String], + params: { + file: PD.File(), + label: PD.makeOptional(PD.Text('')), + isBinary: PD.makeOptional(PD.Boolean(false, { description: 'If true, open file as as binary (string otherwise)' })) + } +})({ + apply({ params: p }) { + return Task.create('Open File', async ctx => { + const data = await readFromFile(p.file).runInContext(ctx); + return new SO.Data.String(data as string, { label: p.label ? p.label : p.file.name }); + }); + }, + update({ oldParams, newParams, b }) { + if (oldParams.label !== newParams.label) { + (b.label as string) = newParams.label || oldParams.file.name; + return Transformer.UpdateResult.Updated; + } + return Transformer.UpdateResult.Unchanged; + }, + isSerializable: () => ({ isSerializable: false, reason: 'Cannot serialize user loaded files.' }) +}); + + +export { ParsePLY } +type ParsePLY = typeof ParsePLY +const ParsePLY = PluginStateTransform.BuiltIn({ + name: 'parse-ply', + display: { name: 'Parse PLY', description: 'Parse OLY from String' }, + from: [SO.Data.String], + to: SO.Format.Ply +})({ + apply({ a }) { + return Task.create('Parse PLY', async ctx => { + const parsed = await (PLY(a.data).runInContext(ctx)); + if (parsed.isError) throw new Error(parsed.message); + return new SO.Format.Ply(parsed.result); + }); + } +}); \ No newline at end of file diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts index ad6c9ebc6..68991f6a7 100644 --- a/src/mol-plugin/index.ts +++ b/src/mol-plugin/index.ts @@ -11,7 +11,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { PluginCommands } from './command'; import { PluginSpec } from './spec'; -import { DownloadStructure, CreateComplexRepresentation, OpenStructure } from './state/actions/basic'; +import {DownloadStructure, CreateComplexRepresentation, OpenStructure, PLYtest} from './state/actions/basic'; import { StateTransforms } from './state/transforms'; import { PluginBehaviors } from './behavior'; @@ -24,6 +24,7 @@ const DefaultSpec: PluginSpec = { actions: [ PluginSpec.Action(DownloadStructure), PluginSpec.Action(OpenStructure), + PluginSpec.Action(PLYtest), PluginSpec.Action(CreateComplexRepresentation), PluginSpec.Action(StateTransforms.Data.Download), PluginSpec.Action(StateTransforms.Data.ParseCif), diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 13a43c24e..0dd4d57aa 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -84,13 +84,31 @@ export const OpenStructure = StateAction.build({ const data = b.toRoot().apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: /\.bcif$/i.test(params.file.name) }); return state.update(createStructureTree(ctx, data, false)); }); +import * as data_functions from "../../../mol-io/reader/ply//read_data/data" +export const PLYtest = StateAction.build({ + display: { name: 'PLY Test', description: 'nothing ply' }, + from: PluginStateObject.Root, + params: { file: PD.File({ accept: '.ply' }) } +})(({ params, state }, ctx: PluginContext) => { + const b = state.build(); + const data = b.toRoot().apply(data_functions.ReadFile_ascii, { file: params.file, isBinary: false }); + return state.update(getPLYdata(ctx, data)); +}); + +function getPLYdata(ctx: PluginContext, b: StateTreeBuilder.To<PluginStateObject.Data.String>, ): StateTree { + let root = b + .apply(data_functions.ParsePLY); + console.log(data_functions.ParsePLY); + + return root.getTree(); +} + function createStructureTree(ctx: PluginContext, b: StateTreeBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, supportProps: boolean): StateTree { let root = b .apply(StateTransforms.Data.ParseCif) .apply(StateTransforms.Model.TrajectoryFromMmCif) .apply(StateTransforms.Model.ModelFromTrajectory, { modelIndex: 0 }); - if (supportProps) { root = root.apply(StateTransforms.Model.CustomModelProperties); } diff --git a/src/mol-plugin/state/objects.ts b/src/mol-plugin/state/objects.ts index 8f90acb58..07cf4afaa 100644 --- a/src/mol-plugin/state/objects.ts +++ b/src/mol-plugin/state/objects.ts @@ -5,6 +5,7 @@ */ import { CifFile } from 'mol-io/reader/cif'; +import { PlyFile } from 'mol-io/reader/ply/parse_data/data-model'; import { Model as _Model, Structure as _Structure } from 'mol-model/structure'; import { VolumeData } from 'mol-model/volume'; import { PluginBehavior } from 'mol-plugin/behavior/behavior'; @@ -56,6 +57,7 @@ export namespace PluginStateObject { export namespace Format { export class Json extends Create<any>({ name: 'JSON Data', typeClass: 'Data' }) { } export class Cif extends Create<CifFile>({ name: 'CIF File', typeClass: 'Data' }) { } + export class Ply extends Create<PlyFile>({ name: 'PLY File', typeClass: 'Data' }) { } } export namespace Molecule { diff --git a/src/mol-plugin/state/transforms/data.ts b/src/mol-plugin/state/transforms/data.ts index 0878ceb36..eadc8593c 100644 --- a/src/mol-plugin/state/transforms/data.ts +++ b/src/mol-plugin/state/transforms/data.ts @@ -90,4 +90,4 @@ const ParseCif = PluginStateTransform.BuiltIn({ return new SO.Format.Cif(parsed.result); }); } -}); \ No newline at end of file +}); diff --git a/src/tests/browser/index.html b/src/tests/browser/index.html index f28af95b2..5a0851f57 100644 --- a/src/tests/browser/index.html +++ b/src/tests/browser/index.html @@ -34,5 +34,6 @@ document.body.appendChild(script) } </script> + <script type="text/javascript" src="./render-shape.js"></script> </body> </html> \ No newline at end of file diff --git a/src/tests/browser/render-shape.ts b/src/tests/browser/render-shape.ts index 943a50476..8020d57fd 100644 --- a/src/tests/browser/render-shape.ts +++ b/src/tests/browser/render-shape.ts @@ -16,6 +16,8 @@ import { Mesh } from 'mol-geo/geometry/mesh/mesh'; import { labelFirst } from 'mol-theme/label'; import { RuntimeContext, Progress } from 'mol-task'; + + const parent = document.getElementById('app')! parent.style.width = '100%' parent.style.height = '100%' @@ -56,7 +58,7 @@ async function getSphereMesh(ctx: RuntimeContext, centers: number[], mesh?: Mesh const builderState = MeshBuilder.createState(centers.length * 128, centers.length * 128 / 2, mesh) const t = Mat4.identity() const v = Vec3.zero() - const sphere = Sphere(2) + const sphere = Sphere(4) builderState.currentGroup = 0 for (let i = 0, il = centers.length / 3; i < il; ++i) { // for production, calls to update should be guarded by `if (ctx.shouldUpdate)` @@ -69,8 +71,8 @@ async function getSphereMesh(ctx: RuntimeContext, centers: number[], mesh?: Mesh } const myData = { - centers: [0, 0, 0, 0, 3, 0], - colors: [ColorNames.tomato, ColorNames.springgreen], + centers: [0, 0, 0, 0, 3, 0, 1, 0 , 4], + colors: [ColorNames.tomato, ColorNames.springgreen,ColorNames.springgreen], labels: ['Sphere 0, Instance A', 'Sphere 1, Instance A', 'Sphere 0, Instance B', 'Sphere 1, Instance B'], transforms: [Mat4.identity(), Mat4.fromTranslation(Mat4.zero(), Vec3.create(3, 0, 0))] } @@ -96,7 +98,7 @@ async function getShape(ctx: RuntimeContext, data: MyData, props: {}, shape?: Sh // Init ShapeRepresentation container const repr = ShapeRepresentation(getShape, Mesh.Utils) -async function init() { +export async function init() { // Create shape from myData and add to canvas3d await repr.createOrUpdate({}, myData).run((p: Progress) => console.log(Progress.format(p))) console.log(repr) @@ -110,4 +112,4 @@ async function init() { await repr.createOrUpdate({}, myData).run() }, 1000) } -init() \ No newline at end of file +export default init(); \ No newline at end of file -- GitLab