Skip to content
Snippets Groups Projects
Unverified Commit 94d95b02 authored by MarcoSchaeferT's avatar MarcoSchaeferT Committed by GitHub
Browse files

Merge pull request #1 from molstar/ply-test-asr

added ShapeProvider and hooked it up in plugin
parents 1efac6d2 6ce4176d
No related branches found
No related tags found
No related merge requests found
......@@ -4,23 +4,11 @@
* @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 Result from '../../result'
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';
import {Task, RuntimeContext, chunkedSubtask } from 'mol-task'
const enum PlyTokenType {
Value = 0,
......@@ -289,13 +277,13 @@ function init(state: State) { // only for first two lines to get the format and
}
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!");
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!");
console.log('ERROR: only ASCII-DECODING is supported!');
throw new Error('only ASCII-DECODING is supported!');
return 0;
}
state.columnCount = state.initialHead.length
......@@ -304,8 +292,8 @@ function init(state: State) { // only for first two lines to get the format and
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!");
console.log('ERROR: parsing file (PLY) failed!')
throw new Error('arsing file (PLY) failed!');
}
await readRecordsChunks(state)
......@@ -322,8 +310,8 @@ async function parseInternal(data: string, ctx: RuntimeContext, opts: PlyOptions
// 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);
// 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);
......
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 {ply_form, PlyFile} from '../../../../mol-io/reader/ply/parse_data/data-model';
import {RuntimeContext, Task} 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 { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
import {Vec3} from '../../../../mol-math/linear-algebra/3d';
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
})
import { ShapeProvider } from 'mol-model/shape/provider';
export interface MyData {
centers: number[],
colors: string[],
colors: Color[],
labels: string[],
transforms: number[]
}
let data:MyData = {
centers: [],
function collectData_for_Shape(parsedData: ply_form): MyData {
// parsedData.data.PLY_File. to access So.format.Ply
console.log('parsedData', parsedData)
const { vertices, colors } = parsedData
const data: MyData = {
centers: vertices,
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.colors[i] = Color.fromRgb(colors[i*3+0], colors[i*3+1], colors[i*3+2]);
data.labels[i] = '';
data.transforms[i] = 0;
}
console.log(data);
console.log('data', 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}` })
if (i % 10000 === 0 && 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)
addSphere(builderState, Vec3.fromArray(v, centers, i * 3), 0.2, 1)
}
let a = MeshBuilder.getMesh(builderState);
// console.log(a);
......@@ -109,35 +51,32 @@ function rgbToHex(r, g, b) {
export async function getShape(ctx: RuntimeContext, parsedData: ply_form, props: {}, shape?: Shape<Mesh>) {
let data:MyData;
data = collectData_for_Shape(parsedData)
const 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
(groupId: 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)
export const PlyShapeParams = {
...Mesh.Params
}
export type PlyShapeParams = typeof PlyShapeParams
export function shapeFromPly(source: PlyFile, params?: {}) {
return Task.create<ShapeProvider<ply_form, Mesh, PlyShapeParams>>('Parse Shape Data', async ctx => {
console.log('source', source)
return {
label: 'Mesh',
data: source.PLY_File,
getShape,
geometryUtils: Mesh.Utils
}
})
}
\ No newline at end of file
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
import { ShapeGetter } from 'mol-repr/shape/representation';
import { Geometry, GeometryUtils } from 'mol-geo/geometry/geometry';
export interface ShapeProvider<D, G extends Geometry, P extends Geometry.Params<G>> {
label: string
data: D
getShape: ShapeGetter<D, G, P>
geometryUtils: GeometryUtils<G>
}
\ No newline at end of file
......@@ -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, PLYtest} from './state/actions/basic';
import {DownloadStructure, CreateComplexRepresentation, OpenStructure, OpenPlyFile} from './state/actions/basic';
import { StateTransforms } from './state/transforms';
import { PluginBehaviors } from './behavior';
......@@ -24,7 +24,7 @@ const DefaultSpec: PluginSpec = {
actions: [
PluginSpec.Action(DownloadStructure),
PluginSpec.Action(OpenStructure),
PluginSpec.Action(PLYtest),
PluginSpec.Action(OpenPlyFile),
PluginSpec.Action(CreateComplexRepresentation),
PluginSpec.Action(StateTransforms.Data.Download),
PluginSpec.Action(StateTransforms.Data.ParseCif),
......
......@@ -14,9 +14,6 @@ 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"
......@@ -88,25 +85,20 @@ export const OpenStructure = StateAction.build({
return state.update(createStructureTree(ctx, data, false));
});
export const PLYtest = StateAction.build({
display: { name: 'PLY Test', description: 'nothing ply' },
export const OpenPlyFile = StateAction.build({
display: { name: 'Open PLY file', description: 'Load a PLY file' },
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 });
let tmp = state.update(getPLYdata(ctx, data));
return tmp ;
const data = b.toRoot()
.apply(StateTransforms.Data.ReadFile, { file: params.file, isBinary: false })
.apply(StateTransforms.Data.ParsePly)
.apply(StateTransforms.Model.ShapeFromPly)
.apply(StateTransforms.Representation.ShapeRepresentation3D)
return state.update(data.getTree());
});
function getPLYdata(ctx: PluginContext, b: StateTreeBuilder.To<PluginStateObject.Data.String>, ): StateTree {
let root = b.apply(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)
......
......@@ -13,6 +13,9 @@ import { Representation } from 'mol-repr/representation';
import { StructureRepresentation } from 'mol-repr/structure/representation';
import { VolumeRepresentation } from 'mol-repr/volume/representation';
import { StateObject, Transformer } from 'mol-state';
import { ShapeRepresentation } from 'mol-repr/shape/representation';
import { Shape as _Shape } from 'mol-model/shape';
import { ShapeProvider } from 'mol-model/shape/provider';
export type TypeClass = 'root' | 'data' | 'prop'
......@@ -71,6 +74,11 @@ export namespace PluginStateObject {
export class Data extends Create<VolumeData>({ name: 'Volume Data', typeClass: 'Object' }) { }
export class Representation3D extends CreateRepresentation3D<VolumeRepresentation<any>>({ name: 'Volume 3D' }) { }
}
export namespace Shape {
export class Provider extends Create<ShapeProvider<any, any, any>>({ name: 'Shape Provider', typeClass: 'Object' }) { }
export class Representation3D extends CreateRepresentation3D<ShapeRepresentation<any, any, any>>({ name: 'Shape 3D' }) { }
}
}
export namespace PluginStateTransform {
......
......@@ -12,6 +12,7 @@ import { PluginContext } from 'mol-plugin/context';
import { ParamDefinition as PD } from 'mol-util/param-definition';
import { Transformer } from 'mol-state';
import { readFromFile } from 'mol-util/data-source';
import * as PLY from 'mol-io/reader/ply/parse_data/ply_parser'
export { Download }
type Download = typeof Download
......@@ -91,3 +92,20 @@ const ParseCif = PluginStateTransform.BuiltIn({
});
}
});
export { ParsePly }
type ParsePly = typeof ParsePly
const ParsePly = PluginStateTransform.BuiltIn({
name: 'parse-ply',
display: { name: 'Parse PLY', description: 'Parse PLY from Binary data' },
from: [SO.Data.String],
to: SO.Format.Ply
})({
apply({ a }) {
return Task.create('Parse PLY', async ctx => {
const parsed = await PLY.parse(a.data).runInContext(ctx);
if (parsed.isError) throw new Error(parsed.message);
return new SO.Format.Ply(parsed.result, { label: parsed.result.name || 'PLY Data' });
});
}
});
\ No newline at end of file
......@@ -15,6 +15,7 @@ import { MolScriptBuilder } from 'mol-script/language/builder';
import { StateObject } from 'mol-state';
import { PluginContext } from 'mol-plugin/context';
import { stringToWords } from 'mol-util/string';
import { shapeFromPly } from 'mol-model/shape/formarts/ply/plyData_to_shape';
export { TrajectoryFromMmCif }
type TrajectoryFromMmCif = typeof TrajectoryFromMmCif
......@@ -191,3 +192,23 @@ async function attachProps(model: Model, ctx: PluginContext, taskCtx: RuntimeCon
await p.attach(model).runInContext(taskCtx);
}
}
export { ShapeFromPly }
type ShapeFromPly = typeof ShapeFromPly
const ShapeFromPly = PluginStateTransform.BuiltIn({
name: 'shape-from-ply',
display: { name: 'Shape from PLY', description: 'Create Shape from PLY data' },
from: SO.Format.Ply,
to: SO.Shape.Provider,
params(a) {
return { };
}
})({
apply({ a, params }) {
return Task.create('Create shape from PLY', async ctx => {
const shape = await shapeFromPly(a.data, params).runInContext(ctx)
const props = { label: 'Shape' };
return new SO.Shape.Provider(shape, props);
});
}
});
\ No newline at end of file
......@@ -15,6 +15,7 @@ import { createTheme } from 'mol-theme/theme';
import { BuiltInStructureRepresentationsName } from 'mol-repr/structure/registry';
import { Structure } from 'mol-model/structure';
import { StructureParams } from 'mol-repr/structure/representation';
import { ShapeRepresentation } from 'mol-repr/shape/representation';
export namespace StructureRepresentation3DHelpers {
export function getDefaultParams(ctx: PluginContext, name: BuiltInStructureRepresentationsName, structure: Structure, structureParams?: Partial<PD.Values<StructureParams>>): Transformer.Params<StructureRepresentation3D> {
......@@ -96,3 +97,25 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({
});
}
});
export { ShapeRepresentation3D }
type ShapeRepresentation3D = typeof ShapeRepresentation3D
const ShapeRepresentation3D = PluginStateTransform.BuiltIn({
name: 'shape-representation-3d',
display: '3D Representation',
from: SO.Shape.Provider,
to: SO.Shape.Representation3D,
params: (a, ctx: PluginContext) => {
return { }
}
})({
apply({ a, params }, plugin: PluginContext) {
return Task.create('Shape Representation', async ctx => {
const props = { ...PD.getDefaultValues(a.data.geometryUtils.Params), params }
const repr = ShapeRepresentation(a.data.getShape, a.data.geometryUtils)
// TODO set initial state, repr.setState({})
await repr.createOrUpdate(props, a.data.data).runInContext(ctx);
return new SO.Shape.Representation3D(repr, { label: a.data.label });
});
}
});
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment