cartoon_trace_atoms for sheets, fast connect_mode=4

This commit is contained in:
Thomas Holder
2015-08-31 02:08:17 +00:00
parent ff758092c1
commit 680f313001
23 changed files with 2785 additions and 1375 deletions

View File

@@ -2,6 +2,15 @@
CHANGE LOG
=========================================================================
2015-08-30 Thomas Holder <thomas.holder@schrodinger.com>
* fix cartoon_trace_atoms for beta-sheets
* fast connect_mode=4: Add $PYMOL_DATA/chem_comp_bond-top100.cif
which is a subset of the components.cif dictionary and contains
only bond records for the 100 most frequent monomers in the PDB.
Download other monomers on-demand from PDBeChem.
2015-08-12 Thomas Holder <thomas.holder@schrodinger.com>
* cif_keepinmemory, pymol.querying.cif_get_array (experimental)

File diff suppressed because it is too large Load Diff

View File

@@ -1,349 +0,0 @@
// cylinder imposter fragment shader
uniform bool lighting_enabled;
uniform float fog_enabled;
uniform bool bg_gradient;
uniform vec3 fog_color_top;
uniform vec3 fog_color_bottom;
uniform float inv_height;
uniform float ortho;
uniform float flat_caps;
uniform bool filter_front_facing;
uniform bool two_sided_lighting_enabled;
uniform int light_count;
uniform float shininess;
uniform float shininess_0;
uniform int spec_count;
uniform float spec_value;
uniform float spec_value_0;
uniform float half_bond;
uniform int stereo_flag;
uniform mat3 matR;
uniform mat3 matL;
uniform float gamma;
//varying vec3 point; // surface point
//varying vec3 axis; // cylinder axis
//varying vec3 base; // cylinder base
//varying vec3 end; // cylinder end
//varying vec3 U; // cylinder base plane coordinates
//varying vec3 V;
//varying float radius; // radius
//varying float cap; // should we draw the endcap
//varying float inv_sqr_height;
varying vec4 packed_data_0 ;
varying vec4 packed_data_1 ;
varying vec4 packed_data_2 ;
varying vec4 packed_data_3 ;
varying vec4 packed_data_4 ;
varying vec4 packed_data_5 ;
// point -> surface_point b/c preprocessor replaces _point
#define surface_point ( packed_data_0.xyz )
#define axis ( packed_data_1.xyz )
#define base ( packed_data_2.xyz )
// end -> end_cyl
#define end_cyl packed_data_3.xyz
#define U ( packed_data_4.xyz )
#define V ( packed_data_5.xyz )
#define radius ( packed_data_3.w )
#define cap ( packed_data_4.w )
#define inv_sqr_height ( packed_data_5.w )
varying vec4 color1;
varying vec4 color2;
vec4 ComputeColorForLight(vec3 N, vec3 L, vec3 H, vec4 ambient, vec4 diffuse, float spec, float shine, vec4 color){
float NdotL, NdotH;
vec4 ret_val = vec4(0.);
ret_val += ambient * color;
NdotL = dot(N, L);
if (NdotL > 0.0) {
ret_val += diffuse * NdotL * color;
NdotH = max(dot(N, H), 0.0);
ret_val += spec * pow(NdotH, shine);
}
return ret_val;
}
void main(void)
{
// cull back face - otherwise we are drawing all pixels twice
// this change gives roughly 2x speedup
// if (filter_front_facing && !gl_FrontFacing)
// discard;
vec3 ray_target = surface_point;
vec3 ray_origin = vec3(0.0);
vec3 ray_direction = mix(normalize(ray_origin - ray_target), vec3(0.0, 0.0, 1.0), ortho);
// basis is local system of coordinates for the cylinder
mat3 basis = mat3(U, V, axis);
vec3 diff = ray_target - 0.5 * (base + end_cyl);
vec3 P = diff * basis;
// angle (cos) between cylinder cylinder_axis and ray direction
float dz = dot(axis, ray_direction);
float radius2 = radius*radius;
// calculate distance to the cylinder from ray origin
vec3 D = vec3(dot(U, ray_direction),
dot(V, ray_direction),
dz);
float a0 = P.x*P.x + P.y*P.y - radius2;
float a1 = P.x*D.x + P.y*D.y;
float a2 = D.x*D.x + D.y*D.y;
// calculate a dicriminant of the above quadratic equation
float d = a1*a1 - a0*a2;
if (d < 0.0)
// outside of the cylinder
discard;
float dist = (-a1 + sqrt(d))/a2;
// point of intersection on cylinder surface
vec3 new_point = ray_target + dist * ray_direction;
vec3 tmp_point = new_point - base;
vec3 normal = normalize(tmp_point - axis * dot(tmp_point, axis));
float ratio = dot(new_point-base, vec3(end_cyl-base)) * inv_sqr_height;
ray_origin = mix(ray_origin, surface_point, ortho);
/* cap : 4 bits : 1st - frontcap
2nd - endcap
3rd - frontcap round
4th - endcap round
*/
int icap = int(cap);
vec4 color;
if (icap > 15){
float dp = clamp(-half_bond*new_point.z*inv_height, 0., .5);
color = mix(color1, color2, smoothstep(.5 - dp, .5 + dp, ratio));
icap = icap - 16;
} else {
color = mix(color1, color2, ratio);
}
float frontcap = 0.0, frontcapround = 0.0;
float endcap = 0.0, endcapround = 0.0;
if (icap == 1 || icap == 3 || icap == 5 || icap == 7 ||
icap == 9 || icap == 11 || icap == 13 || icap == 15)
frontcap = 1.0;
if (icap == 2 || icap == 3 || icap == 6 || icap == 7 ||
icap == 10 || icap == 11 || icap == 14 || icap == 15)
endcap = 1.0;
if (frontcap > 0.5 && flat_caps < 0.5 &&
((icap > 3 && icap < 8) ||
icap > 11))
frontcapround = 1.0;
if (endcap > 0.5 && flat_caps < 0.5 && icap > 7)
endcapround = 1.0;
// test front cap
float cap_test = dot((new_point - base), axis);
// to calculate caps, simply check the angle between
// the point of intersection - cylinder end vector
// and a cap plane normal (which is the cylinder cylinder_axis)
// if the angle < 0, the point is outside of cylinder
// test front cap
// flat
if (frontcapround < 0.5 && cap_test < 0.0) {
// ray-plane intersection
color = color1;
float dNV = dot(-axis, ray_direction);
if (dNV < 0.0) discard;
float near = dot(-axis, (base)) / dNV;
new_point = ray_direction * near + ray_origin;
// within the cap radius?
if (dot(new_point - base, new_point-base) > radius2) discard;
normal = -axis;
}
// round
if (frontcapround > 0.5 && cap_test < 0.0) {
if ( frontcap < 1.0)
discard;
color = color1;
vec3 sphere_direction = mix(base, ray_origin - base, ortho);
float b = dot(sphere_direction, ray_direction);
float pos = b*b + radius2 -dot(sphere_direction, sphere_direction);
if ( pos < 0.0)
discard;
float near = mix(b + sqrt(pos), sqrt(pos) - b, ortho);
new_point = near * ray_direction + ray_origin;
normal = normalize( new_point - base );
}
// test end cap
cap_test = dot((new_point - end_cyl), axis);
// flat
if (endcapround < 0.5 && cap_test > 0.0) {
// ray-plane intersection
color = color1;
float dNV = dot(axis, ray_direction);
if (dNV < 0.0) discard;
float near = dot(axis, end_cyl) / dNV;
new_point = ray_direction * near + ray_origin;
// within the cap radius?
if (dot(new_point - end_cyl, new_point-base) > radius2) discard;
normal = axis;
}
// round
if (endcapround > 0.5 && cap_test > 0.0) {
if ( endcap < 1.0)
discard;
color = color2;
vec3 sphere_direction = mix(end_cyl, ray_origin - end_cyl, ortho);
float b = dot(sphere_direction, ray_direction);
float pos = b*b + radius2 -dot(sphere_direction, sphere_direction);
if ( pos < 0.0)
discard;
float near = mix(b + sqrt(pos), sqrt(pos) - b, ortho);
new_point = near * ray_direction + ray_origin;
normal = normalize( new_point - end_cyl );
}
vec2 clipZW = new_point.z * gl_ProjectionMatrix[2].zw +
gl_ProjectionMatrix[3].zw;
float depth = 0.5 + 0.5 * clipZW.x / clipZW.y;
// this is a workaround necessary for Mac
// otherwise the modified fragment won't clip properly
if (depth <= 0.0)
discard;
if (depth >= 1.0)
discard;
gl_FragDepth = depth;
vec4 final_color;
int i;
float NdotL, NdotH;
final_color = (gl_LightModel.ambient) * color;
if (light_count>0){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[0].position)),
normalize(vec3(gl_LightSource[0].halfVector.xyz)),
gl_LightSource[0].ambient,
gl_LightSource[0].diffuse,
spec_value_0, shininess_0, color);
if (light_count>1){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[1].position)),
normalize(vec3(gl_LightSource[1].halfVector.xyz)),
gl_LightSource[1].ambient,
gl_LightSource[1].diffuse,
spec_value, shininess, color);
if (light_count>2){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[2].position)),
normalize(vec3(gl_LightSource[2].halfVector.xyz)),
gl_LightSource[2].ambient,
gl_LightSource[2].diffuse,
spec_value, shininess, color);
if (light_count>3){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[3].position)),
normalize(vec3(gl_LightSource[3].halfVector.xyz)),
gl_LightSource[3].ambient,
gl_LightSource[3].diffuse,
spec_value, shininess, color);
if (light_count>4){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[4].position)),
normalize(vec3(gl_LightSource[4].halfVector.xyz)),
gl_LightSource[4].ambient,
gl_LightSource[4].diffuse,
spec_value, shininess, color);
if (light_count>5){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[5].position)),
normalize(vec3(gl_LightSource[5].halfVector.xyz)),
gl_LightSource[5].ambient,
gl_LightSource[5].diffuse,
spec_value, shininess, color);
if (light_count>6){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[6].position)),
normalize(vec3(gl_LightSource[6].halfVector.xyz)),
gl_LightSource[6].ambient,
gl_LightSource[6].diffuse,
spec_value, shininess, color);
if (light_count>7){
final_color += ComputeColorForLight(normal, normalize(vec3(gl_LightSource[7].position)),
normalize(vec3(gl_LightSource[7].halfVector.xyz)),
gl_LightSource[7].ambient,
gl_LightSource[7].diffuse,
spec_value, shininess, color);
}}}}}}}}
/*
for (i=0; i<light_count; i++){
vec3 L = normalize(gl_LightSource[i].position.xyz);
vec3 H = normalize(gl_LightSource[i].halfVector.xyz);
float spec = 0., shine = 0.;
if (i==0){
spec = spec_value_0;
shine = shininess_0;
} else if (spec_count >= i){
spec = spec_value;
shine = shininess;
}
final_color += gl_LightSource[i].ambient * color;
NdotL = dot(normal, L);
if (NdotL > 0.0) {
final_color += gl_LightSource[i].diffuse * NdotL * color;
NdotH = max(dot(normal, H), 0.0);
final_color += spec * pow(NdotH, shine);
}
// I don't think we need two sided lighting for cylinders since we do not
draw the insides of the cylinders
if (two_sided_lighting_enabled){
NdotL = dot(-normal, L);
if (NdotL > 0.0) {
final_color += gl_LightSource[i].diffuse * NdotL * color;
NdotH = max(dot(-normal, H), 0.0);
final_color += spec * pow(NdotH, shine);
}
}
//
}
*/
float fog = clamp((gl_Fog.end + new_point.z) * gl_Fog.scale, 0.0, 1.0);
fog = mix(1.0, fog, fog_enabled);
vec3 fog_color;
if (bg_gradient){
fog_color = mix(fog_color_bottom, fog_color_top, gl_FragCoord.y * inv_height);
} else {
fog_color = fog_color_top;
}
final_color.rgb = mix(fog_color, final_color.rgb, fog);
vec4 f = vec4(final_color.rgb, color.a);
if(stereo_flag==-1)
gl_FragColor = vec4(matL * pow(f.rgb,vec3(gamma,gamma,gamma)), f.a);
else if (stereo_flag==0)
gl_FragColor = f;
else if (stereo_flag==1)
gl_FragColor = vec4(matR * pow(f.rgb, vec3(gamma,gamma,gamma)), f.a);
}

