Browse Source

wip, visuals

Alexander Rose 6 years ago
parent
commit
68623ccc11
21 changed files with 140 additions and 59 deletions
  1. 0 1
      src/mol-app/ui/transform/backbone.tsx
  2. 0 1
      src/mol-app/ui/transform/carbohydrate.tsx
  3. 0 1
      src/mol-app/ui/transform/cartoon.tsx
  4. 16 2
      src/mol-app/ui/transform/spacefill.tsx
  5. 1 1
      src/mol-geo/representation/structure/complex-representation.ts
  6. 29 11
      src/mol-geo/representation/structure/complex-visual.ts
  7. 17 0
      src/mol-geo/representation/structure/index.ts
  8. 1 1
      src/mol-geo/representation/structure/units-representation.ts
  9. 22 17
      src/mol-geo/representation/structure/units-visual.ts
  10. 5 2
      src/mol-geo/representation/structure/visual/carbohydrate-link-cylinder.ts
  11. 5 6
      src/mol-geo/representation/structure/visual/carbohydrate-symbol-mesh.ts
  12. 7 4
      src/mol-geo/representation/structure/visual/cross-link-restraint-cylinder.ts
  13. 5 2
      src/mol-geo/representation/structure/visual/element-sphere.ts
  14. 7 4
      src/mol-geo/representation/structure/visual/inter-unit-link-cylinder.ts
  15. 2 1
      src/mol-geo/representation/structure/visual/intra-unit-link-cylinder.ts
  16. 2 1
      src/mol-geo/representation/structure/visual/nucleotide-block-mesh.ts
  17. 2 1
      src/mol-geo/representation/structure/visual/polymer-backbone-cylinder.ts
  18. 2 1
      src/mol-geo/representation/structure/visual/polymer-direction-wedge.ts
  19. 2 1
      src/mol-geo/representation/structure/visual/polymer-gap-cylinder.ts
  20. 2 1
      src/mol-geo/representation/structure/visual/polymer-trace-mesh.ts
  21. 13 0
      src/mol-geo/representation/structure/visual/util/location-iterator.ts

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

