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