123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- /**
- * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { Vec3 } from '../../../../mol-math/linear-algebra';
- import { Unit, StructureElement, Structure } from '../../../../mol-model/structure';
- import { Loci, EmptyLoci } from '../../../../mol-model/loci';
- import { Interval, OrderedSet } from '../../../../mol-data/int';
- import { Mesh } from '../../../../mol-geo/geometry/mesh/mesh';
- import { sphereVertexCount } from '../../../../mol-geo/primitive/sphere';
- import { MeshBuilder } from '../../../../mol-geo/geometry/mesh/mesh-builder';
- import { addSphere } from '../../../../mol-geo/geometry/mesh/builder/sphere';
- import { PickingId } from '../../../../mol-geo/geometry/picking';
- import { LocationIterator } from '../../../../mol-geo/util/location-iterator';
- import { VisualContext } from '../../../../mol-repr/visual';
- import { Theme } from '../../../../mol-theme/theme';
- import { StructureGroup } from '../../../../mol-repr/structure/units-visual';
- import { Spheres } from '../../../../mol-geo/geometry/spheres/spheres';
- import { SpheresBuilder } from '../../../../mol-geo/geometry/spheres/spheres-builder';
- import { isHydrogen } from './common';
- export interface ElementSphereMeshProps {
- detail: number,
- sizeFactor: number,
- ignoreHydrogens: boolean,
- }
- export function createElementSphereMesh(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereMeshProps, mesh?: Mesh): Mesh {
- const { detail, sizeFactor } = props
- const { elements } = unit;
- const elementCount = elements.length;
- const vertexCount = elementCount * sphereVertexCount(detail)
- const builderState = MeshBuilder.createState(vertexCount, vertexCount / 2, mesh)
- const v = Vec3.zero()
- const pos = unit.conformation.invariantPosition
- const l = StructureElement.create()
- l.unit = unit
- for (let i = 0; i < elementCount; i++) {
- if (props.ignoreHydrogens && isHydrogen(unit, elements[i])) continue
- l.element = elements[i]
- pos(elements[i], v)
- builderState.currentGroup = i
- addSphere(builderState, v, theme.size.size(l) * sizeFactor, detail)
- }
- return MeshBuilder.getMesh(builderState)
- }
- export interface ElementSphereImpostorProps {
- ignoreHydrogens: boolean,
- }
- export function createElementSphereImpostor(ctx: VisualContext, unit: Unit, structure: Structure, theme: Theme, props: ElementSphereImpostorProps, spheres?: Spheres): Spheres {
- const { elements } = unit;
- const elementCount = elements.length;
- const builder = SpheresBuilder.create(elementCount, elementCount / 2, spheres)
- const v = Vec3.zero()
- const pos = unit.conformation.invariantPosition
- for (let i = 0; i < elementCount; i++) {
- if (props.ignoreHydrogens && isHydrogen(unit, elements[i])) continue
- pos(elements[i], v)
- builder.add(v[0], v[1], v[2], i)
- }
- return builder.getSpheres()
- }
- export function eachElement(loci: Loci, structureGroup: StructureGroup, apply: (interval: Interval) => boolean) {
- let changed = false
- if (!StructureElement.isLoci(loci)) return false
- const { structure, group } = structureGroup
- if (!Structure.areEquivalent(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
- }
- }
- }
- }
- return changed
- }
- 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(structure, [{ unit, indices }])
- }
- return EmptyLoci
- }
- //
- export function eachSerialElement(loci: Loci, structure: Structure, apply: (interval: Interval) => boolean) {
- let changed = false
- if (!StructureElement.isLoci(loci)) return false
- if (!Structure.areEquivalent(loci.structure, structure)) return false
- const { unitElementCount } = structure.serialMapping
- for (const e of loci.elements) {
- const unitIdx = structure.unitIndexMap.get(e.unit.id)
- if (unitIdx !== undefined) {
- if (Interval.is(e.indices)) {
- const start = unitElementCount[unitIdx] + Interval.start(e.indices)
- const end = unitElementCount[unitIdx] + 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 = unitElementCount[unitIdx] + e.indices[i]
- if (apply(Interval.ofSingleton(idx))) changed = true
- }
- }
- }
- }
- return changed
- }
- export function getSerialElementLoci(pickingId: PickingId, structure: Structure, id: number) {
- const { objectId, groupId } = pickingId
- if (id === objectId) {
- const { unitIndices, unitElementCount } = structure.serialMapping
- const unitIdx = unitIndices[groupId]
- const unit = structure.units[unitIdx]
- const idx = groupId - unitElementCount[unitIdx]
- const indices = OrderedSet.ofSingleton(idx as StructureElement.UnitIndex)
- return StructureElement.Loci(structure, [{ unit, indices }])
- }
- return EmptyLoci
- }
- //
- export namespace ElementIterator {
- export function fromGroup(group: Unit.SymmetryGroup): LocationIterator {
- const groupCount = group.elements.length
- const instanceCount = group.units.length
- const location = StructureElement.create()
- const getLocation = (groupIndex: number, instanceIndex: number) => {
- const unit = group.units[instanceIndex]
- location.unit = unit
- location.element = unit.elements[groupIndex]
- return location
- }
- return LocationIterator(groupCount, instanceCount, getLocation)
- }
- export function fromStructure(structure: Structure): LocationIterator {
- const { units, elementCount } = structure
- const groupCount = elementCount
- const instanceCount = 1
- const { unitIndices, elementIndices } = structure.serialMapping
- const location = StructureElement.create()
- const getLocation = (groupIndex: number) => {
- location.unit = units[unitIndices[groupIndex]]
- location.element = elementIndices[groupIndex]
- return location
- }
- return LocationIterator(groupCount, instanceCount, getLocation, true)
- }
- }
|