Ticket #778: changes_take_2.diff

File changes_take_2.diff, 42.6 KB (added by Tristan Croll, 8 years ago)

Corrected a few bugs in the previous diff

  • src/core/atomic/atomstruct_cpp/Atom.cpp

    diff --git a/src/core/atomic/atomstruct_cpp/Atom.cpp b/src/core/atomic/atomstruct_cpp/Atom.cpp
    index 1903479..9032ebf 100644
    a b Atom::get_idatm_info_map()  
    846846    return _idatm_map;
    847847}
    848848
     849void
     850Atom::bonds_track_change(const std::string& reason) {
     851    for(std::vector<Bond*>::iterator b = _bonds.begin(); b != _bonds.end(); ++b) {
     852        (*b)->track_change(reason);
     853    }
     854}
     855
     856
    849857bool
    850858Atom::has_missing_structure_pseudobond() const
    851859{
    Atom::set_alt_loc(char alt_loc, bool create, bool _from_residue)  
    11121120    if (alt_loc == _alt_loc || alt_loc == ' ')
    11131121        return;
    11141122    graphics_container()->set_gc_shape();
    1115     structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_ALT_LOC);
     1123    track_change(ChangeTracker::REASON_ALT_LOC);
    11161124    if (create) {
    11171125        if (_alt_loc_map.find(alt_loc) != _alt_loc_map.end()) {
    11181126            set_alt_loc(alt_loc, create=false);
    Atom::set_alt_loc(char alt_loc, bool create, bool _from_residue)  
    11351143        _Alt_loc_info &info = (*i).second;
    11361144        _serial_number = info.serial_number;
    11371145        _alt_loc = alt_loc;
    1138         structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_COORD);
     1146        track_change(ChangeTracker::REASON_COORD);
    11391147    } else {
    11401148        residue()->set_alt_loc(alt_loc);
    11411149    }
    Atom::set_aniso_u(float u11, float u12, float u13, float u22, float u23, float u  
    11601168    (*a)[3] = u22;
    11611169    (*a)[4] = u23;
    11621170    (*a)[5] = u33;
    1163     structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_ANISO_U);
     1171    track_change(ChangeTracker::REASON_ANISO_U);
    11641172}
    11651173
    11661174void
    Atom::set_bfactor(float bfactor)  
    11711179        (*i).second.bfactor = bfactor;
    11721180    } else
    11731181        structure()->active_coord_set()->set_bfactor(this, bfactor);
    1174     structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_BFACTOR);
     1182    track_change(ChangeTracker::REASON_BFACTOR);
    11751183}
    11761184
    11771185void
    Atom::set_color(const Rgba& rgba)  
    11801188    if (rgba == _rgba)
    11811189        return;
    11821190    graphics_container()->set_gc_color();
    1183     change_tracker()->add_modified(this, ChangeTracker::REASON_COLOR);
     1191    track_change(ChangeTracker::REASON_COLOR);
     1192    bonds_track_change(ChangeTracker::REASON_COLOR);
    11841193    _rgba = rgba;
    11851194}
    11861195
    11871196void
    11881197Atom::set_coord(const Coord& coord, CoordSet* cs)
    1189 {
    1190     structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_COORD);
     1198{   
     1199    track_change(ChangeTracker::REASON_COORD);
     1200    bonds_track_change(ChangeTracker::REASON_COORD);
    11911201    if (cs == nullptr) {
    11921202        cs = structure()->active_coord_set();
    11931203        if (cs == nullptr) {
    Atom::set_display(bool d)  
    12141224    if (d == _display)
    12151225        return;
    12161226    graphics_container()->set_gc_shape();
    1217     change_tracker()->add_modified(this, ChangeTracker::REASON_DISPLAY);
     1227    structure()->set_visible_atoms_changed(true);
     1228    structure()->set_visible_bonds_changed(true);
     1229    track_change(ChangeTracker::REASON_DISPLAY);
    12181230    _display = d;
    12191231}
    12201232
    Atom::set_draw_mode(DrawMode dm)  
    12231235{
    12241236    if (dm == _draw_mode)
    12251237        return;
     1238    if ( _draw_mode == DrawMode::Sphere || dm == DrawMode::Sphere )
     1239        structure()->set_visible_bonds_changed(true);
    12261240    graphics_container()->set_gc_shape();
    1227     change_tracker()->add_modified(this, ChangeTracker::REASON_DRAW_MODE);
     1241    track_change(ChangeTracker::REASON_DRAW_MODE);
    12281242    _draw_mode = dm;
    12291243}
    12301244
    Atom::set_hide(int h)  
    12341248    if (h == _hide)
    12351249        return;
    12361250    graphics_container()->set_gc_shape();
    1237     change_tracker()->add_modified(this, ChangeTracker::REASON_HIDE);
     1251    structure()->set_visible_atoms_changed(true);
     1252    structure()->set_visible_bonds_changed(true);
     1253    track_change(ChangeTracker::REASON_HIDE);
    12381254    _hide = h;
    12391255}
    12401256
    12411257void
    12421258Atom::set_occupancy(float occupancy)
    12431259{
    1244     structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_OCCUPANCY);
     1260    track_change(ChangeTracker::REASON_OCCUPANCY);
    12451261    if (_alt_loc != ' ') {
    12461262        _Alt_loc_map::iterator i = _alt_loc_map.find(_alt_loc);
    12471263        (*i).second.occupancy = occupancy;
    Atom::set_radius(float r)  
    12591275        return;
    12601276
    12611277    graphics_container()->set_gc_shape();
    1262     change_tracker()->add_modified(this, ChangeTracker::REASON_RADIUS);
     1278    track_change(ChangeTracker::REASON_RADIUS);
    12631279    _radius = r;
    12641280}
    12651281
    Atom::set_selected(bool s)  
    12691285    if (s == _selected)
    12701286        return;
    12711287    graphics_container()->set_gc_select();
    1272     change_tracker()->add_modified(this, ChangeTracker::REASON_SELECTED);
     1288    track_change(ChangeTracker::REASON_SELECTED);
     1289    bonds_track_change(ChangeTracker::REASON_SELECTED);
    12731290    _selected = s;
    12741291}
    12751292
    Atom::set_serial_number(int sn)  
    12811298        _Alt_loc_map::iterator i = _alt_loc_map.find(_alt_loc);
    12821299        (*i).second.serial_number = sn;
    12831300    }
    1284     structure()->change_tracker()->add_modified(this, ChangeTracker::REASON_SERIAL_NUMBER);
     1301    track_change(ChangeTracker::REASON_SERIAL_NUMBER);
    12851302}
    12861303
    12871304std::string
  • src/core/atomic/atomstruct_cpp/Atom.h

    diff --git a/src/core/atomic/atomstruct_cpp/Atom.h b/src/core/atomic/atomstruct_cpp/Atom.h
    index eb8c7ed..e9542da 100644
    a b private:  
    109109    typedef std::map<unsigned char, _Alt_loc_info>  _Alt_loc_map;
    110110    _Alt_loc_map  _alt_loc_map;
    111111    std::vector<float>*  _aniso_u;
     112    bool _changed = false;
    112113    Bonds  _bonds; // _bonds/_neighbors in same order
    113114    mutable AtomType  _computed_idatm_type;
    114115    unsigned int  _coord_index;
    private:  
    128129    mutable Rings  _rings;
    129130    bool  _selected = false;
    130131    int  _serial_number;
    131     void  _set_structure_category(Atom::StructCat sc) const;
     132    void  _set_structure_category(Atom::StructCat sc);
    132133    Structure*  _structure;
    133134    mutable StructCat  _structure_category;
    134135public:
    public:  
    137138    void  _switch_initial_element(const Element& e) { _element = &e; }
    138139
    139140public:
     141    bool changed() const { return _changed; }
     142    void set_changed(bool flag) { _changed = flag; }
    140143    void  add_bond(Bond *b);
    141144    char  alt_loc() const { return _alt_loc; }
    142145    std::set<char>  alt_locs() const;
    public:  
    208211
    209212    // change tracking
    210213    ChangeTracker*  change_tracker() const;
     214    void track_change(const std::string& reason) {
     215        change_tracker()->add_modified(this, reason);
     216        this->set_changed(true);
     217    }
     218   
     219    void bonds_track_change(const std::string& reason);
     220   
    211221
    212222    // graphics related
    213223    const Rgba&  color() const { return _rgba; }
    Atom::idatm_type() const {  
    243253}
    244254
    245255inline void
    246 Atom::_set_structure_category(Atom::StructCat sc) const
     256Atom::_set_structure_category(Atom::StructCat sc)
    247257{
    248258    if (sc == _structure_category)
    249259        return;
    250     change_tracker()->add_modified(const_cast<Atom*>(this),
    251         ChangeTracker::REASON_STRUCTURE_CATEGORY);
     260    track_change(ChangeTracker::REASON_STRUCTURE_CATEGORY);
     261    //change_tracker()->add_modified(const_cast<Atom*>(this),
     262    //    ChangeTracker::REASON_STRUCTURE_CATEGORY);
    252263    _structure_category = sc;
    253264}
    254265
    255266inline void
    256267Atom::set_computed_idatm_type(const char* it) {
    257268    if (!idatm_is_explicit() && _computed_idatm_type != it) {
     269        track_change(ChangeTracker::REASON_IDATM_TYPE);
    258270        change_tracker()->add_modified(this, ChangeTracker::REASON_IDATM_TYPE);
    259271    }
    260272    _computed_idatm_type =  it;
    Atom::set_idatm_type(const char* it) {  
    267279    if (!(_explicit_idatm_type.empty() && _computed_idatm_type == it)
    268280    && !(*it == '\0' && _explicit_idatm_type == _computed_idatm_type)
    269281    && !(!_explicit_idatm_type.empty() && it == _explicit_idatm_type)) {
    270         change_tracker()->add_modified(this, ChangeTracker::REASON_IDATM_TYPE);
     282        track_change(ChangeTracker::REASON_IDATM_TYPE);
     283        //change_tracker()->add_modified(this, ChangeTracker::REASON_IDATM_TYPE);
    271284    }
    272285    _explicit_idatm_type = it;
    273286}
    inline void  
    276289Atom::set_name(const AtomName& name) {
    277290    if (name == _name)
    278291        return;
    279     change_tracker()->add_modified(this, ChangeTracker::REASON_NAME);
     292    track_change(ChangeTracker::REASON_NAME);
     293    //change_tracker()->add_modified(this, ChangeTracker::REASON_NAME);
    280294    _name = name;
     295    _changed = true;
    281296}
    282297
    283298inline Atom::StructCat
  • src/core/atomic/atomstruct_cpp/Bond.cpp

    diff --git a/src/core/atomic/atomstruct_cpp/Bond.cpp b/src/core/atomic/atomstruct_cpp/Bond.cpp
    index 268e3f8..dd23972 100644
    a b Bond::polymeric_start_atom() const  
    174174    return psa;
    175175}
    176176
     177void
     178Bond::set_hide(int h) {
     179    if (h == _hide)
     180        return;
     181    structure()->set_visible_bonds_changed(true);
     182    Connection::set_hide(h);
     183}
     184
     185void
     186Bond::set_display(bool d) {
     187    if (d == _display)
     188        return;
     189    structure()->set_visible_bonds_changed(true);
     190    Connection::set_display(d);
     191}
     192
    177193}  // namespace atomstruct
  • src/core/atomic/atomstruct_cpp/Bond.h

    diff --git a/src/core/atomic/atomstruct_cpp/Bond.h b/src/core/atomic/atomstruct_cpp/Bond.h
    index 43b2fcd..b7db12c 100644
    a b private:  
    4646    const char*  err_msg_loop() const
    4747        { return "Can't bond an atom to itself"; }
    4848    mutable Rings  _rings;
    49 
     49    bool _changed = false;
     50   
    5051    static int  session_base_version(int /*version*/) { return 1; }
    5152    static int  SESSION_NUM_INTS(int /*version*/=CURRENT_SESSION_VERSION) { return 0; }
    5253    static int  SESSION_NUM_FLOATS(int /*version*/=CURRENT_SESSION_VERSION) { return 0; }
    5354public:
     55    void set_hide(int h);
     56    void set_display(bool d);
    5457    virtual ~Bond() {}
    5558    virtual bool shown() const;
    5659    const Rings&  all_rings(bool cross_residues = false, int size_threshold = 0,
    public:  
    6265        return rings(cross_residues, 0, ignore);
    6366    }
    6467    static bool  polymer_bond_atoms(Atom* first, Atom* second);
     68    bool changed() const { return _changed; }
     69    void set_changed(bool flag) { _changed = flag; }
    6570    Atom*  polymeric_start_atom() const;
    6671    const Rings&  rings(bool cross_residues = false, int all_size_threshold = 0,
    6772        std::set<const Residue*>* ignore = nullptr) const;
    public:  
    8085
    8186    // change tracking
    8287    ChangeTracker*  change_tracker() const;
    83     void track_change(const std::string& reason) const {
     88    void track_change(const std::string& reason) {
    8489        change_tracker()->add_modified(this, reason);
     90        this->set_changed(true);
    8591    }
    8692
    8793    // graphics related
  • src/core/atomic/atomstruct_cpp/Connection.h

    diff --git a/src/core/atomic/atomstruct_cpp/Connection.h b/src/core/atomic/atomstruct_cpp/Connection.h
    index d0ba00e..443d9cc 100644
    a b public:  
    106106    }
    107107
    108108    // change tracking
    109     virtual void  track_change(const std::string& reason) const = 0;
     109    virtual void  track_change(const std::string& reason) = 0;
    110110
    111111    // graphics related
    112112    const Rgba&  color() const { return _rgba; }
  • src/core/atomic/atomstruct_cpp/CoordSet.cpp

    diff --git a/src/core/atomic/atomstruct_cpp/CoordSet.cpp b/src/core/atomic/atomstruct_cpp/CoordSet.cpp
    index 69eac6b..94399c5 100644
    a b CoordSet::session_save(int** ints, float** floats) const  
    130130void
    131131CoordSet::set_bfactor(const Atom *a, float val)
    132132{
    133     _bfactor_map.insert(std::pair<const Atom *, float>(a, val));
     133    //_bfactor_map.insert(std::pair<const Atom *, float>(a, val));
     134    _bfactor_map[a] = val;
    134135}
    135136
    136137void
    137138CoordSet::set_occupancy(const Atom *a, float val)
    138139{
    139     _occupancy_map.insert(std::pair<const Atom *, float>(a, val));
     140    //_occupancy_map.insert_or_assign(std::pair<const Atom *, float>(a, val));
     141    _occupancy_map[a] = val;
    140142}
    141143
    142144}  // namespace atomstruct
  • src/core/atomic/atomstruct_cpp/PBGroup.h

    diff --git a/src/core/atomic/atomstruct_cpp/PBGroup.h b/src/core/atomic/atomstruct_cpp/PBGroup.h
    index f8e0eb9..cb5dc9b 100644
    a b protected:  
    7676
    7777    void _check_destroyed_atoms(PBGroup::Pseudobonds& pbonds, const std::set<void*>& destroyed);
    7878    void delete_pbs_check(const std::set<Pseudobond*>& pbs) const;
     79    bool _changed = false;
    7980public:
     81    bool changed() const { return _changed; }
     82    void set_changed(bool flag) { _changed = flag; }
    8083    virtual void  clear() = 0;
    8184    virtual const Rgba&  color() const { return _color; }
    8285    virtual const std::string&  category() const { return _category; }
  • src/core/atomic/atomstruct_cpp/Pseudobond.h

    diff --git a/src/core/atomic/atomstruct_cpp/Pseudobond.h b/src/core/atomic/atomstruct_cpp/Pseudobond.h
    index 52cc7ae..de7d1d9 100644
    a b protected:  
    6060        { return "Can't form pseudobond to itself"; }
    6161    const char*  err_msg_not_end() const
    6262        { return "Atom given to other_end() not in pseudobond!"; }
     63    bool _changed = false;
    6364public:
     65    bool changed() const { return _changed; }
     66    void set_changed(bool flag) { _changed = flag; }
    6467    ChangeTracker*  change_tracker() const;
    6568    GraphicsContainer*  graphics_container() const;
    6669    PBGroup*  group() const { return _group; }
    public:  
    7679    }
    7780    void  session_restore(int version, int** ints, float** floats);
    7881    void  session_save(int** ints, float** floats) const;
    79     void  track_change(const std::string& reason) const {
     82    void  track_change(const std::string& reason) {
    8083        change_tracker()->add_modified(this, reason);
     84        this->set_changed(true);
    8185    }
    8286};
    8387
  • src/core/atomic/atomstruct_cpp/Residue.h

    diff --git a/src/core/atomic/atomstruct_cpp/Residue.h b/src/core/atomic/atomstruct_cpp/Residue.h
    index c1ec67e..a5fecaa 100644
    a b private:  
    7979    int  _ss_id;
    8080    SSType _ss_type;
    8181    Structure *  _structure;
     82    bool _changed = false;
    8283public:
     84    bool changed() const { return _changed; }
     85    void set_changed(bool flag) { _changed = flag; }
    8386    void  add_atom(Atom*);
    8487    const Atoms&  atoms() const { return _atoms; }
    8588    AtomsMap  atoms_map() const;
  • src/core/atomic/atomstruct_cpp/Structure.h

    diff --git a/src/core/atomic/atomstruct_cpp/Structure.h b/src/core/atomic/atomstruct_cpp/Structure.h
    index 60ce973..caa4da8 100644
    a b protected:  
    184184    static int  SESSION_NUM_MISC(int version=CURRENT_SESSION_VERSION) {
    185185        return version > 7 ? 3 : 4;
    186186    }
    187 
     187    bool _visible_atoms_changed = false;
     188    bool _visible_bonds_changed = false;
     189    bool _changed = false;
    188190public:
     191    bool changed() const { return _changed; }
     192    void set_changed(const bool& flag) { _changed = flag; }
     193    bool visible_atoms_changed() const { return _visible_atoms_changed; }
     194    void set_visible_atoms_changed(const bool& flag) { _visible_atoms_changed = flag; }
     195    bool visible_bonds_changed() const { return _visible_bonds_changed; }
     196    void set_visible_bonds_changed(const bool& flag) { _visible_bonds_changed = flag; }
     197   
    189198    Structure(PyObject* logger = nullptr);
    190199    virtual  ~Structure();
    191200
  • src/core/atomic/molarray.py

    diff --git a/src/core/atomic/molarray.py b/src/core/atomic/molarray.py
    index ac0a869..a149860 100644
    a b class Atoms(Collection):  
    342342        "Return list of 2-tuples of (structure, Atoms for that structure)."
    343343        astruct = self.structures._pointers
    344344        return [(us, self.filter(astruct==us._c_pointer.value)) for us in self.unique_structures]
     345   
     346    _changed = cvec_property('atom_changed', bool, doc='Changed since last redraw')
    345347    chain_ids = cvec_property('atom_chain_id', string, read_only = True)
    346348    colors = cvec_property('atom_color', uint8, 4,
    347349        doc="Returns a :mod:`numpy` Nx4 array of uint8 RGBA values. Can be set "
    class Bonds(Collection):  
    611613    def __init__(self, bond_pointers = None):
    612614        Collection.__init__(self, bond_pointers, molobject.Bond, Bonds)
    613615
     616
     617    _changed = cvec_property('bond_changed', bool, doc='Changed since last redraw')
     618    '''
     619    True if the bond or the position(s) of its atoms have been changed
     620    since the last time they were drawn.
     621    Returns a :mod:`numpy` array of bool. Can be set with such an array
     622    (or equivalent sequence), or with a single value.
     623    '''
     624
    614625    atoms = cvec_property('bond_atoms', cptr, 2, astype = _atoms_pair, read_only = True)
    615626    '''
    616627    Returns a two-tuple of :class:`Atoms` objects.
  • src/core/atomic/molc.cpp

    diff --git a/src/core/atomic/molc.cpp b/src/core/atomic/molc.cpp
    index 4e7e24c..abb3782 100755
    a b inline bool normalize(float *v)  
    248248// -------------------------------------------------------------------------
    249249// atom functions
    250250//
     251
     252
     253extern "C" EXPORT void atom_changed(void *atoms, size_t n, npy_bool *flags)
     254{
     255    Atom **a = static_cast<Atom **>(atoms);
     256    error_wrap_array_get(a, n, &Atom::changed, flags);
     257}
     258
     259extern "C" EXPORT void set_atom_changed (void *atoms, size_t n, npy_bool *flags)
     260{
     261    Atom **a = static_cast<Atom **>(atoms);
     262    error_wrap_array_set(a, n, &Atom::set_changed, flags);
     263}
     264   
     265
    251266extern "C" EXPORT void atom_bfactor(void *atoms, size_t n, float32_t *bfactors)
    252267{
    253268    Atom **a = static_cast<Atom **>(atoms);
    extern "C" EXPORT PyObject *atom_intra_bonds(void *atoms, size_t n)  
    10241039// -------------------------------------------------------------------------
    10251040// bond functions
    10261041//
     1042
     1043extern "C" EXPORT void bond_changed(void *bonds, size_t n, npy_bool *flags)
     1044{
     1045    Bond **b = static_cast<Bond **>(bonds);
     1046    error_wrap_array_get(b, n, &Bond::changed, flags);
     1047}
     1048
     1049extern "C" EXPORT void set_bond_changed (void *bonds, size_t n, npy_bool *flags)
     1050{
     1051    Bond **b = static_cast<Bond **>(bonds);
     1052    error_wrap_array_set(b, n, &Bond::set_changed, flags);
     1053}
     1054
     1055
    10271056extern "C" EXPORT void bond_atoms(void *bonds, size_t n, pyobject_t *atoms)
    10281057{
    10291058    Bond **b = static_cast<Bond **>(bonds);
    extern "C" EXPORT void *bond_other_atom(void *bond, void *atom)  
    12241253// -------------------------------------------------------------------------
    12251254// pseudobond functions
    12261255//
     1256
     1257extern "C" EXPORT void pseudobond_changed(void *pbonds, size_t n, npy_bool *flags)
     1258{
     1259    Pseudobond **b = static_cast<Pseudobond **>(pbonds);
     1260    error_wrap_array_get(b, n, &Pseudobond::changed, flags);
     1261}
     1262
     1263extern "C" EXPORT void set_pseudobond_changed (void *pbonds, size_t n, npy_bool *flags)
     1264{
     1265    Pseudobond **b = static_cast<Pseudobond **>(pbonds);
     1266    error_wrap_array_set(b, n, &Pseudobond::set_changed, flags);
     1267}
     1268
     1269
     1270
    12271271extern "C" EXPORT void pseudobond_atoms(void *pbonds, size_t n, pyobject_t *atoms)
    12281272{
    12291273    Pseudobond **b = static_cast<Pseudobond **>(pbonds);
    extern "C" EXPORT void pseudobond_global_manager_session_save_teardown(void *man  
    17341778// -------------------------------------------------------------------------
    17351779// residue functions
    17361780//
     1781
     1782extern "C" EXPORT void residue_changed(void *residues, size_t n, npy_bool *flags)
     1783{
     1784    Residue **r = static_cast<Residue **>(residues);
     1785    error_wrap_array_get(r, n, &Residue::changed, flags);
     1786}
     1787
     1788extern "C" EXPORT void set_residue_changed (void *residues, size_t n, npy_bool *flags)
     1789{
     1790    Residue **r = static_cast<Residue **>(residues);
     1791    error_wrap_array_set(r, n, &Residue::set_changed, flags);
     1792}
     1793
     1794
    17371795extern "C" EXPORT void residue_atoms(void *residues, size_t n, pyobject_t *atoms)
    17381796{
    17391797    Residue **r = static_cast<Residue **>(residues);
    extern "C" EXPORT int sequence_ungapped_to_gapped(void *seq, int32_t index)  
    32113269// -------------------------------------------------------------------------
    32123270// structure functions
    32133271//
     3272
     3273
    32143274extern "C" EXPORT void set_structure_color(void *mol, uint8_t *rgba)
    32153275{
    32163276    Structure *m = static_cast<Structure *>(mol);
    extern "C" EXPORT void structure_atoms(void *mols, size_t n, pyobject_t *atoms)  
    33033363    }
    33043364}
    33053365
     3366extern "C" EXPORT void structure_visible_atoms_changed(void *mols, size_t n, npy_bool *changed)
     3367{
     3368    Structure **m = static_cast<Structure **>(mols);
     3369    try {
     3370        for (size_t i = 0; i != n; ++i) {
     3371            *changed++ = m[i]->visible_atoms_changed();
     3372        }
     3373    } catch (...) {
     3374        molc_error();
     3375    }
     3376}
     3377
     3378extern "C" EXPORT void set_structure_visible_atoms_changed(void *mols, size_t n, npy_bool *changed)
     3379{
     3380    Structure **m = static_cast<Structure **>(mols);
     3381    try {
     3382        for (size_t i = 0; i != n; ++i) {
     3383            m[i]->set_visible_atoms_changed(*changed++);
     3384        }
     3385    } catch (...) {
     3386        molc_error();
     3387    }
     3388}
     3389
     3390extern "C" EXPORT void structure_visible_atoms(void *mols, size_t n, pyobject_t *atoms)
     3391{
     3392    Structure **m = static_cast<Structure **>(mols);
     3393    try {
     3394        for (size_t i = 0; i != n; ++i) {
     3395            const Structure::Atoms &a = m[i]->atoms();
     3396            for (size_t j = 0; j != a.size(); ++j) {
     3397                if ( a[j]->visible() )
     3398                    *atoms++ = a[j];
     3399            }
     3400        }
     3401    } catch (...) {
     3402        molc_error();
     3403    }
     3404}
     3405
     3406
    33063407extern "C" EXPORT void structure_ball_scale(void *mols, size_t n, float32_t *bscales)
    33073408{
    33083409    Structure **m = static_cast<Structure **>(mols);
    extern "C" EXPORT void structure_bonds(void *mols, size_t n, pyobject_t *bonds)  
    33343435    }
    33353436}
    33363437
     3438extern "C" EXPORT void structure_num_bonds_visible(void *mols, size_t n, size_t *nbonds)
     3439{
     3440    Structure **m = static_cast<Structure **>(mols);
     3441    try {
     3442        for (size_t i = 0; i != n; ++i)
     3443          {
     3444            const Structure::Bonds &bonds = m[i]->bonds();
     3445            int c = 0;
     3446            for (auto b: bonds)
     3447              if (b->shown())
     3448                c++;
     3449            nbonds[i] = c;
     3450          }
     3451    } catch (...) {
     3452        molc_error();
     3453    }
     3454}
     3455
     3456extern "C" EXPORT void structure_visible_bonds(void *mols, size_t n, pyobject_t *bonds)
     3457{
     3458    Structure **m = static_cast<Structure **>(mols);
     3459    try {
     3460        for (size_t i = 0; i != n; ++i) {
     3461            const Structure::Bonds &b = m[i]->bonds();
     3462            for (size_t j = 0; j != b.size(); ++j) {
     3463                if ( b[j]->shown() )
     3464                    *bonds++ = b[j];
     3465            }
     3466        }
     3467    } catch (...) {
     3468        molc_error();
     3469    }
     3470}
     3471
     3472extern "C" EXPORT void structure_visible_bonds_changed(void *mols, size_t n, npy_bool *changed)
     3473{
     3474    Structure **m = static_cast<Structure **>(mols);
     3475    try {
     3476        for (size_t i = 0; i != n; ++i) {
     3477            *changed++ = m[i]->visible_bonds_changed();
     3478        }
     3479    } catch (...) {
     3480        molc_error();
     3481    }
     3482}
     3483
     3484extern "C" EXPORT void set_structure_visible_bonds_changed(void *mols, size_t n, npy_bool *changed)
     3485{
     3486    Structure **m = static_cast<Structure **>(mols);
     3487    try {
     3488        for (size_t i = 0; i != n; ++i) {
     3489            m[i]->set_visible_bonds_changed(*changed++);
     3490        }
     3491    } catch (...) {
     3492        molc_error();
     3493    }
     3494}
     3495
     3496
    33373497extern "C" EXPORT void structure_num_residues(void *mols, size_t n, size_t *nres)
    33383498{
    33393499    Structure **m = static_cast<Structure **>(mols);
  • src/core/atomic/molobject.py

    diff --git a/src/core/atomic/molobject.py b/src/core/atomic/molobject.py
    index a4937f2..9413f68 100644
    a b class Atom(State):  
    125125
    126126    def atomspec(self):
    127127        return self.residue.atomspec() + '@' + self.name
    128 
     128   
     129    _changed = c_property('atom_changed', bool, doc='Changed since last redraw')
    129130    alt_loc = c_property('atom_alt_loc', byte, doc='Alternate location indicator')
    130131    bfactor = c_property('atom_bfactor', float32, doc = "B-factor, floating point value.")
    131132    bonds = c_property('atom_bonds', cptr, "num_bonds", astype=_bonds, read_only=True,
    class Bond(State):  
    378379    def atomspec(self):
    379380        return a1.atomspec() + a2.atomspec()
    380381
     382
     383    _changed = c_property('bond_changed', bool, doc='Changed since last redraw')
     384
    381385    atoms = c_property('bond_atoms', cptr, 2, astype = _atom_pair, read_only = True)
    382386    '''Two-tuple of :py:class:`Atom` objects that are the bond end points.'''
    383387    color = c_property('bond_color', uint8, 4)
    class StructureData:  
    14631467    '''Index of the active coordinate set.'''
    14641468    atoms = c_property('structure_atoms', cptr, 'num_atoms', astype = _atoms, read_only = True)
    14651469    ''':class:`.Atoms` collection containing all atoms of the structure.'''
     1470    _visible_atoms = c_property('structure_visible_atoms', cptr, 'num_atoms_visible', astype = _atoms,
     1471                          read_only = True)
     1472    ''':class:`.Atoms` containing only the visible atoms of the structure. Read only.'''
     1473    _visible_atoms_changed = c_property('structure_visible_atoms_changed', bool)
     1474    '''A boolean flag indicating whether any atom has changed its visibility.'''
    14661475    ball_scale = c_property('structure_ball_scale', float32,
    14671476        doc = "Scales sphere radius in ball-and-stick style.")
    14681477    bonds = c_property('structure_bonds', cptr, 'num_bonds', astype = _bonds, read_only = True)
    14691478    ''':class:`.Bonds` collection containing all bonds of the structure.'''
     1479    _visible_bonds = c_property('structure_visible_bonds', cptr, 'num_bonds_visible', astype = _bonds,
     1480                          read_only = True)
     1481    ''':class:`.Bonds` containing only the visible bonds of the structure. Read only.'''
     1482    _visible_bonds_changed = c_property('structure_visible_bonds_changed', bool)
     1483    '''A boolean flag indicating whether any atom has changed its visibility.'''
    14701484    chains = c_property('structure_chains', cptr, 'num_chains', astype = _chains, read_only = True)
    14711485    ''':class:`.Chains` collection containing all chains of the structure.'''
    14721486    coordset_ids = c_property('structure_coordset_ids', int32, 'num_coordsets', read_only = True)
    class StructureData:  
    14771491    '''Structure has lower case chain ids. Boolean'''
    14781492    num_atoms = c_property('structure_num_atoms', size_t, read_only = True)
    14791493    '''Number of atoms in structure. Read only.'''
    1480     num_atoms_visible = c_property('structure_num_atoms_visible', size_t, read_only = True)
     1494    _num_atoms_visible = c_property('structure_num_atoms_visible', size_t, read_only = True)
    14811495    '''Number of visible atoms in structure. Read only.'''
    14821496    num_bonds = c_property('structure_num_bonds', size_t, read_only = True)
    14831497    '''Number of bonds in structure. Read only.'''
     1498    _num_bonds_visible = c_property('structure_num_bonds_visible', size_t, read_only = True)
     1499    '''Number of visible atoms in structure. Read only.'''
    14841500    num_coordsets = c_property('structure_num_coordsets', size_t, read_only = True)
    14851501    '''Number of coordinate sets in structure. Read only.'''
    14861502    num_chains = c_property('structure_num_chains', size_t, read_only = True)
  • src/core/atomic/structure.py

    diff --git a/src/core/atomic/structure.py b/src/core/atomic/structure.py
    index fb07010..95da353 100644
    a b class Structure(Model, StructureData):  
    5454        self._ribbon_t2r = {}         # ribbon triangles-to-residue map
    5555        self._ribbon_r2t = {}         # ribbon residue-to-triangles map
    5656        self._ribbon_tether = []      # ribbon tethers from ribbon to floating atoms
    57 
     57       
     58        self._cached_num_atoms_visible = self._num_atoms_visible
     59        self._cached_visible_atoms = self._visible_atoms
     60        self._cached_num_bonds_visible = self._num_bonds_visible
     61        self._cached_visible_bonds = self._visible_bonds   
     62             
    5863        from . import molobject
    5964        molobject.add_to_object_map(self)
    6065
    class Structure(Model, StructureData):  
    6469                ("save_teardown", "end save session")]:
    6570            self._ses_handlers.append(t.add_handler(trig_name,
    6671                    lambda *args, qual=ses_func: self._ses_call(qual)))
    67 
     72       
    6873        self._make_drawing()
    6974
    7075    def __str__(self):
    class Structure(Model, StructureData):  
    257262        from ..colors import most_common_color
    258263        if ribbon_displays.any():
    259264            return most_common_color(residues.filter(ribbon_displays).ribbon_colors)
    260         atoms = self.atoms
    261         shown = atoms.filter(atoms.displays)
     265        shown = self.visible_atoms
     266        #shown = atoms.filter(atoms.displays)
    262267        if shown:
    263268            return most_common_color(shown.colors)
    264         return most_common_color(atoms.colors)
     269        return most_common_color(self.atoms.colors)
    265270    def _set_single_color(self, color):
    266271        self.atoms.colors = color
    267272        self.residues.ribbon_colors = color
    class Structure(Model, StructureData):  
    269274
    270275    def _make_drawing(self):
    271276        # Create graphics
    272         self._update_atom_graphics()
    273         self._update_bond_graphics()
    274         for pbg in self.pbg_map.values():
    275             pbg._update_graphics()
    276         self._create_ribbon_graphics()
     277        self._update_graphics_if_needed(force_recalc = True)
     278        #~ self._update_atom_graphics()
     279        #~ self._update_bond_graphics()
     280        #~ for pbg in self.pbg_map.values():
     281            #~ pbg._update_graphics()
     282        #~ self._create_ribbon_graphics()
    277283
    278284    @property
    279285    def _level_of_detail(self):
    280286        gu = structure_graphics_updater(self.session)
    281287        return gu.level_of_detail
     288   
     289    @property
     290    def num_atoms_visible(self):
     291        if self._visible_atoms_changed:
     292            self._cached_num_atoms_visible = self._num_atoms_visible
     293        return self._cached_num_atoms_visible
     294   
     295    @property
     296    def visible_atoms(self):
     297        if self._visible_atoms_changed:
     298            self._cached_visible_atoms = self._visible_atoms
     299        return self._cached_visible_atoms
     300   
     301    @property
     302    def num_bonds_visible(self):
     303        if self._visible_bonds_changed:
     304            self._cached_num_bonds_visible = self._num_bonds_visible
     305        return self._cached_num_bonds_visible
    282306
     307    @property
     308    def visible_bonds(self):
     309        if self._visible_bonds_changed:
     310            self._cached_visible_bonds = self._visible_bonds
     311        return self._cached_visible_bonds
     312       
    283313    def new_atoms(self):
    284314        # TODO: Handle instead with a C++ notification that atoms added or deleted
    285315        self._atom_bounds_needs_update = True
    286316
    287     def _update_graphics_if_needed(self, *_):
     317    def _update_graphics_if_needed(self, *_, force_recalc = False):
    288318        gc = self._graphics_changed
    289         if gc == 0:
     319        if gc == 0 and not force_recalc:
    290320            return
    291 
     321       
     322       
    292323        if gc & self._RIBBON_CHANGE:
    293324            self._create_ribbon_graphics()
    294325            # Displaying ribbon can set backbone atom hide bits producing shape change.
    class Structure(Model, StructureData):  
    299330        s = (gc & self._SHAPE_CHANGE)
    300331        if gc & (self._COLOR_CHANGE | self._RIBBON_CHANGE) or s:
    301332            self._update_ribbon_tethers()
    302         self._update_graphics(gc)
     333        self._update_graphics(gc, force_recalc = force_recalc)
    303334        self.redraw_needed(shape_changed = s,
    304335                           selection_changed = (gc & self._SELECT_CHANGE))
    305336        if s:
    class Structure(Model, StructureData):  
    313344                if isinstance(surf, MolecularSurface):
    314345                    surf.update_selection()
    315346
    316     def _update_graphics(self, changes = StructureData._ALL_CHANGE):
    317         self._update_atom_graphics(changes)
    318         self._update_bond_graphics(changes)
     347    def _update_graphics(self, changes = StructureData._ALL_CHANGE, force_recalc = False):
     348        import numpy
     349        atoms = self.visible_atoms
     350        bonds = self.visible_bonds
     351        force_atom_recalc = False
     352        force_bond_recalc = False
     353       
     354        if force_recalc:
     355            force_atom_recalc = True
     356            force_bond_recalc = True
     357       
     358        else:
     359            if self._visible_atoms_changed:
     360                force_atom_recalc = True
     361                self._visible_atoms_changed = False
     362           
     363            if self._visible_bonds_changed:
     364                force_bond_recalc = True
     365                self._visible_bonds_changed = False
     366       
     367       
     368        if force_atom_recalc:
     369            achanged = numpy.array([True]*len(atoms))
     370            ch_atoms = atoms
     371        else:
     372            achanged = atoms._changed
     373            ch_atoms = atoms[achanged]
     374       
     375        if force_bond_recalc:
     376            bchanged = numpy.array([True]*len(bonds))
     377            ch_bonds = bonds
     378        else:
     379            bchanged = bonds._changed
     380            ch_bonds = bonds[bchanged]
     381           
     382       
     383        half_bond_change_filter = numpy.concatenate((bchanged,bchanged))
     384       
     385        self._update_atom_graphics( ch_atoms, achanged, changes = changes, force_recalc = force_atom_recalc)
     386        self._update_bond_graphics(ch_bonds, half_bond_change_filter, changes = changes, force_recalc = force_bond_recalc)
    319387        for pbg in self.pbg_map.values():
    320388            pbg._update_graphics(changes)
    321389        self._update_ribbon_graphics()
     390        self.redraw_needed()
    322391
    323     def _update_atom_graphics(self, changes = StructureData._ALL_CHANGE):
    324         atoms = self.atoms  # optimzation, avoid making new numpy array from C++
    325         avis = atoms.visibles
     392    def _update_atom_graphics(self, atoms, ch_filter, changes = StructureData._ALL_CHANGE, force_recalc = False):
     393        import numpy
    326394        p = self._atoms_drawing
     395        from numpy import empty, float32, multiply
     396        #ch_indices = numpy.where(ch_filter)[0]
     397       
    327398        if p is None:
    328             if avis.sum() == 0:
    329                 return
     399            #avis = atoms.visibles
     400            #if avis.sum() == 0:
     401            #    return
    330402            self._atoms_drawing = p = self.new_drawing('atoms')
    331403            self._atoms_drawing.custom_x3d = self._custom_atom_x3d
    332404            # Update level of detail of spheres
    333405            self._level_of_detail.set_atom_sphere_geometry(p)
     406   
     407        if force_recalc:
     408            n = len(atoms)
     409            xyzr = empty((n, 4), float32)
     410            xyzr[:, :3] = atoms.coords
     411            xyzr[:, 3] = self._atom_display_radii(atoms)
    334412
     413            from ..geometry import Places
     414            p.colors = atoms.colors
     415            p.positions = Places(shift_and_scale=xyzr)
     416            p.display_positions = numpy.array([True]*len(atoms))
     417            p.selected_positions = atoms.selected if atoms.num_selected > 0 else None
     418            atoms._changed = False
     419            return
     420       
     421       
    335422        if changes & self._SHAPE_CHANGE:
    336423            # Set instanced sphere center position and radius
    337424            n = len(atoms)
    338             from numpy import empty, float32, multiply
    339425            xyzr = empty((n, 4), float32)
    340426            xyzr[:, :3] = atoms.coords
    341427            xyzr[:, 3] = self._atom_display_radii(atoms)
    342 
     428           
    343429            from ..geometry import Places
    344             p.positions = Places(shift_and_scale=xyzr)
    345             p.display_positions = avis
     430            p.positions.set_shift_and_scale(ch_filter, xyzr)
     431            # So the drawing knows it needs to redraw positions
     432            p.positions = p.positions
     433            #p.display_positions = avis
     434           
    346435
    347         if changes & (self._COLOR_CHANGE | self._SHAPE_CHANGE):
     436        if changes & (self._COLOR_CHANGE): # | self._SHAPE_CHANGE):
    348437            # Set atom colors
    349             p.colors = atoms.colors
     438            p.set_colors(atoms.colors, ch_filter)
    350439
    351         if changes & (self._SELECT_CHANGE | self._SHAPE_CHANGE):
     440        if changes & (self._SELECT_CHANGE ): #| self._SHAPE_CHANGE):
    352441            # Set selected
    353             p.selected_positions = atoms.selected if atoms.num_selected > 0 else None
     442            vatoms = self.visible_atoms
     443            p.selected_positions = vatoms.selected if vatoms.num_selected > 0 else None
     444        atoms._changed = False
    354445
    355446    def _custom_atom_x3d(self, stream, x3d_scene, indent, place):
    356447        from numpy import empty, float32
    357448        p = self._atoms_drawing
    358         atoms = self.atoms
     449        atoms = self.visible_atoms
    359450        radii = self._atom_display_radii(atoms)
    360451        tab = ' ' * indent
    361452        for v, xyz, r, c in zip(p.display_positions, atoms.coords, radii, p.colors):
    class Structure(Model, StructureData):  
    371462    def _atom_display_radii(self, atoms):
    372463        return atoms.display_radii(self.ball_scale, self.bond_radius)
    373464   
    374     def _update_bond_graphics(self, changes = StructureData._ALL_CHANGE):
    375         bonds = self.bonds  # optimzation, avoid making new numpy array from C++
     465    def _update_bond_graphics(self, bonds, ch_filter, changes = StructureData._ALL_CHANGE, force_recalc = False):
     466        import numpy
     467        #ch_indices = numpy.where(ch_filter)[0]
    376468        p = self._bonds_drawing
    377469        if p is None:
    378             if bonds.num_shown == 0:
    379                 return
     470            #if bonds.num_shown == 0:
     471            #    return
    380472            self._bonds_drawing = p = self.new_drawing('bonds')
    381473            self._bonds_drawing.custom_x3d = self._custom_bond_x3d
    382474            # Update level of detail of cylinders
    383475            self._level_of_detail.set_bond_cylinder_geometry(p)
    384 
    385         if changes & (self._SHAPE_CHANGE | self._SELECT_CHANGE):
     476       
     477        if force_recalc:
    386478            bond_atoms = bonds.atoms
    387         if changes & self._SHAPE_CHANGE:
    388479            ba1, ba2 = bond_atoms
     480            p.colors = bonds.half_colors
    389481            p.positions = _halfbond_cylinder_placements(ba1.coords, ba2.coords, bonds.radii)
    390482            p.display_positions = _shown_bond_cylinders(bonds)
    391         if changes & (self._COLOR_CHANGE | self._SHAPE_CHANGE):
    392             p.colors = c = bonds.half_colors
    393         if changes & (self._SELECT_CHANGE | self._SHAPE_CHANGE):
    394483            p.selected_positions = _selected_bond_cylinders(bond_atoms)
     484            bonds._changed = False
     485            return
     486       
     487        if changes & (self._SHAPE_CHANGE | self._SELECT_CHANGE):
     488            bond_atoms = bonds.atoms
     489        if changes & self._SHAPE_CHANGE:
     490            ba1, ba2 = bond_atoms
     491            p.positions.set_opengl_matrices(ch_filter,
     492                _halfbond_cylinder_placements(ba1.coords, ba2.coords, bonds.radii)._opengl_array)
     493            p.positions = p.positions
     494            #p.display_positions = ch_filter #_shown_bond_cylinders(bonds)
     495        if changes & (self._COLOR_CHANGE): # | self._SHAPE_CHANGE):
     496            p.set_colors(bonds.half_colors, ch_filter)
     497        if changes & (self._SELECT_CHANGE):# | self._SHAPE_CHANGE):
     498            vbonds = self.visible_bonds
     499            p.selected_positions = _selected_bond_cylinders(vbonds.atoms)
     500        bonds._changed = False
    395501
    396502    def _custom_bond_x3d(self, stream, x3d_scene, indent, place):
    397503        from numpy import empty, float32
    398504        p = self._bonds_drawing
    399         bonds = self.bonds
     505        bonds = self.visible_bonds
    400506        ba1, ba2 = bonds.atoms
    401507        cyl_info = _halfbond_cylinder_x3d(ba1.coords, ba2.coords, bonds.radii)
    402508        tab = ' ' * indent
    class Structure(Model, StructureData):  
    13761482    def _update_ribbon_graphics(self):
    13771483        # Set selected ribbons in graphics
    13781484        from .molarray import Residues
    1379         atoms = self.atoms
     1485        atoms = self.visible_atoms
    13801486        if atoms.num_selected > 0:
    13811487            residues = atoms.filter(atoms.selected).unique_residues
    13821488            from numpy import array
    class Structure(Model, StructureData):  
    14501556    def _atom_bounds(self):
    14511557        if not self._atom_bounds_needs_update:
    14521558            return self._cached_atom_bounds
    1453         a = self.atoms
    1454         adisp = a[a.displays]
    1455         xyz = adisp.coords
    1456         radii = adisp.radii
     1559        a = self.visible_atoms
     1560        xyz = a.coords
     1561        radii = a.radii
    14571562        # TODO: Currently 40% of time is taken in getting atom radii because
    14581563        #       they are recomputed from element and bonds every time. Ticket #789.
    14591564        #       If that was fixed by using a precomputed radius, then it would make
    class Structure(Model, StructureData):  
    15311636
    15321637        if not dp is None:
    15331638            anum = dp.nonzero()[0][anum]    # Remap index to include undisplayed positions
    1534         atom = self.atoms[anum]
     1639        atom = self.visible_atoms[anum]
    15351640
    15361641        # Create pick object
    15371642        s = PickedAtom(atom, fmin)
    class Structure(Model, StructureData):  
    15411646    def _bond_first_intercept(self, mxyz1, mxyz2):
    15421647        d = self._bonds_drawing
    15431648        if d and d.display:
    1544             b,f = _bond_intercept(self.bonds, mxyz1, mxyz2)
     1649            b,f = _bond_intercept(self.visible_bonds, mxyz1, mxyz2)
    15451650            if b:
    15461651                return PickedBond(b, f)
    15471652        return None
    class Structure(Model, StructureData):  
    16031708        if pmask.sum() == 0:
    16041709            return []
    16051710
    1606         a = self.atoms
     1711        a = self.visible_atoms
    16071712        if not dp is None:
    16081713            anum = dp.nonzero()[0][pmask]    # Remap index to include undisplayed positions
    16091714            atoms = a.filter(anum)
  • src/core/geometry/place.py

    diff --git a/src/core/geometry/place.py b/src/core/geometry/place.py
    index f5e8bc1..b509ed2 100644
    a b class Places:  
    423423    '''
    424424    def __init__(self, places=None, place_array=None, shift_and_scale=None,
    425425                 opengl_array=None):
     426        import numpy
    426427        if (place_array is not None or shift_and_scale is not None
    427428                or opengl_array is not None):
    428429            pl = None
    class Places:  
    508509    def __setitem__(self, i, p):
    509510        self._place_list[i] = p
    510511
     512    def set_shift_and_scale(self, indices_or_mask, shift_and_scale_array):
     513        self._shift_and_scale[indices_or_mask] = shift_and_scale_array
     514   
     515    def set_opengl_matrices(self, indices_or_mask, opengl_array):
     516        self._opengl_array[indices_or_mask] = opengl_array
     517   
    511518    def __len__(self):
    512519        if self._place_list is not None:
    513520            n = len(self._place_list)
  • src/core/graphics/drawing.py

    diff --git a/src/core/graphics/drawing.py b/src/core/graphics/drawing.py
    index b11585f..3766fbe 100644
    a b class Drawing:  
    466466    def get_colors(self):
    467467        return self._colors
    468468
    469     def set_colors(self, rgba):
     469    def set_colors(self, rgba, indices_or_mask = None):
    470470        from numpy import ndarray, array, uint8
    471471        c = rgba if isinstance(rgba, ndarray) else array(rgba, uint8)
    472         self._colors = c
     472        if indices_or_mask is None:
     473            self._colors = c
     474        else:
     475            self._colors[indices_or_mask] = c
     476            self._attribute_changes.add('_colors')
    473477        self._opaque_color_count = opaque_count(c)
    474         self.redraw_needed()
    475478
    476479    colors = property(get_colors, set_colors)
    477480    '''Color for each position used when per-vertex coloring is not