/* * EuroCarbDB, a framework for carbohydrate bioinformatics * * Copyright (c) 2006-2009, Eurocarb project, or third-party contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * A copy of this license accompanies this distribution in the file LICENSE.txt. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * Last commit: $Rev: 1210 $ by $Author: glycoslave $ on $Date:: 2009-06-12 #$ */ package org.eurocarbdb.resourcesdb.representation; import java.awt.Dimension; import java.util.ArrayList; import org.eurocarbdb.resourcesdb.ResourcesDbException; import org.eurocarbdb.resourcesdb.glycoconjugate_derived.LinkageType; import org.eurocarbdb.resourcesdb.monosaccharide.CoreModification; import org.eurocarbdb.resourcesdb.monosaccharide.CoreModificationTemplate; import org.eurocarbdb.resourcesdb.monosaccharide.Monosaccharide; import org.eurocarbdb.resourcesdb.monosaccharide.MonosaccharideValidation; import org.eurocarbdb.resourcesdb.monosaccharide.Ringtype; import org.eurocarbdb.resourcesdb.monosaccharide.StereoConfiguration; import org.eurocarbdb.resourcesdb.monosaccharide.Substitution; /** * Create Fischer projections of monosaccharides using the <code>SvgFactory</code> class * @author Thomas Lütteke * */ public class Fischer extends SvgFactory { private static int defaultWidth = 120; private static int defaultHeight = 120; private int lineLength = 15; private int backboneX = 60; private int positionY = 0; private static final String OH = "OH"; private static final String HO = "HO"; private static final String H = "H"; private static final String O = "O"; private static final String CH3 = "CH3"; private static final String CH2 = "CH2"; private static final String CH = "CH"; private static final String CHO = "CHO"; private static final String COOH = "COOH"; private static final String CH2OH = "CH2OH"; //***************************************************************************** //*** constructors: *********************************************************** //***************************************************************************** /** * Constructor, creates a Fischer object using the default width and height values */ public Fischer() { super(); this.setSvgWidth(defaultWidth); this.setSvgHeight(defaultHeight); this.getSVGGraph2D().setSVGCanvasSize(new Dimension(defaultWidth, defaultHeight)); } /** * Constructor, creates a Fischer object with the given dimensions * @param width the width of the SVG graphic * @param height the height of the SVG graphic */ public Fischer(int width, int height) { super(); this.setSvgWidth(width); this.setSvgHeight(height); this.getSVGGraph2D().setSVGCanvasSize(new Dimension(width, height)); } //***************************************************************************** //*** drawing methods: ******************************************************** //***************************************************************************** private void drawVerticalLines(double bo) { if(bo == 1) { this.drawLine(this.backboneX, this.positionY, this.backboneX, this.positionY + this.lineLength); } else if(bo == 2) { this.drawLine(this.backboneX -2, this.positionY, this.backboneX -2, this.positionY + this.lineLength); this.drawLine(this.backboneX +2, this.positionY, this.backboneX +2, this.positionY + this.lineLength); } else if(bo == 3) { this.drawLine(this.backboneX -3, this.positionY, this.backboneX -3, this.positionY + this.lineLength); this.drawLine(this.backboneX, this.positionY, this.backboneX, this.positionY + this.lineLength); this.drawLine(this.backboneX +3, this.positionY, this.backboneX +3, this.positionY + this.lineLength); } this.positionY += this.lineLength; } private void drawChainPosition(int pos) throws ResourcesDbException { Monosaccharide ms = this.getMonosacc(); double boToPrevious = 1; String leftLabel = null; double leftBo = 1; String rightLabel = null; double rightBo = 1; String positionLabel = "C"; int cWidthHalf = this.getStringWidth("C") / 2; StereoConfiguration sConf = ms.getStereocode().getPositionConfiguration(pos); if(pos == 1) { this.positionY = this.getTextSize() + 2; boToPrevious = 0; if(ms.isAlditol()) { if(ms.hasCoreModification(CoreModificationTemplate.DEOXY, 1)) { positionLabel = Fischer.CH3; } else { positionLabel = Fischer.CH2OH; } } else if(ms.isAldaric() || ms.isAldonic()) { positionLabel = Fischer.COOH; } else if(ms.hasCoreModification(CoreModificationTemplate.KETO) && !ms.hasCoreModification(CoreModificationTemplate.KETO, 1)) { positionLabel = Fischer.CH2OH; } else { positionLabel = Fischer.CHO;; } //TODO: implement substituents at position 1 if(ms.getSubstitutionsByPosition(pos).size() > 0) { throw new ResourcesDbException("Fischer projection of monosaccharides with terminal substitutions not yet supported."); } this.drawString(positionLabel, this.backboneX - cWidthHalf, this.positionY); this.positionY += 2; } else if(pos < ms.getSize()) { for(CoreModification mod : ms.getCoreModificationsByPosition(pos)) { if(CoreModificationTemplate.EN.equals(mod.getTemplate()) && mod.getIntValuePosition2() == pos) { boToPrevious = 2; } if(CoreModificationTemplate.YN.equals(mod.getTemplate()) && mod.getIntValuePosition2() == pos) { boToPrevious = 3; } } Substitution ohLinkedSubst = ms.getSubstitution(null, pos, LinkageType.H_AT_OH); if(ohLinkedSubst == null) { ohLinkedSubst = ms.getSubstitution(null, pos, LinkageType.DEOXY); } Substitution cLinkedSubst = ms.getSubstitution(null, pos, LinkageType.H_LOSE); if(sConf.equals(StereoConfiguration.Dexter)) { if(ohLinkedSubst != null) { rightLabel = ohLinkedSubst.getTemplate().getHaworthName(); if(ohLinkedSubst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { rightLabel = "O-" + rightLabel; } rightBo = ohLinkedSubst.getBondOrder1(); } else { rightLabel = Fischer.OH; } if(cLinkedSubst != null) { leftLabel = cLinkedSubst.getTemplate().getMirroredHaworthName(); leftBo = cLinkedSubst.getBondOrder1(); } else { leftLabel = Fischer.H; } } else if(sConf.equals(StereoConfiguration.Laevus)) { if(ohLinkedSubst != null) { leftLabel = ohLinkedSubst.getTemplate().getMirroredHaworthName(); if(ohLinkedSubst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { leftLabel += "-O"; } leftBo = ohLinkedSubst.getBondOrder1(); } else { leftLabel = Fischer.HO; } if(cLinkedSubst != null) { rightLabel = cLinkedSubst.getTemplate().getHaworthName(); rightBo = cLinkedSubst.getBondOrder1(); } else { rightLabel = Fischer.H; } } else if(sConf.equals(StereoConfiguration.Nonchiral)) { if(ms.hasDoubleBond(pos)) { if(!ms.hasDoubleBond(pos - 1) || !ms.hasDoubleBond(pos + 1)) { //TODO: implement E/Z notation if(ms.hasCoreModification(CoreModificationTemplate.DEOXY, pos)) { rightLabel = Fischer.H; rightBo = 1; } else { Substitution subst = ms.getSubstitution(null, pos, null); if(subst == null) { rightLabel = Fischer.OH; rightBo = 1; } else { rightLabel = subst.getTemplate().getHaworthName(); if(subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { rightLabel = "O-" + rightLabel; } } } } } else if(ms.hasCoreModification(CoreModificationTemplate.DEOXY, pos)) { rightLabel = Fischer.H; rightBo = 1; leftLabel = Fischer.H; leftBo = 1; } else if(ms.hasCoreModification(CoreModificationTemplate.KETO, pos)) { rightLabel = Fischer.O; rightBo = 2; } else if(ms.hasCoreModification(CoreModificationTemplate.SP2)) { Substitution subst = ms.getSubstitution(null, pos, null); rightLabel = subst.getTemplate().getHaworthName(); rightBo = 2; } } else { throw new ResourcesDbException("Cannot draw Fischer projection for monosaccharide with StereoConfiguration " + sConf.getFullname()); } this.drawVerticalLines(boToPrevious); this.positionY += this.getTextSize() + 2; this.drawString(positionLabel, this.backboneX - cWidthHalf, this.positionY); int lineY = this.positionY - this.getTextSize() / 2; if(leftLabel != null) { int x1 = this.backboneX - cWidthHalf - 2; int x2 = x1 - this.lineLength; if(leftBo == 1) { this.drawLine(x1, lineY, x2, lineY); } else if(leftBo == 2) { this.drawLine(x1, lineY - 2, x2, lineY - 2); this.drawLine(x1, lineY + 2, x2, lineY + 2); } this.drawString(leftLabel, x2 - 2 - this.getStringWidth(leftLabel), this.positionY); } if(rightLabel != null) { int x1 = this.backboneX + cWidthHalf + 2; int x2 = x1 + this.lineLength; if(rightBo == 1) { this.drawLine(x1, lineY, x2, lineY); } else if(rightBo == 2) { this.drawLine(x1, lineY - 2, x2, lineY - 2); this.drawLine(x1, lineY + 2, x2, lineY + 2); } this.drawString(rightLabel, x2 + 2, this.positionY); } this.positionY += 2; } else { //*** pos == ms.size (terminal carbon) *** this.drawVerticalLines(boToPrevious); this.positionY += this.getTextSize() + 2; int centerLabelPosition = this.backboneX - cWidthHalf; if(ms.isUronic() || ms.isAldaric()) { positionLabel = Fischer.COOH; } else if(ms.hasCoreModification(CoreModificationTemplate.DEOXY, pos)) { if(boToPrevious == 3) { positionLabel = Fischer.CH; } else if(boToPrevious == 2) { positionLabel = Fischer.CH2; } else { positionLabel = Fischer.CH3; } } else if(ms.hasCoreModification(CoreModificationTemplate.KETO, pos)) { positionLabel = Fischer.CHO; } else { positionLabel = Fischer.CH2OH; } ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(pos); if(substList.size() > 0) { if(substList.size() == 1) { Substitution subst = substList.get(0); if(ms.isUronic() || ms.isAldaric()) { if(subst.getLinkagetype1().equals(LinkageType.DEOXY)) { positionLabel = "CO" + subst.getTemplate().getHaworthName(); } else { positionLabel = "COO" + subst.getTemplate().getHaworthName(); } } else if(subst.getLinkagetype1().equals(LinkageType.DEOXY) || subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { int hCount = 4 - (int) Math.floor(boToPrevious + subst.getBondOrder1()); positionLabel = "C"; if(hCount > 0) { positionLabel += "H"; } if(hCount > 1) { positionLabel += hCount; } if(subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { positionLabel += "O"; } positionLabel += subst.getTemplate().getHaworthName(); } else { throw new ResourcesDbException("LinkageType " + subst.getLinkagetypeStr1() + " not yet supported in Fischer projection at terminal position"); } } else { throw new ResourcesDbException("Multiple substituents at terminal carbon not yet supported in Fischer projection"); } } this.drawString(positionLabel, centerLabelPosition, this.positionY); } } private void drawRing() throws ResourcesDbException { throw new ResourcesDbException("Fischer projection for ring monosaccharide is not yet implemented."); } private void drawOpenChain() throws ResourcesDbException { for(int pos = 1; pos <= this.getMonosacc().getSize(); pos ++) { this.drawChainPosition(pos); } this.checkSize(); } public void drawMonosaccharide(Monosaccharide ms) throws ResourcesDbException { if(MonosaccharideValidation.checkFuzziness(ms)) { throw new ResourcesDbException("Cannot draw Fischer projection for monosaccharide with uncertain / fuzzy properties."); } if(ms.hasCoreModification(CoreModificationTemplate.ANHYDRO)) { throw new ResourcesDbException("Cannot draw Fischer projection for monosaccharide with anhydro modification."); } if(ms.hasCoreModification(CoreModificationTemplate.LACTONE)) { throw new ResourcesDbException("Cannot draw Fischer projection for monosaccharide with lactono modification."); } if(ms.hasCoreModification(CoreModificationTemplate.EPOXY)) { throw new ResourcesDbException("Cannot draw Fischer projection for monosaccharide with epoxy modification."); } this.setMonosacc(ms); if(ms.getRingtype().equals(Ringtype.PYRANOSE) || ms.getRingtype().equals(Ringtype.FURANOSE)) { this.drawRing(); } else if(ms.getRingtype().equals(Ringtype.OPEN)) { this.drawOpenChain(); } else { throw new ResourcesDbException("Cannot draw Fischer projection for monosaccharide with ring type " + ms.getRingtype().getName()); } this.checkSize(); //*** check, if all elements of the graphic are within the visible area, rescale or resize if not *** } }