structure_set.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:79k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: structure_set.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 18:29:28  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.141
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: structure_set.cpp,v 1000.2 2004/06/01 18:29:28 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Paul Thiessen
  35. *
  36. * File Description:
  37. *      Classes to hold sets of structure data
  38. *
  39. * ===========================================================================
  40. */
  41. #ifdef _MSC_VER
  42. #pragma warning(disable:4018)   // disable signed/unsigned mismatch warning in MSVC
  43. #endif
  44. #include <ncbi_pch.hpp>
  45. #include <corelib/ncbistd.hpp>
  46. #include <corelib/ncbistre.hpp>
  47. #include <corelib/ncbi_limits.h>
  48. #include <corelib/ncbistl.hpp>
  49. #include <deque>
  50. #include <objects/ncbimime/Biostruc_seq.hpp>
  51. #include <objects/ncbimime/Biostruc_seqs.hpp>
  52. #include <objects/ncbimime/Biostruc_align.hpp>
  53. #include <objects/ncbimime/Entrez_general.hpp>
  54. #include <objects/mmdb1/Biostruc_id.hpp>
  55. #include <objects/mmdb1/Mmdb_id.hpp>
  56. #include <objects/mmdb1/Biostruc_descr.hpp>
  57. #include <objects/mmdb2/Biostruc_model.hpp>
  58. #include <objects/mmdb2/Model_type.hpp>
  59. #include <objects/mmdb3/Biostruc_feature.hpp>
  60. #include <objects/mmdb3/Biostruc_feature_id.hpp>
  61. #include <objects/mmdb3/Chem_graph_alignment.hpp>
  62. #include <objects/mmdb3/Transform.hpp>
  63. #include <objects/mmdb3/Move.hpp>
  64. #include <objects/mmdb3/Trans_matrix.hpp>
  65. #include <objects/mmdb3/Rot_matrix.hpp>
  66. #include <objects/mmdb3/Chem_graph_pntrs.hpp>
  67. #include <objects/mmdb3/Residue_pntrs.hpp>
  68. #include <objects/mmdb3/Residue_interval_pntr.hpp>
  69. #include <objects/seqset/Bioseq_set.hpp>
  70. #include <objects/cn3d/Cn3d_style_dictionary.hpp>
  71. #include <objects/cn3d/Cn3d_user_annotations.hpp>
  72. #include <objects/seqalign/Dense_diag.hpp>
  73. #include <objects/seqalign/Dense_seg.hpp>
  74. #include <objects/mmdb3/Biostruc_feature_set_id.hpp>
  75. #include <objects/mmdb1/Molecule_id.hpp>
  76. #include <objects/mmdb1/Residue_id.hpp>
  77. #include <objects/cdd/Reject_id.hpp>
  78. #include <objects/cdd/Update_comment.hpp>
  79. #include "structure_set.hpp"
  80. #include "data_manager.hpp"
  81. #include "coord_set.hpp"
  82. #include "chemical_graph.hpp"
  83. #include "atom_set.hpp"
  84. #include "opengl_renderer.hpp"
  85. #include "show_hide_manager.hpp"
  86. #include "style_manager.hpp"
  87. #include "sequence_set.hpp"
  88. #include "alignment_set.hpp"
  89. #include "alignment_manager.hpp"
  90. #include "messenger.hpp"
  91. #include "asn_converter.hpp"
  92. #include "block_multiple_alignment.hpp"
  93. #include "cn3d_tools.hpp"
  94. #include "molecule_identifier.hpp"
  95. #include "cn3d_cache.hpp"
  96. #include "molecule.hpp"
  97. #include "residue.hpp"
  98. #include "show_hide_dialog.hpp"
  99. #include <objseq.h>
  100. USING_NCBI_SCOPE;
  101. USING_SCOPE(objects);
  102. BEGIN_SCOPE(Cn3D)
  103. const unsigned int
  104.     StructureSet::ePSSMData                   = 0x01,
  105.     StructureSet::eRowOrderData               = 0x02,
  106.     StructureSet::eAnyAlignmentData           = 0x04,
  107.     StructureSet::eStructureAlignmentData     = 0x08,
  108.     StructureSet::eSequenceData               = 0x10,
  109.     StructureSet::eUpdateData                 = 0x20,
  110.     StructureSet::eStyleData                  = 0x40,
  111.     StructureSet::eUserAnnotationData         = 0x80,
  112.     StructureSet::eCDDData                    = 0x100,
  113.     StructureSet::eOtherData                  = 0x200;
  114. StructureSet::StructureSet(CNcbi_mime_asn1 *mime, int structureLimit, OpenGLRenderer *r) :
  115.     StructureBase(NULL), renderer(r)
  116. {
  117.     dataManager = new ASNDataManager(mime);
  118.     Load(structureLimit);
  119. }
  120. StructureSet::StructureSet(CCdd *cdd, int structureLimit, OpenGLRenderer *r) :
  121.     StructureBase(NULL), renderer(r)
  122. {
  123.     dataManager = new ASNDataManager(cdd);
  124.     Load(structureLimit);
  125. }
  126. void StructureSet::LoadSequencesForSingleStructure(void)
  127. {
  128.     sequenceSet = new SequenceSet(this, *(dataManager->GetSequences()));
  129.     if (objects.size() > 1)
  130.         ERRORMSG("LoadSequencesForSingleStructure() called, but there is > 1 structure");
  131.     if (objects.size() != 1) return;
  132.     // look for biopolymer molecules
  133.     ChemicalGraph::MoleculeMap::const_iterator m, me = objects.front()->graph->molecules.end();
  134.     SequenceSet::SequenceList::const_iterator s, se = sequenceSet->sequences.end();
  135.     for (m=objects.front()->graph->molecules.begin(); m!=me; ++m) {
  136.         if (!m->second->IsProtein() && !m->second->IsNucleotide()) continue;
  137.         // find matching sequence for each biopolymer
  138.         for (s=sequenceSet->sequences.begin(); s!=se; ++s) {
  139.             if ((*s)->molecule != NULL) continue; // skip already-matched sequences
  140.             if (m->second->identifier == (*s)->identifier) {
  141.                 // verify length
  142.                 if (m->second->residues.size() != (*s)->Length()) {
  143.                     ERRORMSG(
  144.                         "LoadSequencesForSingleStructure() - length mismatch between sequence gi "
  145.                         << "and matching molecule " << m->second->identifier->ToString());
  146.                     continue;
  147.                 }
  148.                 TRACEMSG("matched sequence " << " gi " << (*s)->identifier->gi << " with object "
  149.                     << objects.front()->pdbID << " moleculeID " << m->second->id);
  150.                 (const_cast<Molecule*>(m->second))->sequence = *s;
  151.                 (const_cast<Sequence*>(*s))->molecule = m->second;
  152.                 break;
  153.             }
  154.         }
  155.         if (s == se)
  156.             ERRORMSG("LoadSequencesForSingleStructure() - can't find sequence for molecule "
  157.                 << m->second->identifier->ToString());
  158.     }
  159. }
  160. bool StructureSet::LoadMaster(int masterMMDBID)
  161. {
  162.     if (objects.size() > 0) return false;
  163.     TRACEMSG("loading master " << masterMMDBID);
  164.     if (dataManager->GetMasterStructure()) {
  165.         objects.push_back(new StructureObject(this, *(dataManager->GetMasterStructure()), true));
  166.         if (masterMMDBID != MoleculeIdentifier::VALUE_NOT_SET && objects.front()->mmdbID != masterMMDBID)
  167.             ERRORMSG("StructureSet::LoadMaster() - mismatched master MMDB ID");
  168.     } else if (masterMMDBID != MoleculeIdentifier::VALUE_NOT_SET && dataManager->GetStructureList()) {
  169.         ASNDataManager::BiostrucList::const_iterator b, be = dataManager->GetStructureList()->end();
  170.         for (b=dataManager->GetStructureList()->begin(); b!=be; ++b) {
  171.             if ((*b)->GetId().front()->IsMmdb_id() &&
  172.                 (*b)->GetId().front()->GetMmdb_id().Get() == masterMMDBID) {
  173.                 objects.push_back(new StructureObject(this, **b, true));
  174.                 usedStructures[b->GetPointer()] = true;
  175.                 break;
  176.             }
  177.         }
  178.     }
  179.     if (masterMMDBID != MoleculeIdentifier::VALUE_NOT_SET && objects.size() == 0) {
  180.         CRef < CBiostruc > biostruc;
  181.         wxString id;
  182.         id.Printf("%i", masterMMDBID);
  183.         if (LoadStructureViaCache(id.c_str(), dataManager->GetBiostrucModelType(), biostruc, NULL))
  184.             objects.push_back(new StructureObject(this, *biostruc, true));
  185.     }
  186.     return (objects.size() > 0);
  187. }
  188. bool StructureSet::MatchSequenceToMoleculeInObject(const Sequence *seq,
  189.     const StructureObject *obj, const Sequence **seqHandle)
  190. {
  191.     ChemicalGraph::MoleculeMap::const_iterator m, me = obj->graph->molecules.end();
  192.     for (m=obj->graph->molecules.begin(); m!=me; ++m) {
  193.         if (!(m->second->IsProtein() || m->second->IsNucleotide())) continue;
  194.         if (m->second->identifier == seq->identifier) {
  195.             // verify length
  196.             if (m->second->residues.size() != seq->Length()) {
  197.                 ERRORMSG(
  198.                     "MatchSequenceToMoleculeInObject() - length mismatch between sequence gi "
  199.                     << "and matching molecule " << m->second->identifier->ToString());
  200.                 continue;
  201.             }
  202.             TRACEMSG("matched sequence " << " gi " << seq->identifier->gi << " with object "
  203.                 << obj->pdbID << " moleculeID " << m->second->id);
  204.             // sanity check
  205.             if (m->second->sequence) {
  206.                 ERRORMSG("Molecule " << m->second->identifier->ToString()
  207.                     << " already has an associated sequence");
  208.                 continue;
  209.             }
  210.             // automatically duplicate Sequence if it's already associated with a molecule
  211.             if (seq->molecule) {
  212.                 TRACEMSG("duplicating sequence " << seq->identifier->ToString());
  213. SequenceSet *seqSetMod = const_cast<SequenceSet*>(sequenceSet);
  214.                 CBioseq& bioseqMod = const_cast<CBioseq&>(seq->bioseqASN.GetObject());
  215.                 seq = new Sequence(seqSetMod, bioseqMod);
  216.                 seqSetMod->sequences.push_back(seq);
  217.                 // update Sequence handle, which should be a handle to a MasterSlaveAlignment slave,
  218.                 // so that this new Sequence* is correctly loaded into the BlockMultipleAlignment
  219.                 if (seqHandle) *seqHandle = seq;
  220.             }
  221.             // do the cross-match
  222.             (const_cast<Molecule*>(m->second))->sequence = seq;
  223.             (const_cast<Sequence*>(seq))->molecule = m->second;
  224.             break;
  225.         }
  226.     }
  227.     return (m != me);
  228. }
  229. static void SetStructureRowFlags(const AlignmentSet *alignmentSet, int *structureLimit,
  230.     vector < bool > *dontLoadRowStructure)
  231. {
  232.     vector < string > titles;
  233.     vector < int > rows;
  234.     // find slave rows with associated structure
  235.     AlignmentSet::AlignmentList::const_iterator l, le = alignmentSet->alignments.end();
  236.     int row;
  237.     for (l=alignmentSet->alignments.begin(), row=0; l!=le; ++l, ++row) {
  238.         if ((*l)->slave->identifier->mmdbID != MoleculeIdentifier::VALUE_NOT_SET) {
  239.             titles.push_back((*l)->slave->identifier->ToString());
  240.             rows.push_back(row);
  241.         }
  242.     }
  243.     if (*structureLimit - 1 >= titles.size()) return;
  244.     // let user select which slaves to load
  245.     wxString *items = new wxString[titles.size()];
  246.     vector < bool > itemsOn(titles.size(), false);
  247.     for (row=0; row<titles.size(); ++row) {
  248.         items[row] = titles[row].c_str();
  249.         if (row < *structureLimit - 1)      // by default, first N-1 are selected
  250.             itemsOn[row] = true;
  251.     }
  252.     ShowHideDialog dialog(items, &itemsOn, NULL, true, NULL, -1, "Choose structures:");
  253.     if (dialog.ShowModal() == wxOK) {
  254.         // figure out which rows the user selected, and adjust structureLimit accordingly
  255.         *structureLimit = 1;     // master always visible
  256.         for (row=0; row<itemsOn.size(); ++row) {
  257.             if (itemsOn[row])
  258.                 (*structureLimit)++;                        // structure should be loaded
  259.             else
  260.                 (*dontLoadRowStructure)[rows[row]] = true;  // structure should not be loaded
  261.         }
  262.     }
  263.     delete[] items;
  264. }
  265. void StructureSet::LoadAlignmentsAndStructures(int structureLimit)
  266. {
  267.     // try to determine the master structure
  268.     int masterMMDBID = MoleculeIdentifier::VALUE_NOT_SET;
  269.     // explicit master structure
  270.     if (dataManager->GetMasterStructure() &&
  271.         dataManager->GetMasterStructure()->GetId().front()->IsMmdb_id())
  272.         masterMMDBID = dataManager->GetMasterStructure()->GetId().front()->GetMmdb_id().Get();
  273.     // master of structure alignments
  274.     else if (dataManager->GetStructureAlignments() &&
  275.                 dataManager->GetStructureAlignments()->IsSetId() &&
  276.                 dataManager->GetStructureAlignments()->GetId().front()->IsMmdb_id())
  277.         masterMMDBID = dataManager->GetStructureAlignments()->GetId().front()->GetMmdb_id().Get();
  278.     // SPECIAL CASE: if there's no explicit master structure, but there is a structure
  279.     // list that contains a single structure, then assume that it is the master structure
  280.     else if (dataManager->GetStructureList() &&
  281.                 dataManager->GetStructureList()->size() == 1 &&
  282.                 dataManager->GetStructureList()->front()->GetId().front()->IsMmdb_id())
  283.         masterMMDBID = dataManager->GetStructureList()->front()->GetId().front()->GetMmdb_id().Get();
  284.     // assume data manager has already screened the alignment list
  285.     ASNDataManager::SeqAnnotList *alignments = dataManager->GetSequenceAlignments();
  286.     typedef list < CRef < CSeq_align > > SeqAlignList;
  287.     const SeqAlignList& seqAligns = alignments->front()->GetData().GetAlign();
  288.     // we need to determine the identity of the master sequence; most rigorous way is to look
  289.     // for a Seq-id that is present in all pairwise alignments
  290.     const Sequence *seq1 = NULL, *seq2 = NULL, *master = NULL;
  291.     bool seq1PresentInAll = true, seq2PresentInAll = true;
  292.     // first, find sequences for first pairwise alignment
  293.     const CSeq_id& frontSid = seqAligns.front()->GetSegs().IsDendiag() ?
  294.         seqAligns.front()->GetSegs().GetDendiag().front()->GetIds().front().GetObject() :
  295.         seqAligns.front()->GetSegs().GetDenseg().GetIds().front().GetObject();
  296.     const CSeq_id& backSid = seqAligns.front()->GetSegs().IsDendiag() ?
  297.         seqAligns.front()->GetSegs().GetDendiag().front()->GetIds().back().GetObject() :
  298.         seqAligns.front()->GetSegs().GetDenseg().GetIds().back().GetObject();
  299.     SequenceSet::SequenceList::const_iterator s, se = sequenceSet->sequences.end();
  300.     for (s=sequenceSet->sequences.begin(); s!=se; ++s) {
  301.         if ((*s)->identifier->MatchesSeqId(frontSid)) seq1 = *s;
  302.         if ((*s)->identifier->MatchesSeqId(backSid)) seq2 = *s;
  303.         if (seq1 && seq2) break;
  304.     }
  305.     if (!(seq1 && seq2)) {
  306.         ERRORMSG("Can't match first pair of Seq-ids to Sequences");
  307.         return;
  308.     }
  309.     // now, make sure one of these sequences is present in all the other pairwise alignments
  310.     SeqAlignList::const_iterator a = seqAligns.begin(), ae = seqAligns.end();
  311.     for (++a; a!=ae; ++a) {
  312.         const CSeq_id& frontSid2 = (*a)->GetSegs().IsDendiag() ?
  313.             (*a)->GetSegs().GetDendiag().front()->GetIds().front().GetObject() :
  314.             (*a)->GetSegs().GetDenseg().GetIds().front().GetObject();
  315.         const CSeq_id& backSid2 = (*a)->GetSegs().IsDendiag() ?
  316.             (*a)->GetSegs().GetDendiag().front()->GetIds().back().GetObject() :
  317.             (*a)->GetSegs().GetDenseg().GetIds().back().GetObject();
  318.         if (!seq1->identifier->MatchesSeqId(frontSid2) && !seq1->identifier->MatchesSeqId(backSid2))
  319.             seq1PresentInAll = false;
  320.         if (!seq2->identifier->MatchesSeqId(frontSid2) && !seq2->identifier->MatchesSeqId(backSid2))
  321.             seq2PresentInAll = false;
  322.     }
  323.     if (!seq1PresentInAll && !seq2PresentInAll) {
  324.         ERRORMSG("All pairwise sequence alignments must have a common master sequence");
  325.         return;
  326.     } else if (seq1PresentInAll && !seq2PresentInAll)
  327.         master = seq1;
  328.     else if (seq2PresentInAll && !seq1PresentInAll)
  329.         master = seq2;
  330.     else if (seq1PresentInAll && seq2PresentInAll && seq1 == seq2)
  331.         master = seq1;
  332.     // if still ambiguous, see if master3d is set in CDD data
  333.     if (!master && dataManager->GetCDDMaster3d()) {
  334.         if (seq1->identifier->MatchesSeqId(*(dataManager->GetCDDMaster3d())))
  335.             master = seq1;
  336.         else if (seq2->identifier->MatchesSeqId(*(dataManager->GetCDDMaster3d())))
  337.             master = seq2;
  338.         else
  339.             ERRORMSG("Unable to match CDD's master3d with either sequence in first pairwise alignment");
  340.     }
  341.     // if still ambiguous, try to use master structure info to find master sequence
  342.     if (!master && masterMMDBID != MoleculeIdentifier::VALUE_NOT_SET) {
  343.         // load master - has side affect of matching gi's with PDB/molecule ID during graph evaluation
  344.         if (structureLimit > 0)
  345.             LoadMaster(masterMMDBID);
  346.         // see if there's a sequence in the master structure that matches
  347.         if (seq1->identifier->mmdbID != MoleculeIdentifier::VALUE_NOT_SET &&
  348.             seq1->identifier->mmdbID != seq2->identifier->mmdbID) {
  349.             if (masterMMDBID == seq1->identifier->mmdbID)
  350.                 master = seq1;
  351.             else if (masterMMDBID == seq2->identifier->mmdbID)
  352.                 master = seq2;
  353.             else {
  354.                 ERRORMSG("Structure master does not contain either sequence in first pairwise alignment");
  355.                 return;
  356.             }
  357.         }
  358.     }
  359.     // if still ambiguous, just use the first one
  360.     if (!master) {
  361.         WARNINGMSG("Ambiguous master; using " << seq1->identifier->ToString());
  362.         master = seq1;
  363.     }
  364.     TRACEMSG("determined that master sequence is " << master->identifier->ToString());
  365.     // load alignments now that we know the identity of the master
  366.     alignmentSet = new AlignmentSet(this, master, *(dataManager->GetSequenceAlignments()));
  367.     // check mmdb id's and load master if not already present (and if master has structure)
  368.     if (masterMMDBID == MoleculeIdentifier::VALUE_NOT_SET) {
  369.         masterMMDBID = master->identifier->mmdbID;
  370.     } else if (master->identifier->mmdbID != MoleculeIdentifier::VALUE_NOT_SET &&
  371.                master->identifier->mmdbID != masterMMDBID) {
  372.         ERRORMSG("master structure (" << masterMMDBID <<
  373.             ") disagrees with master sequence (apparently from " << master->identifier->mmdbID << ')');
  374.         return;
  375.     }
  376.     if (objects.size() == 0 && structureLimit > 0 && masterMMDBID != MoleculeIdentifier::VALUE_NOT_SET &&
  377.             master->identifier->accession != "consensus")   // special case for looking at "raw" CD's
  378.         LoadMaster(masterMMDBID);
  379.     // cross-match master sequence and structure
  380.     if (objects.size() == 1 && !MatchSequenceToMoleculeInObject(master, objects.front())) {
  381.         ERRORMSG("MatchSequenceToMoleculeInObject() - can't find molecule in object "
  382.             << objects.front()->pdbID << " to match master sequence "
  383.             << master->identifier->ToString());
  384.         return;
  385.     }
  386.     // IFF there's a master structure, then also load slave structures and cross-match sequences
  387.     if (objects.size() == 1 && structureLimit > 1) {
  388.         ASNDataManager::BiostrucList::const_iterator b, be;
  389.         if (dataManager->GetStructureList()) be = dataManager->GetStructureList()->end();
  390.         int row;
  391.         vector < bool > loadedStructureForSlaveRow(alignmentSet->alignments.size(), false);
  392.         // first, load each remaining slave structure, and for each one, find the first slave
  393.         // sequence that matches it (and that doesn't already have structure)
  394.         AlignmentSet::AlignmentList::const_iterator l, le = alignmentSet->alignments.end();
  395.         if (dataManager->GetStructureList()) {
  396.             for (b=dataManager->GetStructureList()->begin(); b!=be && objects.size()<structureLimit; ++b) {
  397.                 // load structure
  398.                 if (usedStructures.find(b->GetPointer()) != usedStructures.end()) continue;
  399.                 StructureObject *object = new StructureObject(this, **b, false);
  400.                 objects.push_back(object);
  401.                 if (dataManager->GetStructureAlignments())
  402.                     object->SetTransformToMaster(
  403.                         *(dataManager->GetStructureAlignments()), master->identifier->mmdbID);
  404.                 usedStructures[b->GetPointer()] = true;
  405.                 // find matching unstructured slave sequence
  406.                 for (l=alignmentSet->alignments.begin(), row=0; l!=le; ++l, ++row) {
  407.                     if (loadedStructureForSlaveRow[row]) continue;
  408.                     if (MatchSequenceToMoleculeInObject((*l)->slave, object,
  409.                             &((const_cast<MasterSlaveAlignment*>(*l))->slave))) {
  410.                         loadedStructureForSlaveRow[row] = true;
  411.                         break;
  412.                     }
  413.                 }
  414.                 if (l == le)
  415.                     ERRORMSG("Warning: Structure " << object->pdbID
  416.                         << " doesn't have a matching slave sequence in the multiple alignment");
  417.             }
  418.         }
  419.         // now loop through slave rows of the alignment; if the slave
  420.         // sequence has an MMDB ID but no structure yet, then load it.
  421.         if (objects.size() < structureLimit && (dataManager->IsCDD() || dataManager->IsGeneralMime())) {
  422.             // for CDD's, ask user which structures to load if structureLimit is low
  423.             if (dataManager->IsCDD())
  424.                 SetStructureRowFlags(alignmentSet, &structureLimit, &loadedStructureForSlaveRow);
  425.             for (l=alignmentSet->alignments.begin(), row=0; l!=le && objects.size()<structureLimit; ++l, ++row) {
  426.                 if ((*l)->slave->identifier->mmdbID != MoleculeIdentifier::VALUE_NOT_SET &&
  427.                     !loadedStructureForSlaveRow[row]) {
  428.                     // first check the biostruc list to see if this structure is present already
  429.                     CRef < CBiostruc > biostruc;
  430.                     if (dataManager->GetStructureList()) {
  431.                         for (b=dataManager->GetStructureList()->begin(); b!=be ; ++b) {
  432.                             if ((*b)->GetId().front()->IsMmdb_id() &&
  433.                                 (*b)->GetId().front()->GetMmdb_id().Get() == (*l)->slave->identifier->mmdbID) {
  434.                                 biostruc = *b;
  435.                                 break;
  436.                             }
  437.                         }
  438.                     }
  439.                     // if not in list, load Biostruc via HTTP/cache
  440.                     if (biostruc.Empty()) {
  441.                         wxString id;
  442.                         id.Printf("%i", (*l)->slave->identifier->mmdbID);
  443.                         if (!LoadStructureViaCache(id.c_str(),
  444.                                 dataManager->GetBiostrucModelType(), biostruc, NULL)) {
  445.                             ERRORMSG("Failed to load MMDB #" << (*l)->slave->identifier->mmdbID);
  446.                             continue;
  447.                         }
  448.                     }
  449.                     // create StructureObject and cross-match
  450.                     StructureObject *object = new StructureObject(this, *biostruc, false);
  451.                     objects.push_back(object);
  452.                     if (dataManager->GetStructureAlignments())
  453.                         object->SetTransformToMaster(
  454.                             *(dataManager->GetStructureAlignments()), master->identifier->mmdbID);
  455.                     if (!MatchSequenceToMoleculeInObject((*l)->slave, object,
  456.                             &((const_cast<MasterSlaveAlignment*>(*l))->slave)))
  457.                         ERRORMSG("Failed to match any molecule in structure " << object->pdbID
  458.                             << " with sequence " << (*l)->slave->identifier->ToString());
  459.                     loadedStructureForSlaveRow[row] = true;
  460.                 }
  461.             }
  462.         }
  463.     }
  464. }
  465. void StructureSet::Load(int structureLimit)
  466. {
  467.     // member data initialization
  468.     lastAtomName = OpenGLRenderer::NO_NAME;
  469.     lastDisplayList = OpenGLRenderer::NO_LIST;
  470.     sequenceSet = NULL;
  471.     alignmentSet = NULL;
  472.     alignmentManager = NULL;
  473.     nDomains = 0;
  474.     isAlphaOnly = false;
  475.     parentSet = this;
  476.     showHideManager = new ShowHideManager();
  477.     styleManager = new StyleManager(this);
  478.     havePrevPickedAtomCoord = false;
  479.     hasUserStyle = false;
  480.     // if this is a single structure, then there should be one sequence per biopolymer
  481.     if (dataManager->IsSingleStructure()) {
  482.         const CBiostruc *masterBiostruc = dataManager->GetMasterStructure();
  483.         if (!masterBiostruc && dataManager->GetStructureList() && dataManager->GetStructureList()->size() == 1)
  484.             masterBiostruc = dataManager->GetStructureList()->front().GetPointer();
  485.         if (masterBiostruc)
  486.             objects.push_back(new StructureObject(this, *masterBiostruc, true));
  487.         if (dataManager->GetSequences())
  488.             LoadSequencesForSingleStructure();
  489.     }
  490.     // multiple structure: should have exactly one sequence per structure (plus unstructured sequences)
  491.     else {
  492.         if (!dataManager->GetSequences() || !dataManager->GetSequenceAlignments()) {
  493.             ERRORMSG("Data interpreted as multiple alignment, "
  494.                 "but missing sequences and/or sequence alignments");
  495.             return;
  496.         }
  497.         sequenceSet = new SequenceSet(this, *(dataManager->GetSequences()));
  498.         LoadAlignmentsAndStructures(structureLimit);
  499.     }
  500.     // find center of coordinates
  501.     SetCenter();
  502.     // create alignment manager
  503.     if (sequenceSet) {
  504.         if (dataManager->GetUpdates())
  505.             // if updates present, alignment manager will load those into update viewer
  506.             alignmentManager = new AlignmentManager(sequenceSet, alignmentSet, *(dataManager->GetUpdates()));
  507.         else
  508.             alignmentManager = new AlignmentManager(sequenceSet, alignmentSet);
  509.     }
  510. #ifdef _DEBUG
  511.     VerifyFrameMap();
  512. #endif
  513.     // setup show/hide items
  514.     showHideManager->ConstructShowHideArray(this);
  515.     // alignments always start with aligned domains only
  516.     if (alignmentSet)
  517.         showHideManager->ShowAlignedDomains(this);
  518.     // load style dictionary and user annotations
  519.     const CCn3d_style_dictionary *styles = dataManager->GetStyleDictionary();
  520.     if (styles) {
  521.         if (!styleManager->LoadFromASNStyleDictionary(*styles) ||
  522.             !styleManager->CheckGlobalStyleSettings())
  523.             ERRORMSG("Error loading style dictionary");
  524.         dataManager->RemoveStyleDictionary();   // remove now; recreated with current settings upon save
  525.         hasUserStyle = true;
  526.     }
  527.     const CCn3d_user_annotations *annots = dataManager->GetUserAnnotations();
  528.     if (annots) {
  529.         if (!styleManager->LoadFromASNUserAnnotations(*annots) ||
  530.             !renderer->LoadFromASNViewSettings(*annots))
  531.             ERRORMSG("Error loading user annotations or camera settings");
  532.         dataManager->RemoveUserAnnotations();   // remove now; recreated with current settings upon save
  533.     }
  534.     dataManager->SetDataUnchanged();
  535. }
  536. StructureSet::~StructureSet(void)
  537. {
  538.     delete dataManager;
  539.     delete showHideManager;
  540.     delete styleManager;
  541.     if (alignmentManager) delete alignmentManager;
  542.     GlobalMessenger()->RemoveAllHighlights(false);
  543.     MoleculeIdentifier::ClearIdentifiers();
  544.     BioseqMap::iterator i, ie = bioseqs.end();
  545.     for (i=bioseqs.begin(); i!=ie; ++i) BioseqFree(i->second);
  546. }
  547. BioseqPtr StructureSet::GetOrCreateBioseq(const Sequence *sequence)
  548. {
  549.     if (!sequence || !sequence->isProtein) {
  550.         ERRORMSG("StructureSet::GetOrCreateBioseq() - got non-protein or NULL Sequence");
  551.         return NULL;
  552.     }
  553.     // if already done
  554.     BioseqMap::const_iterator b = bioseqs.find(sequence);
  555.     if (b != bioseqs.end()) return b->second;
  556.     // create new Bioseq and fill it in from Sequence data
  557.     BioseqPtr bioseq = BioseqNew();
  558.     bioseq->mol = Seq_mol_aa;
  559.     bioseq->seq_data_type = Seq_code_ncbieaa;
  560.     bioseq->repr = Seq_repr_raw;
  561.     bioseq->length = sequence->Length();
  562.     bioseq->seq_data = BSNew(bioseq->length);
  563.     BSWrite(bioseq->seq_data, const_cast<char*>(sequence->sequenceString.c_str()), bioseq->length);
  564.     // create Seq-id
  565.     sequence->AddCSeqId(&(bioseq->id), true);
  566.     // store Bioseq
  567.     bioseqs[sequence] = bioseq;
  568.     return bioseq;
  569. }
  570. void StructureSet::CreateAllBioseqs(const BlockMultipleAlignment *multiple)
  571. {
  572.     for (int row=0; row<multiple->NRows(); ++row)
  573.         GetOrCreateBioseq(multiple->GetSequenceOfRow(row));
  574. }
  575. bool StructureSet::AddBiostrucToASN(ncbi::objects::CBiostruc *biostruc)
  576. {
  577.     bool added = dataManager->AddBiostrucToASN(biostruc);
  578.     if (added && objects.size() == 1)
  579.         InitStructureAlignments(objects.front()->mmdbID);
  580.     return added;
  581. }
  582. static const int NO_DOMAIN = -1, MULTI_DOMAIN = 0;
  583. void StructureSet::InitStructureAlignments(int masterMMDBID)
  584. {
  585.     // create or empty the Biostruc-annot-set that will contain these alignments
  586.     // in the asn data, erasing any structure alignments currently stored there
  587.     CBiostruc_annot_set *structureAlignments = dataManager->GetStructureAlignments();
  588.     if (structureAlignments) {
  589.         structureAlignments->SetId().clear();
  590.         structureAlignments->SetDescr().clear();
  591.         structureAlignments->SetFeatures().clear();
  592.     } else {
  593.         structureAlignments = new CBiostruc_annot_set();
  594.         dataManager->SetStructureAlignments(structureAlignments);
  595.     }
  596.     // set up the skeleton of the new Biostruc-annot-set
  597.     // new Mmdb-id
  598.     structureAlignments->SetId().resize(1);
  599.     structureAlignments->SetId().front().Reset(new CBiostruc_id());
  600.     CMmdb_id *mid = new CMmdb_id(masterMMDBID);
  601.     structureAlignments->SetId().front().GetObject().SetMmdb_id(*mid);
  602.     // new Biostruc-feature-set
  603.     CRef<CBiostruc_feature_set> featSet(new CBiostruc_feature_set());
  604.     featSet->SetId().Set(NO_DOMAIN);
  605.     featSet->SetFeatures();    // just create an empty list
  606.     structureAlignments->SetFeatures().resize(1, featSet);
  607.     // flag a change in data
  608.     SetDataChanged(eStructureAlignmentData);
  609. }
  610. void StructureSet::AddStructureAlignment(CBiostruc_feature *feature,
  611.     int masterDomainID, int slaveDomainID)
  612. {
  613.     CBiostruc_annot_set *structureAlignments = dataManager->GetStructureAlignments();
  614.     if (!structureAlignments) {
  615.         WARNINGMSG("StructureSet::AddStructureAlignment() - creating new structure alignment list");
  616.         InitStructureAlignments(objects.front()->mmdbID);
  617.         structureAlignments = dataManager->GetStructureAlignments();
  618.     }
  619.     // check master domain ID, to see if alignments have crossed master's domain boundaries
  620.     int *currentMasterDomainID = &(structureAlignments->SetFeatures().front().GetObject().SetId().Set());
  621.     if (*currentMasterDomainID == NO_DOMAIN)
  622.         *currentMasterDomainID = masterDomainID;
  623.     else if ((*currentMasterDomainID % 100) != (masterDomainID % 100))
  624.         *currentMasterDomainID = (*currentMasterDomainID / 100) * 100;
  625.     // check to see if this slave domain already has an alignment; if so, increment alignment #
  626.     CBiostruc_feature_set::TFeatures::const_iterator
  627.         f, fe = structureAlignments->GetFeatures().front().GetObject().GetFeatures().end();
  628.     for (f=structureAlignments->GetFeatures().front().GetObject().GetFeatures().begin(); f!=fe; ++f) {
  629.         if ((f->GetObject().GetId().Get() / 10) == (slaveDomainID / 10))
  630.             ++slaveDomainID;
  631.     }
  632.     CBiostruc_feature_id id(slaveDomainID);
  633.     feature->SetId(id);
  634.     CRef<CBiostruc_feature> featureRef(feature);
  635.     structureAlignments->SetFeatures().front().GetObject().SetFeatures().resize(
  636.         structureAlignments->GetFeatures().front().GetObject().GetFeatures().size() + 1, featureRef);
  637.     // flag a change in data
  638.     SetDataChanged(eStructureAlignmentData);
  639. }
  640. void StructureSet::RemoveStructureAlignments(void)
  641. {
  642.     dataManager->SetStructureAlignments(NULL);
  643.     // flag a change in data
  644.     SetDataChanged(eStructureAlignmentData);
  645. }
  646. void StructureSet::ReplaceAlignmentSet(AlignmentSet *newAlignmentSet)
  647. {
  648.     ASNDataManager::SeqAnnotList *seqAnnots = dataManager->GetOrCreateSequenceAlignments();
  649.     if (!seqAnnots) {
  650.         ERRORMSG("StructureSet::ReplaceAlignmentSet() - "
  651.             << "can't figure out where in the asn the alignments are to go");
  652.         return;
  653.     }
  654.     // update the AlignmentSet
  655.     if (alignmentSet) {
  656.         _RemoveChild(alignmentSet);
  657.         delete alignmentSet;
  658.     }
  659.     alignmentSet = newAlignmentSet;
  660.     // update the asn alignments
  661.     seqAnnots->resize(alignmentSet->newAsnAlignmentData->size());
  662.     ASNDataManager::SeqAnnotList::iterator o = seqAnnots->begin();
  663.     ASNDataManager::SeqAnnotList::iterator n, ne = alignmentSet->newAsnAlignmentData->end();
  664.     for (n=alignmentSet->newAsnAlignmentData->begin(); n!=ne; ++n, ++o)
  665.         o->Reset(n->GetPointer());   // copy each Seq-annot CRef
  666.     // don't set data PSSM/row order flags here; done by AlignmentManager::SavePairwiseFromMultiple()
  667.     SetDataChanged(eAnyAlignmentData);
  668. }
  669. void StructureSet::ReplaceUpdates(ncbi::objects::CCdd::TPending& newUpdates)
  670. {
  671.     dataManager->ReplaceUpdates(newUpdates);
  672. }
  673. void StructureSet::RemoveUnusedSequences(void)
  674. {
  675. ASNDataManager::SequenceList updateSequences;
  676.     if (alignmentManager) alignmentManager->GetUpdateSequences(&updateSequences);
  677.     dataManager->RemoveUnusedSequences(alignmentSet, updateSequences);
  678. }
  679. bool StructureSet::SaveASNData(const char *filename, bool doBinary, unsigned int *changeFlags)
  680. {
  681.     // force a save of any edits to alignment and updates first (it's okay if this has already been done)
  682.     GlobalMessenger()->SequenceWindowsSave(true);
  683.     /*if (dataManager->HasDataChanged())*/ RemoveUnusedSequences();
  684.     // create and temporarily attach a style dictionary, and annotation set + camera info
  685.     // to the data (and then remove it again, so it's never out of date)
  686.     CRef < CCn3d_style_dictionary > styleDictionary(styleManager->CreateASNStyleDictionary());
  687.     dataManager->SetStyleDictionary(*styleDictionary);
  688.     CRef < CCn3d_user_annotations > userAnnotations(new CCn3d_user_annotations());
  689.     if (!styleManager->SaveToASNUserAnnotations(userAnnotations.GetPointer()) ||
  690.         (objects.size() >= 1 && !renderer->SaveToASNViewSettings(userAnnotations.GetPointer()))) {
  691.         ERRORMSG("StructureSet::SaveASNData() - error creating user annotations blob");
  692.         return false;
  693.     }
  694.     if (userAnnotations->IsSetAnnotations() || userAnnotations->IsSetView())
  695.         dataManager->SetUserAnnotations(*userAnnotations);
  696.     string err;
  697.     bool writeOK = dataManager->WriteDataToFile(filename, doBinary, &err, eFNP_Replace);
  698.     // remove style dictionary and annotations from asn
  699.     dataManager->RemoveStyleDictionary();
  700.     dataManager->RemoveUserAnnotations();
  701.     if (writeOK) {
  702.         *changeFlags = dataManager->GetDataChanged();
  703.         dataManager->SetDataUnchanged();
  704.     } else {
  705.         ERRORMSG("Write failed: " << err);
  706.     }
  707.     return writeOK;
  708. }
  709. // because the frame map (for each frame, a list of diplay lists) is complicated
  710. // to create, this just verifies that all display lists occur exactly once
  711. // in the map. Also, make sure that total # display lists in all frames adds up.
  712. void StructureSet::VerifyFrameMap(void) const
  713. {
  714.     for (unsigned int l=OpenGLRenderer::FIRST_LIST; l<=lastDisplayList; ++l) {
  715.         bool found = false;
  716.         for (unsigned int f=0; f<frameMap.size(); ++f) {
  717.             DisplayLists::const_iterator d, de=frameMap[f].end();
  718.             for (d=frameMap[f].begin(); d!=de; ++d) {
  719.                 if (*d == l) {
  720.                     if (!found)
  721.                         found = true;
  722.                     else
  723.                         ERRORMSG("frameMap: repeated display list " << l);
  724.                 }
  725.             }
  726.         }
  727.         if (!found)
  728.             ERRORMSG("display list " << l << " not in frameMap");
  729.     }
  730.     unsigned int nLists = 0;
  731.     for (unsigned int f=0; f<frameMap.size(); ++f) {
  732.         DisplayLists::const_iterator d, de=frameMap[f].end();
  733.         for (d=frameMap[f].begin(); d!=de; ++d) ++nLists;
  734.     }
  735.     if (nLists != lastDisplayList)
  736.         ERRORMSG("frameMap has too many display lists");
  737. }
  738. void StructureSet::SetCenter(const Vector *given)
  739. {
  740.     Vector siteSum;
  741.     int nAtoms = 0;
  742.     double dist;
  743.     maxDistFromCenter = 0.0;
  744.     // set new center if given one
  745.     if (given) center = *given;
  746.     // loop trough all atoms twice - once to get average center, then once to
  747.     // find max distance from this center
  748.     for (int i=0; i<2; ++i) {
  749.         if (given && i==0) continue; // skip center calculation if given one
  750.         ObjectList::const_iterator o, oe=objects.end();
  751.         for (o=objects.begin(); o!=oe; ++o) {
  752.             StructureObject::CoordSetList::const_iterator c, ce=(*o)->coordSets.end();
  753.             for (c=(*o)->coordSets.begin(); c!=ce; ++c) {
  754.                 AtomSet::AtomMap::const_iterator a, ae=(*c)->atomSet->atomMap.end();
  755.                 for (a=(*c)->atomSet->atomMap.begin(); a!=ae; ++a) {
  756.                     Vector site(a->second.front()->site);
  757.                     if ((*o)->IsSlave() && (*o)->transformToMaster)
  758.                         ApplyTransformation(&site, *((*o)->transformToMaster));
  759.                     if (i==0) {
  760.                         siteSum += site;
  761.                         ++nAtoms;
  762.                     } else {
  763.                         dist = (site - center).length();
  764.                         if (dist > maxDistFromCenter)
  765.                             maxDistFromCenter = dist;
  766.                     }
  767.                 }
  768.             }
  769.         }
  770.         if (i==0) {
  771.             if (nAtoms == 0) {
  772.                 center.Set(0.0, 0.0, 0.0);
  773.                 break;
  774.             }
  775.             center = siteSum / nAtoms;
  776.         }
  777.     }
  778.     TRACEMSG("center: " << center << ", maxDistFromCenter " << maxDistFromCenter);
  779.     rotationCenter = center;
  780. }
  781. void StructureSet::CenterViewOnAlignedResidues(void)
  782. {
  783.     const BlockMultipleAlignment *alignment = alignmentManager->GetCurrentMultipleAlignment();
  784.     if (!alignment || !alignment->GetSequenceOfRow(0) || !alignment->GetSequenceOfRow(0))
  785.         return;                     // no alignment
  786.     const Molecule *masterMolecule = alignment->GetSequenceOfRow(0)->molecule;
  787.     if (!masterMolecule) return;    // no structured master
  788.     const StructureObject *masterObject;
  789.     if (!masterMolecule->GetParentOfType(&masterObject)) return;
  790.     // get coords of all aligned c-alphas
  791.     deque < Vector > coords;
  792.     Molecule::ResidueMap::const_iterator r, re = masterMolecule->residues.end();
  793.     for (r=masterMolecule->residues.begin(); r!=re; ++r) {
  794.         if (!alignment->IsAligned(0, r->first - 1)) continue;
  795.         if (r->second->alphaID == Residue::NO_ALPHA_ID) continue;
  796.         AtomPntr ap(masterMolecule->id, r->first, r->second->alphaID);
  797.         const AtomCoord* atom = masterObject->coordSets.front()->atomSet->GetAtom(ap, true, true);
  798.         if (atom) coords.push_back(atom->site);
  799.     }
  800.     // calculate center
  801.     int i;
  802.     Vector alignedCenter;
  803.     for (i=0; i<coords.size(); ++i) alignedCenter += coords[i];
  804.     alignedCenter /= coords.size();
  805.     // find radius
  806.     double radius = 0.0, d;
  807.     for (i=0; i<coords.size(); ++i) {
  808.         d = (coords[i] - alignedCenter).length();
  809.         if (d > radius) radius = d;
  810.     }
  811.     // set view
  812.     renderer->CenterView(alignedCenter, radius);
  813. }
  814. bool StructureSet::Draw(const AtomSet *atomSet) const
  815. {
  816.     TRACEMSG("drawing StructureSet");
  817.     if (!styleManager->CheckGlobalStyleSettings()) return false;
  818.     return true;
  819. }
  820. unsigned int StructureSet::CreateName(const Residue *residue, int atomID)
  821. {
  822.     ++lastAtomName;
  823.     nameMap[lastAtomName] = make_pair(residue, atomID);
  824.     return lastAtomName;
  825. }
  826. bool StructureSet::GetAtomFromName(unsigned int name, const Residue **residue, int *atomID) const
  827. {
  828.     NameMap::const_iterator i = nameMap.find(name);
  829.     if (i == nameMap.end()) return false;
  830.     *residue = i->second.first;
  831.     *atomID = i->second.second;
  832. return true;
  833. }
  834. void StructureSet::SelectedAtom(unsigned int name, bool setCenter)
  835. {
  836.     const Residue *residue;
  837.     int atomID;
  838.     if (name == OpenGLRenderer::NO_NAME || !GetAtomFromName(name, &residue, &atomID)) {
  839.         INFOMSG("nothing selected");
  840.         return;
  841.     }
  842.     // add highlight
  843.     const Molecule *molecule;
  844.     if (!residue->GetParentOfType(&molecule)) return;
  845.     GlobalMessenger()->ToggleHighlight(molecule, residue->id, true);
  846.     wxString molresid;
  847.     if (molecule->IsHeterogen() || molecule->IsSolvent()) {
  848.         const StructureObject *object;
  849.         if (molecule->GetParentOfType(&object)) {
  850.             // assume hets/solvents are single residue
  851.             if (object->pdbID.size() > 0)
  852.                 molresid.Printf("%s heterogen/solvent molecule %i", object->pdbID.c_str(), molecule->id);
  853.             else
  854.                 molresid = molecule->identifier->ToString().c_str();
  855.         }
  856.     } else
  857.         molresid.Printf("chain %s residue %i", molecule->identifier->ToString().c_str(), residue->id);
  858.     INFOMSG("selected " << molresid.c_str() << " (PDB: " << residue->nameGraph << ' ' << residue->namePDB
  859.         << ") atom " << atomID << " (PDB: " << residue->GetAtomInfo(atomID)->name << ')');
  860.     // get coordinate of picked atom, in coordinates of master frame
  861.     const StructureObject *object;
  862.     if (!molecule->GetParentOfType(&object)) return;
  863.     object->coordSets.front()->atomSet->SetActiveEnsemble(NULL);    // don't actually know which alternate...
  864.     Vector pickedAtomCoord = object->coordSets.front()->atomSet->
  865.         GetAtom(AtomPntr(molecule->id, residue->id, atomID)) ->site;
  866.     if (object->IsSlave() && object->transformToMaster)
  867.         ApplyTransformation(&pickedAtomCoord, *(object->transformToMaster));
  868.     // print out distance to previous picked atom
  869.     if (havePrevPickedAtomCoord)
  870.         INFOMSG("distance to previously selected atom: " << setprecision(3) <<
  871.             (pickedAtomCoord - prevPickedAtomCoord).length() << setprecision(6) << " A");
  872.     prevPickedAtomCoord = pickedAtomCoord;
  873.     havePrevPickedAtomCoord = true;
  874.     // if indicated, use atom site as rotation center; use coordinate from first CoordSet, default altConf
  875.     if (setCenter) {
  876.         INFOMSG("rotating about " << object->pdbID
  877.             << " molecule " << molecule->id << " residue " << residue->id << ", atom " << atomID);
  878.         rotationCenter = pickedAtomCoord;
  879.     }
  880. }
  881. void StructureSet::SelectByDistance(double cutoff, bool biopolymersOnly, bool otherMoleculesOnly) const
  882. {
  883.     StructureObject::ResidueMap residuesToHighlight;
  884.     // add residues to highlight to master list, based on proximities within objects
  885.     ObjectList::const_iterator o, oe = objects.end();
  886.     for (o=objects.begin(); o!=oe; ++o)
  887.         (*o)->SelectByDistance(cutoff, biopolymersOnly, otherMoleculesOnly, &residuesToHighlight);
  888.     // now actually add highlights for new selected residues
  889.     StructureObject::ResidueMap::const_iterator r, re = residuesToHighlight.end();
  890.     for (r=residuesToHighlight.begin(); r!=re; ++r)
  891.         if (!GlobalMessenger()->IsHighlighted(r->second, r->first->id))
  892.             GlobalMessenger()->ToggleHighlight(r->second, r->first->id, false);
  893. }
  894. const Sequence * StructureSet::CreateNewSequence(ncbi::objects::CBioseq& bioseq)
  895. {
  896.     // add Sequence to SequenceSet
  897.     SequenceSet *modifiableSet = const_cast<SequenceSet*>(sequenceSet);
  898.     const Sequence *newSeq = new Sequence(modifiableSet, bioseq);
  899.     if (!newSeq->identifier) {
  900.         ERRORMSG("StructureSet::CreateNewSequence() - identifier conflict, no new sequence created");
  901.         delete newSeq;
  902.         return NULL;
  903.     }
  904.     modifiableSet->sequences.push_back(newSeq);
  905.     // add asn sequence to asn data
  906.     if (dataManager->GetSequences()) {
  907.         CSeq_entry *se = new CSeq_entry();
  908.         se->SetSeq(bioseq);
  909.         dataManager->GetSequences()->push_back(CRef<CSeq_entry>(se));
  910.     } else
  911.         ERRORMSG("StructureSet::CreateNewSequence() - no sequence list in asn data");
  912.     SetDataChanged(eSequenceData);
  913.     return newSeq;
  914. }
  915. void StructureSet::RejectAndPurgeSequence(const Sequence *reject, string reason, bool purge)
  916. {
  917.     if (!dataManager->IsCDD() || !reject || reason.size() == 0) return;
  918.     CReject_id *rejectID = new CReject_id();
  919.     rejectID->SetIds() = reject->bioseqASN->GetId();    // copy Seq-id lists
  920.     CUpdate_comment *comment = new CUpdate_comment();
  921.     comment->SetComment(reason);
  922.     rejectID->SetDescription().push_back(CRef < CUpdate_comment > (comment));
  923.     dataManager->AddReject(rejectID);
  924.     if (purge)
  925.         alignmentManager->PurgeSequence(reject->identifier);
  926. }
  927. const StructureSet::RejectList * StructureSet::GetRejects(void) const
  928. {
  929.     return dataManager->GetRejects();
  930. }
  931. void StructureSet::ShowRejects(void) const
  932. {
  933.     const RejectList *rejects = GetRejects();
  934.     if (!rejects) {
  935.         INFOMSG("No rejects in this CD");
  936.         return;
  937.     }
  938.     INFOMSG("Rejects:");
  939.     RejectList::const_iterator r, re = rejects->end();
  940.     for (r=rejects->begin(); r!=re; ++r) {
  941.         string idstr;
  942.         CReject_id::TIds::const_iterator i, ie = (*r)->GetIds().end();
  943.         for (i=(*r)->GetIds().begin(); i!=ie; ++i)
  944.             idstr += (*i)->AsFastaString() + ", ";
  945.         INFOMSG(idstr << "Reason: " <<
  946.             (((*r)->IsSetDescription() && (*r)->GetDescription().front()->IsComment()) ?
  947.                 (*r)->GetDescription().front()->GetComment() : string("none given")));
  948.     }
  949. }
  950. bool StructureSet::ConvertMimeDataToCDD(const std::string& cddName)
  951. {
  952.     if (!dataManager->ConvertMimeDataToCDD(cddName))
  953.         return false;
  954.     // make sure all structured sequences have MMDB annot tags
  955.     SequenceSet::SequenceList::const_iterator s, se = sequenceSet->sequences.end();
  956.     for (s=sequenceSet->sequences.begin(); s!=se; ++s) {
  957.         if ((*s)->molecule) {
  958.             if ((*s)->identifier->mmdbID == MoleculeIdentifier::VALUE_NOT_SET) {
  959.                 ERRORMSG("sequence " << (*s)->identifier->ToString()
  960.                     << " has associated molecule but no MMDB id");
  961.                 return false;
  962.             }
  963.             (*s)->AddMMDBAnnotTag((*s)->identifier->mmdbID);
  964.         }
  965.     }
  966.     return true;
  967. }
  968. // trivial methods...
  969. bool StructureSet::IsMultiStructure(void) const { return !dataManager->IsSingleStructure(); }
  970. bool StructureSet::HasDataChanged(void) const { return dataManager->HasDataChanged(); }
  971. void StructureSet::SetDataChanged(unsigned int what) const { dataManager->SetDataChanged(what); }
  972. bool StructureSet::IsCDD(void) const { return dataManager->IsCDD(); }
  973. bool StructureSet::IsCDDInMime(void) const { return dataManager->IsCDDInMime(); }
  974. const string& StructureSet::GetCDDName(void) const { return dataManager->GetCDDName(); }
  975. bool StructureSet::SetCDDName(const string& name) { return dataManager->SetCDDName(name); }
  976. const string& StructureSet::GetCDDDescription(void) const { return dataManager->GetCDDDescription(); }
  977. bool StructureSet::SetCDDDescription(const string& descr) { return dataManager->SetCDDDescription(descr); }
  978. bool StructureSet::GetCDDNotes(StructureSet::TextLines *lines) const { return dataManager->GetCDDNotes(lines); }
  979. bool StructureSet::SetCDDNotes(const StructureSet::TextLines& lines) { return dataManager->SetCDDNotes(lines); }
  980. ncbi::objects::CCdd_descr_set * StructureSet::GetCDDDescrSet(void) { return dataManager->GetCDDDescrSet(); }
  981. ncbi::objects::CAlign_annot_set * StructureSet::GetCDDAnnotSet(void) { return dataManager->GetCDDAnnotSet(); }
  982. ///// StructureObject stuff /////
  983. const int StructureObject::NO_MMDB_ID = -1;
  984. const double StructureObject::NO_TEMPERATURE = kMin_Double;
  985. StructureObject::StructureObject(StructureBase *parent, const CBiostruc& biostruc, bool master) :
  986.     StructureBase(parent), isMaster(master), mmdbID(NO_MMDB_ID), transformToMaster(NULL),
  987.     minTemperature(NO_TEMPERATURE), maxTemperature(NO_TEMPERATURE)
  988. {
  989.     // set numerical id simply based on # objects in parentSet
  990.     id = parentSet->objects.size() + 1;
  991.     // get MMDB id
  992.     CBiostruc::TId::const_iterator j, je=biostruc.GetId().end();
  993.     for (j=biostruc.GetId().begin(); j!=je; ++j) {
  994.         if (j->GetObject().IsMmdb_id()) {
  995.             mmdbID = j->GetObject().GetMmdb_id().Get();
  996.             break;
  997.         }
  998.     }
  999.     TRACEMSG("MMDB id " << mmdbID);
  1000.     // get PDB id
  1001.     if (biostruc.IsSetDescr()) {
  1002.         CBiostruc::TDescr::const_iterator k, ke=biostruc.GetDescr().end();
  1003.         for (k=biostruc.GetDescr().begin(); k!=ke; ++k) {
  1004.             if (k->GetObject().IsName()) {
  1005.                 pdbID = k->GetObject().GetName();
  1006.                 break;
  1007.             }
  1008.         }
  1009.     }
  1010.     TRACEMSG("PDB id " << pdbID);
  1011.     // get atom and feature spatial coordinates
  1012.     if (biostruc.IsSetModel()) {
  1013.         // iterate SEQUENCE OF Biostruc-model
  1014.         CBiostruc::TModel::const_iterator i, ie=biostruc.GetModel().end();
  1015.         for (i=biostruc.GetModel().begin(); i!=ie; ++i) {
  1016.             // don't know how to deal with these...
  1017.             if (i->GetObject().GetType() == eModel_type_ncbi_vector ||
  1018.                 i->GetObject().GetType() == eModel_type_other) continue;
  1019. //            // special case, typically for loading CDD's, when we're only interested in a single model type
  1020. //            if (isRawBiostrucFromMMDB && i->GetObject().GetType() != eModel_type_ncbi_all_atom) continue;
  1021.             // otherwise, assume all models in this set are of same type
  1022.             if (i->GetObject().GetType() == eModel_type_ncbi_backbone)
  1023.                 parentSet->isAlphaOnly = true;
  1024.             else
  1025.                 parentSet->isAlphaOnly = false;
  1026.             // load each Biostruc-model into a CoordSet
  1027.             if (i->GetObject().IsSetModel_coordinates()) {
  1028.                 CoordSet *coordSet =
  1029.                     new CoordSet(this, i->GetObject().GetModel_coordinates());
  1030.                 coordSets.push_back(coordSet);
  1031.             }
  1032.         }
  1033.     }
  1034.     TRACEMSG("temperature range: " << minTemperature << " to " << maxTemperature);
  1035.     // get graph - must be done after atom coordinates are loaded, so we can
  1036.     // avoid storing graph nodes for atoms not present in the model
  1037.     graph = new ChemicalGraph(this, biostruc.GetChemical_graph(), biostruc.GetFeatures());
  1038. }
  1039. bool StructureObject::SetTransformToMaster(const CBiostruc_annot_set& annot, int masterMMDBID)
  1040. {
  1041.     CBiostruc_annot_set::TFeatures::const_iterator f1, f1e=annot.GetFeatures().end();
  1042.     for (f1=annot.GetFeatures().begin(); f1!=f1e; ++f1) {
  1043.         CBiostruc_feature_set::TFeatures::const_iterator f2, f2e=f1->GetObject().GetFeatures().end();
  1044.         for (f2=f1->GetObject().GetFeatures().begin(); f2!=f2e; ++f2) {
  1045.             // skip if already used
  1046.             if (f2->GetObject().IsSetId() &&
  1047.                     parentSet->usedFeatures.find(f2->GetObject().GetId().Get()) !=
  1048.                         parentSet->usedFeatures.end())
  1049.                 continue;
  1050.             // look for alignment feature
  1051.             if (f2->GetObject().IsSetType() &&
  1052. f2->GetObject().GetType() == CBiostruc_feature::eType_alignment &&
  1053.                 f2->GetObject().IsSetLocation() &&
  1054.                 f2->GetObject().GetLocation().IsAlignment()) {
  1055.                 const CChem_graph_alignment& graphAlign =
  1056. f2->GetObject().GetLocation().GetAlignment();
  1057.                 // find transform alignment of this object with master
  1058.                 if (graphAlign.GetDimension() == 2 &&
  1059.                     graphAlign.GetBiostruc_ids().size() == 2 &&
  1060.                     graphAlign.IsSetTransform() &&
  1061.                     graphAlign.GetTransform().size() == 1 &&
  1062.                     graphAlign.GetBiostruc_ids().front().GetObject().IsMmdb_id() &&
  1063.                     graphAlign.GetBiostruc_ids().front().GetObject().GetMmdb_id().Get() == masterMMDBID &&
  1064.                     graphAlign.GetBiostruc_ids().back().GetObject().IsMmdb_id() &&
  1065.                     graphAlign.GetBiostruc_ids().back().GetObject().GetMmdb_id().Get() == mmdbID) {
  1066.                     // mark feature as used
  1067.                     if (f2->GetObject().IsSetId())
  1068.                         parentSet->usedFeatures[f2->GetObject().GetId().Get()] = true;
  1069.                     TRACEMSG("got transform for " << pdbID << "->master");
  1070.                     // unpack transform into matrix, moves in reverse order;
  1071.                     Matrix xform;
  1072.                     transformToMaster = new Matrix();
  1073.                     CTransform::TMoves::const_iterator
  1074.                         m, me=graphAlign.GetTransform().front().GetObject().GetMoves().end();
  1075.                     for (m=graphAlign.GetTransform().front().GetObject().GetMoves().begin(); m!=me; ++m) {
  1076.                         Matrix xmat;
  1077.                         double scale;
  1078.                         if (m->GetObject().IsTranslate()) {
  1079.                             const CTrans_matrix& trans = m->GetObject().GetTranslate();
  1080.                             scale = 1.0 / trans.GetScale_factor();
  1081.                             SetTranslationMatrix(&xmat,
  1082.                                 Vector(scale * trans.GetTran_1(),
  1083.                                        scale * trans.GetTran_2(),
  1084.                                        scale * trans.GetTran_3()));
  1085.                         } else { // rotate
  1086.                             const CRot_matrix& rot = m->GetObject().GetRotate();
  1087.                             scale = 1.0 / rot.GetScale_factor();
  1088.                             xmat.m[0]=scale*rot.GetRot_11(); xmat.m[1]=scale*rot.GetRot_21(); xmat.m[2]= scale*rot.GetRot_31(); xmat.m[3]=0;
  1089.                             xmat.m[4]=scale*rot.GetRot_12(); xmat.m[5]=scale*rot.GetRot_22(); xmat.m[6]= scale*rot.GetRot_32(); xmat.m[7]=0;
  1090.                             xmat.m[8]=scale*rot.GetRot_13(); xmat.m[9]=scale*rot.GetRot_23(); xmat.m[10]=scale*rot.GetRot_33(); xmat.m[11]=0;
  1091.                             xmat.m[12]=0;                    xmat.m[13]=0;                    xmat.m[14]=0;                     xmat.m[15]=1;
  1092.                         }
  1093.                         ComposeInto(transformToMaster, xmat, xform);
  1094.                         xform = *transformToMaster;
  1095.                     }
  1096.                     return true;
  1097.                 }
  1098.             }
  1099.         }
  1100.     }
  1101.     WARNINGMSG("Can't get structure alignment for slave " << pdbID
  1102.         << " with master " << masterMMDBID << ";nwill likely require manual realignment");
  1103.     return false;
  1104. }
  1105. static void AddDomain(int *domain, const Molecule *molecule, const Block::Range *range)
  1106. {
  1107.     const StructureObject *object;
  1108.     if (!molecule->GetParentOfType(&object)) return;
  1109.     for (int l=range->from; l<=range->to; ++l) {
  1110.         if (molecule->residueDomains[l] != Molecule::NO_DOMAIN_SET) {
  1111.             if (*domain == NO_DOMAIN)
  1112.                 *domain = object->domainID2MMDB.find(molecule->residueDomains[l])->second;
  1113.             else if (*domain != MULTI_DOMAIN &&
  1114.                      *domain != object->domainID2MMDB.find(molecule->residueDomains[l])->second)
  1115.                 *domain = MULTI_DOMAIN;
  1116.         }
  1117.     }
  1118. }
  1119. void StructureObject::RealignStructure(int nCoords,
  1120.     const Vector * const *masterCoords, const Vector * const *slaveCoords,
  1121.     const double *weights, int slaveRow)
  1122. {
  1123.     Vector masterCOM, slaveCOM; // centers of mass for master, slave
  1124.     Matrix slaveRotation;       // rotation to align slave with master
  1125.     if (!transformToMaster) transformToMaster = new Matrix();
  1126.     // do the fit
  1127.     RigidBodyFit(nCoords, masterCoords, slaveCoords, weights, masterCOM, slaveCOM, slaveRotation);
  1128.     // apply the resulting transform elements from the fit to this object's transform Matrix
  1129.     Matrix single, combined;
  1130.     SetTranslationMatrix(&single, -slaveCOM);
  1131.     ComposeInto(transformToMaster, slaveRotation, single);
  1132.     combined = *transformToMaster;
  1133.     SetTranslationMatrix(&single, masterCOM);
  1134.     ComposeInto(transformToMaster, single, combined);
  1135.     // print out RMSD
  1136.     Vector x;
  1137.     double rmsd = 0.0, d;
  1138.     int n = 0;
  1139.     for (int c=0; c<nCoords; ++c) {
  1140.         if (!slaveCoords[c] || !masterCoords[c]) continue;
  1141.         x = *(slaveCoords[c]);
  1142.         ApplyTransformation(&x, *transformToMaster);
  1143.         d = (*(masterCoords[c]) - x).length();
  1144.         rmsd += d * d;
  1145.         ++n;
  1146.     }
  1147.     rmsd = sqrt(rmsd / n);
  1148.     INFOMSG("RMSD of aligned alpha coordinates between master structure and " << pdbID << ": "
  1149.         << setprecision(3) << rmsd << setprecision(6) << " A");
  1150.     // create a new Biostruc-feature that contains this alignment
  1151.     CBiostruc_feature *feature = new CBiostruc_feature();
  1152.     feature->SetType(CBiostruc_feature::eType_alignment);
  1153.     CRef<CBiostruc_feature::C_Location> location(new CBiostruc_feature::C_Location());
  1154.     feature->SetLocation(*location);
  1155.     CChem_graph_alignment *graphAlignment = new CChem_graph_alignment();
  1156.     location.GetObject().SetAlignment(*graphAlignment);
  1157.     // fill out the Chem-graph-alignment
  1158.     graphAlignment->SetDimension(2);
  1159.     CMmdb_id
  1160.         *masterMID = new CMmdb_id(parentSet->objects.front()->mmdbID),
  1161.         *slaveMID = new CMmdb_id(mmdbID);
  1162.     CBiostruc_id
  1163.         *masterBID = new CBiostruc_id(),
  1164.         *slaveBID = new CBiostruc_id();
  1165.     masterBID->SetMmdb_id(*masterMID);
  1166.     slaveBID->SetMmdb_id(*slaveMID);
  1167.     graphAlignment->SetBiostruc_ids().resize(2);
  1168.     graphAlignment->SetBiostruc_ids().front().Reset(masterBID);
  1169.     graphAlignment->SetBiostruc_ids().back().Reset(slaveBID);
  1170.     graphAlignment->SetAlignment().resize(2);
  1171.     // fill out sequence alignment intervals, tracking domains in alignment
  1172.     const BlockMultipleAlignment *multiple = parentSet->alignmentManager->GetCurrentMultipleAlignment();
  1173.     int masterDomain = NO_DOMAIN, slaveDomain = NO_DOMAIN;
  1174.     const Molecule
  1175.         *masterMolecule = multiple->GetSequenceOfRow(0)->molecule,
  1176.         *slaveMolecule = multiple->GetSequenceOfRow(slaveRow)->molecule;
  1177.     BlockMultipleAlignment::UngappedAlignedBlockList blocks;
  1178.     multiple->GetUngappedAlignedBlocks(&blocks);
  1179.     if (blocks.size() > 0) {
  1180.         CChem_graph_pntrs
  1181.             *masterCGPs = new CChem_graph_pntrs(),
  1182.             *slaveCGPs = new CChem_graph_pntrs();
  1183.         graphAlignment->SetAlignment().front().Reset(masterCGPs);
  1184.         graphAlignment->SetAlignment().back().Reset(slaveCGPs);
  1185.         CResidue_pntrs
  1186.             *masterRPs = new CResidue_pntrs(),
  1187.             *slaveRPs = new CResidue_pntrs();
  1188.         masterCGPs->SetResidues(*masterRPs);
  1189.         slaveCGPs->SetResidues(*slaveRPs);
  1190.         masterRPs->SetInterval().resize(blocks.size());
  1191.         slaveRPs->SetInterval().resize(blocks.size());
  1192.         BlockMultipleAlignment::UngappedAlignedBlockList::const_iterator b, be = blocks.end();
  1193.         CResidue_pntrs::TInterval::iterator
  1194.             mi = masterRPs->SetInterval().begin(),
  1195.             si = slaveRPs->SetInterval().begin();
  1196.         for (b=blocks.begin(); b!=be; ++b, ++mi, ++si) {
  1197.             CResidue_interval_pntr
  1198.                 *masterRIP = new CResidue_interval_pntr(),
  1199.                 *slaveRIP = new CResidue_interval_pntr();
  1200.             mi->Reset(masterRIP);
  1201.             si->Reset(slaveRIP);
  1202.             masterRIP->SetMolecule_id().Set(masterMolecule->id);
  1203.             slaveRIP->SetMolecule_id().Set(slaveMolecule->id);
  1204.             const Block::Range *range = (*b)->GetRangeOfRow(0);
  1205.             masterRIP->SetFrom().Set(range->from + 1); // +1 to convert seqLoc to residueID
  1206.             masterRIP->SetTo().Set(range->to + 1);
  1207.             AddDomain(&masterDomain, masterMolecule, range);
  1208.             range = (*b)->GetRangeOfRow(slaveRow);
  1209.             slaveRIP->SetFrom().Set(range->from + 1);
  1210.             slaveRIP->SetTo().Set(range->to + 1);
  1211.             AddDomain(&slaveDomain, slaveMolecule, range);
  1212.         }
  1213.     }
  1214.     // fill out structure alignment transform
  1215.     CTransform *xform = new CTransform();
  1216.     graphAlignment->SetTransform().resize(1);
  1217.     graphAlignment->SetTransform().front().Reset(xform);
  1218.     xform->SetId(1);
  1219.     xform->SetMoves().resize(3);
  1220.     CTransform::TMoves::iterator m = xform->SetMoves().begin();
  1221.     for (int i=0; i<3; ++i, ++m) {
  1222.         CMove *move = new CMove();
  1223.         m->Reset(move);
  1224.         static const int scaleFactor = 100000;
  1225.         if (i == 0) {   // translate slave so its COM is at origin
  1226.             CTrans_matrix *trans = new CTrans_matrix();
  1227.             move->SetTranslate(*trans);
  1228.             trans->SetScale_factor(scaleFactor);
  1229.             trans->SetTran_1((int)(-(slaveCOM.x * scaleFactor)));
  1230.             trans->SetTran_2((int)(-(slaveCOM.y * scaleFactor)));
  1231.             trans->SetTran_3((int)(-(slaveCOM.z * scaleFactor)));
  1232.         } else if (i == 1) {
  1233.             CRot_matrix *rot = new CRot_matrix();
  1234.             move->SetRotate(*rot);
  1235.             rot->SetScale_factor(scaleFactor);
  1236.             rot->SetRot_11((int)(slaveRotation[0] * scaleFactor));
  1237.             rot->SetRot_12((int)(slaveRotation[4] * scaleFactor));
  1238.             rot->SetRot_13((int)(slaveRotation[8] * scaleFactor));
  1239.             rot->SetRot_21((int)(slaveRotation[1] * scaleFactor));
  1240.             rot->SetRot_22((int)(slaveRotation[5] * scaleFactor));
  1241.             rot->SetRot_23((int)(slaveRotation[9] * scaleFactor));
  1242.             rot->SetRot_31((int)(slaveRotation[2] * scaleFactor));
  1243.             rot->SetRot_32((int)(slaveRotation[6] * scaleFactor));
  1244.             rot->SetRot_33((int)(slaveRotation[10] * scaleFactor));
  1245.         } else if (i == 2) {    // translate slave so its COM is at COM of master
  1246.             CTrans_matrix *trans = new CTrans_matrix();
  1247.             move->SetTranslate(*trans);
  1248.             trans->SetScale_factor(scaleFactor);
  1249.             trans->SetTran_1((int)(masterCOM.x * scaleFactor));
  1250.             trans->SetTran_2((int)(masterCOM.y * scaleFactor));
  1251.             trans->SetTran_3((int)(masterCOM.z * scaleFactor));
  1252.         }
  1253.     }
  1254.     // store the new alignment in the Biostruc-annot-set,
  1255.     // setting the feature id depending on the aligned domain(s)
  1256.     if (masterDomain == NO_DOMAIN) masterDomain = 0;    // can happen if single domain chain
  1257.     if (slaveDomain == NO_DOMAIN) slaveDomain = 0;
  1258.     const StructureObject *masterObject;
  1259.     if (!masterMolecule->GetParentOfType(&masterObject)) return;
  1260.     int
  1261.         masterDomainID = masterObject->mmdbID*10000 + masterMolecule->id*100 + masterDomain,
  1262.         slaveDomainID = mmdbID*100000 + slaveMolecule->id*1000 + slaveDomain*10 + 1;
  1263.     parentSet->AddStructureAlignment(feature, masterDomainID, slaveDomainID);
  1264.     // for backward-compatibility with Cn3D 3.5, need name to encode chain/domain
  1265.     CNcbiOstrstream oss;
  1266.     oss << masterMolecule->identifier->pdbID << ((char) masterMolecule->identifier->pdbChain) << masterDomain << ' '
  1267.         << slaveMolecule->identifier->pdbID << ((char) slaveMolecule->identifier->pdbChain) << slaveDomain << ' '
  1268.         << "Structure alignment of slave " << multiple->GetSequenceOfRow(slaveRow)->identifier->ToString()
  1269.         << " with master " << multiple->GetSequenceOfRow(0)->identifier->ToString()
  1270.         << ", as computed by Cn3D" << '';
  1271.     feature->SetName(string(oss.str()));
  1272.     delete oss.str();
  1273. }
  1274. void StructureObject::SelectByDistance(double cutoff, bool biopolymersOnly, bool otherMoleculesOnly,
  1275.     ResidueMap *selectedResidues) const
  1276. {
  1277.     // first make a list of coordinates of atoms in selected residues,
  1278.     typedef vector < const AtomCoord * > CoordList;
  1279.     CoordList highlightedAtoms;
  1280.     typedef map < const Molecule * , bool > MoleculeList;
  1281.     MoleculeList moleculesWithHighlights;
  1282.     ChemicalGraph::MoleculeMap::const_iterator m, me = graph->molecules.end();
  1283.     for (m=graph->molecules.begin(); m!=me; ++m) {
  1284.         Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
  1285.         for (r=m->second->residues.begin(); r!=re; ++r) {
  1286.             if (GlobalMessenger()->IsHighlighted(m->second, r->second->id)) {
  1287.                 const Residue::AtomInfoMap& atomInfos = r->second->GetAtomInfos();
  1288.                 Residue::AtomInfoMap::const_iterator a, ae = atomInfos.end();
  1289.                 for (a=atomInfos.begin(); a!=ae; ++a) {
  1290.                     const AtomCoord *atomCoord = coordSets.front()->atomSet->
  1291.                         GetAtom(AtomPntr(m->second->id, r->second->id, a->first), true, true);
  1292.                     if (atomCoord) highlightedAtoms.push_back(atomCoord);
  1293.                 }
  1294.                 moleculesWithHighlights[m->second] = true;
  1295.             }
  1296.         }
  1297.     }
  1298.     if (highlightedAtoms.size() == 0) return;
  1299.     // now make a list of unselected residues to check for proximity
  1300.     typedef vector < const Residue * > ResidueList;
  1301.     ResidueList unhighlightedResidues;
  1302.     for (m=graph->molecules.begin(); m!=me; ++m) {
  1303.         Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
  1304.         if (otherMoleculesOnly &&
  1305.                 moleculesWithHighlights.find(m->second) != moleculesWithHighlights.end())
  1306.             continue;
  1307.         for (r=m->second->residues.begin(); r!=re; ++r) {
  1308.             if (!GlobalMessenger()->IsHighlighted(m->second, r->second->id) &&
  1309.                     (!biopolymersOnly || m->second->IsProtein() || m->second->IsNucleotide()))
  1310.                 unhighlightedResidues.push_back(r->second);
  1311.         }
  1312.     }
  1313.     if (unhighlightedResidues.size() == 0) return;
  1314.     // now check all unhighlighted residues, to see if any atoms are within cutoff distance
  1315.     // of any highlighted atoms; if so, add to residue selection list
  1316.     CoordList::const_iterator h, he = highlightedAtoms.end();
  1317.     ResidueList::const_iterator u, ue = unhighlightedResidues.end();
  1318.     for (u=unhighlightedResidues.begin(); u!=ue; ++u) {
  1319.         const Molecule *molecule;
  1320.         if (!(*u)->GetParentOfType(&molecule)) continue;
  1321.         const Residue::AtomInfoMap& atomInfos = (*u)->GetAtomInfos();
  1322.         Residue::AtomInfoMap::const_iterator a, ae = atomInfos.end();
  1323.         for (a=atomInfos.begin(); a!=ae; ++a) {
  1324.             const AtomCoord *uAtomCoord = coordSets.front()->atomSet->
  1325.                 GetAtom(AtomPntr(molecule->id, (*u)->id, a->first), true, true);
  1326.             if (!uAtomCoord) continue;
  1327.             // for each unhighlighted atom, check for proximity to a highlighted atom
  1328.             for (h=highlightedAtoms.begin(); h!=he; ++h) {
  1329.                 if ((uAtomCoord->site - (*h)->site).length() <= cutoff)
  1330.                     break;
  1331.             }
  1332.             if (h != he)
  1333.                 break;
  1334.         }
  1335.         // if any atom of this residue is near a highlighted atom, add to selection list
  1336.         if (a != ae)
  1337.             (*selectedResidues)[*u] = molecule;
  1338.     }
  1339. }
  1340. END_SCOPE(Cn3D)
  1341. /*
  1342. * ---------------------------------------------------------------------------
  1343. * $Log: structure_set.cpp,v $
  1344. * Revision 1000.2  2004/06/01 18:29:28  gouriano
  1345. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.141
  1346. *
  1347. * Revision 1.141  2004/05/21 21:41:40  gorelenk
  1348. * Added PCH ncbi_pch.hpp
  1349. *
  1350. * Revision 1.140  2004/05/21 17:29:51  thiessen
  1351. * allow conversion of mime to cdd data
  1352. *
  1353. * Revision 1.139  2004/03/15 18:32:04  thiessen
  1354. * prefer prefix vs. postfix ++/-- operators
  1355. *
  1356. * Revision 1.138  2004/02/19 17:05:14  thiessen
  1357. * remove cn3d/ from include paths; add pragma to disable annoying msvc warning
  1358. *
  1359. * Revision 1.137  2004/02/05 19:00:08  thiessen
  1360. * change mmdb->pdb upon het selection
  1361. *
  1362. * Revision 1.136  2004/01/05 17:09:16  thiessen
  1363. * abort import and warn if same accession different gi
  1364. *
  1365. * Revision 1.135  2003/10/21 13:48:48  grichenk
  1366. * Redesigned type aliases in serialization library.
  1367. * Fixed the code (removed CRef-s, added explicit
  1368. * initializers etc.)
  1369. *
  1370. * Revision 1.134  2003/07/17 20:13:51  thiessen
  1371. * don't ask for filename on save/termination with -f; add eAnyAlignmentData flag
  1372. *
  1373. * Revision 1.133  2003/07/17 16:52:34  thiessen
  1374. * add FileSaved message with edit typing
  1375. *
  1376. * Revision 1.132  2003/07/14 18:37:08  thiessen
  1377. * change GetUngappedAlignedBlocks() param types; other syntax changes
  1378. *
  1379. * Revision 1.131  2003/06/12 14:38:46  thiessen
  1380. * fix empty feature list bug in blank structure alignment data
  1381. *
  1382. * Revision 1.130  2003/04/02 17:49:18  thiessen
  1383. * allow pdb id's in structure import dialog
  1384. *
  1385. * Revision 1.129  2003/02/05 14:55:22  thiessen
  1386. * always load single structure even if structureLimit == 0
  1387. *
  1388. * Revision 1.128  2003/02/03 19:20:07  thiessen
  1389. * format changes: move CVS Log to bottom of file, remove std:: from .cpp files, and use new diagnostic macros
  1390. *
  1391. * Revision 1.127  2003/01/27 15:52:22  thiessen
  1392. * merge after highlighted row; show rejects; trim rejects from new reject list
  1393. *
  1394. * Revision 1.126  2003/01/10 20:10:53  thiessen
  1395. * undo previous change - don't want full Bioseqs (with multiple Seq-ids) in converted C-Bioseqs
  1396. *
  1397. * Revision 1.125  2003/01/09 16:15:42  thiessen
  1398. * use ConvertAsnFromCPPToC to convert full Bioseqs
  1399. *
  1400. * Revision 1.124  2002/12/19 18:52:28  thiessen
  1401. * rms -> rmsd
  1402. *
  1403. * Revision 1.123  2002/11/21 17:48:12  thiessen
  1404. * fix yet another user style bug
  1405. *
  1406. * Revision 1.122  2002/11/21 15:26:33  thiessen
  1407. * fix style dictionary loading bug
  1408. *
  1409. * Revision 1.121  2002/11/19 21:19:44  thiessen
  1410. * more const changes for objects; fix user vs default style bug
  1411. *
  1412. * Revision 1.120  2002/11/18 19:48:40  grichenk
  1413. * Removed "const" from datatool-generated setters
  1414. *
  1415. * Revision 1.119  2002/11/18 15:02:40  thiessen
  1416. * set flags on style shortcut menus
  1417. *
  1418. * Revision 1.118  2002/11/06 00:18:10  thiessen
  1419. * fixes for new CRef/const rules in objects
  1420. *
  1421. * Revision 1.117  2002/10/08 12:35:43  thiessen
  1422. * use delete[] for arrays
  1423. *
  1424. * Revision 1.116  2002/09/30 17:13:02  thiessen
  1425. * change structure import to do sequences as well; change cache to hold mimes; change block aligner vocabulary; fix block aligner dialog bugs
  1426. *
  1427. * Revision 1.115  2002/09/26 18:30:58  thiessen
  1428. * fix RMS bug when coords missing
  1429. *
  1430. * Revision 1.114  2002/09/26 17:32:13  thiessen
  1431. * show distance between picked atoms; show RMS for structure alignments
  1432. *
  1433. * Revision 1.113  2002/09/19 12:51:08  thiessen
  1434. * fix block aligner / update bug; add distance select for other molecules only
  1435. *
  1436. * Revision 1.112  2002/09/16 21:24:58  thiessen
  1437. * add block freezing to block aligner
  1438. *
  1439. * Revision 1.111  2002/09/14 19:18:32  thiessen
  1440. * fix center-on-aligned bug when no structured master
  1441. *
  1442. * Revision 1.110  2002/09/14 18:41:05  thiessen
  1443. * fix center-on-aligned omission
  1444. *
  1445. * Revision 1.109  2002/09/14 17:03:07  thiessen
  1446. * center initial view on aligned residues
  1447. *
  1448. * Revision 1.108  2002/09/09 13:38:23  thiessen
  1449. * separate save and save-as
  1450. *
  1451. * Revision 1.107  2002/08/15 22:13:17  thiessen
  1452. * update for wx2.3.2+ only; add structure pick dialog; fix MultitextDialog bug
  1453. *
  1454. * Revision 1.106  2002/07/12 13:24:10  thiessen
  1455. * fixes for PSSM creation to agree with cddumper/RPSBLAST
  1456. *
  1457. * Revision 1.105  2002/07/03 13:39:40  thiessen
  1458. * fix for redundant sequence removal
  1459. *
  1460. * Revision 1.104  2002/07/01 15:30:21  thiessen
  1461. * fix for container type switch in Dense-seg
  1462. *
  1463. * Revision 1.103  2002/06/07 12:41:04  thiessen
  1464. * change ambiguous master error to warning
  1465. *
  1466. * Revision 1.102  2002/06/05 17:50:08  thiessen
  1467. * title tweaks
  1468. *
  1469. * Revision 1.101  2002/04/27 16:32:14  thiessen
  1470. * fix small leaks/bugs found by BoundsChecker
  1471. *
  1472. * Revision 1.100  2002/04/11 16:39:54  thiessen
  1473. * fix style manager bug
  1474. *
  1475. * Revision 1.99  2002/04/10 13:16:28  thiessen
  1476. * new selection by distance algorithm
  1477. *
  1478. * Revision 1.98  2002/03/28 14:06:02  thiessen
  1479. * preliminary BLAST/PSSM ; new CD startup style
  1480. *
  1481. * Revision 1.97  2002/02/27 16:29:41  thiessen
  1482. * add model type flag to general mime type
  1483. *
  1484. * Revision 1.96  2002/02/19 14:59:40  thiessen
  1485. * add CDD reject and purge sequence
  1486. *
  1487. * Revision 1.95  2002/02/12 17:19:22  thiessen
  1488. * first working structure import
  1489. *
  1490. * Revision 1.94  2002/02/05 18:53:26  thiessen
  1491. * scroll to residue in sequence windows when selected in structure window
  1492. *
  1493. * Revision 1.93  2002/01/19 02:34:50  thiessen
  1494. * fixes for changes in asn serialization API
  1495. *
  1496. * Revision 1.92  2002/01/03 16:18:40  thiessen
  1497. * add distance selection
  1498. *
  1499. * Revision 1.91  2001/12/21 23:08:48  thiessen
  1500. * add residue info when structure selected
  1501. *
  1502. * Revision 1.90  2001/12/15 03:15:59  thiessen
  1503. * adjustments for slightly changed object loader Set...() API
  1504. *
  1505. * Revision 1.89  2001/12/12 14:04:15  thiessen
  1506. * add missing object headers after object loader change
  1507. *
  1508. * Revision 1.88  2001/12/06 23:13:46  thiessen
  1509. * finish import/align new sequences into single-structure data; many small tweaks
  1510. *
  1511. * Revision 1.87  2001/11/30 14:02:05  thiessen
  1512. * progress on sequence imports to single structures
  1513. *
  1514. * Revision 1.86  2001/11/27 16:26:09  thiessen
  1515. * major update to data management system
  1516. *
  1517. * Revision 1.85  2001/10/30 02:54:13  thiessen
  1518. * add Biostruc cache
  1519. *
  1520. * Revision 1.84  2001/10/17 17:46:22  thiessen
  1521. * save camera setup and rotation center in files
  1522. *
  1523. * Revision 1.83  2001/10/09 18:57:05  thiessen
  1524. * add CDD references editing dialog
  1525. *
  1526. * Revision 1.82  2001/10/08 00:00:09  thiessen
  1527. * estimate threader N random starts; edit CDD name
  1528. *
  1529. * Revision 1.81  2001/10/01 16:04:25  thiessen
  1530. * make CDD annotation window non-modal; add SetWindowTitle to viewers
  1531. *
  1532. * Revision 1.80  2001/09/27 20:58:28  thiessen
  1533. * add VisibleString filter option
  1534. *
  1535. * Revision 1.79  2001/09/27 15:37:59  thiessen
  1536. * decouple sequence import and BLAST
  1537. *
  1538. * Revision 1.78  2001/09/19 22:55:39  thiessen
  1539. * add preliminary net import and BLAST
  1540. *
  1541. * Revision 1.77  2001/09/18 03:10:45  thiessen
  1542. * add preliminary sequence import pipeline
  1543. *
  1544. * Revision 1.76  2001/08/27 00:06:23  thiessen
  1545. * add structure evidence to CDD annotation
  1546. *
  1547. * Revision 1.75  2001/08/13 22:30:59  thiessen
  1548. * add structure window mouse drag/zoom; add highlight option to render settings
  1549. *
  1550. * Revision 1.74  2001/08/10 15:01:57  thiessen
  1551. * fill out shortcuts; add update show/hide menu
  1552. *
  1553. * Revision 1.73  2001/08/09 19:07:13  thiessen
  1554. * add temperature and hydrophobicity coloring
  1555. *
  1556. * Revision 1.72  2001/07/19 19:14:38  thiessen
  1557. * working CDD alignment annotator ; misc tweaks
  1558. *
  1559. * Revision 1.71  2001/07/12 17:35:15  thiessen
  1560. * change domain mapping ; add preliminary cdd annotation GUI
  1561. *
  1562. * Revision 1.70  2001/07/10 16:39:55  thiessen
  1563. * change selection control keys; add CDD name/notes dialogs
  1564. *
  1565. * Revision 1.69  2001/07/04 19:39:17  thiessen
  1566. * finish user annotation system
  1567. *
  1568. * Revision 1.68  2001/06/29 18:13:58  thiessen
  1569. * initial (incomplete) user annotation system
  1570. *
  1571. * Revision 1.67  2001/06/21 02:02:34  thiessen
  1572. * major update to molecule identification and highlighting ; add toggle highlight (via alt)
  1573. *
  1574. * Revision 1.66  2001/06/15 14:06:40  thiessen
  1575. * save/load asn styles now complete
  1576. *
  1577. * Revision 1.65  2001/06/14 17:45:10  thiessen
  1578. * progress in styles<->asn ; add structure limits
  1579. *
  1580. * Revision 1.64  2001/06/14 00:34:01  thiessen
  1581. * asn additions
  1582. *
  1583. * Revision 1.63  2001/06/07 19:05:38  thiessen
  1584. * functional (although incomplete) render settings panel ; highlight title - not sequence - upon mouse click
  1585. *
  1586. * Revision 1.62  2001/06/05 13:21:08  thiessen
  1587. * fix structure alignment list problems
  1588. *
  1589. * Revision 1.61  2001/05/31 18:47:09  thiessen
  1590. * add preliminary style dialog; remove LIST_TYPE; add thread single and delete all; misc tweaks
  1591. *
  1592. * Revision 1.60  2001/05/17 18:32:47  thiessen
  1593. * fix sequence/molecule/master match bug
  1594. *
  1595. * Revision 1.59  2001/05/14 16:04:32  thiessen
  1596. * fix minor row reordering bug
  1597. *
  1598. * Revision 1.58  2001/05/11 18:20:11  thiessen
  1599. * fix loading of cdd with repeated master structure
  1600. *
  1601. * Revision 1.57  2001/05/02 13:46:28  thiessen
  1602. * major revision of stuff relating to saving of updates; allow stored null-alignments
  1603. *
  1604. * Revision 1.56  2001/04/17 20:15:39  thiessen
  1605. * load 'pending' Cdd alignments into update window
  1606. *
  1607. * Revision 1.55  2001/03/23 15:14:07  thiessen
  1608. * load sidechains in CDD's
  1609. *
  1610. * Revision 1.54  2001/03/23 04:18:52  thiessen
  1611. * parse and display disulfides
  1612. *
  1613. * Revision 1.53  2001/03/22 00:33:17  thiessen
  1614. * initial threading working (PSSM only); free color storage in undo stack
  1615. *
  1616. * Revision 1.52  2001/03/01 20:15:51  thiessen
  1617. * major rearrangement of sequence viewer code into base and derived classes
  1618. *
  1619. * Revision 1.51  2001/02/22 00:30:07  thiessen
  1620. * make directories global ; allow only one Sequence per StructureObject
  1621. *
  1622. * Revision 1.50  2001/02/16 00:40:01  thiessen
  1623. * remove unused sequences from asn data
  1624. *
  1625. * Revision 1.49  2001/02/13 01:03:57  thiessen
  1626. * backward-compatible domain ID's in output; add ability to delete rows
  1627. *
  1628. * Revision 1.48  2001/02/08 23:01:51  thiessen
  1629. * hook up C-toolkit stuff for threading; working PSSM calculation
  1630. *
  1631. * Revision 1.47  2001/02/02 20:17:33  thiessen
  1632. * can read in CDD with multi-structure but no struct. alignments
  1633. *
  1634. * Revision 1.46  2001/01/30 20:51:19  thiessen
  1635. * minor fixes
  1636. *
  1637. * Revision 1.45  2001/01/25 20:21:18  thiessen
  1638. * fix ostrstream memory leaks
  1639. *
  1640. * Revision 1.44  2001/01/18 19:37:28  thiessen
  1641. * save structure (re)alignments to asn output
  1642. *
  1643. * Revision 1.43  2001/01/12 01:34:18  thiessen
  1644. * network Biostruc load
  1645. *
  1646. * Revision 1.42  2000/12/29 19:23:40  thiessen
  1647. * save row order
  1648. *
  1649. * Revision 1.41  2000/12/22 19:26:40  thiessen
  1650. * write cdd output files
  1651. *
  1652. * Revision 1.40  2000/12/21 23:42:16  thiessen
  1653. * load structures from cdd's
  1654. *
  1655. * Revision 1.39  2000/12/20 23:47:48  thiessen
  1656. * load CDD's
  1657. *
  1658. * Revision 1.38  2000/12/15 15:51:47  thiessen
  1659. * show/hide system installed
  1660. *
  1661. * Revision 1.37  2000/12/01 19:35:57  thiessen
  1662. * better domain assignment; basic show/hide mechanism
  1663. *
  1664. * Revision 1.36  2000/11/30 15:49:40  thiessen
  1665. * add show/hide rows; unpack sec. struc. and domain features
  1666. *
  1667. * Revision 1.35  2000/11/13 18:06:53  thiessen
  1668. * working structure re-superpositioning
  1669. *
  1670. * Revision 1.34  2000/11/12 04:03:00  thiessen
  1671. * working file save including alignment edits
  1672. *
  1673. * Revision 1.33  2000/11/11 21:15:55  thiessen
  1674. * create Seq-annot from BlockMultipleAlignment
  1675. *
  1676. * Revision 1.32  2000/11/02 16:56:03  thiessen
  1677. * working editor undo; dynamic slave transforms
  1678. *
  1679. * Revision 1.31  2000/09/20 22:22:29  thiessen
  1680. * working conservation coloring; split and center unaligned justification
  1681. *
  1682. * Revision 1.30  2000/09/15 19:24:22  thiessen
  1683. * allow repeated structures w/o different local id
  1684. *
  1685. * Revision 1.29  2000/09/11 22:57:33  thiessen
  1686. * working highlighting
  1687. *
  1688. * Revision 1.28  2000/09/11 14:06:29  thiessen
  1689. * working alignment coloring
  1690. *
  1691. * Revision 1.27  2000/09/11 01:46:16  thiessen
  1692. * working messenger for sequence<->structure window communication
  1693. *
  1694. * Revision 1.26  2000/08/30 19:48:43  thiessen
  1695. * working sequence window
  1696. *
  1697. * Revision 1.25  2000/08/29 04:34:27  thiessen
  1698. * working alignment manager, IBM
  1699. *
  1700. * Revision 1.24  2000/08/28 23:47:19  thiessen
  1701. * functional denseg and dendiag alignment parsing
  1702. *
  1703. * Revision 1.23  2000/08/28 18:52:42  thiessen
  1704. * start unpacking alignments
  1705. *
  1706. * Revision 1.22  2000/08/27 18:52:22  thiessen
  1707. * extract sequence information
  1708. *
  1709. * Revision 1.21  2000/08/21 19:31:48  thiessen
  1710. * add style consistency checking
  1711. *
  1712. * Revision 1.20  2000/08/21 17:22:38  thiessen
  1713. * add primitive highlighting for testing
  1714. *
  1715. * Revision 1.19  2000/08/17 14:24:06  thiessen
  1716. * added working StyleManager
  1717. *
  1718. * Revision 1.18  2000/08/13 02:43:01  thiessen
  1719. * added helix and strand objects
  1720. *
  1721. * Revision 1.17  2000/08/07 14:13:16  thiessen
  1722. * added animation frames
  1723. *
  1724. * Revision 1.16  2000/08/07 00:21:18  thiessen
  1725. * add display list mechanism
  1726. *
  1727. * Revision 1.15  2000/08/04 22:49:04  thiessen
  1728. * add backbone atom classification and selection feedback mechanism
  1729. *
  1730. * Revision 1.14  2000/08/03 15:12:23  thiessen
  1731. * add skeleton of style and show/hide managers
  1732. *
  1733. * Revision 1.13  2000/07/27 13:30:51  thiessen
  1734. * remove 'using namespace ...' from all headers
  1735. *
  1736. * Revision 1.12  2000/07/18 16:50:11  thiessen
  1737. * more friendly rotation center setting
  1738. *
  1739. * Revision 1.11  2000/07/18 00:06:00  thiessen
  1740. * allow arbitrary rotation center
  1741. *
  1742. * Revision 1.10  2000/07/17 22:37:18  thiessen
  1743. * fix vector_math typo; correctly set initial view
  1744. *
  1745. * Revision 1.9  2000/07/17 04:20:50  thiessen
  1746. * now does correct structure alignment transformation
  1747. *
  1748. * Revision 1.8  2000/07/16 23:19:11  thiessen
  1749. * redo of drawing system
  1750. *
  1751. * Revision 1.7  2000/07/12 02:00:15  thiessen
  1752. * add basic wxWindows GUI
  1753. *
  1754. * Revision 1.6  2000/07/11 13:45:31  thiessen
  1755. * add modules to parse chemical graph; many improvements
  1756. *
  1757. * Revision 1.5  2000/07/01 15:43:50  thiessen
  1758. * major improvements to StructureBase functionality
  1759. *
  1760. * Revision 1.4  2000/06/29 16:46:07  thiessen
  1761. * use NCBI streams correctly
  1762. *
  1763. * Revision 1.3  2000/06/29 14:35:06  thiessen
  1764. * new atom_set files
  1765. *
  1766. * Revision 1.2  2000/06/28 13:07:55  thiessen
  1767. * store alt conf ensembles
  1768. *
  1769. * Revision 1.1  2000/06/27 20:09:40  thiessen
  1770. * initial checkin
  1771. *
  1772. */