1 /*  $Id: style_manager.cpp 411368 2013-08-28 11:25:58Z thiessen $
2 * ===========================================================================
3 *
4 *                            PUBLIC DOMAIN NOTICE
5 *               National Center for Biotechnology Information
6 *
7 *  This software/database is a "United States Government Work" under the
8 *  terms of the United States Copyright Act.  It was written as part of
9 *  the author's official duties as a United States Government employee and
10 *  thus cannot be copyrighted.  This software/database is freely available
11 *  to the public for use. The National Library of Medicine and the U.S.
12 *  Government have not placed any restriction on its use or reproduction.
13 *
14 *  Although all reasonable efforts have been taken to ensure the accuracy
15 *  and reliability of the software and data, the NLM and the U.S.
16 *  Government do not and cannot warrant the performance or results that
17 *  may be obtained by using this software or data. The NLM and the U.S.
18 *  Government disclaim all warranties, express or implied, including
19 *  warranties of performance, merchantability or fitness for any particular
20 *  purpose.
21 *
22 *  Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors:  Paul Thiessen
27 *
28 * File Description:
29 *      manager object to track drawing style of objects at various levels
30 *
31 * ===========================================================================
32 */
33 
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbistd.hpp>
36 #include <corelib/ncbiobj.hpp>
37 
38 #include <objects/cn3d/Cn3d_backbone_style.hpp>
39 #include <objects/cn3d/Cn3d_general_style.hpp>
40 #include <objects/cn3d/Cn3d_backbone_label_style.hpp>
41 #include <objects/cn3d/Cn3d_color.hpp>
42 #include <objects/cn3d/Cn3d_style_table_item.hpp>
43 #include <objects/cn3d/Cn3d_style_table_id.hpp>
44 #include <objects/cn3d/Cn3d_user_annotation.hpp>
45 #include <objects/cn3d/Cn3d_object_location.hpp>
46 #include <objects/mmdb1/Biostruc_id.hpp>
47 #include <objects/mmdb1/Mmdb_id.hpp>
48 #include <objects/cn3d/Cn3d_molecule_location.hpp>
49 #include <objects/cn3d/Cn3d_residue_range.hpp>
50 #include <objects/mmdb1/Residue_id.hpp>
51 #include <objects/mmdb1/Molecule_id.hpp>
52 
53 #include <memory>
54 #include <string.h> // for memcpy()
55 
56 #include "remove_header_conflicts.hpp"
57 
58 #include "style_manager.hpp"
59 #include "structure_set.hpp"
60 #include "chemical_graph.hpp"
61 #include "residue.hpp"
62 #include "periodic_table.hpp"
63 #include "bond.hpp"
64 #include "show_hide_manager.hpp"
65 #include "object_3d.hpp"
66 #include "alignment_manager.hpp"
67 #include "messenger.hpp"
68 #include "cn3d_colors.hpp"
69 #include "style_dialog.hpp"
70 #include "annotate_dialog.hpp"
71 #include "molecule_identifier.hpp"
72 #include "atom_set.hpp"
73 #include "cn3d_tools.hpp"
74 #include "block_multiple_alignment.hpp"
75 
76 USING_NCBI_SCOPE;
77 USING_SCOPE(objects);
78 
79 
BEGIN_SCOPE(Cn3D)80 BEGIN_SCOPE(Cn3D)
81 
82 ///// StyleSettings stuff /////
83 
84 static void Vector2ASNColor(const Vector &vec, CCn3d_color *asnColor)
85 {
86     static const int SCALE = 10000;
87     asnColor->SetScale_factor(SCALE);
88     asnColor->SetRed((int) (vec[0] * SCALE));
89     asnColor->SetGreen((int) (vec[1] * SCALE));
90     asnColor->SetBlue((int) (vec[2] * SCALE));
91     asnColor->SetAlpha(SCALE);  // no alpha in Cn3D's colors
92 }
93 
SaveBackboneStyleToASN(const StyleSettings::BackboneStyle bbSettings,CCn3d_backbone_style * bbASN)94 static bool SaveBackboneStyleToASN(
95     const StyleSettings::BackboneStyle bbSettings, CCn3d_backbone_style *bbASN)
96 {
97     // these casts rely on correspondence of enumerated values!
98     bbASN->SetType((ECn3d_backbone_type) bbSettings.type);
99     bbASN->SetStyle((ECn3d_drawing_style) bbSettings.style);
100     bbASN->SetColor_scheme((ECn3d_color_scheme) bbSettings.colorScheme);
101     Vector2ASNColor(bbSettings.userColor, &(bbASN->SetUser_color()));
102     return true;
103 }
104 
SaveGeneralStyleToASN(const StyleSettings::GeneralStyle gSettings,CCn3d_general_style * gASN)105 static bool SaveGeneralStyleToASN(
106     const StyleSettings::GeneralStyle gSettings, CCn3d_general_style *gASN)
107 {
108     // these casts rely on correspondence of enumerated values!
109     gASN->SetIs_on(gSettings.isOn);
110     gASN->SetStyle((ECn3d_drawing_style) gSettings.style);
111     gASN->SetColor_scheme((ECn3d_color_scheme) gSettings.colorScheme);
112     Vector2ASNColor(gSettings.userColor, &(gASN->SetUser_color()));
113     return true;
114 }
115 
SaveLabelStyleToASN(const StyleSettings::LabelStyle lSettings,CCn3d_backbone_label_style * lASN)116 static bool SaveLabelStyleToASN(
117     const StyleSettings::LabelStyle lSettings, CCn3d_backbone_label_style *lASN)
118 {
119     lASN->SetSpacing(lSettings.spacing);
120     // these casts rely on correspondence of enumerated values!
121     lASN->SetType((CCn3d_backbone_label_style::EType) lSettings.type);
122     lASN->SetNumber((CCn3d_backbone_label_style::ENumber) lSettings.numbering);
123     lASN->SetTermini(lSettings.terminiOn);
124     lASN->SetWhite(lSettings.white);
125     return true;
126 }
127 
SaveSettingsToASN(CCn3d_style_settings * styleASN) const128 bool StyleSettings::SaveSettingsToASN(CCn3d_style_settings *styleASN) const
129 {
130     styleASN->SetVirtual_disulfides_on(virtualDisulfidesOn);
131     Vector2ASNColor(virtualDisulfideColor, &(styleASN->SetVirtual_disulfide_color()));
132     styleASN->SetHydrogens_on(hydrogensOn);
133     Vector2ASNColor(backgroundColor, &(styleASN->SetBackground_color()));
134     styleASN->SetIon_labels(ionLabelsOn);
135 
136     static const int SCALE = 10000;
137     styleASN->SetScale_factor(SCALE);
138     styleASN->SetSpace_fill_proportion((int) (spaceFillProportion * SCALE));
139     styleASN->SetBall_radius((int) (ballRadius * SCALE));
140     styleASN->SetStick_radius((int) (stickRadius * SCALE));
141     styleASN->SetTube_radius((int) (tubeRadius * SCALE));
142     styleASN->SetTube_worm_radius((int) (tubeWormRadius * SCALE));
143     styleASN->SetHelix_radius((int) (helixRadius * SCALE));
144     styleASN->SetStrand_width((int) (strandWidth * SCALE));
145     styleASN->SetStrand_thickness((int) (strandThickness * SCALE));
146 
147     return (
148         SaveBackboneStyleToASN(proteinBackbone, &(styleASN->SetProtein_backbone())) &&
149         SaveBackboneStyleToASN(nucleotideBackbone, &(styleASN->SetNucleotide_backbone())) &&
150         SaveGeneralStyleToASN(proteinSidechains, &(styleASN->SetProtein_sidechains())) &&
151         SaveGeneralStyleToASN(nucleotideSidechains, &(styleASN->SetNucleotide_sidechains())) &&
152         SaveGeneralStyleToASN(heterogens, &(styleASN->SetHeterogens())) &&
153         SaveGeneralStyleToASN(solvents, &(styleASN->SetSolvents())) &&
154         SaveGeneralStyleToASN(connections, &(styleASN->SetConnections())) &&
155         SaveGeneralStyleToASN(helixObjects, &(styleASN->SetHelix_objects())) &&
156         SaveGeneralStyleToASN(strandObjects, &(styleASN->SetStrand_objects())) &&
157         SaveLabelStyleToASN(proteinLabels, &(styleASN->SetProtein_labels())) &&
158         SaveLabelStyleToASN(nucleotideLabels, &(styleASN->SetNucleotide_labels()))
159     );
160 }
161 
ASNColor2Vector(const CCn3d_color & asnColor,Vector * vec)162 static void ASNColor2Vector(const CCn3d_color& asnColor, Vector *vec)
163 {
164     int SCALE = asnColor.GetScale_factor();
165     vec->Set(
166         1.0 * asnColor.GetRed() / SCALE,
167         1.0 * asnColor.GetGreen() / SCALE,
168         1.0 * asnColor.GetBlue() / SCALE
169     );
170     // no alpha in Cn3D's colors
171 }
172 
LoadBackboneStyleFromASN(const CCn3d_backbone_style & bbASN,StyleSettings::BackboneStyle * bbSettings)173 static bool LoadBackboneStyleFromASN(
174     const CCn3d_backbone_style& bbASN, StyleSettings::BackboneStyle *bbSettings)
175 {
176     // these casts rely on correspondence of enumerated values!
177     bbSettings->type = (StyleSettings::eBackboneType) bbASN.GetType();
178     bbSettings->style = (StyleSettings::eDrawingStyle) bbASN.GetStyle();
179     bbSettings->colorScheme = (StyleSettings::eColorScheme) bbASN.GetColor_scheme();
180     ASNColor2Vector(bbASN.GetUser_color(), &(bbSettings->userColor));
181     return true;
182 }
183 
LoadGeneralStyleFromASN(const CCn3d_general_style & gASN,StyleSettings::GeneralStyle * gSettings)184 static bool LoadGeneralStyleFromASN(
185     const CCn3d_general_style& gASN, StyleSettings::GeneralStyle *gSettings)
186 {
187     // these casts rely on correspondence of enumerated values!
188     gSettings->isOn = gASN.GetIs_on();
189     gSettings->style = (StyleSettings::eDrawingStyle) gASN.GetStyle();
190     gSettings->colorScheme = (StyleSettings::eColorScheme) gASN.GetColor_scheme();
191     ASNColor2Vector(gASN.GetUser_color(), &(gSettings->userColor));
192     return true;
193 }
194 
LoadLabelStyleFromASN(const CCn3d_backbone_label_style & lASN,StyleSettings::LabelStyle * lSettings)195 static bool LoadLabelStyleFromASN(
196     const CCn3d_backbone_label_style& lASN, StyleSettings::LabelStyle *lSettings)
197 {
198     lSettings->spacing = lASN.GetSpacing();
199     // these casts rely on correspondence of enumerated values!
200     lSettings->type = (StyleSettings::eLabelType) lASN.GetType();
201     lSettings->numbering = (StyleSettings::eNumberType) lASN.GetNumber();
202     lSettings->terminiOn = lASN.GetTermini();
203     lSettings->white = lASN.GetWhite();
204     return true;
205 }
206 
SetDefaultLabelStyle(StyleSettings::LabelStyle * lStyle)207 static void SetDefaultLabelStyle(StyleSettings::LabelStyle *lStyle)
208 {
209     lStyle->spacing = 0;
210     lStyle->type = StyleSettings::eThreeLetter;
211     lStyle->numbering = StyleSettings::eSequentialNumbering;
212     lStyle->terminiOn = false;
213     lStyle->white = true;
214 }
215 
LoadSettingsFromASN(const CCn3d_style_settings & styleASN)216 bool StyleSettings::LoadSettingsFromASN(const CCn3d_style_settings& styleASN)
217 {
218     virtualDisulfidesOn = styleASN.GetVirtual_disulfides_on();
219     ASNColor2Vector(styleASN.GetVirtual_disulfide_color(), &virtualDisulfideColor);
220     hydrogensOn = styleASN.GetHydrogens_on();
221     ASNColor2Vector(styleASN.GetBackground_color(), &backgroundColor);
222 
223     int SCALE = styleASN.GetScale_factor();
224     spaceFillProportion = 1.0 * styleASN.GetSpace_fill_proportion() / SCALE;
225     stickRadius = 1.0 * styleASN.GetStick_radius() / SCALE;
226     tubeRadius = 1.0 * styleASN.GetTube_radius() / SCALE;
227     tubeWormRadius = 1.0 * styleASN.GetTube_worm_radius() / SCALE;
228     helixRadius = 1.0 * styleASN.GetHelix_radius() / SCALE;
229     strandWidth = 1.0 * styleASN.GetStrand_width() / SCALE;
230     strandThickness = 1.0 * styleASN.GetStrand_thickness() / SCALE;
231 
232     // label defaults (since they're optional in ASN spec)
233     if (styleASN.IsSetProtein_labels()) {
234         if (!LoadLabelStyleFromASN(styleASN.GetProtein_labels(), &proteinLabels)) return false;
235     } else
236         SetDefaultLabelStyle(&proteinLabels);
237     if (styleASN.IsSetNucleotide_labels()) {
238         if (!LoadLabelStyleFromASN(styleASN.GetNucleotide_labels(), &nucleotideLabels)) return false;
239     } else
240         SetDefaultLabelStyle(&nucleotideLabels);
241     // ion labels on by default
242     ionLabelsOn = (styleASN.IsSetIon_labels()) ? styleASN.GetIon_labels() : true;
243 
244     return (
245         LoadBackboneStyleFromASN(styleASN.GetProtein_backbone(), &proteinBackbone) &&
246         LoadBackboneStyleFromASN(styleASN.GetNucleotide_backbone(), &nucleotideBackbone) &&
247         LoadGeneralStyleFromASN(styleASN.GetProtein_sidechains(), &proteinSidechains) &&
248         LoadGeneralStyleFromASN(styleASN.GetNucleotide_sidechains(), &nucleotideSidechains) &&
249         LoadGeneralStyleFromASN(styleASN.GetHeterogens(), &heterogens) &&
250         LoadGeneralStyleFromASN(styleASN.GetSolvents(), &solvents) &&
251         LoadGeneralStyleFromASN(styleASN.GetConnections(), &connections) &&
252         LoadGeneralStyleFromASN(styleASN.GetHelix_objects(), &helixObjects) &&
253         LoadGeneralStyleFromASN(styleASN.GetStrand_objects(), &strandObjects)
254     );
255 }
256 
operator =(const StyleSettings & orig)257 StyleSettings& StyleSettings::operator = (const StyleSettings& orig)
258 {
259     memcpy(this, &orig, sizeof(StyleSettings));
260     return *this;
261 }
262 
SetRenderingStyle(ePredefinedRenderingStyle style)263 void StyleSettings::SetRenderingStyle(ePredefinedRenderingStyle style)
264 {
265     // variable settings
266     switch (style) {
267 
268         // set sidechains isOn only
269         case eToggleSidechainsShortcut:
270             proteinSidechains.isOn = !proteinSidechains.isOn;
271             nucleotideSidechains.isOn = !nucleotideSidechains.isOn;
272             return;
273 
274         case eWormShortcut:
275             proteinBackbone.type = nucleotideBackbone.type = eTrace;
276             proteinBackbone.style = nucleotideBackbone.style = eTubeWorm;
277             proteinSidechains.isOn = nucleotideSidechains.isOn = false;
278             proteinSidechains.style = nucleotideSidechains.style = eWire;
279             heterogens.style = eBallAndStick;
280             solvents.isOn = false;
281             solvents.style = eBallAndStick;
282             connections.style = eTubes;
283             helixObjects.isOn = strandObjects.isOn = true;
284             helixObjects.style = strandObjects.style = eWithArrows;
285             break;
286 
287         case eTubeShortcut:
288             proteinBackbone.type = nucleotideBackbone.type = eTrace;
289             proteinBackbone.style = nucleotideBackbone.style = eTubes;
290             proteinSidechains.isOn = nucleotideSidechains.isOn = false;
291             proteinSidechains.style = nucleotideSidechains.style = eWire;
292             heterogens.style = eBallAndStick;
293             solvents.isOn = false;
294             solvents.style = eBallAndStick;
295             connections.style = eTubes;
296             helixObjects.isOn = strandObjects.isOn = false;
297             helixObjects.style = strandObjects.style = eWithArrows;
298             break;
299 
300         case eWireframeShortcut:
301             proteinBackbone.type = nucleotideBackbone.type = eComplete;
302             proteinBackbone.style = nucleotideBackbone.style = eWire;
303             proteinSidechains.isOn = nucleotideSidechains.isOn = true;
304             proteinSidechains.style = nucleotideSidechains.style = eWire;
305             heterogens.style = eWire;
306             solvents.isOn = false;
307             solvents.style = eBallAndStick;
308             connections.style = eWire;
309             helixObjects.isOn = strandObjects.isOn = false;
310             helixObjects.style = strandObjects.style = eWithArrows;
311             break;
312 
313         case eBallAndStickShortcut:
314             proteinBackbone.type = nucleotideBackbone.type = eComplete;
315             proteinBackbone.style = nucleotideBackbone.style = eBallAndStick;
316             proteinSidechains.isOn = nucleotideSidechains.isOn = true;
317             proteinSidechains.style = nucleotideSidechains.style = eBallAndStick;
318             heterogens.style = eBallAndStick;
319             solvents.isOn = false;
320             solvents.style = eBallAndStick;
321             connections.style = eTubes;
322             helixObjects.isOn = strandObjects.isOn = false;
323             helixObjects.style = strandObjects.style = eWithArrows;
324             break;
325 
326         case eSpacefillShortcut:
327             proteinBackbone.type = nucleotideBackbone.type = eComplete;
328             proteinBackbone.style = nucleotideBackbone.style = eSpaceFill;
329             proteinSidechains.isOn = nucleotideSidechains.isOn = true;
330             proteinSidechains.style = nucleotideSidechains.style = eSpaceFill;
331             heterogens.style = eSpaceFill;
332             solvents.isOn = false;
333             solvents.style = eSpaceFill;
334             connections.style = eTubes;
335             helixObjects.isOn = strandObjects.isOn = false;
336             helixObjects.style = strandObjects.style = eWithArrows;
337             break;
338     }
339 
340     // common settings
341     heterogens.isOn = true;
342     connections.isOn = true;
343     virtualDisulfidesOn = true;
344     hydrogensOn = true;
345     helixRadius = 1.8;
346     strandWidth = 2.0;
347     strandThickness = 0.5;
348     spaceFillProportion = 1.0;
349     ballRadius = 0.4;
350     stickRadius = 0.2;
351     tubeRadius = 0.3;
352     tubeWormRadius = 0.3;
353 }
354 
SetColorScheme(ePredefinedColorScheme scheme)355 void StyleSettings::SetColorScheme(ePredefinedColorScheme scheme)
356 {
357     // variable settings
358     switch (scheme) {
359         case eSecondaryStructureShortcut:
360             proteinBackbone.colorScheme = eSecondaryStructure;
361             nucleotideBackbone.colorScheme = eMolecule;
362             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eElement;
363             heterogens.colorScheme = solvents.colorScheme = eElement;
364             helixObjects.colorScheme = strandObjects.colorScheme = eSecondaryStructure;
365             break;
366 
367         case eAlignedShortcut: case eIdentityShortcut: case eVarietyShortcut:
368         case eWeightedVarietyShortcut: case eInformationContentShortcut:
369         case eFitShortcut: case eBlockFitShortcut: case eBlockZFitShortcut: case eBlockRowFitShortcut:
370             switch (scheme) {
371                 case eAlignedShortcut: proteinBackbone.colorScheme = eAligned; break;
372                 case eIdentityShortcut: proteinBackbone.colorScheme = eIdentity; break;
373                 case eVarietyShortcut: proteinBackbone.colorScheme = eVariety; break;
374                 case eWeightedVarietyShortcut: proteinBackbone.colorScheme = eWeightedVariety; break;
375                 case eInformationContentShortcut: proteinBackbone.colorScheme = eInformationContent; break;
376                 case eFitShortcut: proteinBackbone.colorScheme = eFit; break;
377                 case eBlockFitShortcut: proteinBackbone.colorScheme = eBlockFit; break;
378                 case eBlockZFitShortcut: proteinBackbone.colorScheme = eBlockZFit; break;
379                 case eBlockRowFitShortcut: proteinBackbone.colorScheme = eBlockRowFit; break;
380                 default:
381                     break;
382             }
383             nucleotideBackbone.colorScheme = eMolecule;
384             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eElement;
385             heterogens.colorScheme = solvents.colorScheme = eElement;
386             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
387             break;
388 
389         case eObjectShortcut:
390             proteinBackbone.colorScheme = eObject;
391             nucleotideBackbone.colorScheme = eObject;
392             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eObject;
393             heterogens.colorScheme = solvents.colorScheme = eObject;
394             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
395             break;
396 
397         case eDomainShortcut:
398             proteinBackbone.colorScheme = eDomain;
399             nucleotideBackbone.colorScheme = eDomain;
400             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eElement;
401             heterogens.colorScheme = solvents.colorScheme = eElement;
402             helixObjects.colorScheme = strandObjects.colorScheme = eDomain;
403             break;
404 
405         case eMoleculeShortcut:
406             proteinBackbone.colorScheme = eMolecule;
407             nucleotideBackbone.colorScheme = eMolecule;
408             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eMolecule;
409             heterogens.colorScheme = solvents.colorScheme = eMolecule;
410             helixObjects.colorScheme = strandObjects.colorScheme = eMolecule;
411             break;
412 
413         case eResidueShortcut:
414             proteinBackbone.colorScheme = eResidue;
415             nucleotideBackbone.colorScheme = eResidue;
416             proteinSidechains.colorScheme = eResidue;
417             nucleotideSidechains.colorScheme = eResidue;
418             heterogens.colorScheme = solvents.colorScheme = eMolecule;
419             helixObjects.colorScheme = strandObjects.colorScheme = eMolecule;
420             break;
421 
422         case eRainbowShortcut:
423             proteinBackbone.colorScheme = eRainbow;
424             nucleotideBackbone.colorScheme = eRainbow;
425             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eRainbow;
426             heterogens.colorScheme = solvents.colorScheme = eElement;
427             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
428             break;
429 
430         case eHydrophobicityShortcut:
431             proteinBackbone.colorScheme = eHydrophobicity;
432             nucleotideBackbone.colorScheme = eMolecule;
433             proteinSidechains.colorScheme = eHydrophobicity;
434             nucleotideSidechains.colorScheme = eElement;
435             heterogens.colorScheme = solvents.colorScheme = eElement;
436             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
437             break;
438 
439         case eChargeShortcut:
440             proteinBackbone.colorScheme = eCharge;
441             nucleotideBackbone.colorScheme = eElement;
442             proteinSidechains.colorScheme = eCharge;
443             nucleotideSidechains.colorScheme = eElement;
444             heterogens.colorScheme = solvents.colorScheme = eElement;
445             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
446             break;
447 
448         case eTemperatureShortcut:
449             proteinBackbone.colorScheme = eTemperature;
450             nucleotideBackbone.colorScheme = eTemperature;
451             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eTemperature;
452             heterogens.colorScheme = solvents.colorScheme = eTemperature;
453             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
454             break;
455 
456         case eElementShortcut:
457             proteinBackbone.colorScheme = eElement;
458             nucleotideBackbone.colorScheme = eElement;
459             proteinSidechains.colorScheme = nucleotideSidechains.colorScheme = eElement;
460             heterogens.colorScheme = eElement;
461             solvents.colorScheme = eElement;
462             helixObjects.colorScheme = strandObjects.colorScheme = eObject;
463             break;
464     }
465 
466     // common settings
467     connections.colorScheme = eUserSelect;
468     connections.userColor.Set(0.9,0.9,1);
469     virtualDisulfideColor.Set(0.93,0.55,0.05);
470     backgroundColor.Set(0,0,0);
471 
472     proteinSidechains.userColor = nucleotideSidechains.userColor =
473     proteinBackbone.userColor = nucleotideBackbone.userColor =
474     heterogens.userColor = solvents.userColor =
475     helixObjects.userColor = strandObjects.userColor = Vector(0.5,0.5,0.5);
476 }
477 
SetDefaultLabeling(void)478 void StyleSettings::SetDefaultLabeling(void)
479 {
480     SetDefaultLabelStyle(&proteinLabels);
481     SetDefaultLabelStyle(&nucleotideLabels);
482     ionLabelsOn = true;
483 }
484 
485 
486 ///// StyleManager stuff /////
487 
StyleManager(const StructureSet * set)488 StyleManager::StyleManager(const StructureSet *set) : structureSet(set)
489 {
490 }
491 
CheckGlobalStyleSettings()492 bool StyleManager::CheckGlobalStyleSettings()
493 {
494     return CheckStyleSettings(&globalStyle);
495 }
496 
497 // check for inconsistencies in style settings; returns false if there's an uncorrectable problem
CheckStyleSettings(StyleSettings * settings)498 bool StyleManager::CheckStyleSettings(StyleSettings *settings)
499 {
500     // can't do worm with partial or complete backbone
501     if (((settings->proteinBackbone.style == StyleSettings::eWireWorm ||
502           settings->proteinBackbone.style == StyleSettings::eTubeWorm) &&
503          (settings->proteinBackbone.type == StyleSettings::ePartial ||
504           settings->proteinBackbone.type == StyleSettings::eComplete))) {
505         settings->proteinBackbone.type = StyleSettings::eTrace;
506     }
507     if (((settings->nucleotideBackbone.style == StyleSettings::eWireWorm ||
508           settings->nucleotideBackbone.style == StyleSettings::eTubeWorm) &&
509          (settings->nucleotideBackbone.type == StyleSettings::ePartial ||
510           settings->nucleotideBackbone.type == StyleSettings::eComplete))) {
511         settings->nucleotideBackbone.type = StyleSettings::eTrace;
512     }
513 
514     // can't do non-trace backbones for ncbi-backbone models
515     if (structureSet->isAlphaOnly) {
516         if (settings->proteinBackbone.type == StyleSettings::ePartial ||
517             settings->proteinBackbone.type == StyleSettings::eComplete) {
518             settings->proteinBackbone.type = StyleSettings::eTrace;
519         }
520         if (settings->nucleotideBackbone.type == StyleSettings::ePartial ||
521             settings->nucleotideBackbone.type == StyleSettings::eComplete) {
522             settings->nucleotideBackbone.type = StyleSettings::eTrace;
523         }
524     }
525 
526     return true;
527 }
528 
529 const double UNKNOWN_HYDROPHOBICITY = -1.0;
530 
531 // return a hydrophobicity value from [0..1]
GetHydrophobicity(char code)532 double GetHydrophobicity(char code)
533 {
534     // Amino acid scale: Normalized consensus hydrophobicity scale.
535     // Author(s): Eisenberg D., Schwarz E., Komarony M., Wall R.
536     // Reference: J. Mol. Biol. 179:125-142(1984).
537     // Amino acid scale values: (normalized to [0..1])
538     switch (code) {
539         case 'A': return ( 0.620 + 2.530) / (1.380 + 2.530);
540         case 'R': return (-2.530 + 2.530) / (1.380 + 2.530);
541         case 'N': return (-0.780 + 2.530) / (1.380 + 2.530);
542         case 'D': return (-0.900 + 2.530) / (1.380 + 2.530);
543         case 'C': return ( 0.290 + 2.530) / (1.380 + 2.530);
544         case 'Q': return (-0.850 + 2.530) / (1.380 + 2.530);
545         case 'E': return (-0.740 + 2.530) / (1.380 + 2.530);
546         case 'G': return ( 0.480 + 2.530) / (1.380 + 2.530);
547         case 'H': return (-0.400 + 2.530) / (1.380 + 2.530);
548         case 'I': return ( 1.380 + 2.530) / (1.380 + 2.530);
549         case 'L': return ( 1.060 + 2.530) / (1.380 + 2.530);
550         case 'K': return (-1.500 + 2.530) / (1.380 + 2.530);
551         case 'M': return ( 0.640 + 2.530) / (1.380 + 2.530);
552         case 'F': return ( 1.190 + 2.530) / (1.380 + 2.530);
553         case 'P': return ( 0.120 + 2.530) / (1.380 + 2.530);
554         case 'S': return (-0.180 + 2.530) / (1.380 + 2.530);
555         case 'T': return (-0.050 + 2.530) / (1.380 + 2.530);
556         case 'W': return ( 0.810 + 2.530) / (1.380 + 2.530);
557         case 'Y': return ( 0.260 + 2.530) / (1.380 + 2.530);
558         case 'V': return ( 1.080 + 2.530) / (1.380 + 2.530);
559     }
560     return UNKNOWN_HYDROPHOBICITY;
561 }
562 
GetCharge(char code)563 int GetCharge(char code)
564 {
565     switch (code) {
566         case 'R': case 'H': case 'K': return 1;
567         case 'D': case 'E': return -1;
568     }
569     return 0;
570 }
571 
572 #define ATOM_NOT_DISPLAYED do { \
573     atomStyle->style = eNotDisplayed; \
574     return true; } while (0)
575 
576 // get display style for atom, including show/hide status.
577 // May want to cache this eventually, since a
578 // particular atom's style may be queried several times per render (once for
579 // drawing atoms, and once for each bond to the atom).
GetAtomStyle(const Residue * residue,const AtomPntr & atom,const AtomCoord * coord,AtomStyle * atomStyle,const StyleSettings::BackboneStyle ** saveBackboneStyle,const StyleSettings::GeneralStyle ** saveGeneralStyle) const580 bool StyleManager::GetAtomStyle(const Residue *residue,
581     const AtomPntr& atom, const AtomCoord *coord,
582     AtomStyle *atomStyle,
583     const StyleSettings::BackboneStyle* *saveBackboneStyle,
584     const StyleSettings::GeneralStyle* *saveGeneralStyle) const
585 {
586     if (!residue || !atomStyle) {
587         ERRORMSG("StyleManager::GetAtomStyle() got NULL residue or atomStyle");
588         return false;
589     }
590     atomStyle->isHighlighted = false; // queried sometimes even if atom not displayed
591 
592     const Molecule *molecule;
593     if (!residue->GetParentOfType(&molecule)) return false;
594 
595     const StructureObject *object;
596     if (!molecule->GetParentOfType(&object)) return false;
597 
598     const StyleSettings& settings = GetStyleForResidue(object, atom.mID, atom.rID);
599     const Residue::AtomInfo *info = residue->GetAtomInfo(atom.aID);
600     if (!info)
601         ATOM_NOT_DISPLAYED;
602 
603     // set up some pointers for more convenient access to style settings
604     const StyleSettings::BackboneStyle *backboneStyle = NULL;
605     const StyleSettings::GeneralStyle *generalStyle = NULL;
606     if (info->classification == Residue::eAlphaBackboneAtom ||
607         info->classification == Residue::ePartialBackboneAtom ||
608         info->classification == Residue::eCompleteBackboneAtom) {
609         if (residue->IsAminoAcid())
610             backboneStyle = &(settings.proteinBackbone);
611         else
612             backboneStyle = &(settings.nucleotideBackbone);
613 
614     } else if (info->classification == Residue::eSideChainAtom) {
615         if (residue->IsAminoAcid())
616             generalStyle = &(settings.proteinSidechains);
617         else
618             generalStyle = &(settings.nucleotideSidechains);
619 
620     } else { // Residue::eUnknownAtom: basically anything not explicitly marked
621              // solvent is treated as heterogen for style purposes
622         if (molecule->IsSolvent())
623             generalStyle = &(settings.solvents);
624         else
625             generalStyle = &(settings.heterogens);
626     }
627     if ((!backboneStyle && !generalStyle) || (backboneStyle && generalStyle)) {
628         ERRORMSG("StyleManager::GetAtomStyle() - confused about style settings");
629         return false;
630     }
631     if (saveBackboneStyle) *saveBackboneStyle = backboneStyle;
632     if (saveGeneralStyle) *saveGeneralStyle = generalStyle;
633 
634     // first check whether this atom is visible, based on show/hide and backbone and sidechain settings
635     if (object->parentSet->showHideManager->IsHidden(residue))
636         ATOM_NOT_DISPLAYED;
637 
638     if (info->atomicNumber == 1 && !settings.hydrogensOn)
639         ATOM_NOT_DISPLAYED;
640 
641     if (info->classification == Residue::eSideChainAtom && !generalStyle->isOn)
642        ATOM_NOT_DISPLAYED;
643 
644     if (info->classification == Residue::eAlphaBackboneAtom ||
645         info->classification == Residue::ePartialBackboneAtom ||
646         info->classification == Residue::eCompleteBackboneAtom) { // is backbone of some sort
647 
648         // control presence of non CA/C1* backbone atoms
649         if ((residue->IsAminoAcid() && info->classification != Residue::eAlphaBackboneAtom) ||
650             (residue->IsNucleotide() && info->code != " C1*")) {
651 
652             // skip if backbone off
653             if (backboneStyle->type == StyleSettings::eOff)
654                 ATOM_NOT_DISPLAYED;
655 
656             // show only alpha atom if eTrace
657             if (backboneStyle->type == StyleSettings::eTrace &&
658                 info->classification != Residue::eAlphaBackboneAtom)
659                 ATOM_NOT_DISPLAYED;
660 
661             // don't show complete backbone if set to partial
662             if (info->classification == Residue::eCompleteBackboneAtom &&
663                 backboneStyle->type == StyleSettings::ePartial)
664                 ATOM_NOT_DISPLAYED;
665         }
666 
667         // if this is alpha/C1* and backbone is off, but sidechains are on, then
668         // let the atom be visible *and* take the style of the sidechain
669         else if (backboneStyle->type == StyleSettings::eOff ||
670                  (residue->IsNucleotide() && backboneStyle->type != StyleSettings::eComplete)) {
671 
672             const StyleSettings::GeneralStyle *sidechainStyle = NULL;
673             if (residue->IsAminoAcid()) sidechainStyle = &(settings.proteinSidechains);
674             else if (residue->IsNucleotide()) sidechainStyle = &(settings.nucleotideSidechains);
675 
676             if (sidechainStyle && sidechainStyle->isOn) {
677                 backboneStyle = NULL;
678                 generalStyle = sidechainStyle;
679             } else
680                 ATOM_NOT_DISPLAYED;
681         }
682     }
683 
684     if (info->classification == Residue::eUnknownAtom && !generalStyle->isOn)
685         ATOM_NOT_DISPLAYED;
686 
687     const Element *element = PeriodicTable.GetElement(info->atomicNumber);
688 
689     // determine radius
690     switch (backboneStyle ? backboneStyle->style : generalStyle->style) {
691         case StyleSettings::eWire:
692         case StyleSettings::eWireWorm:
693         case StyleSettings::eTubeWorm:
694             // no atom, but don't do ATOM_NOT_DISPLAYED, because bonds to this atom
695             // still may be displayed and need style info about this atom
696             atomStyle->radius = 0.0;
697             break;
698         case StyleSettings::eTubes:
699             atomStyle->radius = settings.tubeRadius;
700             break;
701         case StyleSettings::eBallAndStick:
702             atomStyle->radius = settings.ballRadius;
703             break;
704         case StyleSettings::eSpaceFill:
705             atomStyle->radius = element->vdWRadius * settings.spaceFillProportion;
706             break;
707         default:
708             ERRORMSG("StyleManager::GetAtomStyle() - inappropriate style for atom");
709             return false;
710     }
711 
712     // determine color
713     StyleSettings::eColorScheme
714         colorStyle = backboneStyle ? backboneStyle->colorScheme : generalStyle->colorScheme;
715     switch (colorStyle) {
716 
717         case StyleSettings::eElement:
718             atomStyle->color = element->color;
719             break;
720 
721         case StyleSettings::eAligned:
722         case StyleSettings::eIdentity:
723         case StyleSettings::eVariety:
724         case StyleSettings::eWeightedVariety:
725         case StyleSettings::eInformationContent:
726         case StyleSettings::eFit:
727         case StyleSettings::eBlockFit:
728         case StyleSettings::eBlockZFit:
729         case StyleSettings::eBlockRowFit:
730             if (molecule->sequence &&
731                 molecule->parentSet->alignmentManager->
732                     IsAligned(molecule->sequence, residue->id - 1)) { // assume seqIndex is rID - 1
733                 const Vector * color = molecule->parentSet->alignmentManager->
734                     GetAlignmentColor(molecule->sequence, residue->id - 1, colorStyle);
735                 if (color)
736                     atomStyle->color = *color;
737                 else
738                     atomStyle->color = GlobalColors()->Get(Colors::eUnaligned);
739                 break;
740             }
741             if (colorStyle != StyleSettings::eAligned) {
742                 atomStyle->color = GlobalColors()->Get(Colors::eUnaligned);
743                 break;
744             }
745             // if eAligned and not aligned, then fall through to use eObject coloring
746 
747         case StyleSettings::eObject:
748             atomStyle->color = GlobalColors()->Get(Colors::eCycle1, object->id - 1);
749             break;
750 
751         case StyleSettings::eDomain:
752             atomStyle->color =
753                 (molecule->residueDomains[residue->id - 1] == Molecule::NO_DOMAIN_SET) ?
754                     GlobalColors()->Get(Colors::eNoDomain) :
755                     GlobalColors()->Get(Colors::eCycle1, molecule->residueDomains[residue->id - 1] - 1);
756             break;
757 
758         case StyleSettings::eMolecule:
759             atomStyle->color = GlobalColors()->Get(Colors::eCycle1, molecule->id - 1);
760             break;
761 
762         case StyleSettings::eRainbow: {
763             double pos = -1.0;
764             const BlockMultipleAlignment *multiple = molecule->parentSet->alignmentManager->GetCurrentMultipleAlignment();
765             if (multiple) {
766                 if (molecule->sequence && molecule->parentSet->alignmentManager->IsAligned(molecule->sequence, residue->id - 1)) {
767                     pos = multiple->GetRelativeAlignmentFraction(multiple->GetAlignmentIndex(
768                         multiple->GetRowForSequence(molecule->sequence), residue->id - 1,
769                         BlockMultipleAlignment::eLeft));    // justification is irrelevant since this is aligned
770                 }
771             } else if ((residue->IsAminoAcid() || residue->IsNucleotide()) && molecule->NResidues() > 1) {
772                 pos = 1.0 * (residue->id - 1) / (molecule->NResidues() - 1);
773             }
774             if (pos >= 0.0)
775                 atomStyle->color = GlobalColors()->Get(Colors::eRainbowMap, pos);
776             else
777                 atomStyle->color = GlobalColors()->Get(Colors::eUnaligned);
778             break;
779         }
780 
781         case StyleSettings::eSecondaryStructure:
782             if (molecule->IsResidueInHelix(residue->id))
783                 atomStyle->color = GlobalColors()->Get(Colors::eHelix);
784             else if (molecule->IsResidueInStrand(residue->id))
785                 atomStyle->color = GlobalColors()->Get(Colors::eStrand);
786             else
787                 atomStyle->color = GlobalColors()->Get(Colors::eCoil);
788             break;
789 
790         case StyleSettings::eCharge: {
791             int charge = (residue->IsAminoAcid()) ? GetCharge(residue->code) : 0;
792             atomStyle->color = GlobalColors()->Get(
793                 (charge > 0) ? Colors::ePositive : ((charge < 0) ? Colors::eNegative : Colors::eNeutral));
794             break;
795         }
796 
797         case StyleSettings::eTemperature:
798             atomStyle->color =
799                 (coord && coord->averageTemperature != AtomCoord::NO_TEMPERATURE &&
800 				 object->maxTemperature != object->minTemperature) ?
801                     GlobalColors()->Get(Colors::eTemperatureMap,
802                         (coord->averageTemperature - object->minTemperature) /
803                         (object->maxTemperature - object->minTemperature)) :
804                     GlobalColors()->Get(Colors::eNoTemperature);
805             break;
806 
807         case StyleSettings::eHydrophobicity: {
808             double hydrophobicity = (residue->IsAminoAcid()) ?
809                 GetHydrophobicity(residue->code) : UNKNOWN_HYDROPHOBICITY;
810             atomStyle->color = (hydrophobicity != UNKNOWN_HYDROPHOBICITY) ?
811                 GlobalColors()->Get(Colors::eHydrophobicityMap, hydrophobicity) :
812                 GlobalColors()->Get(Colors::eNoHydrophobicity);
813             break;
814         }
815 
816         case StyleSettings::eResidue:
817             if (residue->IsNucleotide()) {
818                 switch (residue->code) {
819                     case 'A':
820                         atomStyle->color = GlobalColors()->Get(Colors::eNuc_A); break;
821                     case 'T': case 'U':
822                         atomStyle->color = GlobalColors()->Get(Colors::eNuc_T_U); break;
823                     case 'C':
824                         atomStyle->color = GlobalColors()->Get(Colors::eNuc_C); break;
825                     case 'G':
826                         atomStyle->color = GlobalColors()->Get(Colors::eNuc_G); break;
827                     default:
828                         atomStyle->color = GlobalColors()->Get(Colors::eNuc_X);
829                 }
830             } else {
831                 char ch = toupper((unsigned char) residue->code);
832                 if (ch < 'A' || ch > 'Z')
833                     ch = 'X';
834                 atomStyle->color = GlobalColors()->Get(Colors::eRainbowMap, (((double) (ch - 'A')) / ('Z' - 'A')));
835             }
836             break;
837 
838         case StyleSettings::eUserSelect:
839             if (backboneStyle)
840                 atomStyle->color = backboneStyle->userColor;
841             else
842                 atomStyle->color = generalStyle->userColor;
843             break;
844 
845         default:
846             ERRORMSG("StyleManager::GetAtomStyle() - inappropriate color scheme for atom");
847             return false;
848     }
849 
850     // determine transparency and metal ion labeling
851     atomStyle->centerLabel.erase();
852     if (molecule->IsSolvent())
853         atomStyle->style = eTransparentAtom;
854     else if (IsMetal(info->atomicNumber) ||
855              (molecule->NResidues() == 1 && residue->NAtomsInGraph() == 1)) {
856         atomStyle->style = eTransparentAtom;
857         // always big spheres for metals or isolated atoms
858         atomStyle->radius = element->vdWRadius * settings.spaceFillProportion;
859         if (settings.ionLabelsOn)
860             atomStyle->centerLabel = element->symbol;
861     } else
862         atomStyle->style = eSolidAtom;
863 
864     // add transparency; scale by occupancy if transparent
865     if (atomStyle->style == eTransparentAtom) {
866         atomStyle->alpha = 0.6;
867         if (coord && coord->occupancy < 1 && coord->occupancy > 0)
868             atomStyle->alpha *= coord->occupancy;
869     } else
870         atomStyle->alpha = 1.0;
871 
872     // determine whether it's highlighted, but *don't* set the color to the highlight
873     // color yet, since this is used by the sequence viewer where the residue letter is
874     // colored independently of the highlighted background
875     atomStyle->isHighlighted = GlobalMessenger()->IsHighlighted(molecule, residue->id);
876 
877     atomStyle->name = info->glName;
878     return true;
879 }
880 
881 // this is basically a map from StyleSettings enums to StyleManager enums;
882 // sets bond radius, too
SetBondStyleFromResidueStyle(StyleSettings::eDrawingStyle style,const StyleSettings & settings,BondStyle::EndStyle * end)883 static bool SetBondStyleFromResidueStyle(StyleSettings::eDrawingStyle style,
884     const StyleSettings& settings, BondStyle::EndStyle *end)
885 {
886     switch (style) {
887         case StyleSettings::eWire:
888             end->style = StyleManager::eLineBond;
889             break;
890         case StyleSettings::eTubes:
891             end->style = StyleManager::eCylinderBond;
892             end->radius = settings.tubeRadius;
893             break;
894         case StyleSettings::eBallAndStick:
895             end->style = StyleManager::eCylinderBond;
896             end->radius = settings.stickRadius;
897             break;
898         case StyleSettings::eSpaceFill:
899             end->style = StyleManager::eLineBond;
900             break;
901         case StyleSettings::eWireWorm:
902             end->style = StyleManager::eLineWormBond;
903             break;
904         case StyleSettings::eTubeWorm:
905             end->style = StyleManager::eThickWormBond;
906             end->radius = settings.tubeWormRadius;
907             break;
908         default:
909             ERRORMSG("SetBondStyleFromResidueStyle() - invalid style for bond");
910             return false;
911     }
912     return true;
913 }
914 
915 #define BOND_NOT_DISPLAYED do { \
916     bondStyle->end1.style = bondStyle->end2.style = eNotDisplayed; \
917     return true; } while (0)
918 
919 // Bond style is set by the residue style of the atoms at each end; the color
920 // is taken from the atom style (GetAtomStyle()), as well as some convenience
921 // style pointers (backboneStyle, generalStyle). Show/hide status is taken
922 // from the atoms - if either is hidden, the bond isn't shown either.
GetBondStyle(const Bond * bond,const AtomPntr & atom1,const AtomCoord * coord1,const AtomPntr & atom2,const AtomCoord * coord2,double bondLength,BondStyle * bondStyle) const923 bool StyleManager::GetBondStyle(const Bond *bond,
924         const AtomPntr& atom1, const AtomCoord *coord1,
925         const AtomPntr& atom2, const AtomCoord *coord2,
926         double bondLength, BondStyle *bondStyle) const
927 {
928     const StructureObject *object;
929     if (!bond->GetParentOfType(&object)) return false;
930 
931     const Residue::AtomInfo
932         *info1 = object->graph->GetAtomInfo(atom1),
933         *info2 = object->graph->GetAtomInfo(atom2);
934     if (!info1 || !info2) BOND_NOT_DISPLAYED;
935 
936     AtomStyle atomStyle1, atomStyle2;
937     const StyleSettings::BackboneStyle *backboneStyle1, *backboneStyle2;
938     const StyleSettings::GeneralStyle *generalStyle1, *generalStyle2;
939     if (!GetAtomStyle(info1->residue, atom1, coord1, &atomStyle1, &backboneStyle1, &generalStyle1) ||
940         !GetAtomStyle(info2->residue, atom2, coord2, &atomStyle2, &backboneStyle2, &generalStyle2))
941         return false;
942 
943     // if both atoms are hidden, or either one doesn't have coordinates, don't show the bond
944     if ((atomStyle1.style == eNotDisplayed && atomStyle2.style == eNotDisplayed) || (!coord1 || !coord2))
945         BOND_NOT_DISPLAYED;
946 
947      // defaults
948     bondStyle->end1.atomCap = bondStyle->end2.atomCap = false;
949     bondStyle->end1.name = info1->glName;
950     bondStyle->end2.name = info2->glName;
951     bondStyle->midCap = false;
952 
953     // if one atom is hidden, check for special cases to see if bond is visible at all
954     if (atomStyle1.style == eNotDisplayed || atomStyle2.style == eNotDisplayed) {
955         bool isSpecial = false;
956 
957         // is residue PRO, and bond is between CD and N?
958         if (info1->residue->IsAminoAcid() && info1->residue->nameGraph == "PRO" &&
959             atom1.mID == atom2.mID && atom1.rID == atom2.rID)
960         {
961             const Molecule *molecule;
962             if (!info1->residue->GetParentOfType(&molecule))
963                 return false;
964             // atom1 is CD and is visible, switch N (atom2) to side chain style
965             if (info1->code == " CD " && atomStyle1.style != eNotDisplayed && info2->code == " N  ")
966             {
967                 generalStyle2 = generalStyle1;
968                 backboneStyle2 = NULL;
969                 atomStyle2.isHighlighted = GlobalMessenger()->IsHighlighted(molecule, info2->residue->id);
970                 bondStyle->end2.atomCap = true;
971                 isSpecial = true;
972             }
973             // atom2 is CD and is visible
974             else if (info2->code == " CD " && atomStyle2.style != eNotDisplayed && info1->code == " N  ")
975             {
976                 generalStyle1 = generalStyle2;
977                 backboneStyle1 = NULL;
978                 atomStyle1.isHighlighted = GlobalMessenger()->IsHighlighted(molecule, info1->residue->id);
979                 bondStyle->end1.atomCap = true;
980                 isSpecial = true;
981             }
982         }
983 
984         // will show half-bonds in trace backbones
985         if (bond->order == Bond::eVirtual)
986             isSpecial = true;   // will set up style stuff later
987 
988         // otherwise, don't show the bond at all when one atom is hidden
989         if (!isSpecial)
990             BOND_NOT_DISPLAYED;
991     }
992 
993     // use connection style if bond is between molecules
994     if (atom1.mID != atom2.mID && bond->order != Bond::eRealDisulfide && bond->order != Bond::eVirtualDisulfide) {
995         if (globalStyle.connections.isOn == false)
996             BOND_NOT_DISPLAYED;
997         bondStyle->end1.color = bondStyle->end2.color = globalStyle.connections.userColor;
998         if (globalStyle.connections.style == StyleSettings::eWire)
999             bondStyle->end1.style = bondStyle->end2.style = eLineBond;
1000         else if (globalStyle.connections.style == StyleSettings::eTubes) {
1001             bondStyle->end1.style = bondStyle->end2.style = eCylinderBond;
1002             bondStyle->end1.radius = bondStyle->end2.radius = globalStyle.tubeRadius;
1003             bondStyle->end1.atomCap = bondStyle->end2.atomCap = true;
1004         } else {
1005             ERRORMSG("StyleManager::GetBondStyle() - invalid connection style");
1006             return false;
1007         }
1008     }
1009 
1010     // otherwise, need to query atom style to figure bond style parameters
1011     else {
1012 
1013         const StyleSettings&
1014             settings1 = GetStyleForResidue(object, atom1.mID, atom1.rID),
1015             settings2 = GetStyleForResidue(object, atom2.mID, atom2.rID);
1016 
1017         StyleSettings::eDrawingStyle style1;
1018         if (backboneStyle1)
1019             style1 = backboneStyle1->style;
1020         else
1021             style1 = generalStyle1->style;
1022         if (!SetBondStyleFromResidueStyle(style1, settings1, &(bondStyle->end1)))
1023             return false;
1024 
1025         StyleSettings::eDrawingStyle style2;
1026         if (backboneStyle2)
1027             style2 = backboneStyle2->style;
1028         else
1029             style2 = generalStyle2->style;
1030         if (!SetBondStyleFromResidueStyle(style2, settings2, &(bondStyle->end2)))
1031             return false;
1032 
1033         // special handling of alpha virtual bonds
1034         if (bond->order == Bond::eVirtual) {
1035             if (backboneStyle1->type != StyleSettings::eTrace || atomStyle1.style == eNotDisplayed)
1036                 bondStyle->end1.style = eNotDisplayed;
1037             if (backboneStyle2->type != StyleSettings::eTrace || atomStyle2.style == eNotDisplayed)
1038                 bondStyle->end2.style = eNotDisplayed;
1039             if (atomStyle1.style == eNotDisplayed || atomStyle2.style == eNotDisplayed)
1040                 bondStyle->midCap = true;
1041             // set worm tension, tighter for smaller protein alpha-helix
1042             if (info1->residue->IsAminoAcid())
1043                 bondStyle->tension = -0.8;
1044             else
1045                 bondStyle->tension = -0.4;
1046         }
1047 
1048         // special case coloring and rendering for disulfides
1049         if (bond->order == Bond::eVirtualDisulfide) {
1050             if (backboneStyle1->type != StyleSettings::eTrace || backboneStyle2->type != StyleSettings::eTrace ||
1051                 !settings1.virtualDisulfidesOn || !settings2.virtualDisulfidesOn)
1052                     BOND_NOT_DISPLAYED;
1053             // don't use worms for disulfides
1054             if (bondStyle->end1.style == eLineWormBond) bondStyle->end1.style = eLineBond;
1055             else if (bondStyle->end1.style == eThickWormBond) bondStyle->end1.style = eCylinderBond;
1056             if (bondStyle->end2.style == eLineWormBond) bondStyle->end2.style = eLineBond;
1057             else if (bondStyle->end2.style == eThickWormBond) bondStyle->end2.style = eCylinderBond;
1058             bondStyle->end1.color = settings1.virtualDisulfideColor;
1059             bondStyle->end2.color = settings2.virtualDisulfideColor;
1060         }
1061 
1062         // use atom color for all else
1063         else {
1064             bondStyle->end1.color = atomStyle1.color;
1065             bondStyle->end2.color = atomStyle2.color;
1066         }
1067 
1068 
1069         // special case for bonds between side chain and residue - make whole bond
1070         // same style/color as side chain side, and add endCap if atom is of lesser radius
1071         if (info2->classification == Residue::eSideChainAtom &&
1072             (info1->classification == Residue::eAlphaBackboneAtom ||
1073              info1->classification == Residue::ePartialBackboneAtom ||
1074              info1->classification == Residue::eCompleteBackboneAtom)
1075            ) {
1076             bondStyle->end1.style = bondStyle->end2.style;
1077             bondStyle->end1.color = bondStyle->end2.color;
1078             bondStyle->end1.radius = bondStyle->end2.radius;
1079             if (atomStyle1.radius < bondStyle->end1.radius)
1080                 bondStyle->end1.atomCap = true;
1081         }
1082         else if (info1->classification == Residue::eSideChainAtom &&
1083                  (info2->classification == Residue::eAlphaBackboneAtom ||
1084                   info2->classification == Residue::ePartialBackboneAtom ||
1085                   info2->classification == Residue::eCompleteBackboneAtom)
1086                 ) {
1087             bondStyle->end2.style = bondStyle->end1.style;
1088             bondStyle->end2.color = bondStyle->end1.color;
1089             bondStyle->end2.radius = bondStyle->end1.radius;
1090             if (atomStyle2.radius < bondStyle->end2.radius)
1091                 bondStyle->end2.atomCap = true;
1092         }
1093 
1094         // add midCap if style or radius for two sides of bond is different;
1095         if (bondStyle->end1.style != bondStyle->end2.style || bondStyle->end1.radius != bondStyle->end2.radius)
1096             bondStyle->midCap = true;
1097 
1098         // atomCaps needed at ends of thick worms when at end of chain, or if internal residues
1099         // are hidden or of a different style, or when missing coords of prev/next bond
1100         if (bondStyle->end1.style == eThickWormBond || bondStyle->end2.style == eThickWormBond) {
1101 
1102             const Residue::AtomInfo *infoV;
1103             AtomStyle atomStyleV;
1104             const StyleSettings::BackboneStyle *backboneStyleV;
1105             const StyleSettings::GeneralStyle *generalStyleV;
1106             const AtomSet *atomSet;
1107             if (!coord1->GetParentOfType(&atomSet))
1108                 return false;
1109             bool overlayConfs = atomSet->parentSet->showHideManager->OverlayConfEnsembles();
1110 
1111             if (bondStyle->end1.style == eThickWormBond &&
1112                     (!bond->previousVirtual ||
1113                     !(infoV = object->graph->GetAtomInfo(bond->previousVirtual->atom1)) ||
1114                     !GetAtomStyle(infoV->residue, bond->previousVirtual->atom1, NULL,
1115                         &atomStyleV, &backboneStyleV, &generalStyleV) ||
1116                     atomStyleV.style == eNotDisplayed ||
1117                     backboneStyleV->style != style1 ||
1118                     !atomSet->GetAtom(bond->previousVirtual->atom1, overlayConfs, true)))
1119                 bondStyle->end1.atomCap = true;
1120 //            if (bondStyle->end1.atomCap)
1121 //                TRACEMSG("bondStyle->end1.atomCap true at rID " << atom1.rID);
1122 
1123             if (bondStyle->end2.style == eThickWormBond &&
1124                     (!bond->nextVirtual ||
1125                     !(infoV = object->graph->GetAtomInfo(bond->nextVirtual->atom2)) ||
1126                     !GetAtomStyle(infoV->residue, bond->nextVirtual->atom2, NULL,
1127                         &atomStyleV, &backboneStyleV, &generalStyleV) ||
1128                     atomStyleV.style == eNotDisplayed ||
1129                     backboneStyleV->style != style2 ||
1130                     !atomSet->GetAtom(bond->nextVirtual->atom2, overlayConfs, true)))
1131                 bondStyle->end2.atomCap = true;
1132 //            if (bondStyle->end2.atomCap)
1133 //                TRACEMSG("bondStyle->end2.atomCap true at rID " << atom2.rID);
1134         }
1135     }
1136 
1137     // if atom is larger than half bond length, don't show that half of the bond
1138     bondLength /= 2;
1139     if (atomStyle1.radius > bondLength) {
1140         bondStyle->end1.style = eNotDisplayed;
1141         bondStyle->midCap = true;
1142     }
1143     if (atomStyle2.radius > bondLength) {
1144         bondStyle->end2.style = eNotDisplayed;
1145         bondStyle->midCap = true;
1146     }
1147 
1148     // set highlighting color if necessary
1149     if (atomStyle1.isHighlighted) bondStyle->end1.color = GlobalColors()->Get(Colors::eHighlight);
1150     if (atomStyle2.isHighlighted) bondStyle->end2.color = GlobalColors()->Get(Colors::eHighlight);
1151 
1152     return true;
1153 }
1154 
GetObjectStyle(const StructureObject * object,const Object3D & object3D,const StyleSettings::GeneralStyle & generalStyle,ObjectStyle * objectStyle) const1155 bool StyleManager::GetObjectStyle(const StructureObject *object, const Object3D& object3D,
1156     const StyleSettings::GeneralStyle& generalStyle, ObjectStyle *objectStyle) const
1157 {
1158     // check to see if any residue covered by the object is visible
1159     bool anyResidueVisible = false;
1160     const Molecule *molecule = object->graph->molecules.find(object3D.moleculeID)->second;
1161     for (int r=object3D.fromResidueID; r<=object3D.toResidueID; ++r) {
1162         if (object->parentSet->showHideManager->IsVisible(molecule->residues.find(r)->second)) {
1163             anyResidueVisible = true;
1164             break;
1165         }
1166     }
1167     if (!anyResidueVisible) {
1168         objectStyle->style = eNotDisplayed;
1169         return true;
1170     }
1171 
1172     // set drawing style
1173     if (generalStyle.style == StyleSettings::eWithArrows) {
1174         objectStyle->style = eObjectWithArrow;
1175     } else if (generalStyle.style == StyleSettings::eWithoutArrows) {
1176         objectStyle->style = eObjectWithoutArrow;
1177     } else {
1178         WARNINGMSG("StyleManager::GetObjectStyle() - invalid 3d-object style");
1179         return false;
1180     }
1181 
1182     // set color
1183     switch (generalStyle.colorScheme) {
1184         case StyleSettings::eMolecule:
1185             objectStyle->color = GlobalColors()->Get(Colors::eCycle1, object3D.moleculeID - 1);
1186             break;
1187         case StyleSettings::eObject:
1188             objectStyle->color = GlobalColors()->Get(Colors::eCycle1, object->id - 1);
1189             break;
1190         case StyleSettings::eDomain:
1191             {
1192                 int domainID = molecule->residueDomains[object3D.fromResidueID - 1];
1193                 if (domainID == Molecule::NO_DOMAIN_SET)
1194                     objectStyle->color = GlobalColors()->Get(Colors::eNoDomain);
1195                 else
1196                     objectStyle->color = GlobalColors()->Get(Colors::eCycle1, domainID - 1);
1197             }
1198             break;
1199         case StyleSettings::eUserSelect:
1200             objectStyle->color = generalStyle.userColor;
1201             break;
1202         case StyleSettings::eSecondaryStructure:
1203             // set by caller
1204             break;
1205         default:
1206             ERRORMSG("StyleManager::GetObjectStyle() - inappropriate color scheme for 3d-object");
1207             return false;
1208     }
1209 
1210     return true;
1211 }
1212 
GetHelixStyle(const StructureObject * object,const Helix3D & helix,HelixStyle * helixStyle) const1213 bool StyleManager::GetHelixStyle(const StructureObject *object,
1214     const Helix3D& helix, HelixStyle *helixStyle) const
1215 {
1216     // use style of first associated residue
1217     const StyleSettings&
1218         settings = GetStyleForResidue(object, helix.moleculeID, helix.fromResidueID);
1219 
1220     if (!settings.helixObjects.isOn) {
1221         helixStyle->style = eNotDisplayed;
1222         return true;
1223     }
1224 
1225     if (!GetObjectStyle(object, helix, settings.helixObjects, helixStyle))
1226         return false;
1227 
1228     // helix-specific settings
1229     helixStyle->radius = settings.helixRadius;
1230     if (settings.helixObjects.style == StyleSettings::eWithArrows) {
1231         helixStyle->arrowLength = 4.0;
1232         helixStyle->arrowBaseWidthProportion = 1.2;
1233         helixStyle->arrowTipWidthProportion = 0.4;
1234     }
1235     if (settings.helixObjects.colorScheme == StyleSettings::eSecondaryStructure)
1236         helixStyle->color = GlobalColors()->Get(Colors::eHelix);
1237 
1238     return true;
1239 }
1240 
GetStrandStyle(const StructureObject * object,const Strand3D & strand,StrandStyle * strandStyle) const1241 bool StyleManager::GetStrandStyle(const StructureObject *object,
1242     const Strand3D& strand, StrandStyle *strandStyle) const
1243 {
1244     // use style of first associated residue
1245     const StyleSettings&
1246         settings = GetStyleForResidue(object, strand.moleculeID, strand.fromResidueID);
1247 
1248     if (!settings.strandObjects.isOn) {
1249         strandStyle->style = eNotDisplayed;
1250         return true;
1251     }
1252 
1253     if (!GetObjectStyle(object, strand, settings.strandObjects, strandStyle))
1254         return false;
1255 
1256     // strand-specific settings
1257     strandStyle->width = settings.strandWidth;
1258     strandStyle->thickness = settings.strandThickness;
1259     if (settings.strandObjects.style == StyleSettings::eWithArrows) {
1260         strandStyle->arrowLength = 2.8;
1261         strandStyle->arrowBaseWidthProportion = 1.6;
1262     }
1263     if (settings.strandObjects.colorScheme == StyleSettings::eSecondaryStructure)
1264         strandStyle->color = GlobalColors()->Get(Colors::eStrand);
1265 
1266     return true;
1267 }
1268 
GetStyleForResidue(const StructureObject * object,int moleculeID,int residueID) const1269 const StyleSettings& StyleManager::GetStyleForResidue(const StructureObject *object,
1270     int moleculeID, int residueID) const
1271 {
1272     const Molecule *molecule = object->graph->molecules.find(moleculeID)->second;
1273 
1274     // find the highest priority (lowest index) annotation in the list of displayed annotations,
1275     // that also covers this residue
1276     const StyleSettings *style = &globalStyle;
1277 
1278     UserAnnotationList::const_iterator d, de = userAnnotations.end();
1279     for (d=userAnnotations.begin(); d!=de; ++d) {
1280         if (!(*d)->isDisplayed)
1281             continue;
1282         // check to see if the annotation covers this residue
1283         ResidueMap::const_iterator residues = (*d)->residues.find(molecule->identifier);
1284         if (residues != (*d)->residues.end() &&
1285             residues->second[residueID - 1] == true) {
1286             StyleMap::const_iterator userStyle = userStyles.find((*d)->styleID);
1287             if (userStyle == userStyles.end())
1288                 ERRORMSG("User style-id " << (*d)->styleID << " not found in style dictionary!");
1289             else
1290                 style = &(userStyle->second);
1291             break;
1292         }
1293     }
1294 
1295     return *style;
1296 }
1297 
MoleculeHasUserStyle(const StructureObject * object,int moleculeID) const1298 bool StyleManager::MoleculeHasUserStyle(const StructureObject *object, int moleculeID) const
1299 {
1300     const Molecule *molecule = object->graph->molecules.find(moleculeID)->second;
1301 
1302     UserAnnotationList::const_iterator d, de = userAnnotations.end();
1303     for (d=userAnnotations.begin(); d!=de; ++d) {
1304         if (!(*d)->isDisplayed)
1305             continue;
1306         // check to see if the annotation covers any residue
1307         ResidueMap::const_iterator residues = (*d)->residues.find(molecule->identifier);
1308         if (residues != (*d)->residues.end())
1309             return true;
1310     }
1311 
1312     return false;
1313 }
1314 
ResidueHasUserStyle(const StructureObject * object,int moleculeID,int residueID) const1315 bool StyleManager::ResidueHasUserStyle(const StructureObject *object, int moleculeID, int residueID) const
1316 {
1317     const Molecule *molecule = object->graph->molecules.find(moleculeID)->second;
1318 
1319     UserAnnotationList::const_iterator d, de = userAnnotations.end();
1320     for (d=userAnnotations.begin(); d!=de; ++d) {
1321         if (!(*d)->isDisplayed)
1322             continue;
1323         // check to see if the annotation covers this residue
1324         ResidueMap::const_iterator residues = (*d)->residues.find(molecule->identifier);
1325         if (residues != (*d)->residues.end() && residues->second[residueID - 1] == true)
1326             return true;
1327     }
1328 
1329     return false;
1330 }
1331 
GetObjectColor(const Molecule * molecule) const1332 const Vector& StyleManager::GetObjectColor(const Molecule *molecule) const
1333 {
1334     static const Vector black(0,0,0);
1335     const StructureObject *object;
1336     if (!molecule || !molecule->GetParentOfType(&object)) return black;
1337     return GlobalColors()->Get(Colors::eCycle1, object->id - 1);
1338 }
1339 
EditGlobalStyle(wxWindow * parent)1340 bool StyleManager::EditGlobalStyle(wxWindow *parent)
1341 {
1342     StyleDialog dialog(parent, &globalStyle, structureSet);
1343     return (dialog.ShowModal() == wxOK);
1344 }
1345 
CreateASNStyleDictionary(void) const1346 CCn3d_style_dictionary * StyleManager::CreateASNStyleDictionary(void) const
1347 {
1348     auto_ptr<CCn3d_style_dictionary> dictionary(new CCn3d_style_dictionary());
1349     if (!globalStyle.SaveSettingsToASN(&(dictionary->SetGlobal_style()))) return NULL;
1350 
1351     if (userStyles.size() > 0) {
1352 
1353         // create an ordered list of style id's
1354         typedef list < int > IntList;
1355         IntList keys;
1356         StyleMap::const_iterator s, se = userStyles.end();
1357         for (s=userStyles.begin(); s!=se; ++s) keys.push_back(s->first);
1358         keys.sort();
1359 
1360         // create a new style table entry for each user style
1361         IntList::const_iterator i, ie = keys.end();
1362         for (i=keys.begin(); i!=ie; ++i) {
1363             CRef < CCn3d_style_table_item > entry(new CCn3d_style_table_item());
1364             entry->SetId().Set(*i);
1365             if (!userStyles.find(*i)->second.SaveSettingsToASN(&(entry->SetStyle()))) return NULL;
1366             dictionary->SetStyle_table().push_back(entry);
1367         }
1368     }
1369 
1370     return dictionary.release();
1371 }
1372 
LoadFromASNStyleDictionary(const CCn3d_style_dictionary & styleDictionary)1373 bool StyleManager::LoadFromASNStyleDictionary(const CCn3d_style_dictionary& styleDictionary)
1374 {
1375     if (!globalStyle.LoadSettingsFromASN(styleDictionary.GetGlobal_style())) return false;
1376 
1377     userStyles.clear();
1378     if (styleDictionary.IsSetStyle_table()) {
1379         CCn3d_style_dictionary::TStyle_table::const_iterator t, te = styleDictionary.GetStyle_table().end();
1380         for (t=styleDictionary.GetStyle_table().begin(); t!=te; ++t) {
1381             int id = (*t)->GetId().Get();
1382             if (userStyles.find(id) != userStyles.end()) {
1383                 ERRORMSG("repeated style table id in style dictionary");
1384                 return false;
1385             } else
1386                 if (!userStyles[id].LoadSettingsFromASN((*t)->GetStyle())) return false;
1387         }
1388     }
1389     return true;
1390 }
1391 
EditUserAnnotations(wxWindow * parent)1392 bool StyleManager::EditUserAnnotations(wxWindow *parent)
1393 {
1394     AnnotateDialog dialog(parent, this, structureSet);
1395     dialog.ShowModal();
1396     return false;
1397 }
1398 
AddUserStyle(int * id,StyleSettings ** newStyle)1399 bool StyleManager::AddUserStyle(int *id, StyleSettings **newStyle)
1400 {
1401     // create a style with the lowest integer id (above zero) available
1402     static const int max = 10000;
1403     for (int i=1; i<max; ++i) {
1404         if (userStyles.find(i) == userStyles.end()) {
1405             *newStyle = &(userStyles[i]);
1406             *id = i;
1407             structureSet->SetDataChanged(StructureSet::eStyleData);
1408             return true;
1409         }
1410     }
1411     return false;
1412 }
1413 
RemoveUserStyle(int id)1414 bool StyleManager::RemoveUserStyle(int id)
1415 {
1416     StyleMap::iterator u = userStyles.find(id);
1417     if (u == userStyles.end()) return false;
1418     userStyles.erase(u);
1419     structureSet->SetDataChanged(StructureSet::eStyleData);
1420     return true;
1421 }
1422 
AddUserAnnotation(void)1423 StyleManager::UserAnnotation * StyleManager::AddUserAnnotation(void)
1424 {
1425     userAnnotations.resize(userAnnotations.size() + 1);
1426     userAnnotations.back().Reset(new UserAnnotation());
1427     userAnnotations.back()->styleID = -1;
1428     userAnnotations.back()->isDisplayed = false;
1429     structureSet->SetDataChanged(StructureSet::eStyleData);
1430     return userAnnotations.back().GetPointer();
1431 }
1432 
RemoveUserAnnotation(UserAnnotation * annotation)1433 bool StyleManager::RemoveUserAnnotation(UserAnnotation *annotation)
1434 {
1435     // remove annotation from available list
1436     UserAnnotationList::iterator u, ue = userAnnotations.end();
1437     int removedStyleID = -1;
1438     for (u=userAnnotations.begin(); u!=ue; ++u) {
1439         if (annotation == u->GetPointer()) {
1440             if (annotation->isDisplayed) {
1441                 GlobalMessenger()->PostRedrawAllStructures();
1442                 GlobalMessenger()->PostRedrawAllSequenceViewers();
1443             }
1444             removedStyleID = (*u)->styleID;
1445             userAnnotations.erase(u);
1446             break;
1447         }
1448     }
1449     if (u == ue) return false;
1450 
1451     // also remove the style if it's not used by any other annotation
1452     for (u=userAnnotations.begin(); u!=ue; ++u)
1453         if ((*u)->styleID == removedStyleID)
1454             break;
1455     if (u == ue)
1456         RemoveUserStyle(removedStyleID);
1457 
1458     structureSet->SetDataChanged(StructureSet::eStyleData);
1459     return true;
1460 }
1461 
DisplayUserAnnotation(UserAnnotation * annotation,bool display)1462 bool StyleManager::DisplayUserAnnotation(UserAnnotation *annotation, bool display)
1463 {
1464     // first check to make sure this annotation is known
1465     UserAnnotationList::const_iterator a, ae = userAnnotations.end();
1466     for (a=userAnnotations.begin(); a!=ae; ++a)
1467         if (annotation == a->GetPointer())
1468             break;
1469     if (a == ae)
1470         return false;
1471 
1472     // if display flag is changed
1473     if (annotation->isDisplayed != display) {
1474         // set flag
1475         annotation->isDisplayed = display;
1476 
1477         // need to redraw with new flags
1478         GlobalMessenger()->PostRedrawAllStructures();
1479         GlobalMessenger()->PostRedrawAllSequenceViewers();
1480         structureSet->SetDataChanged(StructureSet::eStyleData);
1481     }
1482 
1483     return true;
1484 }
1485 
MoveUserAnnotation(UserAnnotation * annotation,bool moveUp)1486 bool StyleManager::MoveUserAnnotation(UserAnnotation *annotation, bool moveUp)
1487 {
1488     // look for the annotation in the list of annotations
1489     UserAnnotationList::iterator d, de = userAnnotations.end();
1490     for (d=userAnnotations.begin(); d!=de; ++d)
1491         if (annotation == d->GetPointer())
1492             break;
1493     if (d == userAnnotations.end())
1494         return false;
1495 
1496     UserAnnotationList::iterator swap;
1497     bool doSwap = false;
1498     if (moveUp && d != userAnnotations.begin()) {
1499         swap = d;
1500         --swap;     // swap with previous
1501         doSwap = true;
1502     } else if (!moveUp) {
1503         swap = d;
1504         ++swap;     // swap with next
1505         if (swap != userAnnotations.end())
1506             doSwap = true;
1507     }
1508     if (doSwap) {
1509         CRef < UserAnnotation > tmp(*d);
1510         *d = *swap;
1511         *swap = tmp;
1512         structureSet->SetDataChanged(StructureSet::eStyleData);
1513         // need to redraw if displayed annotation order list has changed
1514         if (annotation->isDisplayed) {
1515             GlobalMessenger()->PostRedrawAllStructures();
1516             GlobalMessenger()->PostRedrawAllSequenceViewers();
1517         }
1518     }
1519 
1520     return true;
1521 }
1522 
CreateObjectLocation(CCn3d_user_annotation::TResidues * residuesASN,const StyleManager::ResidueMap & residueMap)1523 static bool CreateObjectLocation(
1524     CCn3d_user_annotation::TResidues *residuesASN,
1525     const StyleManager::ResidueMap& residueMap)
1526 {
1527     residuesASN->clear();
1528 
1529     StyleManager::ResidueMap::const_iterator r, re = residueMap.end();
1530     for (r=residueMap.begin(); r!=re; ++r) {
1531 
1532         // find an existing object location that matches this MMDB ID
1533         CCn3d_user_annotation::TResidues::iterator l, le = residuesASN->end();
1534         for (l=residuesASN->begin(); l!=le; ++l)
1535             if ((*l)->GetStructure_id().GetMmdb_id().Get() == r->first->mmdbID) break;
1536 
1537         // if necessary, create new object location, with Biostruc-id from MMDB ID
1538         if (l == le) {
1539             CRef < CCn3d_object_location > loc(new CCn3d_object_location());
1540             if (r->first->mmdbID != MoleculeIdentifier::VALUE_NOT_SET) {
1541                 CMmdb_id *mmdbID = new CMmdb_id();
1542                 mmdbID->Set(r->first->mmdbID);
1543                 loc->SetStructure_id().SetMmdb_id(*mmdbID);
1544             } else {
1545                 ERRORMSG("CreateObjectLocation() - MoleculeIdentifier must (currently) have MMDB ID");
1546                 return false;
1547             }
1548             residuesASN->push_back(loc);
1549             l = residuesASN->end();
1550             --l;    // set iterator to the new object location
1551         }
1552 
1553         // set molecule location
1554         CRef < CCn3d_molecule_location > molecule(new CCn3d_molecule_location());
1555         molecule->SetMolecule_id().Set(r->first->moleculeID);
1556         (*l)->SetResidues().push_back(molecule);
1557 
1558         // check if covers whole molecule; if so, leave 'residues' field of Cn3d_molecule_location blank
1559         unsigned int i;
1560         for (i=0; i<r->second.size(); ++i)
1561             if (!r->second[i]) break;
1562 
1563         // else break list down into individual contiguous residue ranges
1564         if (i != r->second.size()) {
1565             unsigned int first = 0, last = 0;
1566             while (first < r->second.size()) {
1567                 // find first included residue
1568                 while (first < r->second.size() && !r->second[first]) ++first;
1569                 if (first >= r->second.size()) break;
1570                 // find last in contiguous stretch of included residues
1571                 last = first;
1572                 while (last + 1 < r->second.size() && r->second[last + 1]) ++last;
1573                 CRef < CCn3d_residue_range > range(new CCn3d_residue_range());
1574                 range->SetFrom().Set(first + 1);    // assume moleculeID = index + 1
1575                 range->SetTo().Set(last + 1);
1576                 molecule->SetResidues().push_back(range);
1577                 first = last + 2;
1578             }
1579             if (molecule->GetResidues().size() == 0) {
1580                 ERRORMSG("CreateObjectLocation() - no residue ranges found");
1581                 return false;
1582             }
1583         }
1584     }
1585 
1586     return true;
1587 }
1588 
SaveToASNUserAnnotations(ncbi::objects::CCn3d_user_annotations * annotations) const1589 bool StyleManager::SaveToASNUserAnnotations(ncbi::objects::CCn3d_user_annotations *annotations) const
1590 {
1591     if (!annotations) return false;
1592     annotations->ResetAnnotations();
1593     if (userAnnotations.size() == 0) return true;
1594 
1595     UserAnnotationList::const_iterator a, ae = userAnnotations.end();
1596     for (a=userAnnotations.begin(); a!=ae; ++a) {
1597 
1598         // fill out individual annotations
1599         CRef < CCn3d_user_annotation > annotation(new CCn3d_user_annotation());
1600         annotation->SetName((*a)->name);
1601         annotation->SetDescription((*a)->description);
1602         annotation->SetStyle_id().Set((*a)->styleID);
1603         annotation->SetIs_on((*a)->isDisplayed);
1604 
1605         // fill out residues list
1606         if (!CreateObjectLocation(&(annotation->SetResidues()), (*a)->residues)) {
1607             ERRORMSG("StyleManager::CreateASNUserAnnotations() - error creating object location");
1608             return false;
1609         }
1610 
1611         annotations->SetAnnotations().push_back(annotation);
1612     }
1613 
1614     return true;
1615 }
1616 
ExtractObjectLocation(StyleManager::ResidueMap * residueMap,const CCn3d_user_annotation::TResidues & residuesASN)1617 static bool ExtractObjectLocation(
1618     StyleManager::ResidueMap *residueMap,
1619     const CCn3d_user_annotation::TResidues& residuesASN)
1620 {
1621     CCn3d_user_annotation::TResidues::const_iterator o, oe = residuesASN.end();
1622     for (o=residuesASN.begin(); o!=oe; ++o) {
1623         int mmdbID;
1624         if ((*o)->GetStructure_id().IsMmdb_id()) {
1625             mmdbID = (*o)->GetStructure_id().GetMmdb_id().Get();
1626         } else {
1627             ERRORMSG("ExtractObjectLocation() - can't handle non-MMDB identifiers (yet)");
1628             return false;
1629         }
1630 
1631         // extract molecules
1632         CCn3d_object_location::TResidues::const_iterator m, me = (*o)->GetResidues().end();
1633         for (m=(*o)->GetResidues().begin(); m!=me; ++m) {
1634             int moleculeID = (*m)->GetMolecule_id().Get();
1635 
1636             // get identifier for this molecule
1637             const MoleculeIdentifier *identifier = MoleculeIdentifier::FindIdentifier(mmdbID, moleculeID);
1638             if (!identifier) {
1639                 WARNINGMSG("ExtractObjectLocation() - can't find identifier for molecule location");
1640                 WARNINGMSG("structure MMDB ID " << mmdbID << " not loaded?");
1641                 continue;
1642             }
1643 
1644             // set residue ranges
1645             vector < bool >& residueFlags = (*residueMap)[identifier];
1646             if (residueFlags.size() == 0)
1647                 residueFlags.resize(identifier->nResidues, false);
1648 
1649             if ((*m)->IsSetResidues()) {
1650                 // parse individual ranges
1651                 CCn3d_molecule_location::TResidues::const_iterator r, re = (*m)->GetResidues().end();
1652                 for (r=(*m)->GetResidues().begin(); r!=re; ++r) {
1653                     for (int i=(*r)->GetFrom().Get(); i<=(*r)->GetTo().Get(); ++i) {
1654                         if (i > 0 && i <= (int)residueFlags.size()) {
1655                             residueFlags[i - 1] = true;     // assume index = residue id - 1
1656                         } else {
1657                             ERRORMSG("ExtractObjectLocation() - residue from/to out of range");
1658                             return false;
1659                         }
1660                     }
1661                 }
1662             } else {
1663                 // assume all residues are included if none specified
1664                 for (unsigned int i=0; i<residueFlags.size(); ++i) residueFlags[i] = true;
1665             }
1666         }
1667     }
1668 	return true;
1669 }
1670 
LoadFromASNUserAnnotations(const ncbi::objects::CCn3d_user_annotations & annotations)1671 bool StyleManager::LoadFromASNUserAnnotations(const ncbi::objects::CCn3d_user_annotations& annotations)
1672 {
1673     if (!annotations.IsSetAnnotations()) return true;
1674 
1675     CCn3d_user_annotations::TAnnotations::const_iterator a, ae = annotations.GetAnnotations().end();
1676     for (a=annotations.GetAnnotations().begin(); a!=ae; ++a) {
1677         UserAnnotation *userAnnot = AddUserAnnotation();
1678 
1679         // fill out annotation parameters
1680         userAnnot->name = (*a)->GetName();
1681         if ((*a)->IsSetDescription())
1682             userAnnot->description = (*a)->GetDescription();
1683         userAnnot->styleID = (*a)->GetStyle_id().Get();
1684         userAnnot->isDisplayed = (*a)->GetIs_on();
1685 
1686         // extract object locations
1687         if (!ExtractObjectLocation(&(userAnnot->residues), (*a)->GetResidues()))
1688             return false;
1689     }
1690 
1691     return true;
1692 }
1693 
SetGlobalColorScheme(StyleSettings::ePredefinedColorScheme scheme)1694 void StyleManager::SetGlobalColorScheme(StyleSettings::ePredefinedColorScheme scheme)
1695 {
1696     globalStyle.SetColorScheme(scheme);
1697 //    structureSet->SetDataChanged(StructureSet::eStyleData);
1698 }
1699 
SetGlobalRenderingStyle(StyleSettings::ePredefinedRenderingStyle style)1700 void StyleManager::SetGlobalRenderingStyle(StyleSettings::ePredefinedRenderingStyle style)
1701 {
1702     globalStyle.SetRenderingStyle(style);
1703 //    structureSet->SetDataChanged(StructureSet::eStyleData);
1704 }
1705 
SetGlobalStyle(const ncbi::objects::CCn3d_style_settings & styleASN)1706 bool StyleManager::SetGlobalStyle(const ncbi::objects::CCn3d_style_settings& styleASN)
1707 {
1708     bool okay = globalStyle.LoadSettingsFromASN(styleASN);
1709     if (okay) {
1710         CheckGlobalStyleSettings();
1711 //        structureSet->SetDataChanged(StructureSet::eStyleData);
1712         GlobalMessenger()->PostRedrawAllStructures();
1713         GlobalMessenger()->PostRedrawAllSequenceViewers();
1714     }
1715     return okay;
1716 }
1717 
1718 END_SCOPE(Cn3D)
1719