View File

@@ -7,7 +7,18 @@
#include <string>
#include <vector>
#include <string.h>
std::vector<std::string> strsplit(const std::string &s, char delim=0);
bool cstrlessnat(const char * a, const char * b);
bool strlessnat(const std::string& a, const std::string& b);
/*
* C string comparison class
*/
struct cstrless_t {
bool operator()(const char * a, const char * b) const {
return strcmp(a, b) < 0;
}
};

View File

@@ -53,6 +53,11 @@ typedef float aliased_float;
#define __inline__ __inline
#endif
#ifdef WIN32
#define PATH_SEP "\\"
#else
#define PATH_SEP "/"
#endif
/* commercial product */

View File

@@ -26,6 +26,11 @@ Z* -------------------------------------------------------------------
typedef int PyObject;
#undef _PYMOL_NUMPY
#else
// Python.h will redefine those, undef to avoid compiler warning
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include"Python.h"
#include<pythread.h>

View File

@@ -171,4 +171,13 @@ typedef struct _CObjectUpdateThreadInfo CObjectUpdateThreadInfo;
#define cObjectTypeGroupObjects 9
/* Note: public objects are ones that do not start with "_" */
// object and object-state level setting
template <typename V> void SettingSet(int index, V value, CObject * obj, int state=-1) {
if (obj->fGetSettingHandle) {
auto handle = obj->fGetSettingHandle(obj, state);
if (handle)
SettingSet(obj->G, handle, index, value);
}
}
#endif