@@ -60,7 +60,6 @@ export class Backbone extends View<Controller<any>, BackboneState, { transform:
     }
 
     update(state?: Partial<BackboneState>) {
-        console.log(state)
         const { transform, entity, ctx } = this.props
         const newState = { ...this.state, ...state }
         this.setState(newState)

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

@@ -68,7 +68,6 @@ export class Carbohydrate extends View<Controller<any>, CarbohydrateState, { tra
     }
 
     update(state?: Partial<CarbohydrateState>) {
-        console.log(state)
         const { transform, entity, ctx } = this.props
         const newState = { ...this.state, ...state }
         this.setState(newState)

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

@@ -60,7 +60,6 @@ export class Cartoon extends View<Controller<any>, CartoonState, { transform: Ca
     }
 
     update(state?: Partial<CartoonState>) {
-        console.log(state)
         const { transform, entity, ctx } = this.props
         const newState = { ...this.state, ...state }
         this.setState(newState)

+ 16 - 2
src/mol-app/ui/transform/spacefill.tsx

@@ -46,7 +46,7 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
         detail: 2,
         colorTheme: { name: 'element-symbol' } as ColorThemeProps,
         colorValue: 0x000000,
-        sizeTheme: { name: 'uniform' } as SizeThemeProps,
+        sizeTheme: { name: 'uniform', factor: 1 } as SizeThemeProps,
         visible: true,
         alpha: 1,
         depthMask: true,
@@ -60,7 +60,6 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
     }
 
     update(state?: Partial<SpacefillState>) {
-        console.log(state)
         const { transform, entity, ctx } = this.props
         const newState = { ...this.state, ...state }
         this.setState(newState)
@@ -220,6 +219,21 @@ export class Spacefill extends View<Controller<any>, SpacefillState, { transform
                                 />
                             </div>
                         </div>
+                        <div className='molstar-control-row molstar-options-group'>
+                            <div>
+                                <Slider
+                                    value={this.state.sizeTheme.factor || 1}
+                                    label='Size factor'
+                                    min={0.1}
+                                    max={3}
+                                    step={0.01}
+                                    callOnChangeWhileSliding={true}
+                                    onChange={value => this.update({
+                                        sizeTheme: { ...this.state.sizeTheme, factor: value }
+                                    })}
+                                />
+                            </div>
+                        </div>
                     </div>
                 </div>
             </div>

+ 1 - 1
src/mol-geo/representation/structure/complex-representation.ts

@@ -33,7 +33,7 @@ export function ComplexRepresentation<P extends StructureProps>(visualCtor: () =
                     await update(_props)
                 } else {
                     if (!await visual.update(ctx, _props)) {
-                        await visual.create(ctx, _structure, _props)
+                        await visual.create(ctx, structure, _props)
                     }
                 }
             }

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

@@ -11,7 +11,7 @@ import { Mesh } from '../../shape/mesh';
 import { RuntimeContext } from 'mol-task';
 import { LocationIterator } from './visual/util/location-iterator';
 import { createComplexMeshRenderObject, createColors } from './visual/util/common';
-import { StructureMeshProps, StructureProps } from '.';
+import { StructureProps, DefaultStructureMeshProps, MeshUpdateState } from '.';
 import { deepEqual, ValueCell } from 'mol-util';
 import { updateMeshValues, updateRenderableState } from '../util';
 import { PickingId } from '../../util/picking';
@@ -21,16 +21,23 @@ import { Interval } from 'mol-data/int';
 
 export interface  ComplexVisual<P extends StructureProps> extends Visual<Structure, P> { }
 
-export interface ComplexMeshVisualBuilder<P extends StructureMeshProps> {
+export const DefaultComplexMeshProps = {
+    ...DefaultStructureMeshProps
+}
+export type ComplexMeshProps = typeof DefaultComplexMeshProps
+
+export interface ComplexMeshVisualBuilder<P extends ComplexMeshProps> {
     defaultProps: P
     createMesh(ctx: RuntimeContext, structure: Structure, props: P, mesh?: Mesh): Promise<Mesh>
     createLocationIterator(structure: Structure): LocationIterator
     getLoci(pickingId: PickingId, structure: Structure, id: number): Loci
-    mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean
+    mark(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean): boolean,
+    setUpdateState(state: MeshUpdateState, newProps: P, currentProps: P): void
 }
 
-export function ComplexMeshVisual<P extends StructureMeshProps>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> {
-    const { defaultProps, createMesh, createLocationIterator, getLoci, mark } = builder
+export function ComplexMeshVisual<P extends ComplexMeshProps>(builder: ComplexMeshVisualBuilder<P>): ComplexVisual<P> {
+    const { defaultProps, createMesh, createLocationIterator, getLoci, mark, setUpdateState } = builder
+    const updateState = MeshUpdateState.create()
 
     let renderObject: MeshRenderObject
     let currentProps: P
@@ -54,16 +61,27 @@ export function ComplexMeshVisual<P extends StructureMeshProps>(builder: Complex
 
             if (!renderObject) return false
 
-            let updateColor = false
+            locationIt.reset()
+            MeshUpdateState.reset(updateState)
+            setUpdateState(updateState, newProps, currentProps)
 
-            // TODO create in-place
-            // if (currentProps.radialSegments !== newProps.radialSegments) return false
+            if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) {
+                updateState.createMesh = true
+            }
 
             if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
-                updateColor = true
+                updateState.updateColor = true
+            }
+
+            //
+
+            if (updateState.createMesh) {
+                mesh = await createMesh(ctx, currentStructure, newProps, mesh)
+                ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3)
+                updateState.updateColor = true
             }
 
-            if (updateColor) {
+            if (updateState.updateColor) {
                 createColors(locationIt, newProps.colorTheme, renderObject.values)
             }
 
@@ -71,7 +89,7 @@ export function ComplexMeshVisual<P extends StructureMeshProps>(builder: Complex
             updateRenderableState(renderObject.state, newProps)
 
             currentProps = newProps
-            return false
+            return true
         },
         getLoci(pickingId: PickingId) {
             return getLoci(pickingId, currentStructure, renderObject.id)

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

@@ -26,6 +26,23 @@ export const DefaultStructureMeshProps = {
 }
 export type StructureMeshProps = typeof DefaultStructureMeshProps
 
+export interface MeshUpdateState {
+    updateColor: boolean
+    createMesh: boolean
+}
+export namespace MeshUpdateState {
+    export function create(): MeshUpdateState {
+        return {
+            updateColor: false,
+            createMesh: false
+        }
+    }
+    export function reset(state: MeshUpdateState) {
+        state.updateColor = false
+        state.createMesh = false
+    }
+}
+
 export { ComplexRepresentation } from './complex-representation'
 export { UnitsRepresentation } from './units-representation'
 export { ComplexVisual } from './complex-visual'

+ 1 - 1
src/mol-geo/representation/structure/units-representation.ts

@@ -65,7 +65,7 @@ export function UnitsRepresentation<P extends StructureProps>(visualCtor: () =>
                         }
                     }
 
-                    // for new groups, reuse leftover visuals
+                    // for new groups, re-use leftover visuals
                     const unusedVisuals: UnitsVisual<P>[] = []
                     oldUnitsVisuals.forEach(({ visual }) => unusedVisuals.push(visual))
                     newGroups.forEach(async group => {

+ 22 - 17
src/mol-geo/representation/structure/units-visual.ts

@@ -6,7 +6,7 @@
 
 import { Unit } from 'mol-model/structure';
 import { RepresentationProps, Visual } from '..';
-import { DefaultStructureMeshProps } from '.';
+import { DefaultStructureMeshProps, MeshUpdateState } from '.';
 import { RuntimeContext } from 'mol-task';
 import { PickingId } from '../../util/picking';
 import { LocationIterator } from './visual/util/location-iterator';
@@ -33,10 +33,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
 }
 
 export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisualBuilder<P>): UnitsVisual<P> {
-    const { defaultProps, createMesh, createLocationIterator, getLoci, mark } = builder
+    const { defaultProps, createMesh, createLocationIterator, getLoci, mark, setUpdateState } = builder
+    const updateState = MeshUpdateState.create()
 
     let renderObject: MeshRenderObject
     let currentProps: P
@@ -60,29 +62,32 @@ export function UnitsMeshVisual<P extends UnitsMeshProps>(builder: UnitsMeshVisu
         },
         async update(ctx: RuntimeContext, props: Partial<P>) {
             const newProps = Object.assign({}, currentProps, props)
+            const unit = currentGroup.units[0]
 
             if (!renderObject) return false
 
-            let updateColor = false
+            locationIt.reset()
+            MeshUpdateState.reset(updateState)
+            setUpdateState(updateState, newProps, currentProps)
 
-            // TODO create in-place
-            // if (currentProps.radialSegments !== newProps.radialSegments) return false
-
-            // TODO
-            // if (newProps.detail !== currentProps.detail) {
-            //     const unit = currentGroup.units[0]
-            //     const radius = getElementRadius(unit, newProps.sizeTheme)
-            //     mesh = await createElementSphereMesh(ctx, unit, radius, newProps.detail, mesh)
-            //     ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3)
-            //     updateColor = true
-            // }
+            if (!deepEqual(newProps.sizeTheme, currentProps.sizeTheme)) {
+                updateState.createMesh = true
+            }
 
             if (!deepEqual(newProps.colorTheme, currentProps.colorTheme)) {
-                updateColor = true
+                updateState.updateColor = true
+            }
+
+            //
+
+            if (updateState.createMesh) {
+                mesh = await createMesh(ctx, unit, newProps, mesh)
+                ValueCell.update(renderObject.values.drawCount, mesh.triangleCount * 3)
+                updateState.updateColor = true
             }
 
-            if (updateColor) {
-                createColors(createLocationIterator(currentGroup), newProps.colorTheme, renderObject.values)
+            if (updateState.updateColor) {
+                createColors(locationIt, newProps.colorTheme, renderObject.values)
             }
 
             updateMeshValues(renderObject.values, newProps)

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

@@ -5,7 +5,7 @@
  */
 
 import { Unit, Structure, Link, StructureElement } from 'mol-model/structure';
-import { DefaultStructureProps, ComplexVisual } from '..';
+import { DefaultStructureProps, ComplexVisual, MeshUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
 import { Mesh } from '../../../shape/mesh';
 import { PickingId } from '../../../util/picking';
@@ -64,7 +64,10 @@ export function CarbohydrateLinkVisual(): ComplexVisual<CarbohydrateLinkProps> {
         createMesh: createCarbohydrateLinkCylinderMesh,
         createLocationIterator: CarbohydrateLinkIterator,
         getLoci: getLinkLoci,
-        mark: markLink
+        mark: markLink,
+        setUpdateState: (state: MeshUpdateState, newProps: CarbohydrateLinkProps, currentProps: CarbohydrateLinkProps) => {
+            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        }
     })
 }
 

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

@@ -5,18 +5,17 @@
  */
 
 import { Unit, Structure, StructureElement } from 'mol-model/structure';
-import { DefaultStructureProps, ComplexVisual } from '..';
+import { ComplexVisual } from '..';
 import { RuntimeContext } from 'mol-task'
 import { Mesh } from '../../../shape/mesh';
 import { PickingId } from '../../../util/picking';
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { DefaultMeshProps } from '../../util';
 import { MeshBuilder } from '../../../shape/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 } from '../complex-visual';
+import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual';
 import { SizeThemeProps } from 'mol-view/theme/size';
 
 const t = Mat4.identity()
@@ -113,8 +112,7 @@ async function createCarbohydrateSymbolMesh(ctx: RuntimeContext, structure: Stru
 }
 
 export const DefaultCarbohydrateSymbolProps = {
-    ...DefaultMeshProps,
-    ...DefaultStructureProps,
+    ...DefaultComplexMeshProps,
     sizeTheme: { name: 'physical', factor: 1 } as SizeThemeProps,
     detail: 0,
     unitKinds: [ Unit.Kind.Atomic, Unit.Kind.Spheres ] as Unit.Kind[]
@@ -127,7 +125,8 @@ export function CarbohydrateSymbolVisual(): ComplexVisual<CarbohydrateSymbolProp
         createMesh: createCarbohydrateSymbolMesh,
         createLocationIterator: CarbohydrateElementIterator,
         getLoci: getCarbohydrateLoci,
-        mark: markCarbohydrate
+        mark: markCarbohydrate,
+        setUpdateState: () => {}
     })
 }
 

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

@@ -5,14 +5,14 @@
  */
 
 import { Link, Structure, StructureElement } from 'mol-model/structure';
-import { DefaultStructureProps, ComplexVisual } from '..';
+import { ComplexVisual, MeshUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
 import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link';
 import { Mesh } from '../../../shape/mesh';
 import { PickingId } from '../../../util/picking';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
-import { ComplexMeshVisual } from '../complex-visual';
+import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual';
 import { LocationIterator } from './util/location-iterator';
 import { Interval } from 'mol-data/int';
 import { SizeThemeProps } from 'mol-view/theme/size';
@@ -41,7 +41,7 @@ async function createCrossLinkRestraintCylinderMesh(ctx: RuntimeContext, structu
 }
 
 export const DefaultCrossLinkRestraintProps = {
-    ...DefaultStructureProps,
+    ...DefaultComplexMeshProps,
     ...DefaultLinkCylinderProps,
     sizeTheme: { name: 'physical', factor: 0.3 } as SizeThemeProps,
     flipSided: false,
@@ -55,7 +55,10 @@ export function CrossLinkRestraintVisual(): ComplexVisual<CrossLinkRestraintProp
         createMesh: createCrossLinkRestraintCylinderMesh,
         createLocationIterator: CrossLinkRestraintIterator,
         getLoci: getLinkLoci,
-        mark: markLink
+        mark: markLink,
+        setUpdateState: (state: MeshUpdateState, newProps: CrossLinkRestraintProps, currentProps: CrossLinkRestraintProps) => {
+            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        }
     })
 }
 

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

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

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

@@ -5,7 +5,7 @@
  */
 
 import { Link, Structure, StructureElement } from 'mol-model/structure';
-import { DefaultStructureProps, ComplexVisual } from '..';
+import { ComplexVisual, MeshUpdateState } from '..';
 import { RuntimeContext } from 'mol-task'
 import { LinkCylinderProps, DefaultLinkCylinderProps, createLinkCylinderMesh } from './util/link';
 import { Mesh } from '../../../shape/mesh';
@@ -13,7 +13,7 @@ import { PickingId } from '../../../util/picking';
 import { Vec3 } from 'mol-math/linear-algebra';
 import { Loci, EmptyLoci } from 'mol-model/loci';
 import { LinkIterator } from './util/location-iterator';
-import { ComplexMeshVisual } from '../complex-visual';
+import { ComplexMeshVisual, DefaultComplexMeshProps } from '../complex-visual';
 import { Interval } from 'mol-data/int';
 import { SizeThemeProps } from 'mol-view/theme/size';
 
@@ -40,7 +40,7 @@ async function createInterUnitLinkCylinderMesh(ctx: RuntimeContext, structure: S
 }
 
 export const DefaultInterUnitLinkProps = {
-    ...DefaultStructureProps,
+    ...DefaultComplexMeshProps,
     ...DefaultLinkCylinderProps,
     sizeTheme: { name: 'physical', factor: 0.3 } as SizeThemeProps,
 }
@@ -52,7 +52,10 @@ export function InterUnitLinkVisual(): ComplexVisual<InterUnitLinkProps> {
         createMesh: createInterUnitLinkCylinderMesh,
         createLocationIterator: LinkIterator.fromStructure,
         getLoci: getLinkLoci,
-        mark: markLink
+        mark: markLink,
+        setUpdateState: (state: MeshUpdateState, newProps: InterUnitLinkProps, currentProps: InterUnitLinkProps) => {
+            state.createMesh = newProps.radialSegments !== currentProps.radialSegments
+        }
     })
 }
 

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

@@ -68,7 +68,8 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> {
         createMesh: createIntraUnitLinkCylinderMesh,
         createLocationIterator: LinkIterator.fromGroup,
         getLoci: getLinkLoci,
-        mark: markLink
+        mark: markLink,
+        setUpdateState: () => {}
     })
 }
 

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

