PDBReader

Introduction

vtkPDBReader is a source object that reads Molecule files.

Methods

extend

Method used to decorate a given object (publicAPI+model) with vtkPDBReader characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues IPDBReaderInitialValues No (default: {})

getBaseURL

getDataAccessHelper

getNumberOfAtoms

getRequestCount

getUrl

Get the url of the object to load.

invokeBusy

Argument Type Required Description
busy Boolean Yes

isBusy

loadData

Load the object data.

Argument Type Required Description
options IPDBReaderOptions No

newInstance

Method used to create a new instance of vtkPDBReader

Argument Type Required Description
initialValues IPDBReaderInitialValues No for pre-setting some of its content

onBusy

Argument Type Required Description
callback Yes

parseAsText

Parse data as text.

Argument Type Required Description
content String Yes The content to parse.

requestData

Argument Type Required Description
inData Yes
outData Yes

setDataAccessHelper

Argument Type Required Description
dataAccessHelper Yes

setUrl

Set the url of the object to load.

Argument Type Required Description
url String Yes the url of the object to load.
option IPDBReaderOptions No The PDB reader options.

Source

index.d.ts
import { vtkAlgorithm, vtkObject, vtkSubscription } from "../../../interfaces";
import HtmlDataAccessHelper from "../../Core/DataAccessHelper/HtmlDataAccessHelper";
import HttpDataAccessHelper from "../../Core/DataAccessHelper/HttpDataAccessHelper";
import JSZipDataAccessHelper from "../../Core/DataAccessHelper/JSZipDataAccessHelper";
import LiteHttpDataAccessHelper from "../../Core/DataAccessHelper/LiteHttpDataAccessHelper";


interface IPDBReaderOptions {
binary?: boolean;
compression?: string;
progressCallback?: any;
}

/**
*
*/
export interface IPDBReaderInitialValues {
numberOfAtoms?: number;
requestCount?: number;
}

type vtkPDBReaderBase = vtkObject & Omit<vtkAlgorithm,
| 'getInputData'
| 'setInputData'
| 'setInputConnection'
| 'getInputConnection'
| 'addInputConnection'
| 'addInputData'>;

export interface vtkPDBReader extends vtkPDBReaderBase {

/**
*
*/
getBaseURL(): string;

/**
*
*/
getDataAccessHelper(): HtmlDataAccessHelper | HttpDataAccessHelper | JSZipDataAccessHelper | LiteHttpDataAccessHelper;

/**
* Get the url of the object to load.
*/
getUrl(): string;

/**
*
*/
getNumberOfAtoms(): number;

/**
*
*/
getRequestCount(): number;

/**
*
* @param {Boolean} busy
*/
invokeBusy(busy: boolean): void;

/**
*
*/
isBusy(): number;

/**
* Load the object data.
* @param {IPDBReaderOptions} [options]
*/
loadData(options?: IPDBReaderOptions): Promise<any>;

/**
*
* @param callback
*/
onBusy(callback: (busy: boolean) => any): vtkSubscription;

/**
* Parse data as text.
* @param {String} content The content to parse.
*/
parseAsText(content: string): void;
/**
*
* @param inData
* @param outData
*/
requestData(inData: any, outData: any): void;

/**
*
* @param dataAccessHelper
*/
setDataAccessHelper(dataAccessHelper: HtmlDataAccessHelper | HttpDataAccessHelper | JSZipDataAccessHelper | LiteHttpDataAccessHelper): boolean;

/**
* Set the url of the object to load.
* @param {String} url the url of the object to load.
* @param {IPDBReaderOptions} [option] The PDB reader options.
*/
setUrl(url: string, option?: IPDBReaderOptions): Promise<string>;
}

/**
* Method used to decorate a given object (publicAPI+model) with vtkPDBReader characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {IPDBReaderInitialValues} [initialValues] (default: {})
*/
export function extend(publicAPI: object, model: object, initialValues?: IPDBReaderInitialValues): void;

/**
* Method used to create a new instance of vtkPDBReader
* @param {IPDBReaderInitialValues} [initialValues] for pre-setting some of its content
*/
export function newInstance(initialValues?: IPDBReaderInitialValues): vtkPDBReader;


/**
* vtkPDBReader is a source object that reads Molecule files.
*/
export declare const vtkPDBReader: {
newInstance: typeof newInstance;
extend: typeof extend;
}
export default vtkPDBReader;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkMolecule from 'vtk.js/Sources/Common/DataModel/Molecule';
import DataAccessHelper from 'vtk.js/Sources/IO/Core/DataAccessHelper';

import ATOMS from 'vtk.js/Utilities/XMLConverter/chemistry-mapper/elements.json';

// Enable several sources for DataAccessHelper
import 'vtk.js/Sources/IO/Core/DataAccessHelper/LiteHttpDataAccessHelper'; // Just need HTTP
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HttpDataAccessHelper'; // HTTP + gz
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/HtmlDataAccessHelper'; // html + base64 + zip
// import 'vtk.js/Sources/IO/Core/DataAccessHelper/JSZipDataAccessHelper'; // zip

// ----------------------------------------------------------------------------
// vtkPDBReader methods
// ----------------------------------------------------------------------------

