Browse Source

wip, geometry refactoring

Alexander Rose 6 years ago
parent
commit
8088667e6c
53 changed files with 843 additions and 491 deletions
  1. 3 3
      src/apps/canvas/assembly-symmetry.ts
  2. 2 2
      src/apps/canvas/component/structure-representation.tsx
  3. 2 2
      src/apps/canvas/structure-view.ts
  4. 1 1
      src/mol-app/ui/transform/backbone.tsx
  5. 1 1
      src/mol-app/ui/transform/ball-and-stick.tsx
  6. 1 1
      src/mol-app/ui/transform/carbohydrate.tsx
  7. 1 1
      src/mol-app/ui/transform/cartoon.tsx
  8. 1 1
      src/mol-app/ui/transform/distance-restraint.tsx
  9. 1 1
      src/mol-app/ui/transform/spacefill.tsx
  10. 125 0
      src/mol-geo/geometry/geometry.ts
  11. 1 0
      src/mol-geo/geometry/line/line-builder.ts
  12. 1 0
      src/mol-geo/geometry/line/line.ts
  13. 1 1
      src/mol-geo/geometry/mesh/builder/bounding-box.ts
  14. 2 2
      src/mol-geo/geometry/mesh/builder/cylinder.ts
  15. 0 0
      src/mol-geo/geometry/mesh/builder/sheet.ts
  16. 2 2
      src/mol-geo/geometry/mesh/builder/sphere.ts
  17. 0 0
      src/mol-geo/geometry/mesh/builder/tube.ts
  18. 3 2
      src/mol-geo/geometry/mesh/mesh-builder.ts
  19. 4 1
      src/mol-geo/geometry/mesh/mesh.ts
  20. 38 0
      src/mol-geo/geometry/point/point-builder.ts
  21. 43 0
      src/mol-geo/geometry/point/point.ts
  22. 1 1
      src/mol-geo/representation/shape/index.ts
  23. 9 9
      src/mol-geo/representation/structure/complex-visual.ts
  24. 17 8
      src/mol-geo/representation/structure/index.ts
  25. 15 7
      src/mol-geo/representation/structure/representation/surface.ts
  26. 168 15
      src/mol-geo/representation/structure/units-visual.ts
  27. 5 5
      src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts
  28. 6 6
      src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts
  29. 4 4
      src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts
  30. 26 139
      src/mol-geo/representation/structure/visual/element-point.ts
  31. 3 3
      src/mol-geo/representation/structure/visual/element-sphere.ts
  32. 83 0
      src/mol-geo/representation/structure/visual/gaussian-density-point.ts
  33. 17 111
      src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts
  34. 4 4
      src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts
  35. 4 4
      src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts
  36. 3 3
      src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts
  37. 6 6
      src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts
  38. 2 2
      src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts
  39. 7 7
      src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts
  40. 7 7
      src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts
  41. 13 14
      src/mol-geo/representation/structure/visual/util/common.ts
  42. 3 3
      src/mol-geo/representation/structure/visual/util/element.ts
  43. 124 0
      src/mol-geo/representation/structure/visual/util/gaussian.ts
  44. 4 4
      src/mol-geo/representation/structure/visual/util/link.ts
  45. 1 89
      src/mol-geo/representation/util.ts
  46. 1 1
      src/mol-geo/representation/volume/index.ts
  47. 1 1
      src/mol-geo/representation/volume/surface.ts
  48. 2 1
      src/mol-geo/util/marching-cubes/algorithm.ts
  49. 1 1
      src/mol-geo/util/mesh-data.ts
  50. 20 0
      src/mol-geo/util/point-data.ts
  51. 1 1
      src/mol-io/reader/obj/parser.ts
  52. 51 13
      src/mol-math/linear-algebra/tensor.ts
  53. 1 1
      src/mol-model/shape/shape.ts

+ 3 - 3
src/apps/canvas/assembly-symmetry.ts

@@ -7,10 +7,10 @@
 import { AssemblySymmetry } from 'mol-model-props/rcsb/symmetry';
 import { Table } from 'mol-data/db';
 import { Color, ColorScale } from 'mol-util/color';
-import { MeshBuilder } from 'mol-geo/mesh/mesh-builder';
+import { MeshBuilder } from 'mol-geo/geometry/mesh/mesh-builder';
 import { Tensor } from 'mol-math/linear-algebra';
-import { addSphere } from 'mol-geo/mesh/builder/sphere';
-import { addCylinder } from 'mol-geo/mesh/builder/cylinder';
+import { addSphere } from 'mol-geo/geometry/mesh/builder/sphere';
+import { addCylinder } from 'mol-geo/geometry/mesh/builder/cylinder';
 import { Shape } from 'mol-model/shape';
 import { ColorTheme } from 'mol-view/theme/color';
 import { Location } from 'mol-model/location';

+ 2 - 2
src/apps/canvas/component/structure-representation.tsx

@@ -7,10 +7,10 @@
 import * as React from 'react'
 import { StructureRepresentation, StructureProps } from 'mol-geo/representation/structure';
 import Viewer from 'mol-view/viewer';
-import { VisualQuality, VisualQualityNames } from 'mol-geo/representation/util';
 import { ColorThemeProps, ColorThemeName, ColorThemeNames, ColorTheme } from 'mol-view/theme/color';
 import { Color } from 'mol-util/color';
 import { Progress } from 'mol-task';
