|
@@ -8,11 +8,11 @@
|
|
|
import { Unit, Link, StructureElement, Structure } from 'mol-model/structure';
|
|
|
import { UnitsVisual } from '../representation';
|
|
|
import { VisualUpdateState } from '../../util';
|
|
|
-import { LinkCylinderProps, createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link';
|
|
|
+import { createLinkCylinderMesh, LinkIterator, LinkCylinderParams } from './util/link';
|
|
|
import { Vec3 } from 'mol-math/linear-algebra';
|
|
|
import { Loci, EmptyLoci } from 'mol-model/loci';
|
|
|
import { UnitsMeshVisual, UnitsMeshParams, StructureGroup } from '../units-visual';
|
|
|
-import { Interval } from 'mol-data/int';
|
|
|
+import { Interval, OrderedSet } from 'mol-data/int';
|
|
|
import { BitFlags } from 'mol-util';
|
|
|
import { ParamDefinition as PD } from 'mol-util/param-definition';
|
|
|
import { Mesh } from 'mol-geo/geometry/mesh/mesh';
|
|
@@ -29,7 +29,7 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s
|
|
|
const links = unit.links
|
|
|
const { edgeCount, a, b, edgeProps, offset } = links
|
|
|
const { order: _order, flags: _flags } = edgeProps
|
|
|
- const { sizeFactor } = props
|
|
|
+ const { sizeFactor, sizeAspectRatio } = props
|
|
|
|
|
|
if (!edgeCount) return Mesh.createEmpty(mesh)
|
|
|
|
|
@@ -57,7 +57,7 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s
|
|
|
flags: (edgeIndex: number) => BitFlags.create(_flags[edgeIndex]),
|
|
|
radius: (edgeIndex: number) => {
|
|
|
location.element = elements[a[edgeIndex]]
|
|
|
- return theme.size.size(location) * sizeFactor
|
|
|
+ return theme.size.size(location) * sizeFactor * sizeAspectRatio
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -67,7 +67,8 @@ async function createIntraUnitLinkCylinderMesh(ctx: VisualContext, unit: Unit, s
|
|
|
export const IntraUnitLinkParams = {
|
|
|
...UnitsMeshParams,
|
|
|
...LinkCylinderParams,
|
|
|
- sizeFactor: PD.Numeric(0.2, { min: 0, max: 10, step: 0.01 }),
|
|
|
+ sizeFactor: PD.Numeric(0.3, { min: 0, max: 10, step: 0.01 }),
|
|
|
+ sizeAspectRatio: PD.Numeric(2/3, { min: 0, max: 3, step: 0.01 }),
|
|
|
}
|
|
|
export type IntraUnitLinkParams = typeof IntraUnitLinkParams
|
|
|
|
|
@@ -78,10 +79,14 @@ export function IntraUnitLinkVisual(): UnitsVisual<IntraUnitLinkParams> {
|
|
|
createLocationIterator: LinkIterator.fromGroup,
|
|
|
getLoci: getLinkLoci,
|
|
|
mark: markLink,
|
|
|
- setUpdateState: (state: VisualUpdateState, newProps: LinkCylinderProps, currentProps: LinkCylinderProps) => {
|
|
|
- if (newProps.linkScale !== currentProps.linkScale) state.createGeometry = true
|
|
|
- if (newProps.linkSpacing !== currentProps.linkSpacing) state.createGeometry = true
|
|
|
- if (newProps.radialSegments !== currentProps.radialSegments) state.createGeometry = true
|
|
|
+ setUpdateState: (state: VisualUpdateState, newProps: PD.Values<IntraUnitLinkParams>, currentProps: PD.Values<IntraUnitLinkParams>) => {
|
|
|
+ state.createGeometry = (
|
|
|
+ newProps.sizeFactor !== currentProps.sizeFactor ||
|
|
|
+ newProps.sizeAspectRatio !== currentProps.sizeAspectRatio ||
|
|
|
+ newProps.radialSegments !== currentProps.radialSegments ||
|
|
|
+ newProps.linkScale !== currentProps.linkScale ||
|
|
|
+ newProps.linkSpacing !== currentProps.linkSpacing
|
|
|
+ )
|
|
|
}
|
|
|
})
|
|
|
}
|
|
@@ -96,6 +101,10 @@ function getLinkLoci(pickingId: PickingId, structureGroup: StructureGroup, id: n
|
|
|
Link.Location(
|
|
|
unit, unit.links.a[groupId] as StructureElement.UnitIndex,
|
|
|
unit, unit.links.b[groupId] as StructureElement.UnitIndex
|
|
|
+ ),
|
|
|
+ Link.Location(
|
|
|
+ unit, unit.links.b[groupId] as StructureElement.UnitIndex,
|
|
|
+ unit, unit.links.a[groupId] as StructureElement.UnitIndex
|
|
|
)
|
|
|
])
|
|
|
}
|
|
@@ -105,18 +114,36 @@ function getLinkLoci(pickingId: PickingId, structureGroup: StructureGroup, id: n
|
|
|
|
|
|
function markLink(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
|
|
|
let changed = false
|
|
|
- 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
|
|
|
+ if (Link.isLoci(loci)) {
|
|
|
+ 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
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (StructureElement.isLoci(loci)) {
|
|
|
+ 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 e of loci.elements) {
|
|
|
+ const unitIdx = group.unitIndexMap.get(e.unit.id)
|
|
|
+ if (unitIdx !== undefined) {
|
|
|
+ const { offset } = unit.links
|
|
|
+ OrderedSet.forEach(e.indices, v => {
|
|
|
+ for (let t = offset[v], _t = offset[v + 1]; t < _t; t++) {
|
|
|
+ if (apply(Interval.ofSingleton(unitIdx * groupCount + t))) changed = true
|
|
|
+ }
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
}
|