diff --git a/CHANGELOG.md b/CHANGELOG.md index 72167849c5c8a4fe6a6d8333b58764a8e090cfb0..2117ef1b101d2b800af6d324726cf1b12b2b8804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,9 +10,15 @@ Note that since we don't clearly distinguish between a public and private interf - Add ``Mesh`` processing helper ``.smoothEdges`` - Smooth border of molecular-surface with ``includeParent`` enabled - Hide ``includeParent`` option from gaussian-surface visuals (not particularly useful) -- Improved ``StructureElement.Loci.size`` performance (for marking large cellpack models) - Fix new ``TransformData`` issues (camera/bounding helper not showing up) -- Improve marking performance (avoid superfluous calls to ``StructureElement.Loci.isWholeStructure``) +- Improve marking performance + - Avoid superfluous calls to ``StructureElement.Loci.isWholeStructure`` + - Check if loci is superset of visual + - Check if loci overlaps with unit visual + - Ensure ``Interval`` is used for ranges instead of ``SortedArray`` + - Inline ``StructureElement.Loci.size`` code + - Add uniform marker type + - Special case for reversing previous mark - Add optional marking pass - Outlines visible and hidden parts of highlighted/selected groups - Add highlightStrength/selectStrength renderer params diff --git a/src/mol-model/structure/structure/element/loci.ts b/src/mol-model/structure/structure/element/loci.ts index cce5eff09e4ad7034b57aa74df9860a7914eab83..cb68abbdd7a5597a0543514b876f0b096d8dbf4a 100644 --- a/src/mol-model/structure/structure/element/loci.ts +++ b/src/mol-model/structure/structure/element/loci.ts @@ -253,6 +253,14 @@ export namespace Loci { return isSubset; } + function makeIndexSet(newIndices: ArrayLike<UnitIndex>): OrderedSet<UnitIndex> { + if (newIndices.length > 3 && SortedArray.isRange(newIndices)) { + return Interval.ofRange(newIndices[0], newIndices[newIndices.length - 1]); + } else { + return SortedArray.ofSortedArray(newIndices); + } + } + export function extendToWholeResidues(loci: Loci, restrictToConformation?: boolean): Loci { const elements: Loci['elements'][0][] = []; const residueAltIds = new Set<string>(); @@ -297,7 +305,7 @@ export namespace Loci { } } - elements[elements.length] = { unit: lociElement.unit, indices: SortedArray.ofSortedArray(newIndices) }; + elements[elements.length] = { unit: lociElement.unit, indices: makeIndexSet(newIndices) }; } else { // coarse elements are already by-residue elements[elements.length] = lociElement; @@ -319,14 +327,6 @@ export namespace Loci { return element.unit.elements.length === OrderedSet.size(element.indices); } - function makeIndexSet(newIndices: number[]): OrderedSet<UnitIndex> { - if (newIndices.length > 12 && newIndices[newIndices.length - 1] - newIndices[0] === newIndices.length - 1) { - return Interval.ofRange(newIndices[0], newIndices[newIndices.length - 1]); - } else { - return SortedArray.ofSortedArray(newIndices); - } - } - function collectChains(unit: Unit, chainIndices: Set<ChainIndex>, elements: Loci['elements'][0][]) { const { index } = getChainSegments(unit); const xs = unit.elements; @@ -470,7 +470,10 @@ export namespace Loci { } function getUnitIndices(elements: SortedArray<ElementIndex>, indices: SortedArray<ElementIndex>) { - return OrderedSet.ofSortedArray(SortedArray.indicesOf<ElementIndex, UnitIndex>(elements, indices)); + if (SortedArray.areEqual(elements, indices) && SortedArray.isRange(elements)) { + return Interval.ofLength(elements.length); + } + return makeIndexSet(SortedArray.indicesOf<ElementIndex, UnitIndex>(elements, indices)); } export function extendToAllInstances(loci: Loci): Loci { diff --git a/src/mol-repr/structure/units-visual.ts b/src/mol-repr/structure/units-visual.ts index 8acaf871bab614b675e685ea392ad9bcc19d4017..e4105f9eb16589aefee9e2e547f7a5a3f2e38c67 100644 --- a/src/mol-repr/structure/units-visual.ts +++ b/src/mol-repr/structure/units-visual.ts @@ -290,7 +290,18 @@ export function UnitsVisual<G extends Geometry, P extends StructureParams & Geom return renderObject ? getLoci(pickingId, currentStructureGroup, renderObject.id) : EmptyLoci; }, mark(loci: Loci, action: MarkerAction) { - return Visual.mark(renderObject, loci, action, lociApply, previousMark); + let hasInvariantId = true; + if (StructureElement.Loci.is(loci)) { + hasInvariantId = false; + const { invariantId } = currentStructureGroup.group.units[0]; + for (const e of loci.elements) { + if (e.unit.invariantId === invariantId) { + hasInvariantId = true; + break; + } + } + } + return hasInvariantId ? Visual.mark(renderObject, loci, action, lociApply, previousMark) : false; }, setVisibility(visible: boolean) { Visual.setVisibility(renderObject, visible); diff --git a/src/mol-repr/structure/visual/util/element.ts b/src/mol-repr/structure/visual/util/element.ts index b9a8ea919a3e669edfc8f0921d8456954bd33fe0..34ca57ffaf8d02daa31d2c1200c8cce4d513f6e5 100644 --- a/src/mol-repr/structure/visual/util/element.ts +++ b/src/mol-repr/structure/visual/util/element.ts @@ -164,8 +164,9 @@ export function eachElement(loci: Loci, structureGroup: StructureGroup, apply: ( const { structure, group } = structureGroup; if (!Structure.areEquivalent(loci.structure, structure)) return false; const elementCount = group.elements.length; + const { unitIndexMap } = group; for (const e of loci.elements) { - const unitIdx = group.unitIndexMap.get(e.unit.id); + const unitIdx = unitIndexMap.get(e.unit.id); if (unitIdx !== undefined) { const offset = unitIdx * elementCount; // to target unit instance if (Interval.is(e.indices)) { diff --git a/src/mol-repr/visual.ts b/src/mol-repr/visual.ts index 13689cee537941376284cf6bea4b98144bee1a3e..163a47dfaff3d1d5a1c3b37f86dd80b73039c92e 100644 --- a/src/mol-repr/visual.ts +++ b/src/mol-repr/visual.ts @@ -84,6 +84,7 @@ namespace Visual { intervalSize += Interval.size(interval); return true; }, true); + if (intervalSize === 0) return false; if (intervalSize === count) loci = EveryLoci; }