+import { VisualQuality, VisualQualityNames } from 'mol-geo/geometry/geometry';
 
 export interface StructureRepresentationComponentProps {
     viewer: Viewer
@@ -165,7 +165,7 @@ export class StructureRepresentationComponent extends React.Component<StructureR
                     <span>Iso Value </span>
                     <input type='range'
                         defaultValue={this.state.isoValue.toString()}
-                        min='0.1'
+                        min='1'
                         max='3'
                         step='0.1'
                         onInput={(e) => this.update({ isoValue: parseFloat(e.currentTarget.value) })}

+ 2 - 2
src/apps/canvas/structure-view.ts

@@ -25,7 +25,7 @@ import { BehaviorSubject } from 'rxjs';
 import { SpacefillRepresentation } from 'mol-geo/representation/structure/representation/spacefill';
 import { DistanceRestraintRepresentation } from 'mol-geo/representation/structure/representation/distance-restraint';
 import { SurfaceRepresentation } from 'mol-geo/representation/structure/representation/surface';
-import { Progress } from 'mol-task';
+// import { Progress } from 'mol-task';
 
 export interface StructureView {
     readonly viewer: Viewer
@@ -210,7 +210,7 @@ export async function StructureView(viewer: Viewer, models: ReadonlyArray<Model>
             for (const k in structureRepresentations) {
                 if (active[k]) {
                     await structureRepresentations[k].createOrUpdate({}, structure).run(
-                        progress => console.log(Progress.format(progress))
+                        // progress => console.log(Progress.format(progress))
                     )
                     viewer.add(structureRepresentations[k])
                 } else {

+ 1 - 1
src/mol-app/ui/transform/backbone.tsx

@@ -19,8 +19,8 @@ import { ColorThemeProps, ColorThemeNames, ColorThemeName } from 'mol-view/theme
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
-import { VisualQuality } from 'mol-geo/representation/util';
 import { Unit } from 'mol-model/structure';
+import { VisualQuality } from 'mol-geo/geometry/geometry';
 
 interface BackboneState {
     doubleSided: boolean

+ 1 - 1
src/mol-app/ui/transform/ball-and-stick.tsx

@@ -19,8 +19,8 @@ import { ColorThemeProps, ColorThemeNames, ColorThemeName } from 'mol-view/theme
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
-import { VisualQuality } from 'mol-geo/representation/util';
 import { Unit } from 'mol-model/structure';
+import { VisualQuality } from 'mol-geo/geometry/geometry';
 
 interface BallAndStickState {
     doubleSided: boolean

+ 1 - 1
src/mol-app/ui/transform/carbohydrate.tsx

@@ -19,8 +19,8 @@ import { ColorThemeProps, ColorThemeNames, ColorThemeName } from 'mol-view/theme
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
-import { VisualQuality } from 'mol-geo/representation/util';
 import { Unit } from 'mol-model/structure';
+import { VisualQuality } from 'mol-geo/geometry/geometry';
 
 interface CarbohydrateState {
     doubleSided: boolean

+ 1 - 1
src/mol-app/ui/transform/cartoon.tsx

@@ -19,8 +19,8 @@ import { ColorThemeProps, ColorThemeNames, ColorThemeName } from 'mol-view/theme
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
-import { VisualQuality } from 'mol-geo/representation/util';
 import { Unit } from 'mol-model/structure';
+import { VisualQuality } from 'mol-geo/geometry/geometry';
 
 interface CartoonState {
     doubleSided: boolean

+ 1 - 1
src/mol-app/ui/transform/distance-restraint.tsx

@@ -19,8 +19,8 @@ import { ColorThemeProps, ColorThemeNames, ColorThemeName } from 'mol-view/theme
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
-import { VisualQuality } from 'mol-geo/representation/util';
 import { Unit } from 'mol-model/structure';
+import { VisualQuality } from 'mol-geo/geometry/geometry';
 
 interface DistanceRestraintState {
     doubleSided: boolean

+ 1 - 1
src/mol-app/ui/transform/spacefill.tsx

@@ -19,8 +19,8 @@ import { ColorThemeProps, ColorThemeNames, ColorThemeName } from 'mol-view/theme
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color, ColorNames } from 'mol-util/color';
 import { Slider } from '../controls/slider';
-import { VisualQuality } from 'mol-geo/representation/util';
 import { Unit } from 'mol-model/structure';
+import { VisualQuality } from 'mol-geo/geometry/geometry';
 
 interface SpacefillState {
     doubleSided: boolean

+ 125 - 0
src/mol-geo/geometry/geometry.ts

@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Mesh } from './mesh/mesh';
+import { Point } from './point/point';
+import { PointValues, MeshValues, RenderableState } from 'mol-gl/renderable';
+import { MeshRenderObject, PointRenderObject } from 'mol-gl/render-object';
+import { ValueCell } from 'mol-util';
+import { BaseValues } from 'mol-gl/renderable/schema';
+
+export type GeometryKindType = { 'mesh': Mesh, 'point': Point }
+export type GeometryKind = keyof GeometryKindType
+export type Geometry = Helpers.ValueOf<GeometryKindType>
+
+export type GeometryDef = {
+    'mesh': { 'props': MeshProps, 'values': MeshValues, 'renderObject': MeshRenderObject }
+    'point': { 'props': PointProps, 'values': PointValues, 'renderObject': PointRenderObject }
+}
+
+export namespace Geometry {
+    export function getDrawCount(geometry: Geometry) {
+        switch (geometry.kind) {
+            case 'mesh': return geometry.triangleCount * 3
+            case 'point': return geometry.vertexCount
+        }
+    }
+}
+
+//
+
+export const VisualQualityInfo = {
+    'custom': {},
+    'auto': {},
+    'highest': {},
+    'high': {},
+    'medium': {},
+    'low': {},
+    'lowest': {},
+}
+export type VisualQuality = keyof typeof VisualQualityInfo
+export const VisualQualityNames = Object.keys(VisualQualityInfo)
+
+//
+
+export const DefaultBaseProps = {
+    alpha: 1,
+    visible: true,
+    depthMask: true,
+    useFog: false,
+    quality: 'auto' as VisualQuality
+}
+export type BaseProps = typeof DefaultBaseProps
+
+export const DefaultMeshProps = {
+    ...DefaultBaseProps,
+    doubleSided: false,
+    flipSided: false,
+    flatShaded: false,
+}
+export type MeshProps = typeof DefaultMeshProps
+
+export const DefaultPointProps = {
+    ...DefaultBaseProps,
+    pointSizeAttenuation: true
+}
+export type PointProps = typeof DefaultPointProps
+
+type Counts = { drawCount: number, groupCount: number, instanceCount: number }
+
+export function createBaseValues(props: BaseProps, counts: Counts) {
+    return {
+        uAlpha: ValueCell.create(props.alpha),
+        uGroupCount: ValueCell.create(counts.groupCount),
+        drawCount: ValueCell.create(counts.drawCount),
+        dUseFog: ValueCell.create(props.useFog),
+    }
+}
+
+export function createMeshValues(props: MeshProps, counts: Counts) {
+    return {
+        ...createBaseValues(props, counts),
+        dDoubleSided: ValueCell.create(props.doubleSided),
+        dFlatShaded: ValueCell.create(props.flatShaded),
+        dFlipSided: ValueCell.create(props.flipSided),
+    }
+}
+
+export function createPointValues(props: PointProps, counts: Counts) {
+    return {
+        ...createBaseValues(props, counts),
+        dPointSizeAttenuation: ValueCell.create(props.pointSizeAttenuation),
+    }
+}
+
+export function createRenderableState(props: BaseProps): RenderableState {
+    return {
+        visible: props.visible,
+        depthMask: props.depthMask
+    }
+}
+
+export function updateBaseValues(values: BaseValues, props: BaseProps) {
+    ValueCell.updateIfChanged(values.uAlpha, props.alpha)
+    ValueCell.updateIfChanged(values.dUseFog, props.useFog)
+}
+
+export function updateMeshValues(values: MeshValues, props: MeshProps) {
+    updateBaseValues(values, props)
+    ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided)
+    ValueCell.updateIfChanged(values.dFlatShaded, props.flatShaded)
+    ValueCell.updateIfChanged(values.dFlipSided, props.flipSided)
+}
+
+export function updatePointValues(values: PointValues, props: PointProps) {
+    updateBaseValues(values, props)
+    ValueCell.updateIfChanged(values.dPointSizeAttenuation, props.pointSizeAttenuation)
+}
+
+export function updateRenderableState(state: RenderableState, props: BaseProps) {
+    state.visible = props.visible
+    state.depthMask = props.depthMask
+}

+ 1 - 0
src/mol-geo/geometry/line/line-builder.ts

@@ -0,0 +1 @@
+// TODO

+ 1 - 0
src/mol-geo/geometry/line/line.ts

@@ -0,0 +1 @@
+// TODO

+ 1 - 1
src/mol-geo/mesh/builder/bounding-box.ts → src/mol-geo/geometry/mesh/builder/bounding-box.ts

@@ -7,7 +7,7 @@
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Box3D } from 'mol-math/geometry';
 import { MeshBuilder } from '../mesh-builder';
-import { CylinderProps } from '../../primitive/cylinder';
+import { CylinderProps } from '../../../primitive/cylinder';
 import { addCylinder } from './cylinder';
 import { addSphere } from './sphere';
 

+ 2 - 2
src/mol-geo/mesh/builder/cylinder.ts → src/mol-geo/geometry/mesh/builder/cylinder.ts

@@ -6,8 +6,8 @@
 
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { MeshBuilder } from '../mesh-builder';
-import { Primitive } from '../../primitive/primitive';
-import { Cylinder, CylinderProps } from '../../primitive/cylinder';
+import { Primitive } from '../../../primitive/primitive';
+import { Cylinder, CylinderProps } from '../../../primitive/cylinder';
 
 const cylinderMap = new Map<string, Primitive>()
 const up = Vec3.create(0, 1, 0)

+ 0 - 0
src/mol-geo/mesh/builder/sheet.ts → src/mol-geo/geometry/mesh/builder/sheet.ts


+ 2 - 2
src/mol-geo/mesh/builder/sphere.ts → src/mol-geo/geometry/mesh/builder/sphere.ts

@@ -6,8 +6,8 @@
 
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { MeshBuilder } from '../mesh-builder';
-import { Primitive } from '../../primitive/primitive';
-import { Sphere } from '../../primitive/sphere';
+import { Primitive } from '../../../primitive/primitive';
+import { Sphere } from '../../../primitive/sphere';
 
 const sphereMap = new Map<number, Primitive>()
 const tmpSphereMat = Mat4.identity()

+ 0 - 0
src/mol-geo/mesh/builder/tube.ts → src/mol-geo/geometry/mesh/builder/tube.ts


+ 3 - 2
src/mol-geo/mesh/mesh-builder.ts → src/mol-geo/geometry/mesh/mesh-builder.ts

@@ -8,8 +8,8 @@ import { ValueCell } from 'mol-util/value-cell'
 import { Vec3, Mat4, Mat3 } from 'mol-math/linear-algebra';
 import { ChunkedArray } from 'mol-data/util';
 import { Mesh } from './mesh';
-import { getNormalMatrix } from '../util';
-import { Primitive } from '../primitive/primitive';
+import { getNormalMatrix } from '../../util';
+import { Primitive } from '../../primitive/primitive';
 
 export interface MeshBuilderState {
     readonly currentGroup: number
@@ -67,6 +67,7 @@ export namespace MeshBuilder {
                 const nb = ChunkedArray.compact(normals, true) as Float32Array
                 const gb = ChunkedArray.compact(groups, true) as Float32Array
                 return {
+                    kind: 'mesh',
                     vertexCount: vertices.elementCount,
                     triangleCount: indices.elementCount,
                     vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb),

+ 4 - 1
src/mol-geo/mesh/mesh.ts → src/mol-geo/geometry/mesh/mesh.ts

@@ -8,9 +8,11 @@ import { Task } from 'mol-task'
 import { ValueCell } from 'mol-util'
 import { Vec3, Mat4 } from 'mol-math/linear-algebra'
 import { Sphere3D } from 'mol-math/geometry'
-import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../util';
+import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
 
 export interface Mesh {
+    readonly kind: 'mesh',
+
     /** Number of vertices in the mesh */
     vertexCount: number,
     /** Number of triangles in the mesh */
@@ -39,6 +41,7 @@ export namespace Mesh {
         const nb = mesh ? mesh.normalBuffer.ref.value : new Float32Array(0)
         const gb = mesh ? mesh.groupBuffer.ref.value : new Float32Array(0)
         return {
+            kind: 'mesh',
             vertexCount: 0,
             triangleCount: 0,
             vertexBuffer: mesh ? ValueCell.update(mesh.vertexBuffer, vb) : ValueCell.create(vb),

+ 38 - 0
src/mol-geo/geometry/point/point-builder.ts

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ValueCell } from 'mol-util/value-cell'
+import { ChunkedArray } from 'mol-data/util';
+import { Point } from './point';
+
+export interface PointBuilder {
+    add(x: number, y: number, z: number, group: number): void
+    getPoint(): Point
+}
+
+export namespace PointBuilder {
+    export function create(initialCount = 2048, chunkSize = 1024, point?: Point): PointBuilder {
+        const vertices = ChunkedArray.create(Float32Array, 3, chunkSize, point ? point.vertexBuffer.ref.value : initialCount);
+        const groups = ChunkedArray.create(Float32Array, 1, chunkSize, point ? point.groupBuffer.ref.value : initialCount);
+
+        return {
+            add: (x: number, y: number, z: number, group: number) => {
+                ChunkedArray.add3(vertices, x, y, z);
+                ChunkedArray.add(groups, group);
+            },
+            getPoint: () => {
+                const vb = ChunkedArray.compact(vertices, true) as Float32Array
+                const gb = ChunkedArray.compact(groups, true) as Float32Array
+                return {
+                    kind: 'point',
+                    vertexCount: vertices.elementCount,
+                    vertexBuffer: point ? ValueCell.update(point.vertexBuffer, vb) : ValueCell.create(vb),
+                    groupBuffer: point ? ValueCell.update(point.groupBuffer, gb) : ValueCell.create(gb),
+                }
+            }
+        }
+    }
+}

+ 43 - 0
src/mol-geo/geometry/point/point.ts

@@ -0,0 +1,43 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ValueCell } from 'mol-util'
+import { Mat4 } from 'mol-math/linear-algebra'
+import { transformPositionArray/* , transformDirectionArray, getNormalMatrix */ } from '../../util';
+
+/** Point cloud */
+export interface Point {
+    readonly kind: 'point',
+    /** Number of vertices in the point cloud */
+    vertexCount: number,
+    /** Vertex buffer as array of xyz values wrapped in a value cell */
+    readonly vertexBuffer: ValueCell<Float32Array>,
+    /** Group buffer as array of group ids for each vertex wrapped in a value cell */
+    readonly groupBuffer: ValueCell<Float32Array>,
+}
+
+export namespace Point {
+    export function createEmpty(point?: Point): Point {
+        const vb = point ? point.vertexBuffer.ref.value : new Float32Array(0)
+        const gb = point ? point.groupBuffer.ref.value : new Float32Array(0)
+        return {
+            kind: 'point',
+            vertexCount: 0,
+            vertexBuffer: point ? ValueCell.update(point.vertexBuffer, vb) : ValueCell.create(vb),
+            groupBuffer: point ? ValueCell.update(point.groupBuffer, gb) : ValueCell.create(gb),
+        }
+    }
+
+    export function transformImmediate(point: Point, t: Mat4) {
+        transformRangeImmediate(point, t, 0, point.vertexCount)
+    }
+
+    export function transformRangeImmediate(point: Point, t: Mat4, offset: number, count: number) {
+        const v = point.vertexBuffer.ref.value
+        transformPositionArray(t, v, offset, count)
+        ValueCell.update(point.vertexBuffer, v);
+    }
+}

+ 1 - 1
src/mol-geo/representation/shape/index.ts

@@ -10,7 +10,6 @@ import { RepresentationProps, Representation } from '..';
 import { PickingId } from '../../util/picking';
 import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
 import { MarkerAction, applyMarkerAction, createMarkers } from '../../util/marker-data';
-import { createRenderableState, createMeshValues, DefaultMeshProps } from '../util';
 import { getMeshData } from '../../util/mesh-data';
 import { MeshValues } from 'mol-gl/renderable';
 import { ValueCell } from 'mol-util';
@@ -20,6 +19,7 @@ import { LocationIterator } from '../../util/location-iterator';
 import { createColors } from '../structure/visual/util/common';
 import { OrderedSet, Interval } from 'mol-data/int';
 import { createIdentityTransform } from '../../util/transform-data';
+import { DefaultMeshProps, createMeshValues, createRenderableState } from '../../geometry/geometry';
 
 export interface ShapeRepresentation<P extends RepresentationProps = {}> extends Representation<Shape, P> { }
 

+ 9 - 9
src/mol-geo/representation/structure/complex-visual.ts

@@ -7,17 +7,17 @@
 import { Structure } from 'mol-model/structure';
 import { Visual } from '..';
 import { MeshRenderObject } from 'mol-gl/render-object';
-import { Mesh } from '../../mesh/mesh';
+import { Mesh } from '../../geometry/mesh/mesh';
 import { RuntimeContext } from 'mol-task';
 import { LocationIterator } from '../../util/location-iterator';
 import { createComplexMeshRenderObject, createColors } from './visual/util/common';
-import { StructureProps, DefaultStructureMeshProps, MeshUpdateState } from '.';
+import { StructureProps, DefaultStructureMeshProps, VisualUpdateState } from '.';
 import { deepEqual, ValueCell } from 'mol-util';
-import { updateMeshValues, updateRenderableState } from '../util';
 import { PickingId } from '../../util/picking';
 import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
 import { MarkerAction, applyMarkerAction } from '../../util/marker-data';
 import { Interval } from 'mol-data/int';
+import { updateMeshValues, updateRenderableState } from '../../geometry/geometry';
 
 export interface  ComplexVisual<P extends StructureProps> extends Visual<Structure, P> { }
 
@@ -32,12 +32,12 @@ export interface ComplexMeshVisualBuilder<P extends ComplexMeshProps> {
     createLocationIterator(structure: Structure): LocationIterator
     getLoci(pickingId: PickingId, structure: Structure, id: number): Loci
     mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean,
-    setUpdateState(state: MeshUpdateState, newProps: P, currentProps: P): void
+    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void
 }
 
 export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> {
     const { defaultProps, createMesh, createLocationIterator, getLoci, mark, setUpdateState } = builder
-    const updateState = MeshUpdateState.create()
+    const updateState = VisualUpdateState.create()
 
     let renderObject: MeshRenderObject | undefined
     let currentProps: P
@@ -65,22 +65,22 @@ export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMe
         if (!renderObject) return false
 
         locationIt.reset()
-        MeshUpdateState.reset(updateState)
+        VisualUpdateState.reset(updateState)
         setUpdateState(updateState, newProps, currentProps)
 
         const newConformationHash = Structure.conformationHash(currentStructure)
         if (newConformationHash !== conformationHash) {
             conformationHash = newConformationHash
-            updateState.createMesh = true
+            updateState.createGeometry = true
         }
 
-        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.createMesh = true
+        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.createGeometry = true
         if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateState.updateColor = true
         // if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createMesh = true // TODO
 
         //
 
-        if (updateState.createMesh) {
+        if (updateState.createGeometry) {
             mesh = await createMesh(ctx, currentStructure, newProps, mesh)
             ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3)
             updateState.updateColor = true

+ 17 - 8
src/mol-geo/representation/structure/index.ts

@@ -9,7 +9,7 @@ import { Structure } from 'mol-model/structure';
 import { ColorThemeProps } from 'mol-view/theme/color';
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { Representation, RepresentationProps } from '..';
-import { DefaultBaseProps, DefaultMeshProps } from '../util';
+import { DefaultMeshProps, DefaultBaseProps, DefaultPointProps } from '../../geometry/geometry';
 
 export interface StructureRepresentation<P extends RepresentationProps = {}> extends Representation<Structure, P> { }
 
@@ -26,23 +26,32 @@ export const DefaultStructureMeshProps = {
 }
 export type StructureMeshProps = typeof DefaultStructureMeshProps
 
-export interface MeshUpdateState {
+export const DefaultStructurePointProps = {
+    ...DefaultStructureProps,
+    ...DefaultPointProps
+}
+export type StructurePointProps = typeof DefaultStructurePointProps
+
+export interface VisualUpdateState {
     updateTransform: boolean
     updateColor: boolean
-    createMesh: boolean
+    updateSize: boolean
+    createGeometry: boolean
 }
-export namespace MeshUpdateState {
-    export function create(): MeshUpdateState {
+export namespace VisualUpdateState {
+    export function create(): VisualUpdateState {
         return {
             updateTransform: false,
             updateColor: false,
-            createMesh: false
+            updateSize: false,
+            createGeometry: false
         }
     }
-    export function reset(state: MeshUpdateState) {
+    export function reset(state: VisualUpdateState) {
         state.updateTransform = false
         state.updateColor = false
-        state.createMesh = false
+        state.updateSize = false
+        state.createGeometry = false
     }
 }
 

+ 15 - 7
src/mol-geo/representation/structure/representation/surface.ts

@@ -11,9 +11,12 @@ import { Structure } from 'mol-model/structure';
 import { MarkerAction } from '../../../util/marker-data';
 import { Loci } from 'mol-model/loci';
 import { PickingId } from '../../../util/picking';
+import { Task } from 'mol-task';
+import { GaussianDensityPointVisual, DefaultGaussianDensityPointProps } from '../visual/gaussian-density-point';
 
 export const DefaultSurfaceProps = {
     ...DefaultGaussianSurfaceProps,
+    ...DefaultGaussianDensityPointProps,
 }
 export type SurfaceProps = typeof DefaultSurfaceProps
 
@@ -21,27 +24,32 @@ export type SurfaceRepresentation = StructureRepresentation<SurfaceProps>
 
 export function SurfaceRepresentation(): SurfaceRepresentation {
     let currentProps: SurfaceProps
-    const gaussianRepr = UnitsRepresentation('Gaussian surface', GaussianSurfaceVisual)
+    const gaussianSurfaceRepr = UnitsRepresentation('Gaussian surface', GaussianSurfaceVisual)
+    const gaussianPointRepr = UnitsRepresentation('Gaussian point grid', GaussianDensityPointVisual)
     return {
         label: 'Surface',
         get renderObjects() {
-            return [ ...gaussianRepr.renderObjects ]
+            return [ ...gaussianSurfaceRepr.renderObjects, ...gaussianPointRepr.renderObjects ]
         },
         get props() {
-            return { ...gaussianRepr.props }
+            return { ...gaussianSurfaceRepr.props, ...gaussianPointRepr.props }
         },
         createOrUpdate: (props: Partial<SurfaceProps> = {}, structure?: Structure) => {
             currentProps = Object.assign({}, DefaultSurfaceProps, currentProps, props)
-            return gaussianRepr.createOrUpdate(currentProps, structure)
+            return Task.create('Creating SurfaceRepresentation', async ctx => {
+                await gaussianSurfaceRepr.createOrUpdate(currentProps, structure).runInContext(ctx)
+                await gaussianPointRepr.createOrUpdate(currentProps, structure).runInContext(ctx)
+            })
         },
         getLoci: (pickingId: PickingId) => {
-            return gaussianRepr.getLoci(pickingId)
+            return gaussianSurfaceRepr.getLoci(pickingId)
         },
         mark: (loci: Loci, action: MarkerAction) => {
-            return gaussianRepr.mark(loci, action)
+            return gaussianSurfaceRepr.mark(loci, action)
         },
         destroy() {
-            gaussianRepr.destroy()
+            gaussianSurfaceRepr.destroy()
+            gaussianPointRepr.destroy()
         }
     }
 }

+ 168 - 15
src/mol-geo/representation/structure/units-visual.ts

@@ -5,20 +5,21 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { RepresentationProps, Visual } from '..';
-import { DefaultStructureMeshProps, MeshUpdateState } from '.';
+import { RepresentationProps, Visual } from '../';
+import { DefaultStructureMeshProps, VisualUpdateState, DefaultStructurePointProps } from '.';
 import { RuntimeContext } from 'mol-task';
 import { PickingId } from '../../util/picking';
 import { LocationIterator } from '../../util/location-iterator';
-import { Mesh } from '../../mesh/mesh';
+import { Mesh } from '../../geometry/mesh/mesh';
 import { MarkerAction, applyMarkerAction, createMarkers } from '../../util/marker-data';
 import { Loci, isEveryLoci, EmptyLoci } from 'mol-model/loci';
-import { MeshRenderObject } from 'mol-gl/render-object';
-import { createUnitsMeshRenderObject, createColors } from './visual/util/common';
+import { MeshRenderObject, PointRenderObject } from 'mol-gl/render-object';
+import { createUnitsMeshRenderObject, createColors, createUnitsPointRenderObject } from './visual/util/common';
 import { deepEqual, ValueCell, UUID } from 'mol-util';
-import { updateMeshValues, updateRenderableState } from '../util';
 import { Interval } from 'mol-data/int';
 import { createTransforms } from '../../util/transform-data';
+import { updateMeshValues, updateRenderableState, updatePointValues } from '../../geometry/geometry';
+import { Point } from '../../geometry/point/point';
 
 export type StructureGroup = { structure: Structure, group: Unit.SymmetryGroup }
 
@@ -36,12 +37,12 @@ export interface UnitsMeshVisualBuilder<P extends UnitsMeshProps> {
     createLocationIterator(group: Unit.SymmetryGroup): LocationIterator
     getLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number): Loci
     mark(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean): boolean
-    setUpdateState(state: MeshUpdateState, newProps: P, currentProps: P): void
+    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void
 }
 
 export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> {
     const { defaultProps, createMesh, createLocationIterator, getLoci, mark, setUpdateState } = builder
-    const updateState = MeshUpdateState.create()
+    const updateState = VisualUpdateState.create()
 
     let renderObject: MeshRenderObject | undefined
     let currentProps: P
@@ -75,20 +76,20 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
         const unit = currentGroup.units[0]
 
         locationIt.reset()
-        MeshUpdateState.reset(updateState)
+        VisualUpdateState.reset(updateState)
         setUpdateState(updateState, newProps, currentProps)
 
         const newConformationId = Unit.conformationId(unit)
         if (newConformationId !== currentConformationId) {
             currentConformationId = newConformationId
-            updateState.createMesh = true
+            updateState.createGeometry = true
         }
 
         if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
 
-        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.createMesh = true
+        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.createGeometry = true
         if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateState.updateColor = true
-        if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createMesh = true
+        if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
 
         //
 
@@ -100,7 +101,7 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
             updateState.updateColor = true
         }
 
-        if (updateState.createMesh) {
+        if (updateState.createGeometry) {
             mesh = newProps.unitKinds.includes(unit.kind)
                 ? await createMesh(ctx, unit, currentStructure, newProps, mesh)
                 : Mesh.createEmpty(mesh)
@@ -112,8 +113,9 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
             await createColors(ctx, locationIt, newProps.colorTheme, renderObject.values)
         }
 
-        updateMeshValues(renderObject.values, newProps)
-        updateRenderableState(renderObject.state, newProps)
+        // TODO why do I need to cast here?
+        updateMeshValues(renderObject.values, newProps as UnitsMeshProps)
+        updateRenderableState(renderObject.state, newProps as UnitsMeshProps)
 
         currentProps = newProps
     }
@@ -177,4 +179,155 @@ function sameGroupConformation(groupA: Unit.SymmetryGroup, groupB: Unit.Symmetry
         groupA.units.length === groupB.units.length &&
         Unit.conformationId(groupA.units[0]) === Unit.conformationId(groupB.units[0])
     )
+}
+
+//
+
+export const DefaultUnitsPointProps = {
+    ...DefaultStructurePointProps,
+    unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[]
+}
+export type UnitsPointProps = typeof DefaultUnitsPointProps
+
+export interface UnitsPointVisualBuilder<P extends UnitsPointProps> {
+    defaultProps: P
+    createPoint(ctx: RuntimeContext, unit: Unit, structure: Structure, props: P, point?: Point): Promise<Point>
+    createLocationIterator(group: Unit.SymmetryGroup): LocationIterator
+    getLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number): Loci
+    mark(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean): boolean
+    setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void
+}
+
+export function UnitsPointVisual<P extends UnitsPointProps>(builder: UnitsPointVisualBuilder<P>): UnitsVisual<P> {
+    const { defaultProps, createPoint, createLocationIterator, getLoci, mark, setUpdateState } = builder
+    const updateState = VisualUpdateState.create()
+
+    let renderObject: PointRenderObject | undefined
+    let currentProps: P
+    let point: Point
+    let currentGroup: Unit.SymmetryGroup
+    let currentStructure: Structure
+    let locationIt: LocationIterator
+    let currentConformationId: UUID
+
+    async function create(ctx: RuntimeContext, group: Unit.SymmetryGroup, props: Partial<P> = {}) {
+        currentProps = Object.assign({}, defaultProps, props)
+        currentProps.colorTheme.structure = currentStructure
+        currentGroup = group
+
+        const unit = group.units[0]
+        currentConformationId = Unit.conformationId(unit)
+        point = currentProps.unitKinds.includes(unit.kind)
+            ? await createPoint(ctx, unit, currentStructure, currentProps, point)
+            : Point.createEmpty(point)
+
+        // TODO create empty location iterator when not in unitKinds
+        locationIt = createLocationIterator(group)
+        renderObject = await createUnitsPointRenderObject(ctx, group, point, locationIt, currentProps)
+    }
+
+    async function update(ctx: RuntimeContext, props: Partial<P> = {}) {
+        if (!renderObject) return
+
+        const newProps = Object.assign({}, currentProps, props)
+        newProps.colorTheme.structure = currentStructure
+        const unit = currentGroup.units[0]
+
+        locationIt.reset()
+        VisualUpdateState.reset(updateState)
+        setUpdateState(updateState, newProps, currentProps)
+
+        const newConformationId = Unit.conformationId(unit)
+        if (newConformationId !== currentConformationId) {
+            currentConformationId = newConformationId
+            updateState.createGeometry = true
+        }
+
+        if (currentGroup.units.length !== locationIt.instanceCount) updateState.updateTransform = true
+
+        if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateState.createGeometry = true
+        if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateState.updateColor = true
+        if (!deepEqual(newProps.unitKinds, currentProps.unitKinds)) updateState.createGeometry = true
+
+        //
+
+        if (updateState.updateTransform) {
+            locationIt = createLocationIterator(currentGroup)
+            const { instanceCount, groupCount } = locationIt
+            createTransforms(currentGroup, renderObject.values)
+            createMarkers(instanceCount * groupCount, renderObject.values)
+            updateState.updateColor = true
+        }
+
+        if (updateState.createGeometry) {
+            point = newProps.unitKinds.includes(unit.kind)
+                ? await createPoint(ctx, unit, currentStructure, newProps, point)
+                : Point.createEmpty(point)
+            ValueCell.update(renderObject.values.drawCount, point.vertexCount)
+            updateState.updateColor = true
+        }
+
+        if (updateState.updateColor) {
+            await createColors(ctx, locationIt, newProps.colorTheme, renderObject.values)
+        }
+
+        // TODO why do I need to cast here?
+        updatePointValues(renderObject.values, newProps as UnitsPointProps)
+        updateRenderableState(renderObject.state, newProps as UnitsPointProps)
+
+        currentProps = newProps
+    }
+
+    return {
+        get renderObject () { return renderObject },
+        async createOrUpdate(ctx: RuntimeContext, props: Partial<P> = {}, structureGroup?: StructureGroup) {
+            if (structureGroup) currentStructure = structureGroup.structure
+            const group = structureGroup ? structureGroup.group : undefined
+            if (!group && !currentGroup) {
+                throw new Error('missing group')
+            } else if (group && (!currentGroup || !renderObject)) {
+                // console.log('unit-visual first create')
+                await create(ctx, group, props)
+            } else if (group && group.hashCode !== currentGroup.hashCode) {
+                // console.log('unit-visual group.hashCode !== currentGroup.hashCode')
+                await create(ctx, group, props)
+            } else {
+                // console.log('unit-visual update')
+                if (group && !sameGroupConformation(group, currentGroup)) {
+                    // console.log('unit-visual new conformation')
+                    currentGroup = group
+                }
+                await update(ctx, props)
+            }
+        },
+        getLoci(pickingId: PickingId) {
+            return renderObject ? getLoci(pickingId, currentGroup, renderObject.id) : EmptyLoci
+        },
+        mark(loci: Loci, action: MarkerAction) {
+            if (!renderObject) return false
+            const { tMarker } = renderObject.values
+            const { groupCount, instanceCount } = locationIt
+
+            function apply(interval: Interval) {
+                const start = Interval.start(interval)
+                const end = Interval.end(interval)
+                return applyMarkerAction(tMarker.ref.value.array, start, end, action)
+            }
+
+            let changed = false
+            if (isEveryLoci(loci)) {
+                changed = apply(Interval.ofBounds(0, groupCount * instanceCount))
+            } else {
+                changed = mark(loci, currentGroup, apply)
+            }
+            if (changed) {
+                ValueCell.update(tMarker, tMarker.ref.value)
+            }
+            return changed
+        },
+        destroy() {
+            // TODO
+            renderObject = undefined
+        }
+    }
 }

+ 5 - 5
src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts

@@ -5,12 +5,11 @@
  */
 
 import { Unit, Structure, Link, StructureElement } from 'mol-model/structure';
-import { DefaultStructureProps, ComplexVisual, MeshUpdateState } from '..';
+import { DefaultStructureProps, ComplexVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
+import { Mesh } from '../../../geometry/mesh/mesh';
 import { PickingId } from '../../../util/picking';
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { DefaultMeshProps } from '../../util';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { LocationIterator } from '../../../util/location-iterator';
 import { createLinkCylinderMesh, DefaultLinkCylinderProps, LinkCylinderProps } from './util/link';
@@ -19,6 +18,7 @@ import { ComplexMeshVisual } from '../complex-visual';
 import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
 import { LinkType } from 'mol-model/structure/model/types';
 import { BitFlags } from 'mol-util';
+import { DefaultMeshProps } from '../../../geometry/geometry';
 
 // TODO create seperate visual
 // for (let i = 0, il = carbohydrates.terminalLinks.length; i < il; ++i) {
@@ -77,8 +77,8 @@ export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkProps> {
         createLocationIterator: CarbohydrateLinkIterator,
         getLoci: getLinkLoci,
         mark: markLink,
-        setUpdateState: (state: MeshUpdateState, newProps: CarbohydrateLinkProps, currentProps: CarbohydrateLinkProps) => {
-            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        setUpdateState: (state: VisualUpdateState, newProps: CarbohydrateLinkProps, currentProps: CarbohydrateLinkProps) => {
+            state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
         }
     })
 }

+ 6 - 6
src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts

@@ -5,19 +5,19 @@
  */
 
 import { Unit, Structure, StructureElement } from 'mol-model/structure';
-import { ComplexVisual, MeshUpdateState } from '..';
+import { ComplexVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
+import { Mesh } from '../../../geometry/mesh/mesh';
 import { PickingId } from '../../../util/picking';
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { MeshBuilder } from '../../../mesh/mesh-builder';
+import { MeshBuilder } from '../../../geometry/mesh/mesh-builder';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { getSaccharideShape, SaccharideShapes } from 'mol-model/structure/structure/carbohydrates/constants';
 import { LocationIterator } from '../../../util/location-iterator';
 import { OrderedSet, Interval } from 'mol-data/int';
 import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual';
 import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
-import { addSphere } from '../../../mesh/builder/sphere';
+import { addSphere } from '../../../geometry/mesh/builder/sphere';
 import { Box, PerforatedBox } from '../../../primitive/box';
 import { OctagonalPyramid, PerforatedOctagonalPyramid } from '../../../primitive/pyramid';
 import { Star } from '../../../primitive/star';
@@ -154,8 +154,8 @@ export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolProp
         createLocationIterator: CarbohydrateElementIterator,
         getLoci: getCarbohydrateLoci,
         mark: markCarbohydrate,
-        setUpdateState: (state: MeshUpdateState, newProps: CarbohydrateSymbolProps, currentProps: CarbohydrateSymbolProps) => {
-            state.createMesh = newProps.detail !== currentProps.detail
+        setUpdateState: (state: VisualUpdateState, newProps: CarbohydrateSymbolProps, currentProps: CarbohydrateSymbolProps) => {
+            state.createGeometry = newProps.detail !== currentProps.detail
         }
     })
 }

+ 4 - 4
src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts

@@ -5,10 +5,10 @@
  */
 
 import { Link, Structure, StructureElement } from 'mol-model/structure';
-import { ComplexVisual, MeshUpdateState } from '..';
+import { ComplexVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
 import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link';
-import { Mesh } from '../../../mesh/mesh';
+import { Mesh } from '../../../geometry/mesh/mesh';
 import { PickingId } from '../../../util/picking';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
@@ -65,8 +65,8 @@ export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintProp
         createLocationIterator: CrossLinkRestraintIterator,
         getLoci: getLinkLoci,
         mark: markLink,
-        setUpdateState: (state: MeshUpdateState, newProps: CrossLinkRestraintProps, currentProps: CrossLinkRestraintProps) => {
-            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        setUpdateState: (state: VisualUpdateState, newProps: CrossLinkRestraintProps, currentProps: CrossLinkRestraintProps) => {
+            state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
         }
     })
 }

+ 26 - 139
src/mol-geo/representation/structure/visual/element-point.ts

@@ -2,169 +2,56 @@
  * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  *
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { ValueCell } from 'mol-util/value-cell'
-import { PointRenderObject } from 'mol-gl/render-object'
 import { Unit, Structure } from 'mol-model/structure';
 import { RuntimeContext } from 'mol-task'
-import { UnitsVisual, DefaultStructureProps } from '..';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { getElementLoci, StructureElementIterator, markElement } from './util/element';
-import { createColors, createSizes, createUnitsPointRenderObject } from './util/common';
-import { deepEqual, UUID } from 'mol-util';
-import { Interval } from 'mol-data/int';
-import { PickingId } from '../../../util/picking';
-import { Loci, EmptyLoci, isEveryLoci } from 'mol-model/loci';
-import { MarkerAction, createMarkers, applyMarkerAction } from '../../../util/marker-data';
 import { Vec3 } from 'mol-math/linear-algebra';
-import { fillSerial } from 'mol-util/array';
 import { SizeThemeProps } from 'mol-view/theme/size';
-import { LocationIterator } from '../../../util/location-iterator';
-import { createTransforms } from '../../../util/transform-data';
-import { StructureGroup } from '../units-visual';
-import { updateRenderableState, updateBaseValues } from '../../util';
+import { UnitsPointVisual, DefaultUnitsPointProps } from '../units-visual';
+import { Point } from '../../../geometry/point/point';
+import { PointBuilder } from '../../../geometry/point/point-builder';
 
 export const DefaultElementPointProps = {
-    ...DefaultStructureProps,
+    ...DefaultUnitsPointProps,
 
     sizeTheme: { name: 'uniform', value: 0.2 } as SizeThemeProps,
     pointSizeAttenuation: true,
 }
-export type ElementPointProps = Partial<typeof DefaultElementPointProps>
+export type ElementPointProps = typeof DefaultElementPointProps
 
-export async function createElementPointVertices(ctx: RuntimeContext, unit: Unit, vertices?: ValueCell<Float32Array>) {
+// TODO size
+
+export async function createElementPoint(ctx: RuntimeContext, unit: Unit, structure: Structure, props: ElementPointProps, point: Point) {
     const elements = unit.elements
-    const n = elements.length * 3
-    const array = vertices && vertices.ref.value.length >= n ? vertices.ref.value : new Float32Array(n)
+    const n = elements.length
+    const builder = PointBuilder.create(n, n / 10, point)
 
     const pos = unit.conformation.invariantPosition
-
     const p = Vec3.zero()
-    for (let i = 0; i < n; i += 3) {
-        pos(elements[i / 3], p)
-        array[i] = p[0]
-        array[i + 1] = p[1]
-        array[i + 2] = p[2]
+
+    for (let i = 0; i < n; ++i) {
+        pos(elements[i], p)
+        builder.add(p[0], p[1], p[2], i)
 
         if (i % 10000 === 0 && ctx.shouldUpdate) {
-            await ctx.update({ message: 'Creating points', current: i / 3, max: elements.length });
+            await ctx.update({ message: 'Creating points', current: i, max: n });
         }
-        ++i
     }
-    return vertices ? ValueCell.update(vertices, array) : ValueCell.create(array)
+    return builder.getPoint()
 }
 
 export function ElementPointVisual(): UnitsVisual<ElementPointProps> {
-    let renderObject: PointRenderObject | undefined
-    let currentProps = DefaultElementPointProps
-    let currentGroup: Unit.SymmetryGroup
-    let currentStructure: Structure
-    let locationIt: LocationIterator
-    let vertices: ValueCell<Float32Array>
-    let currentConformationId: UUID
-
-    return {
-        get renderObject () { return renderObject },
-        async createOrUpdate(ctx: RuntimeContext, props: ElementPointProps = {}, structureGroup?: StructureGroup) {
-            if (structureGroup) currentStructure = structureGroup.structure
-            const group = structureGroup ? structureGroup.group : undefined
-            if (!group && !currentGroup) {
-                throw new Error('missing group')
-            } else if (group && !currentGroup) {
-                currentProps = Object.assign({}, DefaultElementPointProps, props)
-                currentProps.colorTheme.structure = currentStructure
-                currentGroup = group
-                locationIt = StructureElementIterator.fromGroup(group)
-
-                const unit = group.units[0]
-                currentConformationId = Unit.conformationId(unit)
-                vertices = await createElementPointVertices(ctx, unit, vertices)
-
-                renderObject = await createUnitsPointRenderObject(ctx, group, vertices, locationIt, currentProps)
-            } else if (renderObject) {
-                if (group) currentGroup = group
-
-                const newProps = { ...currentProps, ...props }
-                const unit = currentGroup.units[0]
-
-                let updateTransform = false
-                let createVertices = false
-                let updateColor = false
-                let updateSize = false
-
-                const newConformationId = Unit.conformationId(unit)
-                if (newConformationId !== currentConformationId) {
-                    currentConformationId = newConformationId
-                    createVertices = true
-                }
-
-                if (currentGroup.units.length !== locationIt.instanceCount) updateTransform = true
+    return UnitsPointVisual<ElementPointProps>({
+        defaultProps: DefaultElementPointProps,
+        createPoint: createElementPoint,
+        createLocationIterator: StructureElementIterator.fromGroup,
+        getLoci: getElementLoci,
+        mark: markElement,
+        setUpdateState: (state: VisualUpdateState, newProps: ElementPointProps, currentProps: ElementPointProps) => {
 
-                if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) createVertices = true
-                if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) updateColor = true
-                if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) updateSize = true
-
-                if (updateTransform) {
-                    locationIt = StructureElementIterator.fromGroup(currentGroup)
-                    const { instanceCount, groupCount } = locationIt
-                    createTransforms(currentGroup, renderObject.values)
-                    createMarkers(instanceCount * groupCount, renderObject.values)
-                    updateColor = true
-                    updateSize = true
-                }
-
-                if (createVertices) {
-                    await createElementPointVertices(ctx, unit, vertices)
-                    ValueCell.update(renderObject.values.aGroup, fillSerial(new Float32Array(locationIt.groupCount))) // TODO reuse array
-                    ValueCell.update(renderObject.values.drawCount, locationIt.groupCount)
-                    updateColor = true
-                    updateSize = true
-                }
-
-                if (updateColor) {
-                    await createColors(ctx, locationIt, newProps.colorTheme, renderObject.values)
-                }
-
-                if (updateSize) {
-                    await createSizes(ctx, locationIt, newProps.sizeTheme, renderObject.values)
-                }
-
-                updateBaseValues(renderObject.values, newProps)
-                updateRenderableState(renderObject.state, newProps)
-
-                currentProps = newProps
-            }
-        },
-        getLoci(pickingId: PickingId) {
-            return renderObject ? getElementLoci(pickingId, currentGroup, renderObject.id) : EmptyLoci
-        },
-        mark(loci: Loci, action: MarkerAction) {
-            if (!renderObject) return false
-            const { tMarker } = renderObject.values
-            const { groupCount, instanceCount } = locationIt
-
-            function apply(interval: Interval) {
-                const start = Interval.start(interval)
-                const end = Interval.end(interval)
-                return applyMarkerAction(tMarker.ref.value.array, start, end, action)
-            }
-
-            let changed = false
-            if (isEveryLoci(loci)) {
-                apply(Interval.ofBounds(0, groupCount * instanceCount))
-                changed = true
-            } else {
-                changed = markElement(loci, currentGroup, apply)
-            }
-            if (changed) {
-                ValueCell.update(tMarker, tMarker.ref.value)
-            }
-            return changed
-        },
-        destroy() {
-            // TODO
-            renderObject = undefined
         }
-    }
-}
+    })
+}

+ 3 - 3
src/mol-geo/representation/structure/visual/element-sphere.ts

@@ -5,7 +5,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { UnitsVisual, MeshUpdateState } from '..';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { createElementSphereMesh, markElement, getElementLoci, StructureElementIterator } from './util/element';
 import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual';
 
@@ -22,8 +22,8 @@ export function ElementSphereVisual(): UnitsVisual<ElementSphereProps> {
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
         mark: markElement,
-        setUpdateState: (state: MeshUpdateState, newProps: ElementSphereProps, currentProps: ElementSphereProps) => {
-            state.createMesh = newProps.detail !== currentProps.detail
+        setUpdateState: (state: VisualUpdateState, newProps: ElementSphereProps, currentProps: ElementSphereProps) => {
+            state.createGeometry = newProps.detail !== currentProps.detail
         }
     })
 }

+ 83 - 0
src/mol-geo/representation/structure/visual/gaussian-density-point.ts

@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Unit, Structure } from 'mol-model/structure';
+import { RuntimeContext } from 'mol-task'
+import { UnitsVisual, VisualUpdateState } from '..';
+import { StructureElementIterator } from './util/element';
+import { EmptyLoci } from 'mol-model/loci';
+import { Vec3 } from 'mol-math/linear-algebra';
+import { SizeThemeProps } from 'mol-view/theme/size';
+import { UnitsPointVisual, DefaultUnitsPointProps } from '../units-visual';
+import { computeGaussianDensity } from './util/gaussian';
+import { Color } from 'mol-util/color';
+import { ColorThemeProps } from 'mol-view/theme/color';
+import { Point } from '../../../geometry/point/point';
+import { PointBuilder } from '../../../geometry/point/point-builder';
+
+export const DefaultGaussianDensityPointProps = {
+    ...DefaultUnitsPointProps,
+
+    sizeTheme: { name: 'uniform', value: 1.5 } as SizeThemeProps,
+    colorTheme: { name: 'uniform', value: Color(0xAAAAAA) } as ColorThemeProps,
+    pointSizeAttenuation: false,
+
+    resolutionFactor: 7,
+    probeRadius: 0,
+    isoValue: 1.5,
+}
+export type GaussianDensityPointProps = typeof DefaultGaussianDensityPointProps
+
+export interface GaussianDensityProps {
+    sizeTheme: SizeThemeProps
+
+    resolutionFactor: number
+    probeRadius: number
+    isoValue: number
+}
+
+export async function createGaussianDensityPoint(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps, point?: Point) {
+    const { transform, field: { space, data } } = await computeGaussianDensity(unit, structure, props).runAsChild(ctx)
+
+    const { dimensions, get } = space
+    const [ xn, yn, zn ] = dimensions
+
+    const n = xn * yn * zn * 3
+    const builder = PointBuilder.create(n, n / 10, point)
+
+    const p = Vec3.zero()
+    let i = 0
+
+    for (let x = 0; x < xn; ++x) {
+        for (let y = 0; y < yn; ++y) {
+            for (let z = 0; z < zn; ++z) {
+                if (get(data, x, y, z) > 0.001) {
+                    Vec3.set(p, x, y, z)
+                    Vec3.transformMat4(p, p, transform)
+                    builder.add(p[0], p[1], p[2], i)
+                }
+                if (i % 100000 === 0 && ctx.shouldUpdate) {
+                    await ctx.update({ message: 'Creating density points', current: i, max: n });
+                }
+                ++i
+            }
+        }
+    }
+    return builder.getPoint()
+}
+
+export function GaussianDensityPointVisual(): UnitsVisual<GaussianDensityPointProps> {
+    return UnitsPointVisual<GaussianDensityPointProps>({
+        defaultProps: DefaultGaussianDensityPointProps,
+        createPoint: createGaussianDensityPoint,
+        createLocationIterator: StructureElementIterator.fromGroup,
+        getLoci: () => EmptyLoci,
+        mark: () => false,
+        setUpdateState: (state: VisualUpdateState, newProps: GaussianDensityPointProps, currentProps: GaussianDensityPointProps) => {
+
+        }
+    })
+}

+ 17 - 111
src/mol-geo/representation/structure/visual/gaussian-surface-mesh.ts

@@ -4,17 +4,17 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Unit, Structure, StructureElement } from 'mol-model/structure';
-import { UnitsVisual, MeshUpdateState } from '..';
+import { Unit, Structure } from 'mol-model/structure';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
+import { Mesh } from '../../../geometry/mesh/mesh';
 import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual';
 import { StructureElementIterator, getElementLoci, markElement } from './util/element';
 import { computeMarchingCubes } from '../../../util/marching-cubes/algorithm';
-import { Tensor, Vec3, Mat4 } from 'mol-math/linear-algebra';
-import { Box3D } from 'mol-math/geometry';
-import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
+import { SizeThemeProps } from 'mol-view/theme/size';
 import { Color } from 'mol-util/color';
+import { computeGaussianDensity } from './util/gaussian';
+import { ColorThemeProps } from 'mol-view/theme/color';
 
 export interface GaussianSurfaceMeshProps {
     sizeTheme: SizeThemeProps
@@ -24,116 +24,22 @@ export interface GaussianSurfaceMeshProps {
     isoValue: number
 }
 
-function getDelta(box: Box3D, resolutionFactor: number) {
-    const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
-
-    const n = Math.pow(Math.pow(2, resolutionFactor), 3)
-    const f = (extent[0] * extent[1] * extent[2]) / n
-    const s = Math.pow(f, 1 / 3)
-    const size = Vec3.zero()
-    // Vec3.scale(size, extent, s)
-    Vec3.ceil(size, Vec3.scale(size, extent, s))
-    const delta = Vec3.div(Vec3.zero(), extent, size)
-    return delta
-}
-
 async function createGaussianSurfaceMesh(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianSurfaceMeshProps, mesh?: Mesh): Promise<Mesh> {
-    const { resolutionFactor, probeRadius, isoValue } = props
-
-    const { elements } = unit;
-    const elementCount = elements.length;
-    const sizeTheme = SizeTheme(props.sizeTheme)
-
-    const v = Vec3.zero()
-    const p = Vec3.zero()
-    const pos = unit.conformation.invariantPosition
-    const l = StructureElement.create()
-    l.unit = unit
-
-    const pad = (probeRadius + 2) * 2 // TODO calculate max radius
-    const box = unit.lookup3d.boundary.box
-    const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad));
-    const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
-    const min = expandedBox.min
-
-    // const n = Math.pow(128, 3)
-    // const f = (extent[0] * extent[1] * extent[2]) / n
-    // const s = Math.pow(f, 1 / 3)
-    // const size = Vec3.zero()
-    // // Vec3.scale(size, extent, s)
-    // Vec3.ceil(size, Vec3.scale(size, extent, s))
-    // const delta = Vec3.div(Vec3.zero(), extent, size)
-
-    // console.log('extent', extent)
-    // console.log('n', n)
-    // console.log('f', f)
-    // console.log('s', s)
-    // console.log('size', size)
-    // console.log('delta', delta)
-    const delta = getDelta(Box3D.expand(Box3D.empty(), structure.boundary.box, Vec3.create(pad, pad, pad)), resolutionFactor)
-    const dim = Vec3.zero()
-    Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
-    // console.log('dim', dim, dim[0] * dim[1] * dim[2])
-
-    const space = Tensor.Space(dim, [0, 1, 2], Float32Array)
-    const data = space.create()
-    const field = Tensor.create(space, data)
-
-    const c = Vec3.zero()
-
-    const radius2 = Vec3.scale(Vec3.zero(), delta, 2)
-    const alpha = 1.5 // smoothness
+    const { isoValue } = props
 
     console.time('surface density')
-    for (let i = 0; i < elementCount; i++) {
-        l.element = elements[i]
-        pos(elements[i], v)
-
-        Vec3.sub(v, v, min)
-        Vec3.mul(c, v, delta)
-
-        const radius = sizeTheme.size(l) // + probeRadius
-
-        const minX = Math.floor(c[0] - radius2[0]) - 1
-        const minY = Math.floor(c[1] - radius2[1]) - 1
-        const minZ = Math.floor(c[2] - radius2[2]) - 1
-        const maxX = Math.ceil(c[0] + radius2[0]) + 1
-        const maxY = Math.ceil(c[1] + radius2[1]) + 1
-        const maxZ = Math.ceil(c[2] + radius2[2]) + 1
-
-        for (let x = minX; x < maxX; ++x) {
-            for (let y = minY; y < maxY; ++y) {
-                for (let z = minZ; z < maxZ; ++z) {
-                    Vec3.set(p, x, y, z)
-                    Vec3.div(p, p, delta)
-                    const dist = Vec3.distance(p, v)
-                    const density = Math.exp(-alpha * Math.pow((dist) / radius, 2))
-                    space.set(data, x, y, z, space.get(data, x, y, z) + density)
-                }
-            }
-        }
-
-        if (i % 100 === 0 && ctx.shouldUpdate) {
-            await ctx.update({ message: 'Gaussian surface', current: i, max: elementCount });
-        }
-    }
+    const { transform, field } = await computeGaussianDensity(unit, structure, props).runAsChild(ctx)
     console.timeEnd('surface density')
 
-    // console.log('data', data)
-
     console.time('surface mc')
     const surface = await computeMarchingCubes({
-        isoLevel: isoValue * Math.exp(-alpha),
+        isoLevel: Math.exp(-isoValue),
         scalarField: field,
         oldSurface: mesh
     }).runAsChild(ctx)
     console.timeEnd('surface mc')
 
-    const t = Mat4.identity()
-    Mat4.fromScaling(t, Vec3.inverse(Vec3.zero(), delta))
-    Mat4.setTranslation(t, expandedBox.min)
-
-    Mesh.transformImmediate(surface, t)
+    Mesh.transformImmediate(surface, transform)
     Mesh.computeNormalsImmediate(surface)
 
     return surface;
@@ -149,11 +55,11 @@ export const DefaultGaussianSurfaceProps = {
     flipSided: true,
     // flatShaded: true,
     alpha: 0.7,
-    colorTheme: { name: 'uniform' as 'uniform', value: Color(0xDDDDDD) },
+    colorTheme: { name: 'uniform' as 'uniform', value: Color(0xDDDDDD) } as ColorThemeProps,
 
     resolutionFactor: 7,
-    probeRadius: 1.4,
-    isoValue: 1,
+    probeRadius: 0,
+    isoValue: 1.5,
 }
 export type GaussianSurfaceProps = typeof DefaultGaussianSurfaceProps
 
@@ -164,10 +70,10 @@ export function GaussianSurfaceVisual(): UnitsVisual<GaussianSurfaceProps> {
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
         mark: markElement,
-        setUpdateState: (state: MeshUpdateState, newProps: GaussianSurfaceProps, currentProps: GaussianSurfaceProps) => {
-            if (newProps.resolutionFactor !== currentProps.resolutionFactor) state.createMesh = true
-            if (newProps.probeRadius !== currentProps.probeRadius) state.createMesh = true
-            if (newProps.isoValue !== currentProps.isoValue) state.createMesh = true
+        setUpdateState: (state: VisualUpdateState, newProps: GaussianSurfaceProps, currentProps: GaussianSurfaceProps) => {
+            if (newProps.resolutionFactor !== currentProps.resolutionFactor) state.createGeometry = true
+            if (newProps.probeRadius !== currentProps.probeRadius) state.createGeometry = true
+            if (newProps.isoValue !== currentProps.isoValue) state.createGeometry = true
         }
     })
 }

+ 4 - 4
src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts

@@ -5,10 +5,10 @@
  */
 
 import { Link, Structure, StructureElement } from 'mol-model/structure';
-import { ComplexVisual, MeshUpdateState } from '..';
+import { ComplexVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
 import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh, LinkIterator } from './util/link';
-import { Mesh } from '../../../mesh/mesh';
+import { Mesh } from '../../../geometry/mesh/mesh';
 import { PickingId } from '../../../util/picking';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
@@ -63,8 +63,8 @@ export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkProps> {
         createLocationIterator: LinkIterator.fromStructure,
         getLoci: getLinkLoci,
         mark: markLink,
-        setUpdateState: (state: MeshUpdateState, newProps: InterUnitLinkProps, currentProps: InterUnitLinkProps) => {
-            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        setUpdateState: (state: VisualUpdateState, newProps: InterUnitLinkProps, currentProps: InterUnitLinkProps) => {
+            state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
         }
     })
 }

+ 4 - 4
src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts

@@ -6,10 +6,10 @@
  */
 
 import { Unit, Link, StructureElement, Structure } from 'mol-model/structure';
-import { UnitsVisual, MeshUpdateState } from '..';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
 import { DefaultLinkCylinderProps, LinkCylinderProps, createLinkCylinderMesh, LinkIterator } from './util/link';
-import { Mesh } from '../../../mesh/mesh';
+import { Mesh } from '../../../geometry/mesh/mesh';
 import { PickingId } from '../../../util/picking';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
@@ -77,8 +77,8 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> {
         createLocationIterator: LinkIterator.fromGroup,
         getLoci: getLinkLoci,
         mark: markLink,
-        setUpdateState: (state: MeshUpdateState, newProps: LinkCylinderProps, currentProps: LinkCylinderProps) => {
-            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        setUpdateState: (state: VisualUpdateState, newProps: LinkCylinderProps, currentProps: LinkCylinderProps) => {
+            state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
         }
     })
 }

+ 3 - 3
src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts

@@ -7,14 +7,14 @@
 import { Unit, Structure } from 'mol-model/structure';
 import { UnitsVisual } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
-import { MeshBuilder } from '../../../mesh/mesh-builder';
+import { Mesh } from '../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../geometry/mesh/mesh-builder';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { Segmentation } from 'mol-data/int';
 import { MoleculeType, isNucleic, isPurinBase, isPyrimidineBase } from 'mol-model/structure/model/types';
 import { getElementIndexForAtomId, getElementIndexForAtomRole } from 'mol-model/structure/util';
 import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual';
-import { addCylinder } from '../../../mesh/builder/cylinder';
+import { addCylinder } from '../../../geometry/mesh/builder/cylinder';
 import { Box } from '../../../primitive/box';
 import { NucleotideLocationIterator, markNucleotideElement, getNucleotideElementLoci } from './util/nucleotide';
 

+ 6 - 6
src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts

@@ -5,10 +5,10 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual, MeshUpdateState } from '..';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
-import { MeshBuilder } from '../../../mesh/mesh-builder';
+import { Mesh } from '../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../geometry/mesh/mesh-builder';
 import { PolymerBackboneIterator } from './util/polymer';
 import { getElementLoci, markElement, StructureElementIterator } from './util/element';
 import { Vec3 } from 'mol-math/linear-algebra';
@@ -16,7 +16,7 @@ import { DefaultUnitsMeshProps, UnitsMeshVisual } from '../units-visual';
 import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
 import { CylinderProps } from '../../../primitive/cylinder';
 import { OrderedSet } from 'mol-data/int';
-import { addCylinder } from '../../../mesh/builder/cylinder';
+import { addCylinder } from '../../../geometry/mesh/builder/cylinder';
 
 export interface PolymerBackboneCylinderProps {
     sizeTheme: SizeThemeProps
@@ -77,8 +77,8 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> {
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
         mark: markElement,
-        setUpdateState: (state: MeshUpdateState, newProps: PolymerBackboneProps, currentProps: PolymerBackboneProps) => {
-            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        setUpdateState: (state: VisualUpdateState, newProps: PolymerBackboneProps, currentProps: PolymerBackboneProps) => {
+            state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
         }
     })
 }

+ 2 - 2
src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts

@@ -7,8 +7,8 @@
 import { Unit, Structure } from 'mol-model/structure';
 import { UnitsVisual } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
-import { MeshBuilder } from '../../../mesh/mesh-builder';
+import { Mesh } from '../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../geometry/mesh/mesh-builder';
 import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer';
 import { Vec3, Mat4 } from 'mol-math/linear-algebra';
 import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';

+ 7 - 7
src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts

@@ -5,17 +5,17 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual, MeshUpdateState } from '..';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
-import { MeshBuilder } from '../../../mesh/mesh-builder';
+import { Mesh } from '../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../geometry/mesh/mesh-builder';
 import { PolymerGapIterator, PolymerGapLocationIterator, markPolymerGapElement, getPolymerGapElementLoci } from './util/polymer';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual';
 import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
 import { CylinderProps } from '../../../primitive/cylinder';
-import { addSphere } from '../../../mesh/builder/sphere';
-import { addFixedCountDashedCylinder } from '../../../mesh/builder/cylinder';
+import { addSphere } from '../../../geometry/mesh/builder/sphere';
+import { addFixedCountDashedCylinder } from '../../../geometry/mesh/builder/cylinder';
 
 const segmentCount = 10
 
@@ -84,8 +84,8 @@ export function PolymerGapVisual(): UnitsVisual<PolymerGapProps> {
         createLocationIterator: PolymerGapLocationIterator.fromGroup,
         getLoci: getPolymerGapElementLoci,
         mark: markPolymerGapElement,
-        setUpdateState: (state: MeshUpdateState, newProps: PolymerGapProps, currentProps: PolymerGapProps) => {
-            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        setUpdateState: (state: VisualUpdateState, newProps: PolymerGapProps, currentProps: PolymerGapProps) => {
+            state.createGeometry = newProps.radialSegments !== currentProps.radialSegments
         }
     })
 }

+ 7 - 7
src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts

@@ -5,16 +5,16 @@
  */
 
 import { Unit, Structure } from 'mol-model/structure';
-import { UnitsVisual, MeshUpdateState } from '..';
+import { UnitsVisual, VisualUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
-import { Mesh } from '../../../mesh/mesh';
-import { MeshBuilder } from '../../../mesh/mesh-builder';
+import { Mesh } from '../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../geometry/mesh/mesh-builder';
 import { PolymerTraceIterator, createCurveSegmentState, interpolateCurveSegment, PolymerLocationIterator, getPolymerElementLoci, markPolymerElement } from './util/polymer';
 import { SecondaryStructureType, isNucleic } from 'mol-model/structure/model/types';
 import { UnitsMeshVisual, DefaultUnitsMeshProps } from '../units-visual';
 import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
-import { addSheet } from '../../../mesh/builder/sheet';
-import { addTube } from '../../../mesh/builder/tube';
+import { addSheet } from '../../../geometry/mesh/builder/sheet';
+import { addTube } from '../../../geometry/mesh/builder/tube';
 
 export interface PolymerTraceMeshProps {
     sizeTheme: SizeThemeProps
@@ -97,8 +97,8 @@ export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> {
         createLocationIterator: PolymerLocationIterator.fromGroup,
         getLoci: getPolymerElementLoci,
         mark: markPolymerElement,
-        setUpdateState: (state: MeshUpdateState, newProps: PolymerTraceProps, currentProps: PolymerTraceProps) => {
-            state.createMesh = (
+        setUpdateState: (state: VisualUpdateState, newProps: PolymerTraceProps, currentProps: PolymerTraceProps) => {
+            state.createGeometry = (
                 newProps.linearSegments !== currentProps.linearSegments ||
                 newProps.radialSegments !== currentProps.radialSegments ||
                 newProps.aspectRatio !== currentProps.aspectRatio ||

+ 13 - 14
src/mol-geo/representation/structure/visual/util/common.ts

@@ -8,12 +8,10 @@
 import { Unit, Structure } from 'mol-model/structure';
 import { createUniformColor, ColorData, createGroupColor, createGroupInstanceColor, createInstanceColor, ColorType } from '../../../../util/color-data';
 import { createUniformSize, SizeData, createGroupSize, createGroupInstanceSize, createInstanceSize, SizeType } from '../../../../util/size-data';
-import { ValueCell } from 'mol-util';
 import { LocationIterator } from '../../../../util/location-iterator';
-import { Mesh } from '../../../../mesh/mesh';
+import { Mesh } from '../../../../geometry/mesh/mesh';
 import { MeshValues, PointValues } from 'mol-gl/renderable';
 import { getMeshData } from '../../../../util/mesh-data';
-import { MeshProps, createMeshValues, createRenderableState, createPointValues } from '../../../util';
 import { StructureProps } from '../..';
 import { createMarkers } from '../../../../util/marker-data';
 import { createMeshRenderObject, createPointRenderObject } from 'mol-gl/render-object';
@@ -21,8 +19,10 @@ import { ColorThemeProps, ColorTheme } from 'mol-view/theme/color';
 import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
 import { RuntimeContext } from 'mol-task';
 import { PointProps } from 'mol-geo/representation/structure/representation/point';
-import { fillSerial } from 'mol-util/array';
 import { TransformData, createIdentityTransform, createTransforms } from '../../../../util/transform-data';
+import { Point } from '../../../../geometry/point/point';
+import { getPointData } from '../../../../util/point-data';
+import { MeshProps, createMeshValues, createRenderableState, createPointValues } from '../../../../geometry/geometry';
 
 function getGranularity(locationIt: LocationIterator, granularity: ColorType | SizeType) {
     // Always use 'group' granularity for 'complex' location iterators,
@@ -52,7 +52,7 @@ export async function createSizes(ctx: RuntimeContext, locationIt: LocationItera
 
 // mesh
 
-type StructureMeshProps = Required<MeshProps & StructureProps>
+type StructureMeshProps = MeshProps & StructureProps
 
 async function _createMeshValues(ctx: RuntimeContext, transforms: TransformData, mesh: Mesh, locationIt: LocationIterator, props: StructureMeshProps): Promise<MeshValues> {
     const { instanceCount, groupCount } = locationIt
@@ -100,19 +100,18 @@ export async function updateComplexMeshRenderObject(ctx: RuntimeContext, structu
 
 // point
 
-type StructurePointProps = Required<PointProps & StructureProps>
+type StructurePointProps = PointProps & StructureProps
 
-async function _createPointValues(ctx: RuntimeContext, transforms: TransformData, vertices: ValueCell<Float32Array>, locationIt: LocationIterator, props: StructurePointProps): Promise<PointValues> {
+async function _createPointValues(ctx: RuntimeContext, transforms: TransformData, point: Point, locationIt: LocationIterator, props: StructurePointProps): Promise<PointValues> {
     const { instanceCount, groupCount } = locationIt
     const color = await createColors(ctx, locationIt, props.colorTheme)
     const size = await createSizes(ctx, locationIt, props.sizeTheme)
     const marker = createMarkers(instanceCount * groupCount)
 
-    const counts = { drawCount: groupCount, groupCount, instanceCount }
+    const counts = { drawCount: point.vertexCount, groupCount, instanceCount }
 
     return {
-        aPosition: vertices,
-        aGroup: ValueCell.create(fillSerial(new Float32Array(groupCount))),
+        ...getPointData(point),
         ...color,
         ...size,
         ...marker,
@@ -121,13 +120,13 @@ async function _createPointValues(ctx: RuntimeContext, transforms: TransformData
     }
 }
 
-export async function createUnitsPointValues(ctx: RuntimeContext, group: Unit.SymmetryGroup, vertices: ValueCell<Float32Array>, locationIt: LocationIterator, props: StructurePointProps): Promise<PointValues> {
+export async function createUnitsPointValues(ctx: RuntimeContext, group: Unit.SymmetryGroup, point: Point, locationIt: LocationIterator, props: StructurePointProps): Promise<PointValues> {
     const transforms = createTransforms(group)
-    return _createPointValues(ctx, transforms, vertices, locationIt, props)
+    return _createPointValues(ctx, transforms, point, locationIt, props)
 }
 
-export async function createUnitsPointRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, vertices: ValueCell<Float32Array>, locationIt: LocationIterator, props: StructurePointProps) {
-    const values = await createUnitsPointValues(ctx, group, vertices, locationIt, props)
+export async function createUnitsPointRenderObject(ctx: RuntimeContext, group: Unit.SymmetryGroup, point: Point, locationIt: LocationIterator, props: StructurePointProps) {
+    const values = await createUnitsPointValues(ctx, group, point, locationIt, props)
     const state = createRenderableState(props)
     return createPointRenderObject(values, state)
 }

+ 3 - 3
src/mol-geo/representation/structure/visual/util/element.ts

@@ -8,14 +8,14 @@ import { Vec3 } from 'mol-math/linear-algebra';
 import { Unit, StructureElement, Structure } from 'mol-model/structure';
 import { RuntimeContext } from 'mol-task';
 import { sphereVertexCount } from '../../../../primitive/sphere';
-import { Mesh } from '../../../../mesh/mesh';
-import { MeshBuilder } from '../../../../mesh/mesh-builder';
+import { Mesh } from '../../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../../geometry/mesh/mesh-builder';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { Interval, OrderedSet } from 'mol-data/int';
 import { PickingId } from '../../../../util/picking';
 import { SizeTheme, SizeThemeProps } from 'mol-view/theme/size';
 import { LocationIterator } from '../../../../util/location-iterator';
-import { addSphere } from '../../../../mesh/builder/sphere';
+import { addSphere } from '../../../../geometry/mesh/builder/sphere';
 
 export interface ElementSphereMeshProps {
     sizeTheme: SizeThemeProps,

+ 124 - 0
src/mol-geo/representation/structure/visual/util/gaussian.ts

@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { Unit, Structure, StructureElement } from 'mol-model/structure';
+import { RuntimeContext, Task } from 'mol-task'
+import { Tensor, Vec3, Mat4 } from 'mol-math/linear-algebra';
+import { Box3D } from 'mol-math/geometry';
+import { SizeThemeProps, SizeTheme } from 'mol-view/theme/size';
+
+export interface GaussianDensityProps {
+    sizeTheme: SizeThemeProps
+
+    resolutionFactor: number
+    probeRadius: number
+    isoValue: number
+}
+
+function getDelta(box: Box3D, resolutionFactor: number) {
+    const extent = Vec3.sub(Vec3.zero(), box.max, box.min)
+
+    const n = Math.pow(Math.pow(2, resolutionFactor), 3)
+    const f = (extent[0] * extent[1] * extent[2]) / n
+    const s = Math.pow(f, 1 / 3)
+    const size = Vec3.zero()
+    // Vec3.scale(size, extent, s)
+    Vec3.ceil(size, Vec3.scale(size, extent, s))
+    const delta = Vec3.div(Vec3.zero(), extent, size)
+    return delta
+}
+
+type Density = { transform: Mat4, field: Tensor }
+
+export function computeGaussianDensity(unit: Unit, structure: Structure, props: GaussianDensityProps) {
+    return Task.create('Gaussian Density', async ctx => {
+        return await GaussianDensity(ctx, unit, structure, props);
+    });
+}
+
+export async function GaussianDensity(ctx: RuntimeContext, unit: Unit, structure: Structure, props: GaussianDensityProps): Promise<Density> {
+    const { resolutionFactor, probeRadius, isoValue } = props
+
+    const { elements } = unit;
+    const elementCount = elements.length;
+    const sizeTheme = SizeTheme(props.sizeTheme)
+
+    const v = Vec3.zero()
+    const p = Vec3.zero()
+    const pos = unit.conformation.invariantPosition
+    const l = StructureElement.create(unit)
+
+    const pad = (probeRadius + 3) * 3 // TODO calculate max radius
+    const box = unit.lookup3d.boundary.box
+    const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad));
+    const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
+    const min = expandedBox.min
+
+    const delta = getDelta(Box3D.expand(Box3D.empty(), structure.boundary.box, Vec3.create(pad, pad, pad)), resolutionFactor)
+    const dim = Vec3.zero()
+    Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
+
+    const space = Tensor.Space(dim, [0, 1, 2], Float32Array)
+    const data = space.create()
+    const field = Tensor.create(space, data)
+
+    const c = Vec3.zero()
+
+    const alpha = isoValue // smoothness
+
+    const _r2 = (probeRadius + 1.4 * 2)
+    const _radius2 = Vec3.create(_r2, _r2, _r2)
+    Vec3.mul(_radius2, _radius2, delta)
+    const updateChunk = Math.ceil(10000 / (_radius2[0] * _radius2[1] * _radius2[2]))
+
+    const beg = Vec3.zero()
+    const end = Vec3.zero()
+
+    for (let i = 0; i < elementCount; i++) {
+        l.element = elements[i]
+        pos(elements[i], v)
+
+        Vec3.sub(v, v, min)
+        Vec3.mul(c, v, delta)
+
+        const radius = sizeTheme.size(l) + probeRadius
+        const rSq = radius * radius
+
+        const r2 = (probeRadius + radius * 2)
+        const radius2 = Vec3.create(r2, r2, r2)
+        Vec3.mul(radius2, radius2, delta)
+        const r2sq = r2 * r2
+
+        const [ begX, begY, begZ ] = Vec3.floor(beg, Vec3.sub(beg, c, radius2))
+        const [ endX, endY, endZ ] = Vec3.ceil(end, Vec3.add(end, c, radius2))
+
+        for (let x = begX; x < endX; ++x) {
+            for (let y = begY; y < endY; ++y) {
+                for (let z = begZ; z < endZ; ++z) {
+                    Vec3.set(p, x, y, z)
+                    Vec3.div(p, p, delta)
+                    const distSq = Vec3.squaredDistance(p, v)
+                    if (distSq <= r2sq) {
+                        space.add(data, x, y, z, Math.exp(-alpha * (distSq / rSq)))
+                    }
+                }
+            }
+        }
+
+        if (i % updateChunk === 0 && ctx.shouldUpdate) {
+            await ctx.update({ message: 'filling density grid', current: i, max: elementCount });
+        }
+    }
+
+    const t = Mat4.identity()
+    Mat4.fromScaling(t, Vec3.inverse(Vec3.zero(), delta))
+    Mat4.setTranslation(t, expandedBox.min)
+
+    return {
+        field,
+        transform: t
+    }
+}

+ 4 - 4
src/mol-geo/representation/structure/visual/util/link.ts

@@ -6,15 +6,15 @@
 
 import { Vec3 } from 'mol-math/linear-algebra';
 import { RuntimeContext } from 'mol-task';
-import { Mesh } from '../../../../mesh/mesh';
-import { MeshBuilder } from '../../../../mesh/mesh-builder';
+import { Mesh } from '../../../../geometry/mesh/mesh';
+import { MeshBuilder } from '../../../../geometry/mesh/mesh-builder';
 import { LinkType } from 'mol-model/structure/model/types';
-import { DefaultMeshProps } from '../../../util';
 import { SizeThemeProps } from 'mol-view/theme/size';
 import { CylinderProps } from '../../../../primitive/cylinder';
 import { LocationIterator } from '../../../../util/location-iterator';
 import { Unit, StructureElement, Structure, Link } from 'mol-model/structure';
-import { addFixedCountDashedCylinder, addCylinder, addDoubleCylinder } from '../../../../mesh/builder/cylinder';
+import { addFixedCountDashedCylinder, addCylinder, addDoubleCylinder } from '../../../../geometry/mesh/builder/cylinder';
+import { DefaultMeshProps } from '../../../../geometry/geometry';
 
 export const DefaultLinkCylinderProps = {
     ...DefaultMeshProps,

+ 1 - 89
src/mol-geo/representation/util.ts

@@ -4,97 +4,9 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { ValueCell } from 'mol-util/value-cell'
-import { BaseValues } from 'mol-gl/renderable/schema';
-import { MeshValues, RenderableState } from 'mol-gl/renderable';
 import { defaults } from 'mol-util';
 import { Structure } from 'mol-model/structure';
-
-export const DefaultBaseProps = {
-    alpha: 1,
-    visible: true,
-    depthMask: true,
-    useFog: false,
-    quality: 'auto' as VisualQuality
-}
-export type BaseProps = typeof DefaultBaseProps
-
-export const DefaultMeshProps = {
-    ...DefaultBaseProps,
-    doubleSided: false,
-    flipSided: false,
-    flatShaded: false,
-}
-export type MeshProps = typeof DefaultMeshProps
-
-export const DefaultPointProps = {
-    ...DefaultBaseProps,
-    pointSizeAttenuation: true
-}
-export type PointProps = typeof DefaultPointProps
-
-type Counts = { drawCount: number, groupCount: number, instanceCount: number }
-
-export function createBaseValues(props: Required<BaseProps>, counts: Counts) {
-    return {
-        uAlpha: ValueCell.create(props.alpha),
-        uGroupCount: ValueCell.create(counts.groupCount),
-        drawCount: ValueCell.create(counts.drawCount),
-        dUseFog: ValueCell.create(props.useFog),
-    }
-}
-
-export function createMeshValues(props: Required<MeshProps>, counts: Counts) {
-    return {
-        ...createBaseValues(props, counts),
-        dDoubleSided: ValueCell.create(props.doubleSided),
-        dFlatShaded: ValueCell.create(props.flatShaded),
-        dFlipSided: ValueCell.create(props.flipSided),
-    }
-}
-
-export function createPointValues(props: Required<PointProps>, counts: Counts) {
-    return {
-        ...createBaseValues(props, counts),
-        dPointSizeAttenuation: ValueCell.create(props.pointSizeAttenuation),
-    }
-}
-
-export function createRenderableState(props: Required<BaseProps>): RenderableState {
-    return {
-        visible: props.visible,
-        depthMask: props.depthMask
-    }
-}
-
-export function updateBaseValues(values: BaseValues, props: Required<BaseProps>) {
-    ValueCell.updateIfChanged(values.uAlpha, props.alpha)
-    ValueCell.updateIfChanged(values.dUseFog, props.useFog)
-}
-
-export function updateMeshValues(values: MeshValues, props: Required<MeshProps>) {
-    updateBaseValues(values, props)
-    ValueCell.updateIfChanged(values.dDoubleSided, props.doubleSided)
-    ValueCell.updateIfChanged(values.dFlatShaded, props.flatShaded)
-    ValueCell.updateIfChanged(values.dFlipSided, props.flipSided)
-}
-
-export function updateRenderableState(state: RenderableState, props: Required<BaseProps>) {
-    state.visible = props.visible
-    state.depthMask = props.depthMask
-}
-
-export const VisualQualityInfo = {
-    'custom': {},
-    'auto': {},
-    'highest': {},
-    'high': {},
-    'medium': {},
-    'low': {},
-    'lowest': {},
-}
-export type VisualQuality = keyof typeof VisualQualityInfo
-export const VisualQualityNames = Object.keys(VisualQualityInfo)
+import { VisualQuality } from '../geometry/geometry';
 
 export interface QualityProps {
     quality: VisualQuality

+ 1 - 1
src/mol-geo/representation/volume/index.ts

@@ -11,7 +11,7 @@ import { VolumeData } from 'mol-model/volume';
 import { PickingId } from '../../util/picking';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { MarkerAction } from '../../util/marker-data';
-import { DefaultBaseProps } from '../util';
+import { DefaultBaseProps } from '../../geometry/geometry';
 
 export interface VolumeVisual<P extends RepresentationProps = {}> extends Visual<VolumeData, P> { }
 

+ 1 - 1
src/mol-geo/representation/volume/surface.ts

@@ -8,7 +8,7 @@
 import { VolumeData, VolumeIsoValue } from 'mol-model/volume'
 import { Task, RuntimeContext } from 'mol-task'
 import { computeMarchingCubes } from '../../util/marching-cubes/algorithm';
-import { Mesh } from '../../mesh/mesh';
+import { Mesh } from '../../geometry/mesh/mesh';
 import { VolumeVisual } from '.';
 import { createMeshRenderObject, MeshRenderObject } from 'mol-gl/render-object';
 import { ValueCell, defaults } from 'mol-util';

+ 2 - 1
src/mol-geo/util/marching-cubes/algorithm.ts

@@ -7,7 +7,7 @@
 import { Task, RuntimeContext } from 'mol-task'
 import { ChunkedArray } from 'mol-data/util'
 import { Tensor } from 'mol-math/linear-algebra'
-import { Mesh } from '../../mesh/mesh'
+import { Mesh } from '../../geometry/mesh/mesh'
 import { Index, EdgeIdInfo, CubeEdges, EdgeTable, TriTable } from './tables'
 import { ValueCell } from 'mol-util'
 
@@ -76,6 +76,7 @@ class MarchingCubesComputation {
         const os = this.parameters.oldSurface
 
         return {
+            kind: 'mesh',
             vertexCount:  this.state.vertexCount,
             triangleCount: this.state.triangleCount,
             vertexBuffer: os ? ValueCell.update(os.vertexBuffer, vb) : ValueCell.create(vb),

+ 1 - 1
src/mol-geo/util/mesh-data.ts

@@ -5,7 +5,7 @@
  */
 
 import { ValueCell } from 'mol-util/value-cell'
-import { Mesh } from '../mesh/mesh';
+import { Mesh } from '../geometry/mesh/mesh';
 
 type MeshData = {
     aPosition: ValueCell<Float32Array>,

+ 20 - 0
src/mol-geo/util/point-data.ts

@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ */
+
+import { ValueCell } from 'mol-util/value-cell'
+import { Point } from '../geometry/point/point';
+
+type PointData = {
+    aPosition: ValueCell<Float32Array>,
+    aGroup: ValueCell<Float32Array>,
+}
+
+export function getPointData(point: Point): PointData {
+    return {
+        aPosition: point.vertexBuffer,
+        aGroup: point.groupBuffer,
+    }
+}

+ 1 - 1
src/mol-io/reader/obj/parser.ts

@@ -6,7 +6,7 @@
 
 import Result from '../result'
 import { Task, RuntimeContext } from 'mol-task'
-import { Mesh } from 'mol-geo/mesh/mesh';
+import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 
 async function parseInternal(data: string, ctx: RuntimeContext): Promise<Result<Mesh>> {
     // TODO

+ 51 - 13
src/mol-math/linear-algebra/tensor.ts

@@ -20,6 +20,7 @@ export namespace Tensor {
         create(array?: ArrayCtor): Tensor.Data,
         get(data: Tensor.Data, ...coords: number[]): number
         set(data: Tensor.Data, ...coordsAndValue: number[]): number
+        add(data: Tensor.Data, ...coordsAndValue: number[]): number
     }
 
     interface Layout {
@@ -45,8 +46,8 @@ export namespace Tensor {
 
     export function Space(dimensions: number[], axisOrderSlowToFast: number[], ctor?: ArrayCtor): Space {
         const layout = Layout(dimensions, axisOrderSlowToFast, ctor);
-        const { get, set } = accessors(layout);
-        return { rank: dimensions.length, dimensions, axisOrderSlowToFast, create: creator(layout), get, set };
+        const { get, set, add } = accessors(layout);
+        return { rank: dimensions.length, dimensions, axisOrderSlowToFast, create: creator(layout), get, set, add };
     }
 
     export function Data1(values: ArrayLike<number>): Data { return values as Data; }
@@ -98,52 +99,89 @@ export namespace Tensor {
         return true;
     }
 
-    function accessors(layout: Layout): { get: Space['get'], set: Space['set'] } {
+    function accessors(layout: Layout): { get: Space['get'], set: Space['set'], add: Space['add'] } {
         const { dimensions, axisOrderFastToSlow: ao } = layout;
         switch (dimensions.length) {
-            case 1: return { get: (t, d) => t[d], set: (t, d, x) => t[d] = x };
+            case 1: return {
+                get: (t, d) => t[d],
+                set: (t, d, x) => t[d] = x,
+                add: (t, d, x) => t[d] += x
+            };
             case 2: {
                 // column major
                 if (ao[0] === 0 && ao[1] === 1) {
                     const rows = dimensions[0];
-                    return { get: (t, i, j) => t[j * rows + i], set: (t, i, j, x) => t[j * rows + i] = x };
+                    return {
+                        get: (t, i, j) => t[j * rows + i],
+                        set: (t, i, j, x) => t[j * rows + i] = x,
+                        add: (t, i, j, x) => t[j * rows + i] += x
+                    };
                 }
                 if (ao[0] === 1 && ao[1] === 0) {
                     const cols = dimensions[1];
-                    return { get: (t, i, j) => t[i * cols + j], set: (t, i, j, x) => t[i * cols + j] = x };
+                    return {
+                        get: (t, i, j) => t[i * cols + j],
+                        set: (t, i, j, x) => t[i * cols + j] = x,
+                        add: (t, i, j, x) => t[i * cols + j] += x
+                    };
                 }
                 throw new Error('bad axis order')
             }
             case 3: {
                 if (ao[0] === 0 && ao[1] === 1 && ao[2] === 2) { // 012 ijk
                     const u = dimensions[0], v = dimensions[1], uv = u * v;
-                    return { get: (t, i, j, k) => t[i + j * u + k * uv], set: (t, i, j, k, x ) => t[i + j * u + k * uv] = x };
+                    return {
+                        get: (t, i, j, k) => t[i + j * u + k * uv],
+                        set: (t, i, j, k, x ) => t[i + j * u + k * uv] = x,
+                        add: (t, i, j, k, x ) => t[i + j * u + k * uv] += x
+                    };
                 }
                 if (ao[0] === 0 && ao[1] === 2 && ao[2] === 1) { // 021 ikj
                     const u = dimensions[0], v = dimensions[2], uv = u * v;
-                    return { get: (t, i, j, k) => t[i + k * u + j * uv], set: (t, i, j, k, x ) => t[i + k * u + j * uv] = x };
+                    return {
+                        get: (t, i, j, k) => t[i + k * u + j * uv],
+                        set: (t, i, j, k, x ) => t[i + k * u + j * uv] = x,
+                        add: (t, i, j, k, x ) => t[i + k * u + j * uv] += x
+                    };
                 }
                 if (ao[0] === 1 && ao[1] === 0 && ao[2] === 2) { // 102 jik
                     const u = dimensions[1], v = dimensions[0], uv = u * v;
-                    return { get: (t, i, j, k) => t[j + i * u + k * uv], set: (t, i, j, k, x ) => t[j + i * u + k * uv] = x };
+                    return {
+                        get: (t, i, j, k) => t[j + i * u + k * uv],
+                        set: (t, i, j, k, x ) => t[j + i * u + k * uv] = x,
+                        add: (t, i, j, k, x ) => t[j + i * u + k * uv] += x
+                    };
                 }
                 if (ao[0] === 1 && ao[1] === 2 && ao[2] === 0) { // 120 jki
                     const u = dimensions[1], v = dimensions[2], uv = u * v;
-                    return { get: (t, i, j, k) => t[j + k * u + i * uv], set: (t, i, j, k, x ) => t[j + k * u + i * uv] = x };
+                    return {
+                        get: (t, i, j, k) => t[j + k * u + i * uv],
+                        set: (t, i, j, k, x ) => t[j + k * u + i * uv] = x,
+                        add: (t, i, j, k, x ) => t[j + k * u + i * uv] += x
+                    };
                 }
                 if (ao[0] === 2 && ao[1] === 0 && ao[2] === 1) { // 201 kij
                     const u = dimensions[2], v = dimensions[0], uv = u * v;
-                    return { get: (t, i, j, k) => t[k + i * u + j * uv], set: (t, i, j, k, x ) => t[k + i * u + j * uv] = x };
+                    return {
+                        get: (t, i, j, k) => t[k + i * u + j * uv],
+                        set: (t, i, j, k, x ) => t[k + i * u + j * uv] = x,
+                        add: (t, i, j, k, x ) => t[k + i * u + j * uv] += x
+                    };
                 }
                 if (ao[0] === 2 && ao[1] === 1 && ao[2] === 0) { // 210 kji
                     const u = dimensions[2], v = dimensions[1], uv = u * v;
-                    return { get: (t, i, j, k) => t[k + j * u + i * uv], set: (t, i, j, k, x ) => t[k + j * u + i * uv] = x };
+                    return {
+                        get: (t, i, j, k) => t[k + j * u + i * uv],
+                        set: (t, i, j, k, x ) => t[k + j * u + i * uv] = x,
+                        add: (t, i, j, k, x ) => t[k + j * u + i * uv] += x
+                    };
                 }
                 throw new Error('bad axis order')
             }
             default: return {
                 get: (t, ...c) => t[dataOffset(layout, c)],
-                set: (t, ...c) => t[dataOffset(layout, c)] = c[c.length - 1]
+                set: (t, ...c) => t[dataOffset(layout, c)] = c[c.length - 1],
+                add: (t, ...c) => t[dataOffset(layout, c)] += c[c.length - 1]
             };
         }
     }

+ 1 - 1
src/mol-model/shape/shape.ts

@@ -4,7 +4,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-import { Mesh } from 'mol-geo/mesh/mesh';
+import { Mesh } from 'mol-geo/geometry/mesh/mesh';
 import { Color } from 'mol-util/color';
 import { UUID, ValueCell } from 'mol-util';
 import { OrderedSet } from 'mol-data/int';