function vtkPDBReader(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkPDBReader');

// Create default dataAccessHelper if not available
if (!model.dataAccessHelper) {
model.dataAccessHelper = DataAccessHelper.get('http');
}

// Internal method to fetch Array
function fetchPDB(url, option) {
return model.dataAccessHelper.fetchText(publicAPI, url, option);
}

// Set DataSet url
publicAPI.setUrl = (url, option) => {
if (url.indexOf('.pdb') === -1) {
model.baseURL = url;
model.url = `${url}`; // `${url}/index.pdb`;
} else {
model.url = url;

// Remove the file in the URL
const path = url.split('/');
path.pop();
model.baseURL = path.join('/');
}

// Fetch metadata
return publicAPI.loadData(option);
};

// Fetch the actual data arrays
publicAPI.loadData = (option) =>
fetchPDB(model.url, option).then(publicAPI.parseAsText);

publicAPI.parseAsText = (txt) => {
model.pdb = txt;
model.molecule = [];
model.molecule = model.pdb.split('\n');
publicAPI.modified();
return true;
};

publicAPI.requestData = (inData, outData) => {
const moleculedata = vtkMolecule.newInstance();

if (model.molecule) {
const jSize = model.molecule.length;

// atom position
const pointValues = [];

// atomicNumber
const atomicNumber = [];

model.numberOfAtoms = 0;

let j = 0;
while (j < jSize && model.molecule[j] !== 'END') {
const iSize = model.molecule[j].length;
const linebuf = model.molecule[j];

const command = linebuf.substr(0, 6).replace(/\s+/g, '');
command.toUpperCase();

// Parse lines
if (command === 'ATOM' || command === 'HETATM') {
const dum1 = linebuf.substr(12, 4).replace(/\s+/g, '');
// const dum2 = (linebuf.substr(17, 3)).replace(/\s+/g, '');
// const chain = (linebuf.substr(21, 1)).replace(/\s+/g, '');
// const resi = ((linebuf.substr(22, 8)).replace(/\s+/g, '')).replace(/\D/g, '');
const x = linebuf.substr(30, 8).replace(/\s+/g, '');
const y = linebuf.substr(38, 8).replace(/\s+/g, '');
const z = linebuf.substr(46, 8).replace(/\s+/g, '');

let elem = '';
if (iSize >= 78) {
elem = linebuf.substr(76, 2).replace(/\s+/g, '');
}
if (elem === '') {
// if element symbol was not specified, just use the "Atom name".
elem = dum1.substr(0, 2).replace(/\d/g, '');
}

// fill polydata
// atoms position
pointValues.push(x);
pointValues.push(y);
pointValues.push(z);

// fetch data from the element database elements.json
const [atomicNumberData] = ATOMS[elem];

// atoms atomicNumber
atomicNumber.push(atomicNumberData);

// residue.push(resi);
// chain.push(chain);
// atomType.push(elem);
// atomTypeStrings.push(dum1);
// isHetatm.push(command === 'HETATM');

model.numberOfAtoms++;
} // if atom or hetatm

/*
else if (command === 'SHEET') {
const startChain = (linebuf.substr(21,1)).replace(/\s+/g, '');
const startResi = (linebuf.substr(22,4)).replace(/\s+/g, '').replace(/\D/g, '');
const endChain = (linebuf.substr(32,1)).replace(/\s+/g, '');
const endResi = (linebuf.substr(33,4)).replace(/\s+/g, '').replace(/\D/g, '');;
const tuple = { startChain, startResi, endChain, endResi };
sheets.push(tuple);
}
else if (command === 'HELIX') {
const startChain = (linebuf.substr(19,2)).replace(/\s+/g, '');
const startResi = (linebuf.substr(21,4)).replace(/\s+/g, '').replace(/\D/g, '');;
const endChain = (linebuf.substr(31,2)).replace(/\s+/g, '');
const endResi = (linebuf.substr(33,4)).replace(/\s+/g, '').replace(/\D/g, '');;
const tuple = { startChain, startResi, endChain, endResi };
helix.push(tuple);
}
*/
j++;
} // lines loop (j)

// fill molecule class
moleculedata.getAtoms().elements = {};
moleculedata.getAtoms().elements.number = Int8Array.from(atomicNumber);
moleculedata.getAtoms().coords = {};
moleculedata.getAtoms().coords['3d'] = Float32Array.from(pointValues);
} // if model.molecule

model.output[0] = moleculedata;
};

// return Busy state
publicAPI.isBusy = () => !!model.requestCount;
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
numberOfAtoms: 0,
requestCount: 0,
// baseURL: null,
// dataAccessHelper: null,
// url: null,
};

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);

// Build VTK API
macro.obj(publicAPI, model);
macro.get(publicAPI, model, [
'url',
'baseURL',
'numberOfAtoms',
'requestCount',
]);
macro.setGet(publicAPI, model, ['dataAccessHelper']);
macro.algo(publicAPI, model, 0, 1);
macro.event(publicAPI, model, 'busy');

// Object methods
vtkPDBReader(publicAPI, model);
}

// ----------------------------------------------------------------------------

export const newInstance = macro.newInstance(extend, 'vtkPDBReader');

// ----------------------------------------------------------------------------

export default { newInstance, extend };