From a80088ec0f0fa6d89a4eecbcae21806408424ed3 Mon Sep 17 00:00:00 2001 From: MarcoSchaeferT <schaefer.marco.ms@web.de> Date: Wed, 20 Feb 2019 09:51:46 +0100 Subject: [PATCH] parser is working + try to get mesh/shape --- .../reader/ply/parse_data/data-model.ts | 7 +- src/mol-io/reader/ply/parse_data/field.ts | 9 -- .../reader/ply/parse_data/ply_parser.ts | 41 ++++- .../shape/formarts/ply/plyData_to_shape.ts | 143 ++++++++++++++++++ src/mol-plugin/state/actions/basic.ts | 12 +- src/tests/browser/index.html | 51 ++++--- src/tests/browser/render-shape.ts | 2 +- 7 files changed, 219 insertions(+), 46 deletions(-) delete mode 100644 src/mol-io/reader/ply/parse_data/field.ts create mode 100644 src/mol-model/shape/formarts/ply/plyData_to_shape.ts 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 36fdb6b1a..e02c061bb 100644 --- a/src/mol-io/reader/ply/parse_data/data-model.ts +++ b/src/mol-io/reader/ply/parse_data/data-model.ts @@ -24,11 +24,14 @@ export interface ply_form { readonly initialHead: ReadonlyArray<string>, readonly propertyNames: ReadonlyArray<string>, readonly properties: number[], + readonly vertices: number[], + readonly colors: number[], + readonly normals: number[], readonly faces: number[], } -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 function PlyStructure(vertexCount: number, faceCount: number, propertyCount: number, initialHead: string[], propertyNames: string[], properties: number[], vertices: number[], colors: number[], normals: number[], faces: number[]): ply_form { + return {vertexCount, faceCount, propertyCount, initialHead: [...initialHead], propertyNames: [...propertyNames], properties: [...properties], vertices: [...vertices], colors: [...colors], normals: [...normals], faces: [...faces]}; } export type PlyColumns = { [name: string]: PlyColumn } diff --git a/src/mol-io/reader/ply/parse_data/field.ts b/src/mol-io/reader/ply/parse_data/field.ts deleted file mode 100644 index a86e45353..000000000 --- a/src/mol-io/reader/ply/parse_data/field.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * 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 index d2a42e49a..6729c87db 100644 --- a/src/mol-io/reader/ply/parse_data/ply_parser.ts +++ b/src/mol-io/reader/ply/parse_data/ply_parser.ts @@ -9,8 +9,15 @@ import { Tokens, TokenBuilder, Tokenizer } from '../../common/text/tokenizer' import * as Data from './data-model' import Result from '../../result' -import { Task, RuntimeContext, chunkedSubtask, } from 'mol-task' - +import {Task, RuntimeContext, chunkedSubtask, Progress,} from 'mol-task' +import * as plyToShape from 'mol-model/shape/formarts/ply/plyData_to_shape' +import {MyData} from 'mol-model/shape/formarts/ply/plyData_to_shape'; +import {Mesh} from '../../../../mol-geo/geometry/mesh/mesh'; +import {ParamDefinition} from '../../../../mol-util/param-definition'; +import Color = ParamDefinition.Color; +import {ColorNames} from '../../../../mol-util/color/tables'; +import {ShapeRepresentation} from '../../../../mol-repr/shape/representation'; +//import {init2} from '../../../../tests/browser/render-shape'; @@ -46,6 +53,9 @@ interface State { initialHead: string[], properties: number[], + vertices: number[], + colors: number[], + normals: number[], faces: number[], propertyNames: string[], check: string[], @@ -80,6 +90,9 @@ function State(data: string, runtimeCtx: RuntimeContext, opts: PlyOptions): Stat initialHead: [], properties: [], + vertices: [], + colors: [], + normals:[], faces: [], propertyNames: [], check: [], @@ -192,6 +205,15 @@ function moveNextInternal(state: State) { { if(state.currentVertex < state.vertexCount){ state.properties[state.currentVertex * state.propertyCount + state.currentProperty] = Number(Tokenizer.getTokenString(state.tokenizer)); + if(state.currentProperty < 3){ + state.vertices[state.currentVertex * 3 + state.currentProperty] = Number(Tokenizer.getTokenString(state.tokenizer)); + } + if(state.currentProperty >= 3 && state.currentProperty <6){ + state.colors[state.currentVertex * 3 + state.currentProperty-3] = Number(Tokenizer.getTokenString(state.tokenizer)); + } + if(state.currentProperty >= 6 && state.currentProperty <9){ + state.normals[state.currentVertex * 3 + state.currentProperty-6] = Number(Tokenizer.getTokenString(state.tokenizer)); + } state.currentProperty++; if(state.currentProperty === state.propertyCount){ state.currentProperty = 0; @@ -287,16 +309,25 @@ async function handleRecords(state: State): Promise<Data.ply_form> { } await readRecordsChunks(state) - return Data.PlyStructure(state.vertexCount, state.faceCount, state.propertyCount, state.initialHead, state.propertyNames, state.properties, state.faces) + return Data.PlyStructure(state.vertexCount, state.faceCount, state.propertyCount, state.initialHead, state.propertyNames, state.properties, state.vertices, state.colors, state.normals, state.faces) } 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.PlyFile(table) + const PLYdata = await handleRecords(state) + const result = Data.PlyFile(PLYdata) console.log(result); + + // let Data_for_Shape = plyToShape.collectData_for_Shape(table, datas); + //console.log(plyToShape.getShape(state.runtimeCtx, table)); + let shape = plyToShape.init_ren(PLYdata); + console.log("shape"+shape); + const script = document.createElement('script'); + script.src = "../../build/src/mol-model/shape/formarts/ply/plyData_to_shape.js"; + document.body.appendChild(script); + return Result.success(result); } diff --git a/src/mol-model/shape/formarts/ply/plyData_to_shape.ts b/src/mol-model/shape/formarts/ply/plyData_to_shape.ts new file mode 100644 index 000000000..f0d56c015 --- /dev/null +++ b/src/mol-model/shape/formarts/ply/plyData_to_shape.ts @@ -0,0 +1,143 @@ +import {ply_form} from '../../../../mol-io/reader/ply/parse_data/data-model'; +import {MyData} from '../../../../../build/src/mol-model/shape/formarts/ply/plyData_to_shape'; +import {Progress, RuntimeContext} from 'mol-task'; +import {Mesh} from '../../../../mol-geo/geometry/mesh/mesh'; +import {MeshBuilder} from '../../../../mol-geo/geometry/mesh/mesh-builder'; +import {Mat4, Vec3} from '../../../../mol-math/linear-algebra/3d'; +import {Sphere} from '../../../../mol-geo/primitive/sphere'; +import {Shape} from '../../shape'; +import {Color} from '../../../../mol-util/color'; +import {Canvas3D} from '../../../../mol-canvas3d/canvas3d'; +import {labelFirst} from '../../../../mol-theme/label'; +import {ColorNames} from '../../../../mol-util/color/tables'; +import {ShapeRepresentation} from '../../../../mol-repr/shape/representation'; + + +const parent = document.getElementById('app')! +parent.style.width = '100%' +parent.style.height = '100%' + +const canvas = document.createElement('canvas') +canvas.style.width = '100%' +canvas.style.height = '100%' +parent.appendChild(canvas) + +const info = document.createElement('div') +info.style.position = 'absolute' +info.style.fontFamily = 'sans-serif' +info.style.fontSize = '24pt' +info.style.bottom = '20px' +info.style.right = '20px' +info.style.color = 'white' +parent.appendChild(info) + +const canvas3d = Canvas3D.create(canvas, parent) +canvas3d.animate() +canvas3d.input.move.subscribe(async ({x, y}) => { + const pickingId = await canvas3d.identify(x, y) + let label = '' + if (pickingId) { + const { loci } = canvas3d.getLoci(pickingId) + label = labelFirst(loci) + } + info.innerText = label +}) + + + + +export interface MyData { + centers: number[], + colors: string[], + labels: string[], + transforms: number[] +} + +let data:MyData = { + centers: [], + colors: [], + labels: [], + transforms:[] +} + + +function componentToHex(c) { + let hex = c.toString(16); + return hex.length == 1 ? "0" + hex : hex; +} + +function rgbToHex(r, g, b) { + return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); +} + + function collectData_for_Shape(parsedData: ply_form):{centers: number[], colors: string[], labels: string[], transforms: number[]}{ + // parsedData.data.PLY_File. to access So.format.Ply + + data.centers = parsedData.vertices; + let hexColor; + + for(let i=0; i<parsedData.vertexCount; i++){ + hexColor = rgbToHex(parsedData.colors[i*3+0],parsedData.colors[i*3+1],parsedData.colors[i*3+2]); + data.colors[i] = hexColor; + data.labels[i] = ''; + data.transforms[i] = 0; + } + console.log(data); + return data; +} + + + + + 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(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)` + await ctx.update({ current: i, max: il, message: `adding sphere ${i}` }) + builderState.currentGroup = i + Mat4.setTranslation(t, Vec3.fromArray(v, centers, i * 3)) + MeshBuilder.addPrimitive(builderState, t, sphere) + } + let a = MeshBuilder.getMesh(builderState); + //console.log(a); + return a +} + + +export async function getShape(ctx: RuntimeContext, parsedData: ply_form, props: {}, shape?: Shape<Mesh>) { + let data:MyData; + data = collectData_for_Shape(parsedData) + await ctx.update('async creation of shape from myData') + const { centers , colors, labels} = data + const mesh = await getSphereMesh(ctx, centers, shape && shape.geometry) + const groupCount = centers.length / 3 + return shape || Shape.create( + 'test', mesh, + (groupId: number) => Color(Number(colors[groupId])), // color: per group, same for instances + () => 1, // size: constant + (groupId: number, instanceId: number) => labels[instanceId * groupCount + groupId] // label: per group and instance + ) +} + +const repr = ShapeRepresentation(getShape, Mesh.Utils) + +export async function init_ren(myData : ply_form) { + // Create shape from myData and add to canvas3d + await repr.createOrUpdate({}, myData).run((p: Progress) => console.log(Progress.format(p))) + canvas3d.add(repr) + canvas3d.resetCamera() + + // Change color after 1s + setTimeout(async () => { + myData.colors[0] = ColorNames.darkmagenta + // Calling `createOrUpdate` with `data` will trigger color and transform update + await repr.createOrUpdate({}, myData).run() + }, 1000) +} + + + diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 31f8ee47f..910e614ff 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -14,7 +14,9 @@ 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" +import * as data_functions from 'mol-io/reader/ply/read_data/data' + + // TODO: "structure parser provider" @@ -86,6 +88,7 @@ export const OpenStructure = StateAction.build({ return state.update(createStructureTree(ctx, data, false)); }); + export const PLYtest = StateAction.build({ display: { name: 'PLY Test', description: 'nothing ply' }, from: PluginStateObject.Root, @@ -93,13 +96,12 @@ export const PLYtest = StateAction.build({ })(({ 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)); + let tmp = state.update(getPLYdata(ctx, data)); + return tmp ; }); function getPLYdata(ctx: PluginContext, b: StateTreeBuilder.To<PluginStateObject.Data.String>, ): StateTree { - let root = b - .apply(data_functions.ParsePLY); - console.log(data_functions.ParsePLY); + let root = b.apply(data_functions.ParsePLY); return root.getTree(); } diff --git a/src/tests/browser/index.html b/src/tests/browser/index.html index 5a0851f57..856790048 100644 --- a/src/tests/browser/index.html +++ b/src/tests/browser/index.html @@ -1,39 +1,42 @@ <!DOCTYPE html> <html lang="en"> - <head> +<head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <title>Mol* Browser Test</title> <style> - * { - margin: 0; - padding: 0; - box-sizing: border-box; - } - html, body { - width: 100%; - height: 100%; - overflow: hidden; - } + * { + margin: 0; + padding: 0; + box-sizing: border-box; + } + html, body { + width: 100%; + height: 100%; + overflow: hidden; + } </style> - </head> - <body> - <div id="app"></div> - <script type="text/javascript"> - function urlQueryParameter (id) { +</head> +<body> +<div id="app"></div> +<script type="text/javascript"> + function urlQueryParameter (id) { if (typeof window === 'undefined') return undefined const a = new RegExp(`${id}=([^&#=]*)`) const m = a.exec(window.location.search) return m ? decodeURIComponent(m[1]) : undefined - } - - const name = urlQueryParameter('name') - if (name) { + } + const name = urlQueryParameter('name') + if (name) { const script = document.createElement('script') script.src = name + '.js' document.body.appendChild(script) - } - </script> - <script type="text/javascript" src="./render-shape.js"></script> - </body> + } +</script> +<script type="text/javascript" > + const script = document.createElement('script'); + script.src = "render-shape.js"; + document.body.appendChild(script); +</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 8020d57fd..5f0de8e1f 100644 --- a/src/tests/browser/render-shape.ts +++ b/src/tests/browser/render-shape.ts @@ -18,6 +18,7 @@ import { RuntimeContext, Progress } from 'mol-task'; + const parent = document.getElementById('app')! parent.style.width = '100%' parent.style.height = '100%' @@ -101,7 +102,6 @@ const repr = ShapeRepresentation(getShape, Mesh.Utils) 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) canvas3d.add(repr) canvas3d.resetCamera() -- GitLab