diff --git a/src/mol-model/shape/shape.ts b/src/mol-model/shape/shape.ts index b911bd340fa8432444d4253b4fbcbed3608a592e..95ab6cd63d1bc859775aa14cd5203b98c145a406 100644 --- a/src/mol-model/shape/shape.ts +++ b/src/mol-model/shape/shape.ts @@ -55,14 +55,14 @@ export namespace Shape { export interface Loci { readonly kind: 'group-loci', + readonly shape: Shape, readonly groups: ReadonlyArray<{ - shape: Shape, ids: OrderedSet<number> }> } - export function Loci(groups: ArrayLike<{ shape: Shape, ids: OrderedSet<number> }>): Loci { - return { kind: 'group-loci', groups: groups as Loci['groups'] }; + export function Loci(shape: Shape, groups: ArrayLike<{ ids: OrderedSet<number> }>): Loci { + return { kind: 'group-loci', shape, groups: groups as Loci['groups'] }; } export function isLoci(x: any): x is Loci { @@ -70,11 +70,11 @@ export namespace Shape { } export function areLociEqual(a: Loci, b: Loci) { + if (a.shape !== b.shape) return false if (a.groups.length !== b.groups.length) return false for (let i = 0, il = a.groups.length; i < il; ++i) { const groupA = a.groups[i] const groupB = b.groups[i] - if (groupA.shape.id !== groupB.shape.id) return false if (!OrderedSet.areEqual(groupA.ids, groupB.ids)) return false } return true diff --git a/src/mol-model/structure/query/selection.ts b/src/mol-model/structure/query/selection.ts index bd258621e8cc202239fb0d5a2c92b801c7047a06..b257170712dc78158da19a0787c0f4718a8a615f 100644 --- a/src/mol-model/structure/query/selection.ts +++ b/src/mol-model/structure/query/selection.ts @@ -50,7 +50,7 @@ namespace StructureSelection { } } - return StructureElement.Loci(loci); + return StructureElement.Loci(sel.source, loci); } export interface Builder { diff --git a/src/mol-model/structure/structure/element.ts b/src/mol-model/structure/structure/element.ts index 197ff5cb7034d2bd0bb6b8ece37ce542bee8ea1d..24594303dae766cec31f905f2952992ca6a4159b 100644 --- a/src/mol-model/structure/structure/element.ts +++ b/src/mol-model/structure/structure/element.ts @@ -8,6 +8,7 @@ import { OrderedSet, SortedArray } from 'mol-data/int' import Unit from './unit' import { ElementIndex } from '../model'; import { ResidueIndex, ChainIndex } from '../model/indexing'; +import Structure from './structure'; interface StructureElement<U = Unit> { readonly kind: 'element-location', @@ -44,6 +45,7 @@ namespace StructureElement { /** Represents multiple element index locations */ export interface Loci { readonly kind: 'element-loci', + readonly structure: Structure, /** Access i-th element as unit.elements[indices[i]] */ readonly elements: ReadonlyArray<{ unit: Unit, @@ -55,8 +57,8 @@ namespace StructureElement { }> } - export function Loci(elements: ArrayLike<{ unit: Unit, indices: OrderedSet<UnitIndex> }>): Loci { - return { kind: 'element-loci', elements: elements as Loci['elements'] }; + export function Loci(structure: Structure, elements: ArrayLike<{ unit: Unit, indices: OrderedSet<UnitIndex> }>): Loci { + return { kind: 'element-loci', structure, elements: elements as Loci['elements'] }; } export function isLoci(x: any): x is Loci { diff --git a/src/mol-model/structure/structure/unit/links.ts b/src/mol-model/structure/structure/unit/links.ts index 12f24b5c0ff5908752907602b2177b5913f49aae..ecefe98af02b59f283ad3a0de0e146808e425053 100644 --- a/src/mol-model/structure/structure/unit/links.ts +++ b/src/mol-model/structure/structure/unit/links.ts @@ -41,11 +41,12 @@ namespace Link { export interface Loci { readonly kind: 'link-loci', + readonly structure: Structure readonly links: ReadonlyArray<Location> } - export function Loci(links: ArrayLike<Location>): Loci { - return { kind: 'link-loci', links: links as Loci['links'] }; + export function Loci(structure: Structure, links: ArrayLike<Location>): Loci { + return { kind: 'link-loci', structure, links: links as Loci['links'] }; } export function isLoci(x: any): x is Loci { diff --git a/src/mol-repr/shape/index.ts b/src/mol-repr/shape/index.ts index ee22bdf32dd6add15d5ab4a1e5ed9b93bb3904b9..632458983dd63be0c085552b95fa36daae7cfeaf 100644 --- a/src/mol-repr/shape/index.ts +++ b/src/mol-repr/shape/index.ts @@ -69,7 +69,7 @@ export function ShapeRepresentation<P extends ShapeProps>(): ShapeRepresentation getLoci(pickingId: PickingId) { const { objectId, groupId } = pickingId if (_renderObject && _renderObject.id === objectId) { - return Shape.Loci([ { shape: _shape, ids: OrderedSet.ofSingleton(groupId) } ]) + return Shape.Loci(_shape, [{ ids: OrderedSet.ofSingleton(groupId) }]) } return EmptyLoci }, diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index c4c8e856418fb1cc91790c6ea96de193c6c7f9d9..29a00fc88bb991cf23f2c88a0fa9b921bea4d1c1 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -50,8 +50,8 @@ interface UnitsVisualBuilder<P extends UnitsProps, G extends Geometry> { defaultProps: P createGeometry(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: P, geometry?: G): Promise<G> 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 + getLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number): Loci + mark(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean): boolean setUpdateState(state: VisualUpdateState, newProps: P, currentProps: P): void } @@ -168,7 +168,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu } }, getLoci(pickingId: PickingId) { - return renderObject ? getLoci(pickingId, currentGroup, renderObject.id) : EmptyLoci + return renderObject ? getLoci(pickingId, { structure: currentStructure, group: currentGroup }, renderObject.id) : EmptyLoci }, mark(loci: Loci, action: MarkerAction) { if (!renderObject) return false @@ -185,7 +185,7 @@ export function UnitsVisual<P extends UnitsProps>(builder: UnitsVisualGeometryBu if (isEveryLoci(loci)) { changed = apply(Interval.ofBounds(0, groupCount * instanceCount)) } else { - changed = mark(loci, currentGroup, apply) + changed = mark(loci, { structure: currentStructure, group: currentGroup }, apply) } if (changed) { ValueCell.update(tMarker, tMarker.ref.value) diff --git a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts index f4c555c956078e76575eb239a31b503fd4ce9e03..9654d7b089baa34308453ae38255c723c5a63d78 100644 --- a/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts +++ b/src/mol-repr/structure/visual/carbohydrate-link-cylinder.ts @@ -114,7 +114,7 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { const indexA = OrderedSet.indexOf(carbA.unit.elements, carbA.anomericCarbon) const indexB = OrderedSet.indexOf(carbB.unit.elements, carbB.anomericCarbon) if (indexA !== -1 && indexB !== -1) { - return Link.Loci([ + return Link.Loci(structure, [ Link.Location( carbA.unit, indexA as StructureElement.UnitIndex, carbB.unit, indexB as StructureElement.UnitIndex diff --git a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts index 4c7597b923640c14c104005990c842802ad9637e..2d760f0b10d0b122fa6bb8b28d55470327d4be92 100644 --- a/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts +++ b/src/mol-repr/structure/visual/carbohydrate-symbol-mesh.ts @@ -193,7 +193,7 @@ function getCarbohydrateLoci(pickingId: PickingId, structure: Structure, id: num const index = OrderedSet.indexOf(unit.elements, carb.anomericCarbon) if (index !== -1) { const indices = OrderedSet.ofSingleton(index as StructureElement.UnitIndex) - return StructureElement.Loci([{ unit, indices }]) + return StructureElement.Loci(structure, [{ unit, indices }]) } } return EmptyLoci diff --git a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts index ff1c7e3b7953624e859b1feed1b4114e0b08caba..1f37817871e789dbd3ce08395919e4bf522b41b3 100644 --- a/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts +++ b/src/mol-repr/structure/visual/cross-link-restraint-cylinder.ts @@ -94,7 +94,7 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { if (id === objectId) { const pair = structure.crossLinkRestraints.pairs[groupId] if (pair) { - return Link.Loci([ Link.Location(pair.unitA, pair.indexA, pair.unitB, pair.indexB) ]) + return Link.Loci(structure, [ Link.Location(pair.unitA, pair.indexA, pair.unitB, pair.indexB) ]) } } return EmptyLoci diff --git a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts index 715e64e518e8cb79b5b1994da19d31f6ae5baec2..7a96419a33dff1f19d4710eb2a24768692e05ccb 100644 --- a/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/inter-unit-link-cylinder.ts @@ -73,7 +73,7 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { const { objectId, groupId } = pickingId if (id === objectId) { const bond = structure.links.bonds[groupId] - return Link.Loci([ + return Link.Loci(structure, [ Link.Location( bond.unitA, bond.indexA as StructureElement.UnitIndex, bond.unitB, bond.indexB as StructureElement.UnitIndex @@ -85,12 +85,11 @@ function getLinkLoci(pickingId: PickingId, structure: Structure, id: number) { function markLink(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) { let changed = false - if (Link.isLoci(loci)) { - for (const b of loci.links) { - const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit) - if (idx !== -1) { - if (apply(Interval.ofSingleton(idx))) changed = true - } + if (!Link.isLoci(loci)) return false + for (const b of loci.links) { + const idx = structure.links.getBondIndex(b.aIndex, b.aUnit, b.bIndex, b.bUnit) + if (idx !== -1) { + if (apply(Interval.ofSingleton(idx))) changed = true } } return changed diff --git a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts index ca5e2a295d119467190d9a166465ac49d1a1b32d..69d2aafd1fc1f377ebe200cd00511dc477d0d439 100644 --- a/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts +++ b/src/mol-repr/structure/visual/intra-unit-link-cylinder.ts @@ -11,7 +11,7 @@ import { VisualUpdateState } from '../../util'; import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link'; import { Vec3 } from 'mol-math/linear-algebra'; import { Loci, EmptyLoci } from 'mol-model/loci'; -import { UnitsMeshVisual, UnitsMeshParams } from '../units-visual'; +import { UnitsMeshVisual, UnitsMeshParams, StructureGroup } from '../units-visual'; import { Interval } from 'mol-data/int'; import { SizeThemeName, SizeThemeOptions } from 'mol-theme/size'; import { BitFlags } from 'mol-util'; @@ -87,33 +87,37 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkProps> { }) } -function getLinkLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { +function getLinkLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) { const { objectId, instanceId, groupId } = pickingId - const unit = group.units[instanceId] - if (id === objectId && Unit.isAtomic(unit)) { - return Link.Loci([ - Link.Location( - unit, unit.links.a[groupId] as StructureElement.UnitIndex, - unit, unit.links.b[groupId] as StructureElement.UnitIndex - ) - ]) + if (id === objectId) { + const { structure, group } = structureGroup + const unit = group.units[instanceId] + if (Unit.isAtomic(unit)) { + return Link.Loci(structure, [ + Link.Location( + unit, unit.links.a[groupId] as StructureElement.UnitIndex, + unit, unit.links.b[groupId] as StructureElement.UnitIndex + ) + ]) + } } return EmptyLoci } -function markLink(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean) { - const unit = group.units[0] - +function markLink(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) { let changed = false - if (Unit.isAtomic(unit) && Link.isLoci(loci)) { - const groupCount = unit.links.edgeCount * 2 - for (const b of loci.links) { - const unitIdx = group.unitIndexMap.get(b.aUnit.id) - if (unitIdx !== undefined) { - const idx = unit.links.getDirectedEdgeIndex(b.aIndex, b.bIndex) - if (idx !== -1) { - if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true - } + if (!Link.isLoci(loci)) return false + const { structure, group } = structureGroup + if (loci.structure !== structure) return false + const unit = group.units[0] + if (!Unit.isAtomic(unit)) return false + const groupCount = unit.links.edgeCount * 2 + for (const b of loci.links) { + const unitIdx = group.unitIndexMap.get(b.aUnit.id) + if (unitIdx !== undefined) { + const idx = unit.links.getDirectedEdgeIndex(b.aIndex, b.bIndex) + if (idx !== -1) { + if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true } } } diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index e1ccb69774b2497ffd08b7a936f497d67c1ca5e8..5bc0407967feadb297c55e6570e0d1549d32398a 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -16,6 +16,7 @@ import { PickingId } from 'mol-geo/geometry/picking'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { VisualContext } from 'mol-repr'; import { Theme } from 'mol-geo/geometry/geometry'; +import { StructureGroup } from 'mol-repr/structure/units-visual'; export interface ElementSphereMeshProps { detail: number, @@ -49,23 +50,23 @@ export async function createElementSphereMesh(ctx: VisualContext, unit: Unit, st return meshBuilder.getMesh() } -export function markElement(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean) { - const elementCount = group.elements.length - +export function markElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) { let changed = false - if (StructureElement.isLoci(loci)) { - for (const e of loci.elements) { - const unitIdx = group.unitIndexMap.get(e.unit.id) - if (unitIdx !== undefined) { - if (Interval.is(e.indices)) { - const start = unitIdx * elementCount + Interval.start(e.indices); - const end = unitIdx * elementCount + Interval.end(e.indices); - if (apply(Interval.ofBounds(start, end))) changed = true - } else { - for (let i = 0, _i = e.indices.length; i < _i; i++) { - const idx = unitIdx * elementCount + e.indices[i]; - if (apply(Interval.ofSingleton(idx))) changed = true - } + if (!StructureElement.isLoci(loci)) return false + const { structure, group } = structureGroup + if (loci.structure !== structure) return false + const elementCount = group.elements.length + for (const e of loci.elements) { + const unitIdx = group.unitIndexMap.get(e.unit.id) + if (unitIdx !== undefined) { + if (Interval.is(e.indices)) { + const start = unitIdx * elementCount + Interval.start(e.indices); + const end = unitIdx * elementCount + Interval.end(e.indices); + if (apply(Interval.ofBounds(start, end))) changed = true + } else { + for (let i = 0, _i = e.indices.length; i < _i; i++) { + const idx = unitIdx * elementCount + e.indices[i]; + if (apply(Interval.ofSingleton(idx))) changed = true } } } @@ -73,12 +74,13 @@ export function markElement(loci: Loci, group: Unit.SymmetryGroup, apply: (inter return changed } -export function getElementLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { +export function getElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) { const { objectId, instanceId, groupId } = pickingId if (id === objectId) { + const { structure, group } = structureGroup const unit = group.units[instanceId] const indices = OrderedSet.ofSingleton(groupId as StructureElement.UnitIndex); - return StructureElement.Loci([{ unit, indices }]) + return StructureElement.Loci(structure, [{ unit, indices }]) } return EmptyLoci } diff --git a/src/mol-repr/structure/visual/util/nucleotide.ts b/src/mol-repr/structure/visual/util/nucleotide.ts index 2ce7b7cb97e55d11c9d6c4f2f500590ed3283206..9d5b0981f7a0c3a96ee6904bcab4fc536151bcd1 100644 --- a/src/mol-repr/structure/visual/util/nucleotide.ts +++ b/src/mol-repr/structure/visual/util/nucleotide.ts @@ -10,6 +10,7 @@ import { Loci, EmptyLoci } from 'mol-model/loci'; import { OrderedSet, Interval } from 'mol-data/int'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; +import { StructureGroup } from 'mol-repr/structure/units-visual'; export namespace NucleotideLocationIterator { export function fromGroup(group: Unit.SymmetryGroup): LocationIterator { @@ -28,41 +29,44 @@ export namespace NucleotideLocationIterator { } } -export function getNucleotideElementLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { +export function getNucleotideElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) { const { objectId, instanceId, groupId } = pickingId if (id === objectId) { + const { structure, group } = structureGroup const unit = group.units[instanceId] if (Unit.isAtomic(unit)) { const unitIndex = OrderedSet.indexOf(unit.elements, unit.nucleotideElements[groupId]) as StructureElement.UnitIndex if (unitIndex !== -1) { const indices = OrderedSet.ofSingleton(unitIndex) - return StructureElement.Loci([{ unit, indices }]) + return StructureElement.Loci(structure, [{ unit, indices }]) } } } return EmptyLoci } -export function markNucleotideElement(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean) { +export function markNucleotideElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) { let changed = false - const u = group.units[0] - if (StructureElement.isLoci(loci) && Unit.isAtomic(u)) { - const groupCount = u.nucleotideElements.length - for (const e of loci.elements) { - const unitIdx = group.unitIndexMap.get(e.unit.id) - if (unitIdx !== undefined && Unit.isAtomic(e.unit)) { - if (Interval.is(e.indices)) { - const min = OrderedSet.indexOf(e.unit.nucleotideElements, e.unit.elements[Interval.min(e.indices)]) - const max = OrderedSet.indexOf(e.unit.nucleotideElements, e.unit.elements[Interval.max(e.indices)]) - if (min !== -1 && max !== -1) { - if (apply(Interval.ofRange(unitIdx * groupCount + min, unitIdx * groupCount + max))) changed = true - } - } else { - for (let i = 0, _i = e.indices.length; i < _i; i++) { - const idx = OrderedSet.indexOf(e.unit.nucleotideElements, e.unit.elements[e.indices[i]]) - if (idx !== -1) { - if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true - } + if (!StructureElement.isLoci(loci)) return false + const { structure, group } = structureGroup + if (loci.structure !== structure) return false + const unit = group.units[0] + if (!Unit.isAtomic(unit)) return false + const groupCount = unit.nucleotideElements.length + for (const e of loci.elements) { + const unitIdx = group.unitIndexMap.get(e.unit.id) + if (unitIdx !== undefined && Unit.isAtomic(e.unit)) { + if (Interval.is(e.indices)) { + const min = OrderedSet.indexOf(e.unit.nucleotideElements, e.unit.elements[Interval.min(e.indices)]) + const max = OrderedSet.indexOf(e.unit.nucleotideElements, e.unit.elements[Interval.max(e.indices)]) + if (min !== -1 && max !== -1) { + if (apply(Interval.ofRange(unitIdx * groupCount + min, unitIdx * groupCount + max))) changed = true + } + } else { + for (let i = 0, _i = e.indices.length; i < _i; i++) { + const idx = OrderedSet.indexOf(e.unit.nucleotideElements, e.unit.elements[e.indices[i]]) + if (idx !== -1) { + if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true } } } diff --git a/src/mol-repr/structure/visual/util/polymer.ts b/src/mol-repr/structure/visual/util/polymer.ts index 80ff883ab70a95da86bf43de69a4f738a96e73a0..79e24b21f6001e9420bebf7daa763586e8cd9823 100644 --- a/src/mol-repr/structure/visual/util/polymer.ts +++ b/src/mol-repr/structure/visual/util/polymer.ts @@ -10,6 +10,7 @@ import { OrderedSet, Interval } from 'mol-data/int'; import { EmptyLoci, Loci } from 'mol-model/loci'; import { LocationIterator } from 'mol-geo/util/location-iterator'; import { PickingId } from 'mol-geo/geometry/picking'; +import { StructureGroup } from 'mol-repr/structure/units-visual'; export * from './polymer/backbone-iterator' export * from './polymer/gap-iterator' @@ -64,9 +65,10 @@ export namespace PolymerGapLocationIterator { } } -export function getPolymerElementLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { +export function getPolymerElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) { const { objectId, instanceId, groupId } = pickingId if (id === objectId) { + const { structure, group } = structureGroup const unit = group.units[instanceId] if (unit === undefined) { console.log(id, { objectId, instanceId, groupId }, group.units) @@ -74,32 +76,32 @@ export function getPolymerElementLoci(pickingId: PickingId, group: Unit.Symmetry const unitIndex = OrderedSet.indexOf(unit.elements, unit.polymerElements[groupId]) as StructureElement.UnitIndex if (unitIndex !== -1) { const indices = OrderedSet.ofSingleton(unitIndex) - return StructureElement.Loci([{ unit, indices }]) + return StructureElement.Loci(structure, [{ unit, indices }]) } } return EmptyLoci } -export function markPolymerElement(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean) { - const groupCount = group.units[0].polymerElements.length - +export function markPolymerElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) { let changed = false - if (StructureElement.isLoci(loci)) { - for (const e of loci.elements) { - const unitIdx = group.unitIndexMap.get(e.unit.id) - if (unitIdx !== undefined) { - if (Interval.is(e.indices)) { - const min = + OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[Interval.min(e.indices)]) - const max = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[Interval.max(e.indices)]) - if (min !== -1 && max !== -1) { - if (apply(Interval.ofRange(unitIdx * groupCount + min, unitIdx * groupCount + max))) changed = true - } - } else { - for (let i = 0, _i = e.indices.length; i < _i; i++) { - const idx = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[e.indices[i]]) - if (idx !== -1) { - if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true - } + if (!StructureElement.isLoci(loci)) return false + const { structure, group } = structureGroup + if (loci.structure !== structure) return false + const groupCount = group.units[0].polymerElements.length + for (const e of loci.elements) { + const unitIdx = group.unitIndexMap.get(e.unit.id) + if (unitIdx !== undefined) { + if (Interval.is(e.indices)) { + const min = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[Interval.min(e.indices)]) + const max = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[Interval.max(e.indices)]) + if (min !== -1 && max !== -1) { + if (apply(Interval.ofRange(unitIdx * groupCount + min, unitIdx * groupCount + max))) changed = true + } + } else { + for (let i = 0, _i = e.indices.length; i < _i; i++) { + const idx = OrderedSet.indexOf(e.unit.polymerElements, e.unit.elements[e.indices[i]]) + if (idx !== -1) { + if (apply(Interval.ofSingleton(unitIdx * groupCount + idx))) changed = true } } } @@ -108,31 +110,33 @@ export function markPolymerElement(loci: Loci, group: Unit.SymmetryGroup, apply: return changed } -export function getPolymerGapElementLoci(pickingId: PickingId, group: Unit.SymmetryGroup, id: number) { +export function getPolymerGapElementLoci(pickingId: PickingId, structureGroup: StructureGroup, id: number) { const { objectId, instanceId, groupId } = pickingId if (id === objectId) { + const { structure, group } = structureGroup const unit = group.units[instanceId] const unitIndexA = OrderedSet.indexOf(unit.elements, unit.gapElements[groupId]) as StructureElement.UnitIndex const unitIndexB = OrderedSet.indexOf(unit.elements, unit.gapElements[groupId % 2 ? groupId - 1 : groupId + 1]) as StructureElement.UnitIndex if (unitIndexA !== -1 && unitIndexB !== -1) { - return Link.Loci([ Link.Location(unit, unitIndexA, unit, unitIndexB) ]) + return Link.Loci(structure, [ Link.Location(unit, unitIndexA, unit, unitIndexB) ]) } } return EmptyLoci } -export function markPolymerGapElement(loci: Loci, group: Unit.SymmetryGroup, apply: (interval: Interval) => boolean) { +export function markPolymerGapElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) { let changed = false - if (Link.isLoci(loci)) { - const groupCount = group.units[0].gapElements.length - for (const b of loci.links) { - const unitIdx = group.unitIndexMap.get(b.aUnit.id) - if (unitIdx !== undefined) { - const idxA = OrderedSet.indexOf(b.aUnit.gapElements, b.aUnit.elements[b.aIndex]) - const idxB = OrderedSet.indexOf(b.bUnit.gapElements, b.bUnit.elements[b.bIndex]) - if (idxA !== -1 && idxB !== -1) { - if (apply(Interval.ofSingleton(unitIdx * groupCount + idxA))) changed = true - } + if (!Link.isLoci(loci)) return false + const { structure, group } = structureGroup + if (loci.structure !== structure) return false + const groupCount = group.units[0].gapElements.length + for (const b of loci.links) { + const unitIdx = group.unitIndexMap.get(b.aUnit.id) + if (unitIdx !== undefined) { + const idxA = OrderedSet.indexOf(b.aUnit.gapElements, b.aUnit.elements[b.aIndex]) + const idxB = OrderedSet.indexOf(b.bUnit.gapElements, b.bUnit.elements[b.bIndex]) + if (idxA !== -1 && idxB !== -1) { + if (apply(Interval.ofSingleton(unitIdx * groupCount + idxA))) changed = true } } }