diff --git a/src/mol-model/structure/export/mmcif.ts b/src/mol-model/structure/export/mmcif.ts index 24fcf9c7186541ab053dfe74c46133dc9b4b0c72..b94604b104dae5a250080db2bfc3c94c0c9c036a 100644 --- a/src/mol-model/structure/export/mmcif.ts +++ b/src/mol-model/structure/export/mmcif.ts @@ -100,8 +100,32 @@ export const mmCIF_Export_Filters = { } } +function encodeCustomProp(customProp: CustomPropertyDescriptor, ctx: CifExportContext, encoder: CifWriter.Encoder, params: encode_mmCIF_categories_Params) { + if (!customProp.cifExport || customProp.cifExport.categories.length === 0) return; + + const prefix = customProp.cifExport.prefix; + const cats = customProp.cifExport.categories; + + let propCtx = ctx; + if (customProp.cifExport.context) { + const propId = CustomPropertyDescriptor.getUUID(customProp); + if (ctx.cache[propId + '__ctx']) propCtx = ctx.cache[propId + '__ctx']; + else { + propCtx = customProp.cifExport.context(ctx) || ctx; + ctx.cache[propId + '__ctx'] = propCtx; + } + } + for (const cat of cats) { + if (params.skipCategoryNames && params.skipCategoryNames.has(cat.name)) continue; + if (cat.name.indexOf(prefix) !== 0) throw new Error(`Custom category '${cat.name}' name must start with prefix '${prefix}.'`); + encoder.writeCategory(cat, propCtx); + } +} + +type encode_mmCIF_categories_Params = { skipCategoryNames?: Set<string>, exportCtx?: CifExportContext } + /** Doesn't start a data block */ -export function encode_mmCIF_categories(encoder: CifWriter.Encoder, structures: Structure | Structure[], params?: { skipCategoryNames?: Set<string>, exportCtx?: CifExportContext }) { +export function encode_mmCIF_categories(encoder: CifWriter.Encoder, structures: Structure | Structure[], params?: encode_mmCIF_categories_Params) { const first = Array.isArray(structures) ? structures[0] : (structures as Structure); const models = first.models; if (models.length !== 1) throw 'Can\'t export stucture composed from multiple models.'; @@ -115,26 +139,15 @@ export function encode_mmCIF_categories(encoder: CifWriter.Encoder, structures: } for (const customProp of models[0].customProperties.all) { - if (!customProp.cifExport || customProp.cifExport.categories.length === 0) continue; - - const prefix = customProp.cifExport.prefix; - const cats = customProp.cifExport.categories; - - let propCtx = ctx; - if (customProp.cifExport.context) { - const propId = CustomPropertyDescriptor.getUUID(customProp); - if (ctx.cache[propId + '__ctx']) propCtx = ctx.cache[propId + '__ctx']; - else { - propCtx = customProp.cifExport.context(ctx) || ctx; - ctx.cache[propId + '__ctx'] = propCtx; - } - } - for (const cat of cats) { - if (_params.skipCategoryNames && _params.skipCategoryNames.has(cat.name)) continue; - if (cat.name.indexOf(prefix) !== 0) throw new Error(`Custom category '${cat.name}' name must start with prefix '${prefix}.'`); - encoder.writeCategory(cat, propCtx); - } + encodeCustomProp(customProp, ctx, encoder, _params); + } + + const structureCustomProps = new Set<CustomPropertyDescriptor>(); + for (const s of ctx.structures) { + if (!s.hasCustomProperties) continue; + for (const p of s.customPropertyDescriptors.all) structureCustomProps.add(p); } + structureCustomProps.forEach(customProp => encodeCustomProp(customProp, ctx, encoder, _params)); } function to_mmCIF(name: string, structure: Structure, asBinary = false) { diff --git a/src/mol-model/structure/structure/structure.ts b/src/mol-model/structure/structure/structure.ts index b344d0e677fc10bebd733a4e98a9edb69c4bda47..5243b670ff63ffe4c5d13052525010479372ef96 100644 --- a/src/mol-model/structure/structure/structure.ts +++ b/src/mol-model/structure/structure/structure.ts @@ -26,6 +26,7 @@ import { Vec3, Mat4 } from 'mol-math/linear-algebra'; import { idFactory } from 'mol-util/id-factory'; import { GridLookup3D } from 'mol-math/geometry'; import { UUID } from 'mol-util'; +import { CustomProperties } from '../common/custom-property'; class Structure { /** Maps unit.id to unit */ @@ -50,7 +51,9 @@ class Structure { transformHash: number, elementCount: number, polymerResidueCount: number, - coordinateSystem: SymmetryOperator + coordinateSystem: SymmetryOperator, + propertyData?: any, + customProps?: CustomProperties } = { hashCode: -1, transformHash: -1, @@ -68,6 +71,30 @@ class Structure { return this._props.elementCount; } + get hasCustomProperties() { + return !!this._props.customProps && this._props.customProps.all.length > 0; + } + + get customPropertyDescriptors() { + if (!this._props.customProps) this._props.customProps = new CustomProperties(); + return this._props.customProps; + } + + /** + * Property data unique to this instance of the structure. + */ + get currentPropertyData() { + if (!this._props.propertyData) this._props.propertyData = Object.create(null); + return this._props.propertyData; + } + + /** + * Property data of the parent structure if it exists, currentPropertyData otherwise. + */ + get inheritedPropertyData() { + return this.parent ? this.parent.currentPropertyData : this.currentPropertyData; + } + /** Count of all polymer residues in the structure */ get polymerResidueCount() { return this._props.polymerResidueCount;