001package com.hfg.bio.glyco; 002 003 004import java.awt.*; 005import java.awt.geom.Point2D; 006import java.awt.geom.Rectangle2D; 007import java.util.ArrayList; 008import java.util.HashMap; 009import java.util.List; 010import java.util.Map; 011import java.util.Set; 012 013import com.hfg.chem.IonizableGroup; 014import com.hfg.chem.Molecule; 015import com.hfg.svg.SVG; 016import com.hfg.svg.SvgAttr; 017import com.hfg.svg.SvgGroup; 018import com.hfg.svg.SvgNode; 019import com.hfg.svg.SvgPath; 020import com.hfg.util.CompareUtil; 021import com.hfg.util.StringUtil; 022import com.hfg.util.collection.CollectionUtil; 023import com.hfg.util.collection.OrderedSet; 024 025 026//------------------------------------------------------------------------------ 027/** 028 Common mammalian polysaccharide structures. 029 Masses / elemental compositions for glycans are for intact structures. 030 A water is removed when a glycan is attached to a protein. 031 <div> 032 @author J. Alex Taylor, hairyfatguy.com 033 </div> 034 */ 035//------------------------------------------------------------------------------ 036// com.hfg XML/HTML Coding Library 037// 038// This library is free software; you can redistribute it and/or 039// modify it under the terms of the GNU Lesser General Public 040// License as published by the Free Software Foundation; either 041// version 2.1 of the License, or (at your option) any later version. 042// 043// This library is distributed in the hope that it will be useful, 044// but WITHOUT ANY WARRANTY; without even the implied warranty of 045// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 046// Lesser General Public License for more details. 047// 048// You should have received a copy of the GNU Lesser General Public 049// License along with this library; if not, write to the Free Software 050// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 051// 052// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 053// jataylor@hairyfatguy.com 054//------------------------------------------------------------------------------ 055 056public class Glycan extends Molecule 057{ 058 //########################################################################## 059 // PUBLIC FIELDS 060 //########################################################################## 061 062 // Complex 063 public static Glycan A2G0 = new Glycan("A2G0"); 064 public static Glycan A2G0F = new Glycan("A2G0F"); 065 public static Glycan A2G1 = new Glycan("A2G1"); 066 public static Glycan A2G1F = new Glycan("A2G1F"); 067 public static Glycan A2G2 = new Glycan("A2G2"); 068 public static Glycan A2G2F = new Glycan("A2G2F"); 069 public static Glycan A2S1G0F = new Glycan("A2S1G0F"); 070 public static Glycan A2S1G1 = new Glycan("A2S1G1"); 071 public static Glycan A2S1G1F = new Glycan("A2S1G1F"); 072 public static Glycan A2S2 = new Glycan("A2S2"); 073 public static Glycan A3G0 = new Glycan("A3G0"); 074 public static Glycan A3G0F = new Glycan("A3G0F"); 075 public static Glycan A3G1 = new Glycan("A3G1"); 076 public static Glycan A3G1F = new Glycan("A3G1F"); 077 public static Glycan A3G2 = new Glycan("A3G2"); 078 public static Glycan A3G2F = new Glycan("A3G2F"); 079 public static Glycan A3S1G2 = new Glycan("A3S1G2"); 080 public static Glycan A3G3 = new Glycan("A3G3"); 081 public static Glycan A3S3 = new Glycan("A3S3"); 082 public static Glycan A3S2G1 = new Glycan("A3S2G1"); 083 084 // Hybrid 085 public static Glycan M3F = new Glycan("M3F"); // Core-F 086 public static Glycan A1G0 = new Glycan("A1G0"); 087 public static Glycan A1G0F = new Glycan("A1G0F"); 088 public static Glycan A1G0M4F = new Glycan("A1G0M4F"); 089 public static Glycan A1G1F = new Glycan("A1G1F"); 090 public static Glycan A1G1M4F = new Glycan("A1G1M4F"); 091 public static Glycan A1G1M5F = new Glycan("A1G1M5F"); 092 public static Glycan A1S1M4F = new Glycan("A1S1M4F"); 093 public static Glycan A2G0M4F = new Glycan("A2G0M4F"); 094 public static Glycan A2S2F = new Glycan("A2S2F"); 095 public static Glycan A3G3F = new Glycan("A3G3F"); 096 public static Glycan A3S1G2F = new Glycan("A3S1G2F"); 097 public static Glycan A3S2G1F = new Glycan("A3S2G1F"); 098 public static Glycan A3S3F = new Glycan("A3S3F"); 099 100 // High-Mannose 101 public static Glycan M3 = new Glycan("M3"); // Core 102 public static Glycan M4 = new Glycan("M4"); 103 public static Glycan M5 = new Glycan("M5"); 104 public static Glycan M6 = new Glycan("M6"); 105 public static Glycan M7 = new Glycan("M7"); 106 public static Glycan M8 = new Glycan("M8"); 107 public static Glycan M9 = new Glycan("M9"); 108 109 110 //########################################################################## 111 // PRIVATE FIELDS 112 //########################################################################## 113 114 private String mName; 115 private String mAbbrev; 116 private Map<Monosaccharide, Integer> mMonosaccharideCountMap = new HashMap<>(5); 117 118 // This declaration has to come before the public constants below. 119 private static Set<Glycan> sValues = new OrderedSet<>(); 120 121 static 122 { 123 124 M3.add(Monosaccharide.GlcNAc, 2) 125 .add(Monosaccharide.Mannose, 3) 126 .lock() 127 .register(); 128 129 A2G0.add(Monosaccharide.GlcNAc, 4) 130 .add(Monosaccharide.Mannose, 3) 131 .lock() 132 .register(); 133 134 A2G0F.add(Monosaccharide.GlcNAc, 4) 135 .add(Monosaccharide.Mannose, 3) 136 .add(Monosaccharide.Fucose, 1) 137 .lock() 138 .register(); 139 140 A2G1.add(Monosaccharide.GlcNAc, 4) 141 .add(Monosaccharide.Mannose, 3) 142 .add(Monosaccharide.Hexose, 1) 143 .lock() 144 .register(); 145 146 A2G1F.add(Monosaccharide.GlcNAc, 4) 147 .add(Monosaccharide.Mannose, 3) 148 .add(Monosaccharide.Hexose, 1) 149 .add(Monosaccharide.Fucose, 1) 150 .lock() 151 .register(); 152 153 A2G2.add(Monosaccharide.GlcNAc, 4) 154 .add(Monosaccharide.Mannose, 3) 155 .add(Monosaccharide.Hexose, 2) 156 .lock() 157 .register(); 158 159 A2G2F.add(Monosaccharide.GlcNAc, 4) 160 .add(Monosaccharide.Mannose, 3) 161 .add(Monosaccharide.Hexose, 2) 162 .add(Monosaccharide.Fucose, 1) 163 .lock() 164 .register(); 165 166 A2S1G0F.add(Monosaccharide.GlcNAc, 4) 167 .add(Monosaccharide.Mannose, 3) 168 .add(Monosaccharide.Hexose, 1) 169 .add(Monosaccharide.NeuAc, 1) 170 .lock() 171 .register(); 172 173 A2S1G1.add(Monosaccharide.GlcNAc, 4) 174 .add(Monosaccharide.Mannose, 3) 175 .add(Monosaccharide.Hexose, 2) 176 .add(Monosaccharide.NeuAc, 1) 177 .lock() 178 .register(); 179 180 A2S1G1F.add(Monosaccharide.GlcNAc, 4) 181 .add(Monosaccharide.Mannose, 3) 182 .add(Monosaccharide.Hexose, 2) 183 .add(Monosaccharide.Fucose, 1) 184 .add(Monosaccharide.NeuAc, 1) 185 .lock() 186 .register(); 187 188 A2S2.add(Monosaccharide.GlcNAc, 4) 189 .add(Monosaccharide.Mannose, 3) 190 .add(Monosaccharide.Hexose, 2) 191 .add(Monosaccharide.NeuAc, 2) 192 .lock() 193 .register(); 194 195 A3G0.add(Monosaccharide.GlcNAc, 5) 196 .add(Monosaccharide.Mannose, 3) 197 .lock() 198 .register(); 199 200 A3G0F.add(Monosaccharide.GlcNAc, 5) 201 .add(Monosaccharide.Mannose, 3) 202 .add(Monosaccharide.Fucose, 1) 203 .lock() 204 .register(); 205 206 A3G1.add(Monosaccharide.GlcNAc, 5) 207 .add(Monosaccharide.Mannose, 3) 208 .add(Monosaccharide.Hexose, 1) 209 .lock() 210 .register(); 211 212 A3G1F.add(Monosaccharide.GlcNAc, 5) 213 .add(Monosaccharide.Mannose, 3) 214 .add(Monosaccharide.Hexose, 1) 215 .add(Monosaccharide.Fucose, 1) 216 .lock() 217 .register(); 218 219 A3G2.add(Monosaccharide.GlcNAc, 5) 220 .add(Monosaccharide.Mannose, 3) 221 .add(Monosaccharide.Hexose, 2) 222 .lock() 223 .register(); 224 225 A3G2F.add(Monosaccharide.GlcNAc, 5) 226 .add(Monosaccharide.Mannose, 3) 227 .add(Monosaccharide.Hexose, 2) 228 .add(Monosaccharide.Fucose, 1) 229 .lock() 230 .register(); 231 232 A3S1G2.add(Monosaccharide.GlcNAc, 5) 233 .add(Monosaccharide.Mannose, 3) 234 .add(Monosaccharide.Hexose, 3) 235 .add(Monosaccharide.NeuAc, 1) 236 .lock() 237 .register(); 238 239 A3S2G1.add(Monosaccharide.GlcNAc, 5) 240 .add(Monosaccharide.Mannose, 3) 241 .add(Monosaccharide.Hexose, 3) 242 .add(Monosaccharide.NeuAc, 2) 243 .lock() 244 .register(); 245 246 A3G3.add(Monosaccharide.GlcNAc, 5) 247 .add(Monosaccharide.Mannose, 3) 248 .add(Monosaccharide.Hexose, 3) 249 .lock() 250 .register(); 251 252 A3S3.add(Monosaccharide.GlcNAc, 5) 253 .add(Monosaccharide.Mannose, 3) 254 .add(Monosaccharide.Hexose, 3) 255 .add(Monosaccharide.NeuAc, 3) 256 .lock() 257 .register(); 258 259 260 261 M3F.add(Monosaccharide.GlcNAc, 2) 262 .add(Monosaccharide.Mannose, 3) 263 .add(Monosaccharide.Fucose, 1) 264 .lock() 265 .register(); 266 267 A1G0.add(Monosaccharide.GlcNAc, 3) 268 .add(Monosaccharide.Mannose, 3) 269 .lock() 270 .register(); 271 272 A1G0F.add(Monosaccharide.GlcNAc, 3) 273 .add(Monosaccharide.Mannose, 3) 274 .add(Monosaccharide.Fucose, 1) 275 .lock() 276 .register(); 277 278 A1G0M4F.add(Monosaccharide.GlcNAc, 3) 279 .add(Monosaccharide.Mannose, 4) 280 .add(Monosaccharide.Fucose, 1) 281 .lock() 282 .register(); 283 284 A1G1F.add(Monosaccharide.GlcNAc, 3) 285 .add(Monosaccharide.Mannose, 3) 286 .add(Monosaccharide.Hexose, 1) 287 .add(Monosaccharide.Fucose, 1) 288 .lock() 289 .register(); 290 291 A1G1M4F.add(Monosaccharide.GlcNAc, 3) 292 .add(Monosaccharide.Mannose, 4) 293 .add(Monosaccharide.Hexose, 1) 294 .add(Monosaccharide.Fucose, 1) 295 .lock() 296 .register(); 297 298 A1G1M5F.add(Monosaccharide.GlcNAc, 3) 299 .add(Monosaccharide.Mannose, 5) 300 .add(Monosaccharide.Hexose, 1) 301 .add(Monosaccharide.Fucose, 1) 302 .lock() 303 .register(); 304 305 A1S1M4F.add(Monosaccharide.GlcNAc, 3) 306 .add(Monosaccharide.Mannose, 4) 307 .add(Monosaccharide.Hexose, 1) 308 .add(Monosaccharide.Fucose, 1) 309 .add(Monosaccharide.NeuAc, 1) 310 .lock() 311 .register(); 312 313 A2G0M4F.add(Monosaccharide.GlcNAc, 4) 314 .add(Monosaccharide.Mannose, 4) 315 .add(Monosaccharide.Fucose, 1) 316 .lock() 317 .register(); 318 319 A2S2F.add(Monosaccharide.GlcNAc, 4) 320 .add(Monosaccharide.Mannose, 3) 321 .add(Monosaccharide.Hexose, 2) 322 .add(Monosaccharide.Fucose, 1) 323 .add(Monosaccharide.NeuAc, 2) 324 .lock() 325 .register(); 326 327 A3G3F.add(Monosaccharide.GlcNAc, 5) 328 .add(Monosaccharide.Mannose, 3) 329 .add(Monosaccharide.Hexose, 3) 330 .add(Monosaccharide.Fucose, 1) 331 .lock() 332 .register(); 333 334 A3S1G2F.add(Monosaccharide.GlcNAc, 5) 335 .add(Monosaccharide.Mannose, 3) 336 .add(Monosaccharide.Hexose, 3) 337 .add(Monosaccharide.Fucose, 1) 338 .add(Monosaccharide.NeuAc, 1) 339 .lock() 340 .register(); 341 342 A3S2G1F.add(Monosaccharide.GlcNAc, 5) 343 .add(Monosaccharide.Mannose, 3) 344 .add(Monosaccharide.Hexose, 3) 345 .add(Monosaccharide.Fucose, 1) 346 .add(Monosaccharide.NeuAc, 2) 347 .lock() 348 .register(); 349 350 A3S3F.add(Monosaccharide.GlcNAc, 5) 351 .add(Monosaccharide.Mannose, 3) 352 .add(Monosaccharide.Hexose, 3) 353 .add(Monosaccharide.Fucose, 1) 354 .add(Monosaccharide.NeuAc, 3) 355 .lock() 356 .register(); 357 358 359 360 361 M4.add(Monosaccharide.GlcNAc, 2) 362 .add(Monosaccharide.Mannose, 4) 363 .lock() 364 .register(); 365 366 M5.add(Monosaccharide.GlcNAc, 2) 367 .add(Monosaccharide.Mannose, 5) 368 .lock() 369 .register(); 370 371 M6.add(Monosaccharide.GlcNAc, 2) 372 .add(Monosaccharide.Mannose, 6) 373 .lock() 374 .register(); 375 376 M7.add(Monosaccharide.GlcNAc, 2) 377 .add(Monosaccharide.Mannose, 7) 378 .lock() 379 .register(); 380 381 M8.add(Monosaccharide.GlcNAc, 2) 382 .add(Monosaccharide.Mannose, 8) 383 .lock() 384 .register(); 385 386 M9.add(Monosaccharide.GlcNAc, 2) 387 .add(Monosaccharide.Mannose, 9) 388 .lock() 389 .register(); 390 } 391 392 //########################################################################## 393 // CONSTRUCTORS 394 //########################################################################## 395 396 //-------------------------------------------------------------------------- 397 private Glycan(String inName) 398 { 399 mName = inName; 400 mAbbrev = inName; 401 } 402 403 //########################################################################## 404 // PUBLIC METHODS 405 //########################################################################## 406 407 //-------------------------------------------------------------------------- 408 public static Glycan valueOf(String inString) 409 { 410 Glycan value = null; 411 412 if (StringUtil.isSet(inString)) 413 { 414 for (Glycan glycan : sValues) 415 { 416 if (glycan.name().equalsIgnoreCase(inString) 417 || glycan.getAbbrev().equals(inString)) 418 { 419 value = glycan; 420 break; 421 } 422 } 423 } 424 425 return value; 426 } 427 428 //-------------------------------------------------------------------------- 429 public static Glycan[] values() 430 { 431 return sValues.toArray(new Glycan[sValues.size()]); 432 } 433 434 435 //-------------------------------------------------------------------------- 436 /** 437 Puts the Glycan into the Set of unique Glycans returned by Glycan.values(). 438 */ 439 public void register() 440 { 441 if (! isLocked()) 442 { 443 throw new RuntimeException("Only locked Glycans can be added to the values list!"); 444 } 445 446 sValues.add(this); 447 } 448 449 //-------------------------------------------------------------------------- 450 @Override 451 public int compareTo(Object inObj2) 452 { 453 int result = -1; 454 455 if (inObj2 != null) 456 { 457 if (inObj2 instanceof Glycan) 458 { 459 Glycan glycan2 = (Glycan) inObj2; 460 461 result = CompareUtil.compare(name(), glycan2.name()); 462 } 463 else 464 { 465 result = CompareUtil.compare(hashCode(), inObj2.hashCode()); 466 } 467 } 468 469 return result; 470 } 471 472 //-------------------------------------------------------------------------- 473 @Override 474 public Glycan lock() 475 { 476 return (Glycan) super.lock(); 477 } 478 479 //-------------------------------------------------------------------------- 480 public String name() 481 { 482 return mName; 483 } 484 485 //-------------------------------------------------------------------------- 486 public String getAbbrev() 487 { 488 return mAbbrev; 489 } 490 491 //-------------------------------------------------------------------------- 492 @Override 493 public String toString() 494 { 495 return getAbbrev(); 496 } 497 498 //-------------------------------------------------------------------------- 499 public SVG toSVG() 500 { 501 SVG svg = new SVG(); 502 503 SvgGroup backbone = svg.addGroup().addStyle(SvgAttr.stroke + ": #000000"); 504 505 // Start with the M3 core 506 SvgGroup core = svg.addGroup(); 507 508 SvgNode glcNAc1 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Float(130, 27)); 509 core.addSubtag(glcNAc1); 510 511 SvgNode glcNAc2 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Float(110, 27)); 512 core.addSubtag(glcNAc2); 513 backbone.addLine(glcNAc1.getCenterPoint(), glcNAc2.getCenterPoint()); 514 515 SvgNode man1 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(90, 27)); 516 core.addSubtag(man1); 517 backbone.addLine(glcNAc2.getCenterPoint(), man1.getCenterPoint()); 518 519 SvgNode man2 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(70, 12)); 520 core.addSubtag(man2); 521 backbone.addLine(man1.getCenterPoint(), man2.getCenterPoint()); 522 523 SvgNode man3 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(70, 37)); 524 core.addSubtag(man3); 525 backbone.addLine(man1.getCenterPoint(), man3.getCenterPoint()); 526 527 if (name().endsWith("F")) 528 { 529 SvgNode svgNode = Monosaccharide.Fucose.toSVGNode().setPosition(new Point2D.Float(130, 7)); 530 svg.addSubtag(svgNode); 531 backbone.addLine(glcNAc1.getCenterPoint(), svgNode.getCenterPoint()); 532 } 533 534 int mannoseCount = mMonosaccharideCountMap.containsKey(Monosaccharide.Mannose) ? mMonosaccharideCountMap.get(Monosaccharide.Mannose) : 0; 535 int glcNAcCount = mMonosaccharideCountMap.containsKey(Monosaccharide.GlcNAc) ? mMonosaccharideCountMap.get(Monosaccharide.GlcNAc) : 0; 536 int hexoseCount = mMonosaccharideCountMap.containsKey(Monosaccharide.Hexose) ? mMonosaccharideCountMap.get(Monosaccharide.Hexose) : 0; 537 int sialicAcidCount = mMonosaccharideCountMap.containsKey(Monosaccharide.NeuAc) ? mMonosaccharideCountMap.get(Monosaccharide.NeuAc) : 0; 538 539 Rectangle2D man2bbox = man2.getBoundsBox(); 540 Rectangle2D man3bbox = man3.getBoundsBox(); 541 542 if (3 == mannoseCount) 543 { 544 if (3 == glcNAcCount) 545 { 546 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(man2bbox.getX() - 4, man2bbox.getY()), 547 new Point2D.Double(man3bbox.getX() - 4, (man3bbox.getY() + man3bbox.getHeight())), 10); 548 svg.addSubtag(curlyBrace); 549 550 Rectangle2D curlyBraceBBox = curlyBrace.getBoundsBox(); 551 552 svg.addSubtag(Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5))); 553 } 554 else if (4 == glcNAcCount) 555 { 556 SvgNode glcNac3 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Double(man2bbox.getX() - 20, man2bbox.getY())); 557 svg.addSubtag(glcNac3); 558 backbone.addLine(man2.getCenterPoint(), glcNac3.getCenterPoint()); 559 560 SvgNode glcNac4 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Double(man3bbox.getX() - 20, man3bbox.getY())); 561 svg.addSubtag(glcNac4); 562 backbone.addLine(man3.getCenterPoint(), glcNac4.getCenterPoint()); 563 564 Rectangle2D glcNac3bbox = glcNac3.getBoundsBox(); 565 Rectangle2D glcNac4bbox = glcNac4.getBoundsBox(); 566 567 if (1 == hexoseCount) 568 { 569 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(glcNac3bbox.getX() - 4, glcNac3bbox.getY()), 570 new Point2D.Double(glcNac4bbox.getX() - 4, (glcNac4bbox.getY() + glcNac4bbox.getHeight())), 10); 571 svg.addSubtag(curlyBrace); 572 573 Rectangle2D curlyBraceBBox = curlyBrace.getBoundsBox(); 574 575 SvgNode hex = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5)); 576 svg.addSubtag(hex); 577 578 if (sialicAcidCount > 0) 579 { 580 Rectangle2D hexBBox = hex.getBoundsBox(); 581 582 SvgNode sialicAcid = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hexBBox.getX() - 20, hexBBox.getY())); 583 svg.addSubtag(sialicAcid); 584 backbone.addLine(hex.getCenterPoint(), sialicAcid.getCenterPoint()); 585 } 586 } 587 else if (2 == hexoseCount) 588 { 589 SvgNode hex1 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(glcNac3bbox.getX() - 20, glcNac3bbox.getY())); 590 svg.addSubtag(hex1); 591 backbone.addLine(glcNac3.getCenterPoint(), hex1.getCenterPoint()); 592 593 SvgNode hex2 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(glcNac4bbox.getX() - 20, glcNac4bbox.getY())); 594 svg.addSubtag(hex2); 595 backbone.addLine(glcNac4.getCenterPoint(), hex2.getCenterPoint()); 596 597 Rectangle2D hex1bbox = hex1.getBoundsBox(); 598 Rectangle2D hex2bbox = hex2.getBoundsBox(); 599 600 if (1 == sialicAcidCount) 601 { 602 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(hex1bbox.getX() - 4, hex1bbox.getY()), 603 new Point2D.Double(hex2bbox.getX() - 4, (hex2bbox.getY() + hex2bbox.getHeight())), 10); 604 svg.addSubtag(curlyBrace); 605 606 Rectangle curlyBraceBBox = curlyBrace.getBoundsBox(); 607 608 svg.addSubtag(Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5))); 609 } 610 else if (2 == sialicAcidCount) 611 { 612 SvgNode sialicAcid1 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex1bbox.getX() - 20, hex1bbox.getY())); 613 svg.addSubtag(sialicAcid1); 614 backbone.addLine(hex1.getCenterPoint(), sialicAcid1.getCenterPoint()); 615 616 SvgNode sialicAcid2 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex2bbox.getX() - 20, hex2bbox.getY())); 617 svg.addSubtag(sialicAcid2); 618 backbone.addLine(hex2.getCenterPoint(), sialicAcid2.getCenterPoint()); 619 } 620 } 621 } 622 else if (5 == glcNAcCount) 623 { 624 SvgNode glcNac3 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Double(man2bbox.getX() - 20, man2bbox.getY() - 10)); 625 svg.addSubtag(glcNac3); 626 backbone.addLine(man2.getCenterPoint(), glcNac3.getCenterPoint()); 627 628 SvgNode glcNac4 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Double(man3bbox.getX() - 20, man2bbox.getY() + 7)); 629 svg.addSubtag(glcNac4); 630 backbone.addLine(man2.getCenterPoint(), glcNac4.getCenterPoint()); 631 632 SvgNode glcNac5 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Double(man3bbox.getX() - 20, man3bbox.getY())); 633 svg.addSubtag(glcNac5); 634 backbone.addLine(man3.getCenterPoint(), glcNac5.getCenterPoint()); 635 636 Rectangle2D glcNac3bbox = glcNac3.getBoundsBox(); 637 Rectangle2D glcNac4bbox = glcNac4.getBoundsBox(); 638 Rectangle2D glcNac5bbox = glcNac5.getBoundsBox(); 639 640 if (hexoseCount >= 1 641 && hexoseCount <= 2) 642 { 643 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(glcNac3bbox.getX() - 4, glcNac3bbox.getY()), 644 new Point2D.Double(glcNac5bbox.getX() - 4, (glcNac5bbox.getY() + glcNac5bbox.getHeight())), 10); 645 svg.addSubtag(curlyBrace); 646 647 Rectangle2D curlyBraceBBox = curlyBrace.getBoundsBox(); 648 649 if (1 == hexoseCount) 650 { 651 SvgNode hex = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5)); 652 svg.addSubtag(hex); 653 654 if (sialicAcidCount > 0) 655 { 656 Rectangle2D hexBBox = hex.getBoundsBox(); 657 658 SvgNode sialicAcid = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hexBBox.getX() - 20, hexBBox.getY())); 659 svg.addSubtag(sialicAcid); 660 backbone.addLine(hex.getCenterPoint(), sialicAcid.getCenterPoint()); 661 } 662 } 663 else 664 { 665 SvgNode hex1 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() * 0.25) - 5)); 666 svg.addSubtag(hex1); 667 668 SvgNode hex2 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() * 0.75) - 5)); 669 svg.addSubtag(hex2); 670 671 Rectangle2D hex1BBox = hex1.getBoundsBox(); 672 Rectangle2D hex2BBox = hex2.getBoundsBox(); 673 674 if (sialicAcidCount > 0) 675 { 676 SvgNode sialicAcid = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex1BBox.getX() - 20, hex1BBox.getY())); 677 svg.addSubtag(sialicAcid); 678 backbone.addLine(hex1.getCenterPoint(), sialicAcid.getCenterPoint()); 679 680 if (2 == sialicAcidCount) 681 { 682 SvgNode sialicAcid2 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex2BBox.getX() - 20, hex2BBox.getY())); 683 svg.addSubtag(sialicAcid2); 684 backbone.addLine(hex2.getCenterPoint(), sialicAcid2.getCenterPoint()); 685 } 686 } 687 } 688 } 689 else if (3 == hexoseCount) 690 { 691 SvgNode hex1 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(glcNac3bbox.getX() - 20, glcNac3bbox.getY())); 692 svg.addSubtag(hex1); 693 backbone.addLine(glcNac3.getCenterPoint(), hex1.getCenterPoint()); 694 695 SvgNode hex2 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(glcNac4bbox.getX() - 20, glcNac4bbox.getY())); 696 svg.addSubtag(hex2); 697 backbone.addLine(glcNac4.getCenterPoint(), hex2.getCenterPoint()); 698 699 SvgNode hex3 = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Double(glcNac5bbox.getX() - 20, glcNac5bbox.getY())); 700 svg.addSubtag(hex3); 701 backbone.addLine(glcNac5.getCenterPoint(), hex3.getCenterPoint()); 702 703 Rectangle2D hex1bbox = hex1.getBoundsBox(); 704 Rectangle2D hex2bbox = hex2.getBoundsBox(); 705 Rectangle2D hex3bbox = hex3.getBoundsBox(); 706 707 if (sialicAcidCount >= 1 708 && sialicAcidCount <= 2) 709 { 710 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(hex1bbox.getX() - 4, hex1bbox.getY()), 711 new Point2D.Double(hex3bbox.getX() - 4, (hex3bbox.getY() + hex3bbox.getHeight())), 10); 712 svg.addSubtag(curlyBrace); 713 714 Rectangle2D curlyBraceBBox = curlyBrace.getBoundsBox(); 715 716 if (1 == sialicAcidCount) 717 { 718 svg.addSubtag(Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5))); 719 } 720 else if (2 == sialicAcidCount) 721 { 722 SvgNode sialicAcid1 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() * 0.25) - 5)); 723 svg.addSubtag(sialicAcid1); 724 725 SvgNode sialicAcid2 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() * 0.75) - 5)); 726 svg.addSubtag(sialicAcid2); 727 } 728 } 729 else if (3 == sialicAcidCount) 730 { 731 SvgNode sialicAcid1 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex1bbox.getX() - 20, hex1bbox.getY())); 732 svg.addSubtag(sialicAcid1); 733 backbone.addLine(hex1.getCenterPoint(), sialicAcid1.getCenterPoint()); 734 735 SvgNode sialicAcid2 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex2bbox.getX() - 20, hex2bbox.getY())); 736 svg.addSubtag(sialicAcid2); 737 backbone.addLine(hex2.getCenterPoint(), sialicAcid2.getCenterPoint()); 738 739 SvgNode sialicAcid3 = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Double(hex3bbox.getX() - 20, hex3bbox.getY())); 740 svg.addSubtag(sialicAcid3); 741 backbone.addLine(hex3.getCenterPoint(), sialicAcid3.getCenterPoint()); 742 } 743 } 744 } 745 } 746 else if (4 == mannoseCount) 747 { 748 if (glcNAcCount > 2) 749 { 750 SvgNode man4 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(50, 7)); 751 svg.addSubtag(man4); 752 backbone.addLine(man2.getCenterPoint(), man4.getCenterPoint()); 753 754 SvgNode glcNac3 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Float(50, 37)); 755 svg.addSubtag(glcNac3); 756 backbone.addLine(man3.getCenterPoint(), glcNac3.getCenterPoint()); 757 758 if (hexoseCount > 0) 759 { 760 SvgNode hex = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Float(30, 37)); 761 svg.addSubtag(hex); 762 backbone.addLine(glcNac3.getCenterPoint(), hex.getCenterPoint()); 763 764 if (sialicAcidCount > 0) 765 { 766 SvgNode sialicAcid = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Float(10, 37)); 767 svg.addSubtag(sialicAcid); 768 backbone.addLine(hex.getCenterPoint(), sialicAcid.getCenterPoint()); 769 } 770 } 771 } 772 else 773 { 774 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(man2bbox.getX() - 4, man2bbox.getY()), 775 new Point2D.Double(man3bbox.getX() - 4, (man3bbox.getY() + man3bbox.getHeight())), 10); 776 svg.addSubtag(curlyBrace); 777 778 Rectangle2D curlyBraceBBox = curlyBrace.getBoundsBox(); 779 780 svg.addSubtag(Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5))); 781 } 782 } 783 else if (5 == mannoseCount) 784 { 785 SvgNode man4 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(50, 2)); 786 svg.addSubtag(man4); 787 backbone.addLine(man2.getCenterPoint(), man4.getCenterPoint()); 788 789 SvgNode man5 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(50, 19)); 790 svg.addSubtag(man5); 791 backbone.addLine(man2.getCenterPoint(), man5.getCenterPoint()); 792 793 if (glcNAcCount > 2) 794 { 795 SvgNode glcNac3 = Monosaccharide.GlcNAc.toSVGNode().setPosition(new Point2D.Float(50, 37)); 796 svg.addSubtag(glcNac3); 797 backbone.addLine(man3.getCenterPoint(), glcNac3.getCenterPoint()); 798 799 if (hexoseCount > 0) 800 { 801 SvgNode hex = Monosaccharide.Hexose.toSVGNode().setPosition(new Point2D.Float(30, 37)); 802 svg.addSubtag(hex); 803 backbone.addLine(glcNac3.getCenterPoint(), hex.getCenterPoint()); 804 805 if (sialicAcidCount > 0) 806 { 807 SvgNode sialicAcid = Monosaccharide.NeuAc.toSVGNode().setPosition(new Point2D.Float(10, 37)); 808 svg.addSubtag(sialicAcid); 809 backbone.addLine(hex.getCenterPoint(), sialicAcid.getCenterPoint()); 810 } 811 } 812 } 813 } 814 else if (6 <= mannoseCount) 815 { 816 SvgNode man4 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(50, 2)); 817 svg.addSubtag(man4); 818 backbone.addLine(man2.getCenterPoint(), man4.getCenterPoint()); 819 820 SvgNode man5 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(50, 19)); 821 svg.addSubtag(man5); 822 backbone.addLine(man2.getCenterPoint(), man5.getCenterPoint()); 823 824 SvgNode man6 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(50, 37)); 825 svg.addSubtag(man6); 826 backbone.addLine(man3.getCenterPoint(), man6.getCenterPoint()); 827 828 if (9 == mannoseCount) 829 { 830 SvgNode man7 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(30, 2)); 831 svg.addSubtag(man7); 832 backbone.addLine(man4.getCenterPoint(), man7.getCenterPoint()); 833 834 SvgNode man8 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(30, 19)); 835 svg.addSubtag(man8); 836 backbone.addLine(man5.getCenterPoint(), man8.getCenterPoint()); 837 838 SvgNode man9 = Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Float(30, 37)); 839 svg.addSubtag(man9); 840 backbone.addLine(man6.getCenterPoint(), man9.getCenterPoint()); 841 } 842 else if (mannoseCount > 6) 843 { 844 Rectangle2D man4bbox = man4.getBoundsBox(); 845 Rectangle2D man6bbox = man6.getBoundsBox(); 846 847 SvgPath curlyBrace = SvgPath.generateCurlyBracket(new Point2D.Double(man4bbox.getX() - 4, man4bbox.getY()), 848 new Point2D.Double(man6bbox.getX() - 4, man6bbox.getY() + man6bbox.getHeight()), 10); 849 svg.addSubtag(curlyBrace); 850 851 Rectangle2D curlyBraceBBox = curlyBrace.getBoundsBox(); 852 853 if (7 == mannoseCount) 854 { 855 svg.addSubtag(Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() / 2) - 5))); 856 } 857 else if (8 == mannoseCount) 858 { 859 svg.addSubtag(Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() * 0.25) - 5))); 860 861 svg.addSubtag(Monosaccharide.Mannose.toSVGNode().setPosition(new Point2D.Double(curlyBraceBBox.getX() - 14, (curlyBraceBBox.getY() + curlyBraceBBox.getHeight() * 0.75) - 5))); 862 } 863 } 864 } 865 866 return svg; 867 } 868 869 870 //-------------------------------------------------------------------------- 871 public Glycan add(Monosaccharide inMonosaccharide, int inCount) 872 { 873 Integer currentCount = mMonosaccharideCountMap.get(inMonosaccharide); 874 int newCount = (currentCount != null ? currentCount : 0) + inCount; 875 876 int newBondCount = inCount - 1 + (mMonosaccharideCountMap.size() > 0 ? 1 : 0); 877 878 mMonosaccharideCountMap.put(inMonosaccharide, newCount); 879 880 super.add(inMonosaccharide, inCount); 881 882 super.remove(Molecule.H2O, newBondCount); 883 884 return this; 885 } 886 887 888 //-------------------------------------------------------------------------- 889 /** 890 Returns a List of IonizableGroup objects. 891 @return List of IonizableGroups 892 */ 893 public List<IonizableGroup> getKas() 894 { 895 List<IonizableGroup> ionizableGroups = null; 896 897 for (Monosaccharide monosaccharide : mMonosaccharideCountMap.keySet()) 898 { 899 List<IonizableGroup> monosaccharideKas = monosaccharide.getKas(); 900 if (CollectionUtil.hasValues(monosaccharideKas)) 901 { 902 if (null == ionizableGroups) 903 { 904 ionizableGroups = new ArrayList<>(5); 905 } 906 907 for (IonizableGroup ionizableGroup : monosaccharideKas) 908 { 909 for (int i = 0; i < mMonosaccharideCountMap.get(monosaccharide); i++) 910 { 911 ionizableGroups.add(ionizableGroup); 912 } 913 } 914 } 915 } 916 917 return ionizableGroups; 918 } 919 920}