layer2/CoordSet.cpp (1,475 lines of code) (raw):

/* A* ------------------------------------------------------------------- B* This file contains source code for the PyMOL computer program C* copyright 1998-2000 by Warren Lyford Delano of DeLano Scientific. D* ------------------------------------------------------------------- E* It is unlawful to modify or remove this copyright notice. F* ------------------------------------------------------------------- G* Please see the accompanying LICENSE file for further information. H* ------------------------------------------------------------------- I* Additional authors of this source file include: -* -* -* Z* ------------------------------------------------------------------- */ #include"os_python.h" #include"os_numpy.h" #include"os_std.h" #include <algorithm> #include"Base.h" #include"OOMac.h" #include"MemoryDebug.h" #include"Err.h" #include"Scene.h" #include"CoordSet.h" #include"Color.h" #include"PConv.h" #include"P.h" #include"Matrix.h" #include"Sphere.h" #include"Util.h" #include"Feedback.h" #include"RepWireBond.h" #include"RepCylBond.h" #include"RepDot.h" #include"RepMesh.h" #include"RepSphere.h" #include"RepSphereImmediate.h" #include"RepRibbon.h" #include"RepCartoon.h" #include"RepSurface.h" #include"RepLabel.h" #include"RepNonbonded.h" #include"RepNonbondedSphere.h" #include"RepEllipsoid.h" #include"PyMOLGlobals.h" #include"PyMOLObject.h" #include "Executive.h" #include "Lex.h" #ifdef _PYMOL_IP_PROPERTIES #include "Property.h" #endif /*========================================================================*/ /* * Get coordinate index for given atom index */ int CoordSet::atmToIdx(int atm) const { if (Obj->DiscreteFlag) { if (this == Obj->DiscreteCSet[atm]) return Obj->DiscreteAtmToIdx[atm]; return -1; } return AtmToIdx[atm]; } /*========================================================================*/ static char sATOM[] = "ATOM "; static char sHETATM[] = "HETATM"; int CoordSetValidateRefPos(CoordSet * I) { if(I->RefPos) { VLACheck(I->RefPos, RefPosType, I->NIndex); return true; } else { int ok = true && (I->RefPos = VLACalloc(RefPosType, I->NIndex)); if(ok) { int a; for(a = 0; a < I->NIndex; a++) { float *src = I->Coord + 3 * a; copy3f(src, I->RefPos[a].coord); I->RefPos[a].specified = true; } } return ok; } } /*========================================================================*/ int BondCompare(BondType * a, BondType * b) { int ai0 = a->index[0]; int bi0 = b->index[0]; if(ai0 == bi0) { int ai1 = a->index[1]; int bi1 = b->index[1]; if(ai1 == bi1) { return 0; } else if(ai1 > bi1) { return 1; } else { return -1; } } else if(ai0 > bi0) { return 1; } else { return -1; } } /*========================================================================*/ int BondInOrder(BondType * a, int b1, int b2) { return (BondCompare(a + b1, a + b2) <= 0); } int CoordSetFromPyList(PyMOLGlobals * G, PyObject * list, CoordSet ** cs) { CoordSet *I = NULL; int ok = true; int ll = 0; if(*cs) { (*cs)->fFree(); *cs = NULL; } if(list == Py_None) { /* allow None for CSet */ *cs = NULL; } else { if(ok) I = CoordSetNew(G); if(ok) ok = (I != NULL); if(ok) ok = (list != NULL); if(ok) ok = PyList_Check(list); if(ok) ll = PyList_Size(list); /* TO SUPPORT BACKWARDS COMPATIBILITY... Always check ll when adding new PyList_GetItem's */ if(ok) ok = PConvPyIntToInt(PyList_GetItem(list, 0), &I->NIndex); if(ok) ok = PConvPyIntToInt(PyList_GetItem(list, 1), &I->NAtIndex); if(ok) ok = PConvPyListToFloatVLA(PyList_GetItem(list, 2), &I->Coord); if(ok) ok = PConvPyListToIntVLA(PyList_GetItem(list, 3), &I->IdxToAtm); if(ok && (ll > 5)) ok = PConvPyStrToStr(PyList_GetItem(list, 5), I->Name, sizeof(WordType)); if(ok && (ll > 6)) ok = ObjectStateFromPyList(G, PyList_GetItem(list, 6), &I->State); if(ok && (ll > 7)) I->Setting = SettingNewFromPyList(G, PyList_GetItem(list, 7)); if(ok && (ll > 8)) ok = PConvPyListToLabPosVLA(PyList_GetItem(list, 8), &I->LabPos); #ifdef _PYMOL_IP_PROPERTIES #endif if(ok && (ll > 10)){ CPythonVal *val = CPythonVal_PyList_GetItem(G, list, 10); if (!CPythonVal_IsNone(val)) I->SculptCGO = CGONewFromPyList(G, val, 0, 1); else { I->SculptShaderCGO = I->SculptCGO = NULL; } CPythonVal_Free(val); } if(ok){ if(ll > 11){ // load in atom-state settings CPythonVal *val = CPythonVal_PyList_GetItem(G, list, 11); if (!CPythonVal_IsNone(val)){ int a; I->atom_state_setting_id = VLACalloc(int, I->NIndex); I->has_atom_state_settings = VLACalloc(char, I->NIndex); for (a=0; a<I->NIndex; a++){ CPythonVal *val2 = CPythonVal_PyList_GetItem(G, val, a); if (!CPythonVal_IsNone(val2)){ CPythonVal_PConvPyIntToInt(val2, &I->atom_state_setting_id[a]); I->has_atom_state_settings[a] = (I->atom_state_setting_id[a]) ? 1 : 0; if (I->atom_state_setting_id[a]) { I->atom_state_setting_id[a] = SettingUniqueConvertOldSessionID(G, I->atom_state_setting_id[a]); } } CPythonVal_Free(val2); } } else { I->atom_state_setting_id = NULL; I->has_atom_state_settings = NULL; } CPythonVal_Free(val); } else { // check I->LabPos.offset to see if its set if (I->LabPos){ int a; for (a=0; a<I->NIndex; a++){ if(length3f(I->LabPos[a].offset) > R_SMALL4) { SettingSet(cSetting_label_placement_offset, I->LabPos[a].offset, I, a); } } } } } if(!ok) { if(I) I->fFree(); *cs = NULL; } else { *cs = I; } } return (ok); } /* * Coord set as numpy array */ PyObject *CoordSetAsNumPyArray(CoordSet * cs, short copy) { #ifndef _PYMOL_NUMPY PRINTFB(cs->State.G, FB_CoordSet, FB_Errors) "No numpy support\n" ENDFB(cs->State.G); return NULL; #else PyObject *result = NULL; const int base_size = sizeof(float); int typenum = -1; npy_intp dims[2] = {0, 3}; import_array1(NULL); switch(base_size) { case 4: typenum = NPY_FLOAT32; break; case 8: typenum = NPY_FLOAT64; break; } if(typenum == -1) { printf("error: no typenum for float size %d\n", base_size); return NULL; } dims[0] = cs->NIndex; if(copy) { if((result = PyArray_SimpleNew(2, dims, typenum))) memcpy(PyArray_DATA((PyArrayObject *)result), cs->Coord, cs->NIndex * 3 * base_size); } else { result = PyArray_SimpleNewFromData(2, dims, typenum, cs->Coord); } return result; #endif } PyObject *CoordSetAsPyList(CoordSet * I) { PyObject *result = NULL; if(I) { int pse_export_version = SettingGetGlobal_f(I->State.G, cSetting_pse_export_version) * 1000; bool dump_binary = SettingGetGlobal_b(I->State.G, cSetting_pse_binary_dump) && (!pse_export_version || pse_export_version >= 1765); result = PyList_New(12); PyList_SetItem(result, 0, PyInt_FromLong(I->NIndex)); PyList_SetItem(result, 1, PyInt_FromLong(I->NAtIndex)); PyList_SetItem(result, 2, PConvFloatArrayToPyList(I->Coord, I->NIndex * 3, dump_binary)); PyList_SetItem(result, 3, PConvIntArrayToPyList(I->IdxToAtm, I->NIndex, dump_binary)); if(I->AtmToIdx && pse_export_version < 1770) PyList_SetItem(result, 4, PConvIntArrayToPyList(I->AtmToIdx, I->NAtIndex, dump_binary)); else PyList_SetItem(result, 4, PConvAutoNone(NULL)); PyList_SetItem(result, 5, PyString_FromString(I->Name)); PyList_SetItem(result, 6, ObjectStateAsPyList(&I->State)); PyList_SetItem(result, 7, SettingAsPyList(I->Setting)); PyList_SetItem(result, 8, PConvLabPosVLAToPyList(I->LabPos, I->NIndex)); PyList_SetItem(result, 9, #ifdef _PYMOL_IP_PROPERTIES #endif PConvAutoNone(Py_None)); if(I->SculptCGO) { PyList_SetItem(result, 10, CGOAsPyList(I->SculptCGO)); } else { PyList_SetItem(result, 10, PConvAutoNone(NULL)); } if (I->has_atom_state_settings){ int a; PyObject *settings_list = NULL; settings_list = PyList_New(I->NIndex); for (a=0; a<I->NIndex; a++){ if (I->has_atom_state_settings[a]){ PyList_SetItem(settings_list, a, PyInt_FromLong(I->atom_state_setting_id[a])); } else { PyList_SetItem(settings_list, a, PConvAutoNone(NULL)); } } PyList_SetItem(result, 11, settings_list); } else { PyList_SetItem(result, 11, PConvAutoNone(NULL)); } /* TODO symmetry, spheroid, periodic box ... */ } return (PConvAutoNone(result)); } void CoordSetAdjustAtmIdx(CoordSet * I, int *lookup, int nAtom) /* performs second half of removal */ { /* NOTE: only works in a compressive mode, where lookup[a]<=a */ int a, a0, atm; char *new_has_atom_state_settings_by_atom = NULL; int *new_atom_state_setting_id_by_atom = NULL; int nIndex = I->NIndex; PRINTFD(I->State.G, FB_CoordSet) " CoordSetAdjustAtmIdx-Debug: entered NAtIndex: %d NIndex %d\n I->AtmToIdx %p\n", I->NAtIndex, I->NIndex, (void *) I->AtmToIdx ENDFD; if (I->has_atom_state_settings){ new_has_atom_state_settings_by_atom = VLACalloc(char, nIndex); new_atom_state_setting_id_by_atom = VLACalloc(int, nIndex); } for(a = 0; a < nIndex; a++) { atm = I->IdxToAtm[a]; a0 = lookup[atm]; if (a0 < 0){ if (I->has_atom_state_settings){ if (I->has_atom_state_settings[a]){ SettingUniqueDetachChain(I->State.G, I->atom_state_setting_id[a]); I->has_atom_state_settings[a] = 0; I->atom_state_setting_id[a] = 0; } } } else if (new_has_atom_state_settings_by_atom){ new_has_atom_state_settings_by_atom[a0] = I->has_atom_state_settings[a]; new_atom_state_setting_id_by_atom[a0] = I->atom_state_setting_id[a]; } } if (I->AtmToIdx){ for(a = 0; a < I->NAtIndex; a++) { a0 = lookup[a]; if(a0 >= 0) { I->AtmToIdx[a0] = I->AtmToIdx[a]; } } } I->NAtIndex = nAtom; if (I->AtmToIdx){ VLASize(I->AtmToIdx, int, nAtom); } for(a = 0; a < I->NIndex; a++) { atm = I->IdxToAtm[a] = lookup[I->IdxToAtm[a]]; if (new_has_atom_state_settings_by_atom){ I->has_atom_state_settings[a] = new_has_atom_state_settings_by_atom[atm]; I->atom_state_setting_id[a] = new_atom_state_setting_id_by_atom[atm]; } } if (new_has_atom_state_settings_by_atom){ VLAFreeP(new_has_atom_state_settings_by_atom); VLAFreeP(new_atom_state_setting_id_by_atom); } PRINTFD(I->State.G, FB_CoordSet) " CoordSetAdjustAtmIdx-Debug: leaving... NAtIndex: %d NIndex %d\n", I->NAtIndex, I->NIndex ENDFD; } /*========================================================================*/ int CoordSetMerge(ObjectMolecule *OM, CoordSet * I, CoordSet * cs) { /* must be non-overlapping */ int nIndex; int a, i0; int ok = true; /* calculate new size and make room for new data */ nIndex = I->NIndex + cs->NIndex; VLASize(I->IdxToAtm, int, nIndex); CHECKOK(ok, I->IdxToAtm); if (ok) VLACheck(I->Coord, float, nIndex * 3); CHECKOK(ok, I->Coord); if (ok){ for(a = 0; a < cs->NIndex; a++) { i0 = a + I->NIndex; I->IdxToAtm[i0] = cs->IdxToAtm[a]; if (OM->DiscreteFlag){ int idx = cs->IdxToAtm[a]; OM->DiscreteAtmToIdx[idx] = i0; OM->DiscreteCSet[idx] = I; } else { I->AtmToIdx[cs->IdxToAtm[a]] = i0; } copy3f(cs->Coord + a * 3, I->Coord + i0 * 3); } } if (ok){ if(cs->LabPos) { if(!I->LabPos) I->LabPos = VLACalloc(LabPosType, nIndex); else VLACheck(I->LabPos, LabPosType, nIndex); if(I->LabPos) { UtilCopyMem(I->LabPos + I->NIndex, cs->LabPos, sizeof(LabPosType) * cs->NIndex); } } else if(I->LabPos) { VLACheck(I->LabPos, LabPosType, nIndex); } } if (ok){ if(cs->RefPos) { if(!I->RefPos) I->RefPos = VLACalloc(RefPosType, nIndex); else VLACheck(I->RefPos, RefPosType, nIndex); if(I->RefPos) { UtilCopyMem(I->RefPos + I->NIndex, cs->RefPos, sizeof(RefPosType) * cs->NIndex); } } else if(I->RefPos) { VLACheck(I->RefPos, RefPosType, nIndex); } I->invalidateRep(cRepAll, cRepInvAll); } I->NIndex = nIndex; return ok; } /*========================================================================*/ void CoordSetPurge(CoordSet * I) /* performs first half of removal */ { int offset = 0; int a, a1, ao; AtomInfoType *ai; ObjectMolecule *obj; float *c0, *c1; LabPosType *l0, *l1; RefPosType *r0, *r1; int *atom_state0, *atom_state1; char *has_atom_state0, *has_atom_state1; obj = I->Obj; PRINTFD(I->State.G, FB_CoordSet) " CoordSetPurge-Debug: entering..." ENDFD; c0 = c1 = I->Coord; r0 = r1 = I->RefPos; l0 = l1 = I->LabPos; atom_state0 = atom_state1 = I->atom_state_setting_id; has_atom_state0 = has_atom_state1 = I->has_atom_state_settings; /* This loop slides down the atoms that are not deleted (deleteFlag) it moves the Coord, RefPos, and LabPos */ for(a = 0; a < I->NIndex; a++) { a1 = I->IdxToAtm[a]; ai = obj->AtomInfo + a1; if(ai->deleteFlag) { offset--; c0 += 3; if(l0) l0++; if(r0) r0++; if (has_atom_state0){ atom_state0++; has_atom_state0++; } } else if(offset) { ao = a + offset; *(c1++) = *(c0++); *(c1++) = *(c0++); *(c1++) = *(c0++); if(r1) { *(r1++) = *(r0++); } if(l0) { *(l1++) = *(l0++); } if (has_atom_state0){ *(atom_state1++) = *(atom_state0++); *(has_atom_state1++) = *(has_atom_state0++); } if (I->AtmToIdx) I->AtmToIdx[a1] = ao; I->IdxToAtm[ao] = a1; /* no adjustment of these indexes yet... */ if (I->Obj->DiscreteFlag){ I->Obj->DiscreteAtmToIdx[a1] = ao; I->Obj->DiscreteCSet[a1] = I; } } else { c0 += 3; c1 += 3; if(r1) { r0++; r1++; } if(l0) { l0++; l1++; } if (has_atom_state0){ atom_state0++; atom_state1++; has_atom_state0++; has_atom_state1++; } } } if(offset) { /* If there were deleted atoms, (offset < 0), then re-adjust the array sizes */ I->NIndex += offset; VLASize(I->Coord, float, I->NIndex * 3); if(I->LabPos) { VLASize(I->LabPos, LabPosType, I->NIndex); } if(I->RefPos) { VLASize(I->RefPos, RefPosType, I->NIndex); } if(I->has_atom_state_settings) { VLASize(I->has_atom_state_settings, char, I->NIndex); VLASize(I->atom_state_setting_id, int, I->NIndex); } VLASize(I->IdxToAtm, int, I->NIndex); PRINTFD(I->State.G, FB_CoordSet) " CoordSetPurge-Debug: I->IdxToAtm shrunk to %d\n", I->NIndex ENDFD; I->invalidateRep(cRepAll, cRepInvAtoms); /* this will free Color */ } PRINTFD(I->State.G, FB_CoordSet) " CoordSetPurge-Debug: leaving NAtIndex %d NIndex %d...\n", I->NAtIndex, I->NIndex ENDFD; } /*========================================================================*/ int CoordSetTransformAtomTTTf(CoordSet * I, int at, const float *TTT) { int a1 = I->atmToIdx(at); float *v1; if(a1 < 0) return false; v1 = I->Coord + 3 * a1; MatrixTransformTTTfN3f(1, v1, TTT, v1); return true; } /*========================================================================*/ int CoordSetTransformAtomR44f(CoordSet * I, int at, const float *matrix) { int a1 = I->atmToIdx(at); float *v1; if(a1 < 0) return false; v1 = I->Coord + 3 * a1; MatrixTransformR44fN3f(1, v1, matrix, v1); return true; } /*========================================================================*/ void CoordSetRecordTxfApplied(CoordSet * I, const float *matrix, int homogenous) { double temp[16]; if(!homogenous) { convertTTTfR44d(matrix, temp); } else { convert44f44d(matrix, temp); } ObjectStateLeftCombineMatrixR44d(&I->State, temp); } /*========================================================================*/ int CoordSetMoveAtom(CoordSet * I, int at, const float *v, int mode) { int a1 = I->atmToIdx(at); float *v1; if(a1 < 0) return false; v1 = I->Coord + 3 * a1; if(mode) { add3f(v, v1, v1); } else { copy3f(v, v1); } return true; } /*========================================================================*/ int CoordSetMoveAtomLabel(CoordSet * I, int at, const float *v, const float *diff) { ObjectMolecule *obj = I->Obj; int a1 = I->atmToIdx(at); int result = 0; /* if label is valid, get the label offset * and set the new position relative to that */ if(a1 >= 0) { float at_offset[3]; const float * at_offset_ptr; int at_label_relative_mode = 0; AtomInfoType *ai = obj->AtomInfo + at; AtomStateGetSetting_i(I->State.G, obj, I, a1, ai, cSetting_label_relative_mode, &at_label_relative_mode); switch (at_label_relative_mode){ case 0: AtomStateGetSetting(I->State.G, obj, I, a1, ai, cSetting_label_placement_offset, &at_offset_ptr); add3f(v, at_offset_ptr, at_offset); SettingSet(cSetting_label_placement_offset, at_offset, I, a1); break; case 1: // screen relative case 2: // screen pixel space { float voff[3]; int width, height; SceneGetWidthHeight(I->State.G, &width, &height); if (at_label_relative_mode==1){ voff[0] = 2.f * diff[0] / width; voff[1] = 2.f * diff[1] / height; } else { voff[0] = diff[0]; voff[1] = diff[1]; } voff[2] = 0.f; AtomStateGetSetting(I->State.G, obj, I, a1, ai, cSetting_label_screen_point, &at_offset_ptr); add3f(voff, at_offset_ptr, at_offset); SettingSet(cSetting_label_screen_point, at_offset, I, a1); } break; } } return (result); } /*========================================================================*/ int CoordSetGetAtomVertex(CoordSet * I, int at, float *v) { int a1 = I->atmToIdx(at); if(a1 < 0) return false; copy3f(I->Coord + 3 * a1, v); return true; } /*========================================================================*/ int CoordSetGetAtomTxfVertex(CoordSet * I, int at, float *v) { ObjectMolecule *obj = I->Obj; int a1 = I->atmToIdx(at); if(a1 < 0) return false; copy3f(I->Coord + 3 * a1, v); /* apply state transformation */ if(I->State.Matrix && (SettingGet_i(I->State.G, obj->Obj.Setting, I->Setting, cSetting_matrix_mode) > 0)) { transform44d3f(I->State.Matrix, v, v); } /* object transformation */ if(obj->Obj.TTTFlag) { transformTTT44f3f(obj->Obj.TTT, v, v); } return true; } /*========================================================================*/ int CoordSetSetAtomVertex(CoordSet * I, int at, const float *v) { int a1 = I->atmToIdx(at); if(a1 < 0) return false; copy3f(v, I->Coord + 3 * a1); return true; } /*========================================================================*/ void CoordSetRealToFrac(CoordSet * I, const CCrystal * cryst) { int a; float *v; v = I->Coord; for(a = 0; a < I->NIndex; a++) { transform33f3f(cryst->RealToFrac, v, v); v += 3; } } /*========================================================================*/ void CoordSetTransform44f(CoordSet * I, const float *mat) { int a; float *v; v = I->Coord; for(a = 0; a < I->NIndex; a++) { transform44f3f(mat, v, v); v += 3; } } /*========================================================================*/ void CoordSetTransform33f(CoordSet * I, const float *mat) { int a; float *v; v = I->Coord; for(a = 0; a < I->NIndex; a++) { transform33f3f(mat, v, v); v += 3; } } /*========================================================================*/ void CoordSetGetAverage(CoordSet * I, float *v0) { int a; float *v; double accum[3]; if(I->NIndex) { v = I->Coord; accum[0] = *(v++); accum[1] = *(v++); accum[2] = *(v++); for(a = 1; a < I->NIndex; a++) { accum[0] += *(v++); accum[1] += *(v++); accum[2] += *(v++); } v0[0] = (float) (accum[0] / I->NIndex); v0[1] = (float) (accum[1] / I->NIndex); v0[2] = (float) (accum[2] / I->NIndex); } } /*========================================================================*/ void CoordSetFracToReal(CoordSet * I, const CCrystal * cryst) { int a; float *v; v = I->Coord; for(a = 0; a < I->NIndex; a++) { transform33f3f(cryst->FracToReal, v, v); v += 3; } } /* * Apply the `sca` (SCALEn) transformation to transform to fractional space, * and then the crystals `FracToReal` transformation to transform back to * cartesian space. * * Don't do anything if pdb_insure_orthogonal=off. * * Don't do anything if SCALEn or CRYST1 look bogus. There is a number of * structures in the PDB which have meaningless values for those. * * Without this, creating symmetry mates might produce wrong results. */ bool CoordSetInsureOrthogonal(PyMOLGlobals * G, CoordSet * cset, // coord set to modify const float * sca, // 4x4 SCALE const CCrystal *cryst, bool quiet) { if (!SettingGetGlobal_b(G, cSetting_pdb_insure_orthogonal)) return false; if (!cryst) cryst = cset->Symmetry->Crystal; const float * r2f = cryst->RealToFrac; // are the matrices sufficiently close to be the same? if (!sca[3] && !sca[7] && !sca[11] && is_allclosef(3, r2f, 3, sca, 4, R_SMALL4)) { return false; } // is the cell a orthogonal 1x1x1? If so, then it should probably be ignored... // is SCALEn the identity matrix? If so, then it should probably be ignored... if (is_identityf(3, r2f, R_SMALL4) || is_identityf(4, sca, R_SMALL4)) { PRINTFB(G, FB_ObjectMolecule, FB_Blather) " ObjectMolReadPDBStr: ignoring SCALEn (identity matrix).\n" ENDFB(G); return false; } // is SCALEn invalid? If so, then it should definitely be ignored... if (determinant33f(sca, 4) < R_SMALL8 || determinant33f(r2f, 3) < R_SMALL8) { PRINTFB(G, FB_ObjectMolecule, FB_Blather) " ObjectMolReadPDBStr: ignoring SCALEn (invalid matrix).\n" ENDFB(G); return false; } PRINTFB(G, FB_ObjectMolecule, quiet ? FB_Blather : FB_Actions) " ObjectMolecule: using SCALEn to compute orthogonal coordinates.\n" ENDFB(G); CoordSetTransform44f(cset, sca); CoordSetFracToReal(cset, cryst); return true; } /*========================================================================*/ static char RotateU(const double *matrix, float *anisou) /* Rotates the ANISOU vector * * matrix: flat 4x4, but only rotation (upper left 3x3) is considered * anisou: has 6 elements (of symmetric 3x3) and will be rotated in-place */ { int i, j, k; float Re[3][3]; double e_val[3], e_vec[3][3]; double U[3][3] = { { anisou[0], anisou[3], anisou[4] }, { anisou[3], anisou[1], anisou[5] }, { anisou[4], anisou[5], anisou[2] }, }; // e_val, e_vec = linalg.eigh(U) if(!xx_matrix_jacobi_solve(*e_vec, e_val, &i, *U, 3)) return false; // Re = dot(matrix[:3,:3], e_vec) for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) { Re[i][j] = 0.0; for (k = 0; k < 3; k++) Re[i][j] += matrix[i * 4 + k] * e_vec[k][j]; } // U = dot(Re * e_val, Re.T) for (i = 0; i < 3; i++) for (j = 0; j <= i; j++) { U[i][j] = 0.0; for (k = 0; k < 3; k++) U[i][j] += Re[i][k] * e_val[k] * Re[j][k]; } anisou[0] = U[0][0]; anisou[1] = U[1][1]; anisou[2] = U[2][2]; anisou[3] = U[1][0]; anisou[4] = U[2][0]; anisou[5] = U[2][1]; return true; } /*========================================================================*/ void CoordSetAtomToPDBStrVLA(PyMOLGlobals * G, char **charVLA, int *c, const AtomInfoType * ai, const float *v, int cnt, const PDBInfoRec * pdb_info, const double *matrix) /* * v: 3x1 vertex in final output space * matrix: 4x4 homogenous transformation matrix from model space to output * space (view matrix * state matrix). Used for ANISOU. */ { char *aType; AtomName name; ResName resn; lexidx_t chain; char formalCharge[4]; int ignore_pdb_segi = SettingGetGlobal_b(G, cSetting_ignore_pdb_segi); WordType x, y, z; AtomInfoGetAlignedPDBResidueName(G, ai, resn); AtomInfoGetAlignedPDBAtomName(G, ai, resn, name); formalCharge[0] = 0; if(SettingGetGlobal_b(G, cSetting_pdb_formal_charges)) { if((ai->formalCharge > 0) && (ai->formalCharge < 10)) { sprintf(formalCharge, "%d+", ai->formalCharge); } else if((ai->formalCharge < 0) && (ai->formalCharge > -10)) { sprintf(formalCharge, "%d-", -ai->formalCharge); } } if(ai->hetatm) aType = sHETATM; else aType = sATOM; char inscode = ai->getInscode(true); VLACheck(*charVLA, char, (*c) + 1000); if(SettingGetGlobal_b(G, cSetting_pdb_retain_ids)) { cnt = ai->id - 1; } if(cnt > 99998) cnt = 99998; if((!pdb_info) || (!pdb_info->is_pqr_file())) { /* relying upon short-circuit */ short linelen; sprintf(x, "%8.3f", v[0]); x[8] = 0; sprintf(y, "%8.3f", v[1]); y[8] = 0; sprintf(z, "%8.3f", v[2]); z[8] = 0; linelen = sprintf((*charVLA) + (*c), "%6s%5i %-4s%1s%-4s%1.1s%4i%c %s%s%s%6.2f%6.2f %-4.4s%2s%2s\n", aType, cnt + 1, name, ai->alt, resn, LexStr(G, ai->chain), ai->resv % 10000, inscode, x, y, z, ai->q, ai->b, ignore_pdb_segi ? "" : LexStr(G, ai->segi), ai->elem, formalCharge); if(ai->anisou) { // Columns 7 - 27 and 73 - 80 are identical to the corresponding ATOM/HETATM record. char *atomline = (*charVLA) + (*c); char *anisoline = atomline + linelen; float anisou[6]; memcpy(anisou, ai->anisou, 6 * sizeof(float)); if(matrix && !RotateU(matrix, anisou)) { PRINTFB(G, FB_CoordSet, FB_Errors) "RotateU failed\n" ENDFB(G); return; } strncpy(anisoline + 6, atomline + 6, 22); sprintf(anisoline + 28, "%7.0f%7.0f%7.0f%7.0f%7.0f%7.0f", anisou[0] * 1e4, anisou[1] * 1e4, anisou[2] * 1e4, anisou[3] * 1e4, anisou[4] * 1e4, anisou[5] * 1e4); strcpy(anisoline + 70, atomline + 70); strncpy(anisoline, "ANISOU", 6); (*c) += linelen; } (*c) += linelen; } else { Chain alt; if(pdb_info->is_pqr_file() && pdb_info->pqr_workarounds) { inscode = ' '; chain = 0; /* no chain IDs */ alt[0] = 0; /* not alt conf identifiers */ } else { alt[0] = ai->alt[0]; alt[1] = 0; chain = ai->chain; } sprintf(x, "%8.3f", v[0]); if(x[0] != 32) sprintf(x, " %7.2f", v[0]); x[8] = 0; sprintf(y, "%8.3f", v[1]); y[8] = 0; if(y[0] != 32) sprintf(y, " %7.2f", v[1]); y[8] = 0; sprintf(z, "%8.3f", v[2]); if(z[0] != 32) sprintf(z, " %7.2f", v[2]); z[8] = 0; (*c) += sprintf((*charVLA) + (*c), "%6s%5i %-4s%1s%-4s%1.1s%4i%c %s%s%s %11.8f %7.3f\n", aType, cnt + 1, name, alt, resn, LexStr(G, chain), ai->resv, inscode, x, y, z, ai->partialCharge, ai->elec_radius); } } /*========================================================================*/ PyObject *CoordSetAtomToChemPyAtom(PyMOLGlobals * G, AtomInfoType * ai, const float *v, const float *ref, int index, const double *matrix) { #ifdef _PYMOL_NOPY return NULL; #else PyObject *atom = PYOBJECT_CALLMETHOD(P_chempy, "Atom", ""); if(!atom) ErrMessage(G, "CoordSetAtomToChemPyAtom", "can't create atom"); else { float tmp_array[6] = { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f }; if (ai->anisou) { memcpy(tmp_array, ai->anisou, 6 * sizeof(float)); if (matrix) RotateU(matrix, tmp_array); } PConvFloat3ToPyObjAttr(atom, "coord", v); if(ref) PConvFloat3ToPyObjAttr(atom, "ref_coord", ref); if (ai->name) PConvStringToPyObjAttr(atom, "name", LexStr(G, ai->name)); PConvStringToPyObjAttr(atom, "symbol", ai->elem); // TODO defaults to UNK if (ai->resn) PConvStringToPyObjAttr(atom, "resn", LexStr(G, ai->resn)); if (ai->inscode) { char ins_code[2] = {ai->inscode, 0}; PConvStringToPyObjAttr(atom, "ins_code", ins_code); } if (ai->ssType[0]) PConvStringToPyObjAttr(atom, "ss", ai->ssType); // TODO defaults to 1 if (ai->resv) PConvIntToPyObjAttr(atom, "resi_number", ai->resv); if (ai->stereo) PConvIntToPyObjAttr(atom, "stereo", ai->stereo); if (ai->chain) PConvStringToPyObjAttr(atom, "chain", LexStr(G, ai->chain)); if(ai->alt[0]) PConvStringToPyObjAttr(atom, "alt", ai->alt); if (ai->segi) PConvStringToPyObjAttr(atom, "segi", LexStr(G, ai->segi)); if (ai->q != 1.) PConvFloatToPyObjAttr(atom, "q", ai->q); if (ai->b) PConvFloatToPyObjAttr(atom, "b", ai->b); if (ai->anisou) { { PyObject *tmp_obj = PConvFloatArrayToPyList(tmp_array, 6); if(tmp_obj) { PyObject_SetAttrString(atom, "u_aniso", tmp_obj); Py_XDECREF(tmp_obj); } } } PConvFloatToPyObjAttr(atom, "vdw", ai->vdw); if (ai->elec_radius) PConvFloatToPyObjAttr(atom, "elec_radius", ai->elec_radius); if (ai->partialCharge) PConvFloatToPyObjAttr(atom, "partial_charge", ai->partialCharge); if (ai->formalCharge) PConvIntToPyObjAttr(atom, "formal_charge", ai->formalCharge); // TODO customType=0 from most files if(ai->customType != -9999) PConvIntToPyObjAttr(atom, "numeric_type", ai->customType); if (ai->textType) PConvStringToPyObjAttr(atom, "text_type", LexStr(G, ai->textType)); if (ai->custom) PConvStringToPyObjAttr(atom, "custom", LexStr(G, ai->custom)); PConvIntToPyObjAttr(atom, "hetatm", ai->hetatm); PConvIntToPyObjAttr(atom, "flags", ai->flags); PConvIntToPyObjAttr(atom, "id", ai->id); /* not necc. unique */ PConvIntToPyObjAttr(atom, "index", index + 1); /* fragile */ } if(PyErr_Occurred()) PyErr_Print(); return (atom); #endif } /*========================================================================*/ void CoordSet::invalidateRep(int type, int level) { CoordSet * I = this; int a; if(level >= cRepInvVisib) { if (I->Obj) I->Obj->RepVisCacheValid = false; } /* graphical representations need redrawing */ if(level == cRepInvVisib) { /* cartoon_side_chain_helper */ if(SettingGet_b(I->State.G, I->Setting, I->Obj->Obj.Setting, cSetting_cartoon_side_chain_helper)) { if((type == cRepCyl) || (type == cRepLine) || (type == cRepSphere)) invalidateRep(cRepCartoon, cRepInvVisib2); else if(type == cRepCartoon) { invalidateRep(cRepLine, cRepInvVisib2); invalidateRep(cRepCyl, cRepInvVisib2); invalidateRep(cRepSphere, cRepInvVisib2); } } /* ribbon_side_chain_helper */ if(SettingGet_b(I->State.G, I->Setting, I->Obj->Obj.Setting, cSetting_ribbon_side_chain_helper)) { if((type == cRepCyl) || (type == cRepLine) || (type == cRepSphere)) invalidateRep(cRepRibbon, cRepInvVisib2); else if(type == cRepRibbon) { invalidateRep(cRepLine, cRepInvVisib2); invalidateRep(cRepCyl, cRepInvVisib2); invalidateRep(cRepSphere, cRepInvVisib2); } } /* line_stick helper */ if(SettingGet_b(I->State.G, I->Setting, I->Obj->Obj.Setting, cSetting_line_stick_helper)) { if(type == cRepCyl) invalidateRep(cRepLine, cRepInvVisib2); else if(type == cRepLine) { invalidateRep(cRepCyl, cRepInvVisib2); } } } if(I->Spheroid) if(I->NSpheroid != I->NAtIndex * I->SpheroidSphereSize) { FreeP(I->Spheroid); FreeP(I->SpheroidNormal); } /* invalidate basd on one representation, 'type' */ for (RepIterator iter(I->State.G, type); iter.next(); ){ int eff_level = level; a = iter.rep; if(level == cRepInvPick) { switch (a) { case cRepSurface: case cRepMesh: case cRepDot: /* skip the expensive to recompute, non-pickable representations */ break; default: /* default behavior is to blow away the representation */ eff_level = cRepInvRep; break; } } if(eff_level >= cRepInvVisib) /* make active if visibility has changed */ I->Active[a] = true; if(I->Rep[a]) { if(I->Rep[a]->fInvalidate && (eff_level < cRepInvPurge)) I->Rep[a]->fInvalidate(I->Rep[a], I, eff_level); else if(eff_level >= cRepInvExtColor) { I->Rep[a]->fFree(I->Rep[a]); I->Rep[a] = NULL; } } } if(level >= cRepInvCoord) { /* if coordinates change, then this map becomes invalid */ MapFree(I->Coord2Idx); I->Coord2Idx = NULL; ExecutiveInvalidateSelectionIndicatorsCGO(I->State.G); SceneInvalidatePicking(I->State.G); /* invalidate distances */ } #ifndef NO_MMLIBS if (level >= cRepInvProp) { if (validMMStereo == MMPYMOLX_PROP_STATE_AUTO) validMMStereo = MMPYMOLX_PROP_STATE_NULL; if (validTextType == MMPYMOLX_PROP_STATE_AUTO) validTextType = MMPYMOLX_PROP_STATE_NULL; } #endif SceneChanged(I->State.G); } /*========================================================================*/ #define RepUpdateMacro(I,rep,new_fn,state) {\ if(I->Active[rep]&&(!G->Interrupt)) {\ if(!I->Rep[rep]) {\ I->Rep[rep]=new_fn(I,state);\ if(I->Rep[rep]){ \ I->Rep[rep]->fNew=(struct Rep *(*)(struct CoordSet *,int state))new_fn;\ SceneInvalidatePicking(G);\ } else { \ I->Active[rep] = false; \ } \ } else {\ if(I->Rep[rep]->fUpdate)\ I->Rep[rep] = I->Rep[rep]->fUpdate(I->Rep[rep],I,state,rep);\ }\ }\ OrthoBusyFast(I->State.G,rep,cRepCnt);\ } /*========================================================================*/ void CoordSet::update(int state) { CoordSet * I = this; int a; PyMOLGlobals *G = I->Obj->Obj.G; PRINTFB(G, FB_CoordSet, FB_Blather) " CoordSetUpdate-Entered: object %s state %d cset %p\n", I->Obj->Obj.Name, state, (void *) I ENDFB(G); OrthoBusyFast(G, 0, cRepCnt); RepUpdateMacro(I, cRepLine, RepWireBondNew, state); RepUpdateMacro(I, cRepCyl, RepCylBondNew, state); RepUpdateMacro(I, cRepDot, RepDotNew, state); RepUpdateMacro(I, cRepMesh, RepMeshNew, state); RepUpdateMacro(I, cRepSphere, RepSphereNew, state); RepUpdateMacro(I, cRepRibbon, RepRibbonNew, state); RepUpdateMacro(I, cRepCartoon, RepCartoonNew, state); RepUpdateMacro(I, cRepSurface, RepSurfaceNew, state); RepUpdateMacro(I, cRepLabel, RepLabelNew, state); RepUpdateMacro(I, cRepNonbonded, RepNonbondedNew, state); RepUpdateMacro(I, cRepNonbondedSphere, RepNonbondedSphereNew, state); RepUpdateMacro(I, cRepEllipsoid, RepEllipsoidNew, state); for(a = 0; a < cRepCnt; a++) if(!I->Rep[a]) I->Active[a] = false; SceneInvalidate(G); OrthoBusyFast(G, 1, 1); if(Feedback(G, FB_CoordSet, FB_Blather)) { printf(" CoordSetUpdate-Leaving: object %s state %d cset %p\n", I->Obj->Obj.Name, state, (void *) I); } } /*========================================================================*/ void CoordSetUpdateCoord2IdxMap(CoordSet * I, float cutoff) { if(cutoff < R_SMALL4) cutoff = R_SMALL4; if(I->NIndex > 10) { if(I->Coord2Idx) { if((I->Coord2IdxDiv < cutoff) || (((cutoff - I->Coord2IdxReq) / I->Coord2IdxReq) < -0.5F)) { MapFree(I->Coord2Idx); I->Coord2Idx = NULL; } } if(I->NIndex && (!I->Coord2Idx)) { /* NOTE: map based on stored coords */ I->Coord2IdxReq = cutoff; I->Coord2IdxDiv = cutoff * 1.25F; I->Coord2Idx = MapNew(I->State.G, I->Coord2IdxDiv, I->Coord, I->NIndex, NULL); if(I->Coord2IdxDiv < I->Coord2Idx->Div) I->Coord2IdxDiv = I->Coord2Idx->Div; } } } /* * RepToTransparencySetting: maps rep to transparency setting */ static int RepToTransparencySetting(const int rep_id){ switch(rep_id){ // based on the rep, // transparency is set with different settings case cRepCyl: return cSetting_stick_transparency; case cRepSurface: return cSetting_transparency; case cRepSphere: return cSetting_sphere_transparency; case cRepEllipsoid: return cSetting_ellipsoid_transparency; case cRepCartoon: return cSetting_cartoon_transparency; case cRepRibbon: return cSetting_ribbon_transparency; } return 0; } /*========================================================================*/ void CoordSet::render(RenderInfo * info) { CoordSet * I = this; PyMOLGlobals *G = I->State.G; PRINTFD(G, FB_CoordSet) " CoordSetRender: entered (%p).\n", (void *) I ENDFD; if(!(info->ray || info->pick) && (SettingGet_i(G, I->Setting, I->Obj->Obj.Setting, cSetting_defer_builds_mode) == 5)) { if(!info->pass) { ObjectUseColor((CObject *) I->Obj); if(I->Active[cRepLine]) RepWireBondRenderImmediate(I, info); if(I->Active[cRepNonbonded]) RepNonbondedRenderImmediate(I, info); if(I->Active[cRepSphere]) RepSphereRenderImmediate(I, info); if(I->Active[cRepCyl]) RepCylBondRenderImmediate(I, info); if(I->Active[cRepRibbon]) RepRibbonRenderImmediate(I, info); } } else { int pass = info->pass; CRay *ray = info->ray; auto pick = info->pick; int a, aa, abit, aastart = 0, aaend = cRepCnt; ::Rep *r; int sculpt_vdw_vis_mode = SettingGet_i(G, I->Setting, I->Obj->Obj.Setting, cSetting_sculpt_vdw_vis_mode); if((!pass) && sculpt_vdw_vis_mode && I->SculptCGO && (I->Obj->Obj.visRep & cRepCGOBit)) { if(ray) { int ok = CGORenderRay(I->SculptCGO, ray, info, ColorGet(G, I->Obj->Obj.Color), NULL, I->Setting, I->Obj->Obj.Setting); if (!ok){ CGOFree(I->SculptCGO); CGOFree(I->SculptShaderCGO); } } else if(G->HaveGUI && G->ValidContext) { if(!pick) { int use_shader = SettingGetGlobal_b(G, cSetting_use_shaders); if (use_shader){ if (!I->SculptShaderCGO){ CGO *convertcgo = NULL; convertcgo = CGOCombineBeginEnd(I->SculptCGO, 0); if (convertcgo){ I->SculptShaderCGO = CGOOptimizeToVBONotIndexed(convertcgo, 0); I->SculptShaderCGO->use_shader = true; CGOFree(convertcgo); } } } else { CGOFree(I->SculptShaderCGO); } if (I->SculptShaderCGO){ CGORenderGL(I->SculptShaderCGO, NULL, I->Setting, I->Obj->Obj.Setting, info, NULL); } else { CGORenderGL(I->SculptCGO, NULL, I->Setting, I->Obj->Obj.Setting, info, NULL); } } } } if (pick){ int pick_labels = SettingGet_i(G, I->Setting, I->Obj->Obj.Setting, cSetting_pick_labels); if (pick_labels == 2){ // only pick labels aastart = cRepLabel; aaend = aastart + 1; } } for(aa = aastart; aa < aaend; aa++) { if(aa == cRepSurface) { /* reorder */ a = cRepCell; } else if(aa == cRepCell) { a = cRepSurface; } else { a = aa; } abit = (1 << a); if(I->Active[a] && I->Rep[a]) { r = I->Rep[a]; if(!ray) { ObjectUseColor((CObject *) I->Obj); } else { if(I->Obj) ray->wobble( SettingGet_i(G, I->Setting, I->Obj->Obj.Setting, cSetting_ray_texture), SettingGet_3fv(G, I->Setting, I->Obj->Obj.Setting, cSetting_ray_texture_settings)); else ray->wobble( SettingGet_i(G, I->Setting, NULL, cSetting_ray_texture), SettingGet_3fv(G, I->Setting, NULL, cSetting_ray_texture_settings)); ray->color3fv(ColorGet(G, I->Obj->Obj.Color)); } if(r->fRender) { /* do OpenGL rendering in three passes */ if(ray || pick) { /* here we need to iterate through and apply coordinate set matrices */ r->fRender(r, info); } else { bool t_mode_3 = SettingGetGlobal_i(G, cSetting_transparency_mode) == 3; bool render_both = t_mode_3; // render both opaque (1) and transparent (-1) pass if t_mode_3 /* here we need to iterate through and apply coordinate set matrices */ switch (a) { case cRepVolume: { int t_mode = SettingGetGlobal_i(G, cSetting_transparency_mode); if (t_mode == 3 && pass == -1){ r->fRender(r, info); } } break; case cRepLabel: { int t_mode_3 = SettingGetGlobal_i(G, cSetting_transparency_mode) == 3; if (pass == -1 || (t_mode_3 && pass == 1)) r->fRender(r, info); } break; case cRepDot: case cRepCGO: case cRepCallback: if(pass == 1) r->fRender(r, info); break; case cRepLine: case cRepMesh: case cRepDash: case cRepCell: case cRepExtent: if(!pass) r->fRender(r, info); break; case cRepNonbonded: case cRepRibbon: render_both = false; // cartoon and nonbonded do not have atom-level transparency case cRepNonbondedSphere: case cRepSurface: case cRepEllipsoid: case cRepCyl: case cRepCartoon: case cRepSphere: { if (render_both){ // for transparency_mode 3, render both opaque and transparent pass if (pass != 0){ r->fRender(r, info); } } else { bool checkAlphaCGO = abit & (cRepSurfaceBit); int check_setting = RepToTransparencySetting(a); bool cont = true; if (checkAlphaCGO){ if(info->alpha_cgo) { if(pass == 1){ r->fRender(r, info); } cont = false; } } if (cont){ if(check_setting && SettingGet_f(G, r->cs->Setting, r->obj->Setting, check_setting) > 0.0001) { /* if object has transparency, only render in -1 pass */ if(pass == -1) r->fRender(r, info); } else if(pass == 1){ r->fRender(r, info); } } } } break; } } } /* if(ray) ray->fWobble(ray,0,NULL); */ } } } PRINTFD(G, FB_CoordSet) " CoordSetRender: leaving...\n" ENDFD; } /*========================================================================*/ CoordSet *CoordSetNew(PyMOLGlobals * G) { OOCalloc(G, CoordSet); /* NULL-initializes all fields */ ObjectStateInit(G, &I->State); I->State.G = G; I->PeriodicBoxType = cCSet_NoPeriodicity; I->SpheroidSphereSize = I->State.G->Sphere->Sphere[1]->nDot; /* does this make any sense? */ return (I); } /*========================================================================*/ CoordSet *CoordSetCopy(const CoordSet * cs) { if (!cs) return NULL; PyMOLGlobals * G = const_cast<PyMOLGlobals*>(cs->State.G); /* OOAlloc declares and defines, I: * I = ... */ OOCalloc(G, CoordSet); /* shallow copy */ (*I) = (*cs); /* NOTE: must deep-copy all pointers in this struct */ /* deep copy state struct */ ObjectStateCopy(&I->State, &cs->State); /* deep copy & return ptr to new symmetry */ I->Symmetry = SymmetryCopy(cs->Symmetry); if(I->PeriodicBox) I->PeriodicBox = CrystalCopy(I->PeriodicBox); // copy VLAs I->Coord = VLACopy2(cs->Coord); I->LabPos = VLACopy2(cs->LabPos); I->RefPos = VLACopy2(cs->RefPos); I->AtmToIdx = VLACopy2(cs->AtmToIdx); I->IdxToAtm = VLACopy2(cs->IdxToAtm); UtilZeroMem(I->Rep, sizeof(::Rep *) * cRepCnt); #ifdef _PYMOL_IP_PROPERTIES #endif I->Setting = NULL; I->atom_state_setting_id = NULL; I->has_atom_state_settings = NULL; I->SculptCGO = NULL; I->SculptShaderCGO = NULL; I->TmpLinkBond = NULL; I->TmpBond = NULL; I->Spheroid = NULL; I->SpheroidNormal = NULL; I->Coord2Idx = NULL; return (I); } /*========================================================================*/ int CoordSet::extendIndices(int nAtom) { CoordSet * I = this; int a, b; ObjectMolecule *obj = I->Obj; int ok = true; if(obj->DiscreteFlag) { ok = obj->setNDiscrete(nAtom); if(I->AtmToIdx) { /* convert to discrete if necessary */ VLAFree(I->AtmToIdx); I->AtmToIdx = NULL; if (ok){ for(a = 0; a < I->NIndex; a++) { b = I->IdxToAtm[a]; obj->DiscreteAtmToIdx[b] = a; obj->DiscreteCSet[b] = I; } } } } if(ok && I->NAtIndex < nAtom) { if(I->AtmToIdx) { VLASize(I->AtmToIdx, int, nAtom); CHECKOK(ok, I->AtmToIdx); if(ok && nAtom) { for(a = I->NAtIndex; a < nAtom; a++) I->AtmToIdx[a] = -1; } I->NAtIndex = nAtom; } else if(!obj->DiscreteFlag) { I->AtmToIdx = VLACalloc(int, nAtom); CHECKOK(ok, I->AtmToIdx); if (ok){ for(a = 0; a < nAtom; a++) I->AtmToIdx[a] = -1; I->NAtIndex = nAtom; } } } return ok; } /*========================================================================*/ void CoordSet::appendIndices(int offset) { CoordSet * I = this; int a, b; ObjectMolecule *obj = I->Obj; I->IdxToAtm = VLACalloc(int, I->NIndex); if(I->NIndex) { ErrChkPtr(I->State.G, I->IdxToAtm); for(a = 0; a < I->NIndex; a++) I->IdxToAtm[a] = a + offset; } if(obj->DiscreteFlag) { VLACheck(obj->DiscreteAtmToIdx, int, I->NIndex + offset); VLACheck(obj->DiscreteCSet, CoordSet *, I->NIndex + offset); for(a = 0; a < I->NIndex; a++) { b = a + offset; obj->DiscreteAtmToIdx[b] = a; obj->DiscreteCSet[b] = I; } } else { I->AtmToIdx = VLACalloc(int, I->NIndex + offset); if(I->NIndex + offset) { ErrChkPtr(I->State.G, I->AtmToIdx); for(a = 0; a < offset; a++) I->AtmToIdx[a] = -1; for(a = 0; a < I->NIndex; a++) I->AtmToIdx[a + offset] = a; } } I->NAtIndex = I->NIndex + offset; } /*========================================================================*/ void CoordSet::enumIndices() { CoordSet * I = this; /* set up for simple case where 1 = 1, etc. */ int a; I->AtmToIdx = VLACalloc(int, I->NIndex); I->IdxToAtm = VLACalloc(int, I->NIndex); if(I->NIndex) { ErrChkPtr(I->State.G, I->AtmToIdx); ErrChkPtr(I->State.G, I->IdxToAtm); for(a = 0; a < I->NIndex; a++) { I->AtmToIdx[a] = a; I->IdxToAtm[a] = a; } } I->NAtIndex = I->NIndex; } /*========================================================================*/ void CoordSet::fFree() { CoordSet * I = this; int a; ObjectMolecule *obj; if(I) { #ifdef _PYMOL_IP_PROPERTIES #endif if (I->has_atom_state_settings){ for(a = 0; a < I->NIndex; a++){ if (I->has_atom_state_settings[a]){ SettingUniqueDetachChain(I->State.G, I->atom_state_setting_id[a]); } } VLAFreeP(I->has_atom_state_settings); VLAFreeP(I->atom_state_setting_id); } for(a = 0; a < cRepCnt; a++) if(I->Rep[a]) I->Rep[a]->fFree(I->Rep[a]); obj = I->Obj; if(obj) if(obj->DiscreteFlag) /* remove references to the atoms in discrete objects */ for(a = 0; a < I->NIndex; a++) { obj->DiscreteAtmToIdx[I->IdxToAtm[a]] = -1; obj->DiscreteCSet[I->IdxToAtm[a]] = NULL; } VLAFreeP(I->AtmToIdx); VLAFreeP(I->IdxToAtm); MapFree(I->Coord2Idx); VLAFreeP(I->Coord); VLAFreeP(I->TmpBond); if(I->Symmetry) SymmetryFree(I->Symmetry); if(I->PeriodicBox) CrystalFree(I->PeriodicBox); FreeP(I->Spheroid); FreeP(I->SpheroidNormal); SettingFreeP(I->Setting); ObjectStatePurge(&I->State); CGOFree(I->SculptCGO); VLAFreeP(I->LabPos); VLAFreeP(I->RefPos); /* free and make null */ OOFreeP(I); } } void LabPosTypeCopy(const LabPosType * src, LabPosType * dst){ dst->mode = src->mode; copy3f(src->pos, dst->pos); copy3f(src->offset, dst->offset); } void RefPosTypeCopy(const RefPosType * src, RefPosType * dst){ copy3f(src->coord, dst->coord); dst->specified = src->specified; } #ifndef _PYMOL_NOPY int CoordSetSetSettingFromPyObject(PyMOLGlobals * G, CoordSet *cs, int at, int setting_id, PyObject *val){ if (val == Py_None) val = NULL; if (!val) { if (!cs->has_atom_state_settings || !cs->has_atom_state_settings[at]) return true; } CoordSetCheckUniqueID(G, cs, at); cs->has_atom_state_settings[at] = true; return SettingUniqueSetPyObject(G, cs->atom_state_setting_id[at], setting_id, val); } #endif int CoordSetCheckSetting(PyMOLGlobals * G, CoordSet *cs, int at, int setting_id){ if(!cs->has_atom_state_settings || !cs->has_atom_state_settings[at]) { return 0; } else { if(!SettingUniqueCheck(G, cs->atom_state_setting_id[at], setting_id)) { return 0; } else { return 1; } } } PyObject *SettingGetIfDefinedPyObject(PyMOLGlobals * G, CoordSet *cs, int at, int setting_id){ if(cs->has_atom_state_settings && cs->has_atom_state_settings[at]){ return SettingUniqueGetPyObject(G, cs->atom_state_setting_id[at], setting_id); } return NULL; } int CoordSetCheckUniqueID(PyMOLGlobals * G, CoordSet *I, int at){ if (!I->atom_state_setting_id){ I->atom_state_setting_id = VLACalloc(int, I->NIndex); } if (!I->has_atom_state_settings){ I->has_atom_state_settings = VLACalloc(char, I->NIndex); } if (!I->atom_state_setting_id[at]){ I->atom_state_setting_id[at] = AtomInfoGetNewUniqueID(G); } return I->atom_state_setting_id[at]; } template <typename V> void AtomStateGetSetting(ATOMSTATEGETSETTINGARGS, V * out) { if (cs->has_atom_state_settings && cs->has_atom_state_settings[idx] && SettingUniqueGetIfDefined(G, cs->atom_state_setting_id[idx], setting_id, out)) return; if (AtomSettingGetIfDefined(G, ai, setting_id, out)) return; *out = SettingGet<V>(G, cs->Setting, obj->Obj.Setting, setting_id); } template void AtomStateGetSetting(ATOMSTATEGETSETTINGARGS, int * out); template void AtomStateGetSetting(ATOMSTATEGETSETTINGARGS, float * out); template void AtomStateGetSetting(ATOMSTATEGETSETTINGARGS, const float ** out);