From 299f3baf7b03a90f15a72818d754620277296c14 Mon Sep 17 00:00:00 2001 From: MarcoSchaeferT <schaefer.marco.ms@web.de> Date: Thu, 14 Feb 2019 17:59:29 +0100 Subject: [PATCH] parsing ply-file to ply-data-structure is working --- src/apps/structure-info/volume.ts | 1 - 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 | 17 +- .../reader/ply/parse_data/ply_parser.ts | 161 ++++++++++++------ src/mol-io/reader/ply/read_data/data.ts | 2 +- src/mol-plugin/state/actions/basic.ts | 3 +- 7 files changed, 119 insertions(+), 67 deletions(-) diff --git a/src/apps/structure-info/volume.ts b/src/apps/structure-info/volume.ts index f74a5440e..2faaf7086 100644 --- a/src/apps/structure-info/volume.ts +++ b/src/apps/structure-info/volume.ts @@ -35,7 +35,6 @@ 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/reader/cif/text/parser.ts b/src/mol-io/reader/cif/text/parser.ts index 4fa0605e8..3ee75e270 100644 --- a/src/mol-io/reader/cif/text/parser.ts +++ b/src/mol-io/reader/cif/text/parser.ts @@ -60,7 +60,6 @@ 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 601309348..60f14c1b1 100644 --- a/src/mol-io/reader/common/text/tokenizer.ts +++ b/src/mol-io/reader/common/text/tokenizer.ts @@ -85,7 +85,6 @@ 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 index 293f4b762..36fdb6b1a 100644 --- a/src/mol-io/reader/ply/parse_data/data-model.ts +++ b/src/mol-io/reader/ply/parse_data/data-model.ts @@ -4,33 +4,34 @@ * @author Alexander Rose <alexander.rose@weirdbyte.de> */ -import { CifField as CsvColumn } from '../../cif/data-model' +import { CifField as PlyColumn } from '../../cif/data-model' -export { CsvColumn } +export { PlyColumn } export interface PlyFile { readonly name?: string, readonly PLY_File: ply_form } -export function CsvFile(PLY_File: ply_form, name?: string): PlyFile { +export function PlyFile(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 + readonly propertyNames: ReadonlyArray<string>, + readonly properties: number[], + readonly faces: number[], } -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 function PlyStructure(vertexCount: number, faceCount: number, propertyCount: number, initialHead: string[], propertyNames: string[], properties: number[], faces: number[]): ply_form { + return {vertexCount, faceCount, propertyCount, initialHead: [...initialHead], propertyNames: [...propertyNames], properties: [...properties], faces: [...faces]}; } -export type CsvColumns = { [name: string]: CsvColumn } +export type PlyColumns = { [name: string]: PlyColumn } // export namespace CsvTable { // export function empty(name: string): Table { diff --git a/src/mol-io/reader/ply/parse_data/ply_parser.ts b/src/mol-io/reader/ply/parse_data/ply_parser.ts index 31a91deb0..d2a42e49a 100644 --- a/src/mol-io/reader/ply/parse_data/ply_parser.ts +++ b/src/mol-io/reader/ply/parse_data/ply_parser.ts @@ -7,18 +7,23 @@ // 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 + property = 3, + element = 4 } + interface State { data: string; tokenizer: Tokenizer, @@ -28,14 +33,26 @@ interface State { tokens: Tokens[], fieldCount: number, - recordCount: number, columnCount: number, + propertyCount: number, + vertexCount: number, + currentVertex: number, + currentProperty: number, + currentFace: number, + currentFaceElement: number, + faceCount: number, + endHeader: number, + initialHead: string[], + properties: number[], + faces: number[], propertyNames: string[], + check: string[], commentCharCode: number, - propertyCharCode: number + propertyCharCode: number, + elementCharCode: number } function State(data: string, runtimeCtx: RuntimeContext, opts: PlyOptions): State { @@ -50,14 +67,26 @@ function State(data: string, runtimeCtx: RuntimeContext, opts: PlyOptions): Stat tokens: [], fieldCount: 0, - recordCount: 0, columnCount: 0, + propertyCount: 0, + vertexCount: 0, + currentVertex: 0, + currentProperty: 0, + currentFace: 0, + currentFaceElement: 0, + faceCount: 0, + endHeader: 0, + initialHead: [], + properties: [], + faces: [], propertyNames: [], + check: [], commentCharCode: opts.comment.charCodeAt(0), - propertyCharCode: opts.property.charCodeAt(0) + propertyCharCode: opts.property.charCodeAt(0), + elementCharCode: opts.element.charCodeAt(0) }; } @@ -75,7 +104,7 @@ function eatValue(state: Tokenizer) { case 13: // \r return true; case 32: // ' ' Delimeter of ply is space (Unicode 32) - return; + return true; case 9: // \t case 32: // ' ' break; @@ -86,37 +115,25 @@ function eatValue(state: Tokenizer) { } } - - -function skipWhitespace(state: Tokenizer) { - let prev = -1; +function eatLine (state: Tokenizer) { while (state.position < state.length) { const c = state.data.charCodeAt(state.position); + ++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; + return true; + case 9: // \t break; default: - return; + ++state.tokenEnd; + break; } } + } + function skipLine(state: Tokenizer) { while (state.position < state.length) { const c = state.data.charCodeAt(state.position); @@ -125,13 +142,20 @@ function skipLine(state: Tokenizer) { } } +function getColumns(state: State, NumberofColumns: number){ + eatLine(state.tokenizer); + let tmp = (Tokenizer.getTokenString(state.tokenizer)) + let split = tmp.split(" ", NumberofColumns); + return split; +} + + /** * 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; @@ -146,12 +170,45 @@ function moveNextInternal(state: State) { state.tokenType = PlyTokenType.Comment; skipLine(tokenizer); break; - case state.propertyCharCode: - state.tokenType = PlyTokenType.property; - //return eatProperty(tokenizer); - default: + case state.propertyCharCode: // checks all line beginning with 'p' + state.check = getColumns(state,3); + if(state.check[0] !== 'ply' && state.faceCount === 0){ + state.propertyNames.push(state.check[1]); + state.propertyNames.push(state.check[2]); + state.propertyCount++; + } + return; + case state.elementCharCode: // checks all line beginning with 'e' + state.check = getColumns(state, 3); + if(state.check[1] === 'vertex') state.vertexCount= Number(state.check[2]); + if(state.check[1] === 'face') state.faceCount = Number(state.check[2]); + if(state.check[0] === 'end_header') state.endHeader = 1; + return; + default: // for all the other lines state.tokenType = PlyTokenType.Value; - return eatValue(tokenizer); + let return_value = eatValue(tokenizer); + + if(state.endHeader === 1) + { + if(state.currentVertex < state.vertexCount){ + state.properties[state.currentVertex * state.propertyCount + state.currentProperty] = Number(Tokenizer.getTokenString(state.tokenizer)); + state.currentProperty++; + if(state.currentProperty === state.propertyCount){ + state.currentProperty = 0; + state.currentVertex++; + } + return return_value; + } + if(state.currentFace < state.faceCount && state.currentVertex === state.vertexCount){ + state.faces[state.currentFace * 4 + state.currentFaceElement] = Number(Tokenizer.getTokenString(state.tokenizer)); + state.currentFaceElement++; + if(state.currentProperty === 4){ + state.currentFaceElement = 0; + state.currentFace++; + } + } + } + return return_value; } } @@ -161,25 +218,24 @@ function moveNextInternal(state: State) { */ function moveNext(state: State) { let newRecord = moveNextInternal(state); - while (state.tokenType === PlyTokenType.Comment) { // skip comment lines (marco + 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 - + moveNext(state); 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 + moveNext(state); ++counter; } return counter; @@ -190,24 +246,26 @@ function readRecordsChunks(state: State) { (ctx, state) => ctx.update({ message: 'Parsing...', current: state.tokenizer.position, max: state.data.length })); } -function addColumn (state: State) { +function addHeadEntry (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) + + +function init(state: State) { // only for first two lines to get the format and the coding! (marco) let newRecord = moveNext(state) while (!newRecord) { // newRecord is only true when a newline occurs (marco) - addColumn(state) + addHeadEntry(state) newRecord = moveNext(state); } - addColumn(state) + addHeadEntry(state) newRecord = moveNext(state); while (!newRecord) { - addColumn(state) + addHeadEntry(state) newRecord = moveNext(state); } - addColumn(state) + addHeadEntry(state) if(state.initialHead[0] !== 'ply'){ console.log("ERROR: this is not a .ply file!") throw new Error("this is not a .ply file!"); @@ -229,13 +287,7 @@ async function handleRecords(state: State): Promise<Data.ply_form> { } 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) + return Data.PlyStructure(state.vertexCount, state.faceCount, state.propertyCount, state.initialHead, state.propertyNames, state.properties, state.faces) } async function parseInternal(data: string, ctx: RuntimeContext, opts: PlyOptions): Promise<Result<Data.PlyFile>> { @@ -243,7 +295,7 @@ async function parseInternal(data: string, ctx: RuntimeContext, opts: PlyOptions ctx.update({ message: 'Parsing...', current: 0, max: data.length }); const table = await handleRecords(state) - const result = Data.CsvFile(table) + const result = Data.PlyFile(table) console.log(result); return Result.success(result); } @@ -251,10 +303,11 @@ async function parseInternal(data: string, ctx: RuntimeContext, opts: PlyOptions interface PlyOptions { comment: string; property: string; + element: string; } export function parse(data: string, opts?: Partial<PlyOptions>) { - const completeOpts = Object.assign({}, { comment: 'c', property: 'p' }, opts) + const completeOpts = Object.assign({}, { comment: 'c', property: 'p', element: 'e' }, opts) return Task.create<Result<Data.PlyFile>>('Parse PLY', async ctx => { return await parseInternal(data, ctx, completeOpts); }); diff --git a/src/mol-io/reader/ply/read_data/data.ts b/src/mol-io/reader/ply/read_data/data.ts index 699353a18..6e0be3ad2 100644 --- a/src/mol-io/reader/ply/read_data/data.ts +++ b/src/mol-io/reader/ply/read_data/data.ts @@ -46,7 +46,7 @@ export { ParsePLY } type ParsePLY = typeof ParsePLY const ParsePLY = PluginStateTransform.BuiltIn({ name: 'parse-ply', - display: { name: 'Parse PLY', description: 'Parse OLY from String' }, + display: { name: 'Parse PLY', description: 'Parse PLY from String' }, from: [SO.Data.String], to: SO.Format.Ply })({ diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 0dd4d57aa..31f8ee47f 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -14,6 +14,7 @@ import { PluginStateObject } from '../objects'; import { StateTransforms } from '../transforms'; import { Download } from '../transforms/data'; import { StructureRepresentation3DHelpers } from '../transforms/representation'; +import * as data_functions from "mol-io/reader/ply//read_data/data" // TODO: "structure parser provider" @@ -84,7 +85,7 @@ 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, -- GitLab