View File

@@ -278,12 +278,6 @@ static int SettingUniqueEntry_IsSame(SettingUniqueEntry *entry, int setting_type
}
static void SettingUniqueEntry_Set(SettingUniqueEntry *entry, int setting_type, const void *value){
if (SettingInfo[entry->setting_id].type != setting_type){
printf("SettingUniqueEntry_Set-Warning: type mismatch %s(%d) %d != %d\n",
SettingInfo[entry->setting_id].name, entry->setting_id,
SettingInfo[entry->setting_id].type, setting_type);
}
switch (setting_type) {
case cSetting_boolean:
case cSetting_int:
@@ -1844,6 +1838,8 @@ int SettingSet_s(CSetting * I, int index, const char *value)
case cSetting_string:
I->info[index].set_s(value);
break;
case cSetting_color:
return SettingSet_color(I, index, value);
default:
PRINTFB(G, FB_Setting, FB_Errors)
"Setting-Error: type set mismatch (string) %d\n", index ENDFB(G);

View File

@@ -325,4 +325,29 @@ bool SettingLevelCheck(PyMOLGlobals * G, int index, unsigned char level);
bool CPyMOLInitSetting(OVLexicon * Lex, OVOneToOne * Setting);
extern "C" OVreturn_word get_setting_id(CPyMOL * I, const char *setting);
/*
* Overloaded setters for templatted programming
*/
inline void SettingSet(CSetting * s, int i, bool v) { SettingSet_b(s, i, v); }
inline void SettingSet(CSetting * s, int i, int v) { SettingSet_i(s, i, v); }
inline void SettingSet(CSetting * s, int i, long int v) { SettingSet_i(s, i, v); }
inline void SettingSet(CSetting * s, int i, float v) { SettingSet_f(s, i, v); }
inline void SettingSet(CSetting * s, int i, const char *v) { SettingSet_s(s, i, v); }
inline void SettingSet(CSetting * s, int i, const float *v) { SettingSet_3fv(s, i, v); }
inline void SettingUniqueSet(PyMOLGlobals * G, int uid, int i, bool v) { SettingUniqueSet_b(G, uid, i, v); }
inline void SettingUniqueSet(PyMOLGlobals * G, int uid, int i, int v) { SettingUniqueSet_i(G, uid, i, v); }
inline void SettingUniqueSet(PyMOLGlobals * G, int uid, int i, float v) { SettingUniqueSet_f(G, uid, i, v); }
template <typename V> void SettingSet(PyMOLGlobals * G, CSetting ** handle, int index, V value) {
SettingCheckHandle(G, handle);
SettingSet(*handle, index, value);
}
// global setting
template <typename V> void SettingSet(PyMOLGlobals * G, int index, V value) {
SettingSet(G->Setting, index, value);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -131,6 +131,7 @@ Z* -------------------------------------------------------------------
#define cAN_Ca 20
#define cAN_Ti 22
#define cAN_V 23
#define cAN_Cr 24
#define cAN_Mn 25
@@ -148,6 +149,7 @@ Z* -------------------------------------------------------------------
#define cAN_Rb 37
#define cAN_Sr 38
#define cAN_Y 39
#define cAN_Pd 46
#define cAN_Ag 47
@@ -402,4 +404,20 @@ bool SideChainHelperFilterBond(const int *marked,
const AtomInfoType *ati2,
int b1, int b2, int na_mode, int *c1, int *c2);
void atomicnumber2elem(char * dst, int protons);
// atom-level setting
template <typename V> void SettingSet(PyMOLGlobals * G, int index, V value, AtomInfoType * ai) {
AtomInfoCheckUniqueID(G, ai);
ai->has_setting = true;
SettingUniqueSet(G, ai->unique_id, index, value);
}
// bond-level setting
template <typename V> void SettingSet(PyMOLGlobals * G, int index, V value, BondType * b) {
AtomInfoCheckUniqueBondID(G, b);
b->has_setting = true;
SettingUniqueSet(G, b->unique_id, index, value);
}
#endif

View File

@@ -15,6 +15,9 @@
#include <map>
#include <algorithm>
#include "os_std.h"
#include "PyMOLGlobals.h"
#if 1
// (2)
// Optimized implementation, tuned on speed and memory usage.
@@ -61,17 +64,18 @@ class bond_dict_t : public std::map<std::int_fast64_t, res_bond_dict_t> {
return i;
}
std::set<key_type> unknown_resn;
public:
void set_unknown(const char * resn) {
unknown_resn.insert(make_key(resn));
}
void set(const char * resn, const char * name1, const char * name2, int order) {
(*this)[make_key(resn)].set(name1, name2, order);
}
const mapped_type * get(const char * resn) const {
auto it = find(make_key(resn));
if (it == end())
return NULL;
return &it->second;
}
const mapped_type * get(PyMOLGlobals *, const char * resn, bool try_download=true);
};
#else

View File

@@ -23,6 +23,7 @@
#include "AtomInfo.h"
#include "Base.h"
#include "Executive.h"
#include "P.h"
#include "Util.h"
#include "Scene.h"
#include "Rep.h"
@@ -233,8 +234,16 @@ static bool read_chem_comp_bond_dict(const cif_data * data, bond_dict_t &bond_di
if( !(arr_id_1 = data->get_arr("_chem_comp_bond.atom_id_1")) ||
!(arr_id_2 = data->get_arr("_chem_comp_bond.atom_id_2")) ||
!(arr_order = data->get_arr("_chem_comp_bond.value_order")) ||
!(arr_comp_id = data->get_arr("_chem_comp_bond.comp_id")))
!(arr_comp_id = data->get_arr("_chem_comp_bond.comp_id"))) {
if ((arr_comp_id = data->get_arr("_chem_comp_atom.comp_id"))) {
// atom(s) but no bonds (e.g. metals)
bond_dict.set_unknown(arr_comp_id->as_s());
return true;
}
return false;
}
const char *name1, *name2, *resn;
int order_value;
@@ -255,33 +264,25 @@ static bool read_chem_comp_bond_dict(const cif_data * data, bond_dict_t &bond_di
}
/*
* parse components.cif (or $COMPONENTS_CIF) into dictionary. The file is
* only parsed once and the dictionary is global (static). Return NULL
* if file not available.
* parse $PYMOL_DATA/chem_comp_bond-top100.cif (subset of components.cif) into
* a static (global) dictionary.
*/
static const bond_dict_t * get_global_components_bond_dict(PyMOLGlobals * G) {
static bond_dict_t * get_global_components_bond_dict(PyMOLGlobals * G) {
static bond_dict_t bond_dict;
if (bond_dict.empty()) {
const char *filename = getenv("COMPONENTS_CIF");
if (!filename || !filename[0])
filename = "components.cif";
const char * pymol_data = getenv("PYMOL_DATA");
if (!pymol_data || !pymol_data[0])
return NULL;
cif_file cif(filename);
std::string path(pymol_data);
path.append(PATH_SEP).append("chem_comp_bond-top100.cif");
cif_file cif(path.c_str());
for (m_str_cifdatap_t::iterator data_it = cif.datablocks.begin(),
data_it_end = cif.datablocks.end(); data_it != data_it_end; ++data_it) {
read_chem_comp_bond_dict(data_it->second, bond_dict);
}
if (bond_dict.empty()) {
PRINTFB(G, FB_ObjectMolecule, FB_Errors)
" Error: Please download 'components.cif' from http://www.wwpdb.org/data/ccd\n"
" and place it in the current directory or set the COMPONENTS_CIF environment"
" variable.\n"
ENDFB(G);
return NULL;
}
}
return &bond_dict;
@@ -292,7 +293,7 @@ static const bond_dict_t * get_global_components_bond_dict(PyMOLGlobals * G) {
* based on components.cif
*/
static void ConnectComponent(ObjectMolecule * I, int i_start, int i_end,
const bond_dict_t * bond_dict) {
bond_dict_t * bond_dict) {
if (i_end - i_start < 2)
return;
@@ -301,7 +302,7 @@ static void ConnectComponent(ObjectMolecule * I, int i_start, int i_end,
int order;
// get residue bond dictionary
auto res_dict = bond_dict->get(ai[i_start].resn);
auto res_dict = bond_dict->get(I->Obj.G, ai[i_start].resn);
if (res_dict == NULL)
return;
@@ -333,7 +334,7 @@ static void ConnectComponent(ObjectMolecule * I, int i_start, int i_end,
* connecting bonds (C->N, O3*->P)
*/
static int ObjectMoleculeConnectComponents(ObjectMolecule * I,
const bond_dict_t * bond_dict=NULL) {
bond_dict_t * bond_dict=NULL) {
PyMOLGlobals * G = I->Obj.G;
int i_start = 0, i_prev_c = 0, i_prev_o3 = 0;
@@ -710,10 +711,8 @@ static bool read_pdbx_coordinate_model(PyMOLGlobals * G, cif_data * data, Object
for (int i = 0, nrows = VLAGetSize(mol->AtomInfo); i < nrows; ++i) {
AtomInfoType * ai = mol->AtomInfo + i;
if (asyms.count(ai->segi)) {
AtomInfoCheckUniqueID(G, ai);
ai->has_setting = true;
SettingUniqueSet_i(G, ai->unique_id, cSetting_cartoon_trace_atoms, 1);
SettingUniqueSet_i(G, ai->unique_id, cSetting_ribbon_trace_atoms, 1);
SettingSet(G, cSetting_cartoon_trace_atoms, true, ai);
SettingSet(G, cSetting_ribbon_trace_atoms, true, ai);
}
}
@@ -1026,10 +1025,6 @@ static CoordSet ** read_atom_site(PyMOLGlobals * G, cif_data * data,
VLACheck(*atInfoPtr, AtomInfoType, atomCount);
ai = *atInfoPtr + atomCount;
if (discrete) {
ai->discrete_state = mod_num;
}
ai->rank = atomCount;
ai->alt[0] = arr_alt->as_s(i)[0];
@@ -1851,8 +1846,7 @@ static ObjectMolecule *ObjectMoleculeReadCifData(PyMOLGlobals * G, cif_data * da
// all_states for multi-model assembly
if (I->NCSet > 1) {
SettingCheckHandle(G, &I->Obj.Setting);
SettingSet_b(I->Obj.Setting, cSetting_all_states, 1);
SettingSet(cSetting_all_states, true, &I->Obj);
}
}
}
@@ -1923,4 +1917,60 @@ ObjectMolecule *ObjectMoleculeReadCifStr(PyMOLGlobals * G, ObjectMolecule * I,
return NULL;
}
/*
* Bond dictionary getter, with on-demand download of residue dictionaries
*/
const bond_dict_t::mapped_type * bond_dict_t::get(PyMOLGlobals * G, const char * resn, bool try_download) {
auto key = make_key(resn);
auto it = find(key);
if (it != end())
return &it->second;
if (unknown_resn.count(key))
return NULL;
#ifndef _PYMOL_NOPY
if (try_download) {
int blocked = PAutoBlock(G);
bool downloaded = false;
// call into Python
PyObject * pyfilename = PYOBJECT_CALLMETHOD(G->P_inst->cmd,
"download_chem_comp", "siO", resn,
!Feedback(G, FB_Executive, FB_Details),
G->P_inst->cmd);
if (pyfilename) {
const char * filename = PyString_AsString(pyfilename);
// update
if ((downloaded = (filename && filename[0]))) {
cif_file cif(filename);
for (auto it = cif.datablocks.begin(); it != cif.datablocks.end(); ++it)
read_chem_comp_bond_dict(it->second, *this);
}
Py_DECREF(pyfilename);
}
PAutoUnblock(G, blocked);
if (downloaded) {
// second attempt to look up, from eventually updated dictionary
return get(G, resn, false);
}
}
#endif
PRINTFB(G, FB_Executive, FB_Warnings)
" ExecutiveLoad-Warning: No _chem_comp_bond data for residue '%s'\n", resn
ENDFB(G);
// don't try downloading again
unknown_resn.insert(key);
return NULL;
}
// vi:sw=2:ts=2:expandtab

View File

@@ -169,4 +169,9 @@ void CoordSetUpdateThread(CCoordSetUpdateThreadInfo * T);
void LabPosTypeCopy(const LabPosType * src, LabPosType * dst);
void RefPosTypeCopy(const RefPosType * src, RefPosType * dst);
// object-state level setting
template <typename V> void SettingSet(int index, V value, CoordSet *cs) {
SettingSet(cs->State.G, &cs->Setting, index, value);
}
#endif

View File

@@ -13292,6 +13292,7 @@ bool ObjectMolecule::updateAtmToIdx() {
if (DiscreteFlag) {
DiscreteAtmToIdx[atm] = idx;
DiscreteCSet[atm] = cset;
AtomInfo[atm].discrete_state = i + 1;
} else {
cset->AtmToIdx[atm] = idx;
}

View File

@@ -510,4 +510,9 @@ int *AtomInfoGetSortedIndex(PyMOLGlobals * G, ObjectMolecule * obj, AtomInfoType
ObjectMolecule *ObjectMoleculeReadCifStr(PyMOLGlobals * G, ObjectMolecule * I,
const char *st, int frame, int discrete, int quiet, int multiplex, int zoom);
// object and object-state level setting
template <typename V> void SettingSet(int index, V value, ObjectMolecule * I, int state=-1) {
SettingSet(index, value, (CObject*)I, state);
}
#endif

View File

@@ -3776,6 +3776,9 @@ int ObjectMoleculeConnect(ObjectMolecule * I, int *nbond, BondType ** bond, Atom
bondSearchMode = true;
cs->NTmpBond = 0;
VLAFreeP(cs->TmpBond);
} else if (connect_mode == 4) {
// mmCIF specific, fall back to default to get any bonds for PDB, XYZ, etc.
connect_mode = 0;
}
/* FeedbackMask[FB_ObjectMolecule]=0xFF; */

View File

@@ -3037,6 +3037,22 @@ Rep *RepCartoonNew(CoordSet * cs, int state)
fp++;
if (trace) {
if ((a3 = cs->atmToIdx(a1 - 1)) == -1 ||
(a4 = cs->atmToIdx(a1 + 1)) == -1) {
zero3f(vo);
} else {
float t0[3], t1[3];
subtract3f(cs->coordPtr(a), cs->coordPtr(a3), t0);
subtract3f(cs->coordPtr(a), cs->coordPtr(a4), t1);
add3f(t0, t1, vo);
normalize3f(vo);
}
vo += 3;
continue;
}
// pointers to C+N+O coordinates
v_c = NULL;
v_n = NULL;
v_o = NULL;

View File

@@ -479,69 +479,6 @@ ok_except1:
return obj;
}
static void atomicnumber2elem(char * dst, int protons) {
const char * p = NULL;
switch(protons) {
case cAN_LP: p = "LP"; break;
case cAN_H: p = "H"; break;
case cAN_He: p = "He"; break;
case cAN_Li: p = "Li"; break;
case cAN_Be: p = "Be"; break;
case cAN_B: p = "B"; break;
case cAN_C: p = "C"; break;
case cAN_N: p = "N"; break;
case cAN_O: p = "O"; break;
case cAN_F: p = "F"; break;
case cAN_Ne: p = "Ne"; break;
case cAN_Na: p = "Na"; break;
case cAN_Mg: p = "Mg"; break;
case cAN_Al: p = "Al"; break;
case cAN_Si: p = "Si"; break;
case cAN_P: p = "P"; break;
case cAN_S: p = "S"; break;
case cAN_Cl: p = "Cl"; break;
case cAN_Ar: p = "Ar"; break;
case cAN_K: p = "K"; break;
case cAN_Ca: p = "Ca"; break;
case cAN_Ti: p = "Ti"; break;
case cAN_Cr: p = "Cr"; break;
case cAN_Mn: p = "Mn"; break;
case cAN_Fe: p = "Fe"; break;
case cAN_Co: p = "Co"; break;
case cAN_Ni: p = "Ni"; break;
case cAN_Cu: p = "Cu"; break;
case cAN_Zn: p = "Zn"; break;
case cAN_Ga: p = "Ga"; break;
case cAN_Ge: p = "Ge"; break;
case cAN_As: p = "As"; break;
case cAN_Se: p = "Se"; break;
case cAN_Br: p = "Br"; break;
case cAN_Kr: p = "Kr"; break;
case cAN_Rb: p = "Rb"; break;
case cAN_Sr: p = "Sr"; break;
case cAN_Pd: p = "Pd"; break;
case cAN_Ag: p = "Ag"; break;
case cAN_Cd: p = "Cd"; break;
case cAN_In: p = "In"; break;
case cAN_Sn: p = "Sn"; break;
case cAN_Sb: p = "Sb"; break;
case cAN_Te: p = "Te"; break;
case cAN_I: p = "I"; break;
case cAN_Xe: p = "Xe"; break;
case cAN_Cs: p = "Cs"; break;
case cAN_Ba: p = "Ba"; break;
case cAN_Ce: p = "Ce"; break;
case cAN_Pt: p = "Pt"; break;
case cAN_Au: p = "Au"; break;
case cAN_Hg: p = "Hg"; break;
case cAN_Tl: p = "Tl"; break;
case cAN_Pb: p = "Pb"; break;
case cAN_U: p = "U"; break;
default: p = "X";
}
strncpy(dst, p, cElemNameLen);
}
static CSymmetry * SymmetryNewFromTimestep(PyMOLGlobals * G, molfile_timestep_t * ts)
{
CSymmetry * symm = NULL;

View File

@@ -36,6 +36,7 @@ def fetchdialog():
"cid (PubChem Compound)",
"sid (PubChem Substance)",
"emd (EMDB Density)",
"cc (Chemical Component)",
]
var_code = Tkinter.StringVar(self)

View File

@@ -431,6 +431,7 @@ from experimenting import \
test
from internal import \
download_chem_comp, \
file_read
#--------------------------------------------------------------------

View File

@@ -1221,6 +1221,7 @@ PYMOL API
"http://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?{type}={code}&disopt=SaveSDF",
],
"emd": "/../emdb/structures/EMD-{code}/map/emd_{code}.map.gz",
"cc": "ftp://ftp.ebi.ac.uk/pub/databases/msd/pdbechem/files/mmcif/{code}.cif",
}
def _fetch(code, name, state, finish, discrete, multiplex, zoom, type, path,
@@ -1258,6 +1259,8 @@ PYMOL API
nameFmt = '{type}_{code}.sdf'
elif type == 'cif':
pass
elif type == 'cc':
nameFmt = '{code}.cif'
elif re.match(r'pdb\d+$', type):
bioType = 'bio'
else:
@@ -1269,13 +1272,14 @@ PYMOL API
url_list += [url] if '://' in url else [fetch_host + url
for fetch_host in fetch_host_list]
code = code.lower()
if bioType not in ['cc']:
code = code.lower()
fobj = None
contents = None
if not file or file in (1, '1', 'auto'):
file = os.path.join(path, nameFmt.format(code=code.lower(), type=type))
file = os.path.join(path, nameFmt.format(code=code, type=type))
if not isinstance(file, basestring):
fobj = file

View File

@@ -1,4 +1,5 @@
import os
import cmd
import types
from pymol import _cmd
@@ -326,6 +327,41 @@ def file_read(finfo, _self=cmd):
return contents
def download_chem_comp(resn, quiet=1, _self=cmd):
'''
WARNING: internal routine, subject to change
Download the chemical components CIF for the given residue name
and return its local filename, or an empty string on failure.
'''
filename = os.path.join(_self.get('fetch_path'), resn + ".cif")
if os.path.exists(filename):
return filename
url = "ftp://ftp.ebi.ac.uk/pub/databases/msd/pdbechem/files/mmcif/" + resn + ".cif"
if not quiet:
print ' Downloading', url
try:
contents = _self.file_read(url)
if not contents: raise
except:
print ' Error: Download failed'
return ''
try:
with open(filename, 'w') as handle:
handle.write(contents)
except IOError as e:
print e
print 'Your "fetch_path" setting might point to a read-only directory'
return ''
if not quiet:
print ' ->', filename
return filename
def _load(oname,finfo,state,ftype,finish,discrete,
quiet=1,multiplex=0,zoom=-1,mimic=1,
plugin='',