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 e36ae7af9ce505faf9b6a0c6e8505f45fa3ad104..9f126bc0328162e9cf8abcda76ac2addc6fdc117 100644 --- a/src/mol-io/reader/ply/parse_data/ply_parser.ts +++ b/src/mol-io/reader/ply/parse_data/ply_parser.ts @@ -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, @@ -92,7 +80,7 @@ function State(data: string, runtimeCtx: RuntimeContext, opts: PlyOptions): Stat properties: [], vertices: [], colors: [], - normals:[], + normals: [], faces: [], propertyNames: [], check: [], @@ -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) @@ -320,13 +308,13 @@ async function parseInternal(data: string, ctx: RuntimeContext, opts: PlyOptions 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); + // 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 index f0d56c015168e34023fdcdbdfa697c8f4939fa77..bcc3e37a66d9cde09e9a22ae5e1a8b171a75f4b4 100644 --- a/src/mol-model/shape/formarts/ply/plyData_to_shape.ts +++ b/src/mol-model/shape/formarts/ply/plyData_to_shape.ts @@ -1,143 +1,82 @@ -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: [], - 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[]}{ +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: [] + } - 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; + for (let i = 0; i<parsedData.vertexCount; i++) { + 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) { +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); + // 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) + const data = collectData_for_Shape(parsedData) await ctx.update('async creation of shape from myData') - const { centers , colors, labels} = data + 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 diff --git a/src/mol-model/shape/provider.ts b/src/mol-model/shape/provider.ts new file mode 100644 index 0000000000000000000000000000000000000000..2cd0950dbce113c2a05de7bcf7d9b93c6fdf234c --- /dev/null +++ b/src/mol-model/shape/provider.ts @@ -0,0 +1,15 @@ +/** + * 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 diff --git a/src/mol-plugin/index.ts b/src/mol-plugin/index.ts index 68991f6a73a77ef5594f68c76154f05f24345b07..c645fe4f75ffe9afe6a2e44f8669bde598b20449 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, 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), diff --git a/src/mol-plugin/state/actions/basic.ts b/src/mol-plugin/state/actions/basic.ts index 910e614ff571ceacf7949ee60804109259441366..969473511681136adce73d85d5e3a4f69869314e 100644 --- a/src/mol-plugin/state/actions/basic.ts +++ b/src/mol-plugin/state/actions/basic.ts @@ -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) diff --git a/src/mol-plugin/state/objects.ts b/src/mol-plugin/state/objects.ts index 07cf4afaae19415afee2511cae08cac89143bcbb..1ff541cc0613fe20841191b2a4dd75cc1aaba683 100644 --- a/src/mol-plugin/state/objects.ts +++ b/src/mol-plugin/state/objects.ts @@ -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 { diff --git a/src/mol-plugin/state/transforms/data.ts b/src/mol-plugin/state/transforms/data.ts index eadc8593ca08bdf20a19754fd709b73c6873f4bf..4f9e663a06c1979887baf909070bc5e219af1486 100644 --- a/src/mol-plugin/state/transforms/data.ts +++ b/src/mol-plugin/state/transforms/data.ts @@ -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 diff --git a/src/mol-plugin/state/transforms/model.ts b/src/mol-plugin/state/transforms/model.ts index 51c5cfc6da08f2c10523aae1d5ddb8ebbd2f9f75..54434b2e50d606df8caae1096df38cc08fdeda22 100644 --- a/src/mol-plugin/state/transforms/model.ts +++ b/src/mol-plugin/state/transforms/model.ts @@ -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 @@ -190,4 +191,24 @@ async function attachProps(model: Model, ctx: PluginContext, taskCtx: RuntimeCon const p = ctx.customModelProperties.get(name); await p.attach(model).runInContext(taskCtx); } -} \ No newline at end of file +} + +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 diff --git a/src/mol-plugin/state/transforms/representation.ts b/src/mol-plugin/state/transforms/representation.ts index 942816e5e0463b49aef7da8014af37a51ca69958..eef2b6d671de1d810c72fe26dada2309d4971817 100644 --- a/src/mol-plugin/state/transforms/representation.ts +++ b/src/mol-plugin/state/transforms/representation.ts @@ -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> { @@ -95,4 +96,26 @@ const StructureRepresentation3D = PluginStateTransform.BuiltIn({ return Transformer.UpdateResult.Updated; }); } +}); + +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 diff --git a/src/mol-repr/measurements/representation.ts b/src/mol-repr/measurements/representation.ts new file mode 100644 index 0000000000000000000000000000000000000000..86bfef9b924e9ee472c9733de63950ecd85e266d --- /dev/null +++ b/src/mol-repr/measurements/representation.ts @@ -0,0 +1,207 @@ +// /** +// * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. +// * +// * @author Alexander Rose <alexander.rose@weirdbyte.de> +// */ + +// import { ParamDefinition as PD } from 'mol-util/param-definition'; +// import { Loci as _Loci, EmptyLoci } from 'mol-model/loci'; +// import { Vec3 } from 'mol-math/linear-algebra'; +// import { Mesh } from 'mol-geo/geometry/mesh/mesh'; +// import { Representation, RepresentationContext } from 'mol-repr/representation'; +// import { Subject } from 'rxjs'; +// import { RenderObject, MeshRenderObject, createMeshRenderObject } from 'mol-gl/render-object'; +// import { createEmptyTheme } from 'mol-theme/theme'; +// import { LocationIterator } from 'mol-geo/util/location-iterator'; +// import { Task } from 'mol-task'; +// import { Geometry } from 'mol-geo/geometry/geometry'; +// import { createIdentityTransform } from 'mol-geo/geometry/transform-data'; +// import { PickingId } from 'mol-geo/geometry/picking'; +// import { MarkerAction } from 'mol-geo/geometry/marker-data'; +// import { Lines } from 'mol-geo/geometry/lines/lines'; +// import { Text } from 'mol-geo/geometry/text/text'; +// import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder'; +// import { LinesBuilder } from 'mol-geo/geometry/lines/lines-builder'; +// import { TextBuilder } from 'mol-geo/geometry/text/text-builder'; + + + +// export interface Measurements { +// readonly inputs: Measurements.Inputs +// } + +// export namespace Measurements { +// export interface Loci { +// readonly kind: 'measurements-loci', +// readonly data: any, +// readonly tag: string +// readonly indices: OrderedSet<number> +// } + +// export interface DistanceInput { +// kind: 'distance-input' +// lociA: _Loci, +// lociB: _Loci +// } +// export function createDistanceInput(lociA: _Loci, lociB: _Loci): DistanceInput { +// return { kind: 'distance-input', lociA, lociB } +// } + +// export interface AngleInput { +// kind: 'angle-input' +// lociA: _Loci, +// lociB: _Loci, +// lociC: _Loci +// } + +// export interface DihedralInput { +// kind: 'dihedral-input' +// lociA: _Loci, +// lociB: _Loci, +// lociC: _Loci, +// lociD: _Loci +// } + +// // export type MeasurementInput = [Vec3, Vec3] | [Vec3, Vec3, Vec3] | [Vec3, Vec3, Vec3, Vec3] +// export type Input = DistanceInput | AngleInput | DihedralInput +// export type Inputs = Input[] +// } + +// // const measureVecA = Vec3.zero() +// // const measureVecB = Vec3.zero() +// // export function measure(input: MeasurementInput): number | null { +// // switch (input.length) { +// // case 2: return Vec3.distance(input[0], input[1]) +// // case 3: return Vec3.angle(Vec3.sub(measureVecA, input[1], input[0]), Vec3.sub(measureVecB, input[2], input[1])) +// // default: +// // // TODO +// // return null +// // } +// // } + +// // + +// export interface MeasurementsMeshProps { +// detail: number, +// sizeFactor: number +// } + +// interface MeasurementsGeometries { mesh?: Mesh, lines?: Lines, text?: Text } + +// export function createMeasurementsGeometries(inputs: Measurements.Inputs, props: MeasurementsMeshProps, geometries: MeasurementsGeometries): MeasurementsGeometries { +// const { mesh, lines, text } = geometries +// const { detail, sizeFactor } = props + +// const vertexCount = inputs.length * 10 +// const meshBuilderState = MeshBuilder.createState(vertexCount, vertexCount / 2, mesh) +// const linesBuilder = LinesBuilder.create(vertexCount, vertexCount / 2, lines) +// const textBuilder = TextBuilder.create(props, vertexCount, vertexCount / 2, text) + +// const vA = Vec3.zero() +// const vB = Vec3.zero() +// const vC = Vec3.zero() +// const vD = Vec3.zero() + +// for (let i = 0, il = inputs.length; i < il; i++) { +// const input = inputs[i] +// if (input.lociA) Loci.getCenter(input.lociA, vA) + +// meshBuilderState.currentGroup = i +// linesBuilder.add() +// } + +// return { +// mesh: MeshBuilder.getMesh(meshBuilderState), +// lines: linesBuilder.getLines(), +// text: textBuilder.getText() +// } +// } + +// // + +// export interface MeasurementsRepresentation<P extends MeasurementsParams> extends Representation<MeasurementInputs, P> { } + +// export const MeasurementsParams = { +// ...Mesh.Params, +// } +// export type MeasurementsParams = typeof MeasurementsParams + +// export function MeasuresRepresentation<P extends MeasurementsParams>(ctx: RepresentationContext): MeasurementsRepresentation<P> { +// let version = 0 +// const updated = new Subject<number>() +// const _state = Representation.createState() +// const renderObjects: RenderObject[] = [] +// let _renderObject: MeshRenderObject | undefined +// let _inputs: Measurements.Inputs + +// let _mesh: Mesh +// let _lines: Lines +// let _text: Text + +// let _theme = createEmptyTheme() +// let currentProps: PD.Values<P> = PD.getDefaultValues(MeasurementsParams) as PD.Values<P> +// let currentParams: P +// let locationIt: LocationIterator + +// function createOrUpdate(props: Partial<PD.Values<P>> = {}, inputs?: MeasurementInputs) { +// currentProps = Object.assign({}, currentProps, props) +// if (inputs) _inputs = inputs + +// return Task.create('MeasurementRepresentation.create', async runtime => { +// renderObjects.length = 0 + +// if (!_inputs) return + +// const mesh = _shape.mesh +// locationIt = ShapeGroupIterator.fromShape(_shape) +// const transform = createIdentityTransform() + +// const values = Mesh.createValues(mesh, transform, locationIt, _theme, currentProps) +// const state = Geometry.createRenderableState(currentProps) + +// _renderObject = createMeshRenderObject(values, state) +// renderObjects.push(_renderObject) +// updated.next(version++) +// }); +// } + +// return { +// label: 'Measures mesh', +// get groupCount () { return locationIt ? locationIt.count : 0 }, +// get renderObjects () { return renderObjects }, +// get props () { return currentProps }, +// get params () { return currentParams }, +// get state() { return _state }, +// get theme() { return _theme }, +// updated, +// createOrUpdate, +// getLoci(pickingId: PickingId) { return EmptyLoci }, +// mark(loci: Loci, action: MarkerAction) { return false }, +// setState(state: Partial<Representation.State>) { +// if (state.visible !== undefined) renderObjects.forEach(ro => ro.state.visible = state.visible!) + +// Representation.updateState(_state, state) +// }, +// setTheme(theme: Theme) { +// _theme = theme +// }, +// destroy() { +// // TODO +// renderObjects.length = 0 +// _renderObject = undefined +// } +// } +// } + +// export namespace ShapeGroupIterator { +// export function fromShape(shape: Shape): LocationIterator { +// const { groupCount } = shape +// const instanceCount = 1 +// const location = Shape.Location(shape) +// const getLocation = (groupIndex: number) => { +// location.group = groupIndex +// return location +// } +// return LocationIterator(groupCount, instanceCount, getLocation) +// } +// } \ No newline at end of file