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