@@ -114,6 +114,7 @@ export function NucleotideBlockVisual(): UnitsVisual<NucleotideBlockProps> {
         createMesh: createNucleotideBlockMesh,
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
-        mark: markElement
+        mark: markElement,
+        setUpdateState: () => {}
     })
 }

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

@@ -60,6 +60,7 @@ export function PolymerBackboneVisual(): UnitsVisual<PolymerBackboneProps> {
         createMesh: createPolymerBackboneCylinderMesh,
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
-        mark: markElement
+        mark: markElement,
+        setUpdateState: () => {}
     })
 }

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

@@ -87,6 +87,7 @@ export function PolymerDirectionVisual(): UnitsVisual<PolymerDirectionProps> {
         createMesh: createPolymerDirectionWedgeMesh,
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
-        mark: markElement
+        mark: markElement,
+        setUpdateState: () => {}
     })
 }

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

@@ -66,6 +66,7 @@ export function PolymerGapVisual(): UnitsVisual<PolymerGapProps> {
         createMesh: createPolymerGapCylinderMesh,
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
-        mark: markElement
+        mark: markElement,
+        setUpdateState: () => {}
     })
 }

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

@@ -80,6 +80,7 @@ export function PolymerTraceVisual(): UnitsVisual<PolymerTraceProps> {
         createMesh: createPolymerTraceMesh,
         createLocationIterator: StructureElementIterator.fromGroup,
         getLoci: getElementLoci,
-        mark: markElement
+        mark: markElement,
+        setUpdateState: () => {}
     })
 }

+ 13 - 0
src/mol-geo/representation/structure/visual/util/location-iterator.ts

@@ -30,6 +30,7 @@ export interface LocationIterator extends Iterator<LocationValue> {
     readonly elementCount: number
     readonly instanceCount: number
     move(): LocationValue
+    reset(): void
     skipInstance(): void
 }
 
@@ -74,6 +75,18 @@ export function LocationIterator(elementCount: number, instanceCount: number, ge
             }
             return value
         },
+        reset() {
+            value.location = NullLocation
+            value.index = 0
+            value.elementIndex = 0
+            value.instanceIndex = 0
+            value.isSecondary = false
+
+            hasNext = value.elementIndex < elementCount
+            isNextNewInstance = false
+            elementIndex = 0
+            instanceIndex = 0
+        },
         skipInstance() {
             if (hasNext && value.instanceIndex === instanceIndex) {
                 ++instanceIndex