/* * 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.*; import java.util.ArrayList; import org.eurocarbdb.resourcesdb.ResourcesDbException; import org.eurocarbdb.resourcesdb.atom.Atom; import org.eurocarbdb.resourcesdb.glycoconjugate_derived.LinkageType; import org.eurocarbdb.resourcesdb.monosaccharide.*; /** * Create Haworth projections of monosaccharide rings using the <code>SvgFactory</code> class * @author Thomas Lütteke * */ public class Haworth extends SvgFactory { /** * The X coordinates of the default basepoints of a pyranose ring */ private static int[] pyranoseX = {100, 80, 40, 20, 40, 80}; /** * The Y coordinates of the default basepoints of a pyranose ring */ private static int[] pyranoseY = {60, 90, 90, 60, 30, 30}; /** * The X coordinates of the default basepoints of a furanose ring */ private static int[] furanoseX = {100, 85, 35, 20, 60}; /** * The Y coordinates of the default basepoints of a furanose ring */ private static int[] furanoseY = {50, 80, 80, 50, 30}; /** * The basepoints, i.e. the corner points of the haworth penta- or hexagon shape */ private ArrayList<Point> basepoints; /** * The center of the haworth penta- or hexagon shape */ private Point baseCenter; private static final String OH = "OH"; private static final String HO = "HO"; private static final String CH3 = "CH3"; private static final String H3C = "H3C"; private static final String COOH = "COOH"; private static final String HOOC = "HOOC"; private static final String COO = "COO"; private static final String OOC = "OOC"; private static int defaultWidth = 120; private static int defaultHeight = 120; private int lineLength = 15; //***************************************************************************** //*** constructors: *********************************************************** //***************************************************************************** /** * Constructor, creates a Haworth object using the default width and height values */ public Haworth() { super(); this.setSvgWidth(defaultWidth); this.setSvgHeight(defaultHeight); this.getSVGGraph2D().setSVGCanvasSize(new Dimension(defaultWidth, defaultHeight)); } /** * Constructor, creates a Haworth object with the given dimensions * @param width the width of the SVG graphic * @param height the height of the SVG graphic */ public Haworth(int width, int height) { super(); this.setSvgWidth(width); this.setSvgHeight(height); this.getSVGGraph2D().setSVGCanvasSize(new Dimension(width, height)); } //***************************************************************************** //*** getters/setters: ******************************************************** //***************************************************************************** private ArrayList<Point> getBasepoints() { return this.basepoints; } private Point getBasepoint(int index) { return(this.getBasepoints().get(index - 1)); } private void setBasepoints(ArrayList<Point> pointList) { this.basepoints = pointList; } private Point getBaseCenter() { return this.baseCenter; } private void setBaseCenter(Point baseCenter) { this.baseCenter = baseCenter; } /** * Set the basepoints of a pyranose ring from the coordinates of the <code>pyranoseX</code> and <code>pyranoseY</code> arrays */ private void setPyranoseBasepoints() { setBasepoints(new ArrayList<Point>()); for(int i = 0; i < 6; i++) { this.getBasepoints().add(new Point(pyranoseX[i], pyranoseY[i])); } } /** * Set the basepoints of a furanose ring from the coordinates of the <code>furanoseX</code> and <code>furanoseY</code> arrays */ private void setFuranoseBasepoints() { setBasepoints(new ArrayList<Point>()); for(int i = 0; i < 5; i++) { this.getBasepoints().add(new Point(furanoseX[i], furanoseY[i])); } } //***************************************************************************** //*** drawing methods: ******************************************************** //***************************************************************************** /** * Draw a pyranose ring template, i.e. the hexagon shape with the ring oxygen, but without any exocyclic atoms */ private void drawPyranoseRingTemplate() { String ringOStr = "O"; if(this.getMonosacc().getRingEnd() > 0) { Substitution ringOSubst = this.getMonosacc().getSubstitution(null, this.getMonosacc().getRingEnd(), LinkageType.DEOXY); if(ringOSubst != null) { Atom ringAtom; try { ringAtom = ringOSubst.getTemplate().getLinkingAtom(ringOSubst.getIntValueSubstituentPosition1()); } catch(ResourcesDbException rEx) { ringAtom = null; } if(ringAtom == null) { ringOStr = "X"; } else { ringOStr = ringAtom.getElementSymbol(); } } } int oOffset = this.getCharacterCenterXOffset(ringOStr, true); this.drawLine(getBasepoint(4).x, getBasepoint(4).y, getBasepoint(5).x, getBasepoint(5).y); this.drawLineWithOffset(getBasepoint(6).x, getBasepoint(6).y, getBasepoint(5).x, getBasepoint(5).y, this.getStringWidth(ringOStr)); this.drawLineWithOffset(getBasepoint(6).x, getBasepoint(6).y, getBasepoint(1).x, getBasepoint(1).y, this.getTextSize() * 0.6); Polygon pg = new Polygon(); int dp = Math.abs(getBasepoint(1).y - getBasepoint(2).y) / 10; pg.addPoint(getBasepoint(1).x, getBasepoint(1).y); pg.addPoint(getBasepoint(2).x, getBasepoint(2).y - dp); pg.addPoint(getBasepoint(3).x, getBasepoint(3).y - dp); pg.addPoint(getBasepoint(4).x, getBasepoint(4).y); pg.addPoint(getBasepoint(3).x, getBasepoint(3).y + dp); pg.addPoint(getBasepoint(2).x, getBasepoint(2).y + dp); this.fillShape(pg); this.drawString(ringOStr, getBasepoint(6).x + oOffset, getBasepoint(6).y + (this.getTextSize() / 2)); } /** * Draw a furanose ring template, i.e. the pentagon shape with the ring oxygen, but without any exocyclic atoms */ private void drawFuranoseRingTemplate() { String ringOStr = "O"; int oOffset = this.getCharacterCenterXOffset(ringOStr, false); this.drawLineWithOffset(getBasepoint(5).x, getBasepoint(5).y, getBasepoint(4).x, getBasepoint(4).y, this.getTextSize() * 0.6); this.drawLineWithOffset(getBasepoint(5).x, getBasepoint(5).y, getBasepoint(1).x, getBasepoint(1).y, this.getTextSize() * 0.6); Polygon pg = new Polygon(); int dp = Math.abs(getBasepoint(1).y - getBasepoint(2).y) / 10; pg.addPoint(getBasepoint(1).x, getBasepoint(1).y); pg.addPoint(getBasepoint(2).x, getBasepoint(2).y - dp); pg.addPoint(getBasepoint(3).x, getBasepoint(3).y - dp); pg.addPoint(getBasepoint(4).x, getBasepoint(4).y); pg.addPoint(getBasepoint(3).x, getBasepoint(3).y + dp); pg.addPoint(getBasepoint(2).x, getBasepoint(2).y + dp); this.fillShape(pg); this.drawString(ringOStr, getBasepoint(5).x + oOffset, getBasepoint(5).y + (int)(Math.floor(this.getTextSize() * 0.6))); } /** * Draw a pyranose residue in Haworth projection * @throws ResourcesDbException */ private void drawPyranose() throws ResourcesDbException { this.setPyranoseBasepoints(); this.calculateBasecenter(); this.drawPyranoseRingTemplate(); //*** draw modifications / OH groups at ring carbons: *** for(int i = 1; i < 6; i++) { this.drawPyranoseRingPosition(i); } } /** * Add a single position to a pyranose ring graphic * If exocyclic carbons are present at ring positions 1 or 5, these are drawn together with these positions (represented by an "R" in case more than one exocyclic carbon is present at a position) * @param ringPos the carbon position within the pyranose ring (1 to 5, i.e. C1 to C5 of an aldose or e.g. C2 to C6 of a 2-ketose) * @throws ResourcesDbException */ private void drawPyranoseRingPosition(int i) throws ResourcesDbException { this.drawRingPosition(i); } private void drawRingPosition(int ringPos) throws ResourcesDbException { Monosaccharide ms = this.getMonosacc(); //*** 'pos' marks position within the pyranose ring, while 'msPos' marks position within the monosaccharide *** //*** (values differ for monosaccharides with a carbonyl position other than one, e.g. ketoses) *** int msPos = ringPos - 1 + ms.getRingStart(); //*** get stereo configuration: *** StereoConfiguration sConf = ms.getStereocode().getPositionConfiguration(msPos); if(msPos == ms.getRingEnd()) { sConf = StereoConfiguration.invert(sConf); } //*** calculate coordinates: *** Point p = this.getBasepoint(ringPos); //*** coordinates of line start (x1/y1), end (x2/y2) and label (xt/yt) of the OH group or an o-linked or deoxy substituent: *** int x1 = p.x; int y1 = p.y; int x2 = x1; int y2 = y1; int yt = y1; int xt = x1; //*** coordinates of line end (x2_c/y2_c) and label (xt_c/yt_c) of a potential c-linked substituent (line start is the same as above) *** int x2_c = x1; int y2_c = y1; int xt_c = xt; int yt_c = yt; boolean alignLabelRight = false; boolean alignLabelRight_c = false; String substLabel = ""; String substLabel_c = null; int bo = 1; if(sConf.equals(StereoConfiguration.Dexter)) { x2 = p.x; y2 = p.y + this.lineLength; yt = y2 + this.getTextSize(); bo = 1; x2_c = p.x; y2_c = p.y - this.lineLength; yt_c = y2_c - 2; } else if(sConf.equals(StereoConfiguration.Laevus)) { x2 = p.x; y2 = p.y - this.lineLength; yt = y2 - 2; x2_c = p.x; y2_c = p.y + this.lineLength; yt_c = y2_c + this.getTextSize(); bo = 1; } else if(sConf.equals(StereoConfiguration.Nonchiral)) { for(CoreModification mod : ms.getCoreModificationsByPosition(msPos)) { if(mod.getTemplate().equals(CoreModificationTemplate.DEOXY)) { bo = 0; } if(mod.getTemplate().equals(CoreModificationTemplate.EN)) { if(mod.getIntValuePosition1() == msPos) { this.drawRingDoubleBond(ringPos); } int xc = this.getBaseCenter().x; int yc = this.getBaseCenter().y; x2 = x1 - xc; y2 = y1 - yc; double len = 15.0 / Math.round((float)Math.sqrt(x2 * x2 + y2 * y2)); x2 = (int) (x1 + len * x2); y2 = (int) (y1 + len * y2); if(x2 > x1) { xt = x2; } else { xt = x2; alignLabelRight = true; } if(y2 > y1) { yt = y2 + this.getSVGGraph2D().getFontMetrics().getHeight(); } else if(y2 == y1) { yt = y2 + this.getSVGGraph2D().getFontMetrics().getHeight() / 2; } else { yt = y2 - 2; } } if(mod.getTemplate().equals(CoreModificationTemplate.SP2)) { bo = 2; } } } else { throw new MonosaccharideException("Unsupported stereochemistry in Haworth formula: " + sConf.getFullname()); } if(bo > 0) { //*** at position 4 (any chirality) or at position 2 (and subst. pointing up, i.e. L-chirality) the label has to point to the right: *** //TODO: check position 3, take into account chirality of position 2 to avoid overlappings (esp. if both 2 and 3 point up) if(ringPos == 4) { alignLabelRight = true; } else if(ringPos == 2) { if(sConf.equals(StereoConfiguration.Laevus)) { alignLabelRight = true; } } //*** get position label: *** if(msPos != ms.getRingEnd()) { ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(msPos); if(substList != null && substList.size() > 0) { for(Substitution subst : substList) { if(!subst.getLinkagetype1().equals(LinkageType.H_LOSE)) { if(alignLabelRight) { substLabel = subst.getTemplate().getMirroredHaworthName(); if(subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { substLabel += "O"; } } else { substLabel = subst.getTemplate().getHaworthName(); if(subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { substLabel = "O" + substLabel; } } } else { //*** add c-linked substituent: *** if(alignLabelRight_c) { substLabel_c = subst.getTemplate().getMirroredHaworthName(); } else { substLabel_c = subst.getTemplate().getHaworthName(); } } } } if(substLabel.equals("")) { if(alignLabelRight) { substLabel = Haworth.HO; } else { substLabel = Haworth.OH; } } } //*** carbon connected to ring oxygen: check, if "tail" (C6 (aldopyranose) or respective groups) has to be added *** if(msPos == ms.getRingEnd()) { if(msPos == ms.getSize()) { //TODO: check for substituents with r/s-config linkage type return; } if((ms.getSize() - msPos) == 1) { if(ms.isAldaric() || ms.isUronic()) { ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(ms.getSize()); Substitution subst = null; if(substList != null && substList.size() > 0) { subst = substList.get(0); if(!subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { throw new ResourcesDbException("cannot draw haworth projection for monosaccharide with substitution at acid group and linkage type " + subst.getLinkagetypeStr1()); } } if(sConf.equals(StereoConfiguration.Laevus) || sConf.equals(StereoConfiguration.Nonchiral) || ms.getRingtype().equals(Ringtype.FURANOSE)) { if(subst == null) { substLabel = HOOC; } else { substLabel = subst.getTemplate().getHaworthName() + "-" + OOC; } alignLabelRight = true; } else { if(subst == null) { substLabel = COOH; } else { substLabel = COO + "-" + subst.getTemplate().getHaworthName(); } } } else { if(!ms.hasCoreModification(CoreModificationTemplate.DEOXY, msPos + 1)) { if(sConf.equals(StereoConfiguration.Laevus) || sConf.equals(StereoConfiguration.Nonchiral) || ms.getRingtype().equals(Ringtype.FURANOSE)) { this.drawLine(x2, y2, x2 - this.lineLength, y2); String c6label = Haworth.HO; ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(msPos + 1); if(substList != null && substList.size() > 0) { Substitution subst = substList.get(0); c6label = subst.getTemplate().getMirroredHaworthName(); if(subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { c6label += "O"; } } this.drawString(c6label, x2 - this.lineLength - 2 - this.getSVGGraph2D().getFontMetrics().stringWidth(c6label), y2 - 2 + this.getSVGGraph2D().getFontMetrics().getHeight() / 2); } else { this.drawLine(x2, y2, x2 + this.lineLength, y2); String c6label = Haworth.OH; ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(msPos + 1); if(substList != null && substList.size() > 0) { Substitution subst = substList.get(0); c6label = subst.getTemplate().getHaworthName(); if(subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { c6label = "O" + c6label; } } this.drawString(c6label, x2 + this.lineLength + 2, y2 - 2 + this.getSVGGraph2D().getFontMetrics().getHeight() / 2); } } else { if(sConf.equals(StereoConfiguration.Laevus) || sConf.equals(StereoConfiguration.Nonchiral) || ms.getRingtype().equals(Ringtype.FURANOSE)) { substLabel = H3C; alignLabelRight = true; } else { substLabel = CH3; } } } } else { if(ms.getRingStart() > 2) { substLabel = "R2"; } else { substLabel = "R"; } } } //*** draw position data: *** if(bo == 1) { this.drawLine(x1, y1, x2, y2); if(!substLabel.equals("")) { if(xt == x1) { xt += this.getCharacterCenterXOffset(substLabel, alignLabelRight); } else if(xt == x2 && alignLabelRight) { xt -= this.getSVGGraph2D().getFontMetrics().stringWidth(substLabel); } this.drawString(substLabel, xt, yt); } if(substLabel_c != null) { this.drawLine(x1, y1, x2_c, y2_c); if(xt_c == x1) { xt_c += this.getCharacterCenterXOffset(substLabel, alignLabelRight); } else if(xt_c == x2_c && alignLabelRight) { xt_c -= this.getSVGGraph2D().getFontMetrics().stringWidth(substLabel); } if(!substLabel_c.equals("")) { this.drawString(substLabel_c, xt_c, yt_c); } } } else if(bo == 2) { throw new MonosaccharideException("Double bonds outside the ring are not supported yet."); } } //*** ring position 1: check, if monosaccharide position > 1 (i.e. exocyclic backbone carbons have to be added) *** if(ringPos == 1 && msPos > 1) { //*** carbonyl position > 1: add C1 *** int x2b = x1; int y2b = y1; int xt2 = x1; int yt2 = y1; String substLabelC1 = null; if(sConf.equals(StereoConfiguration.Dexter)) { y2b = y1 - this.lineLength; yt2 = y2b - 2; } else if(sConf.equals(StereoConfiguration.Laevus)) { y2b = y1 + this.lineLength; yt2 = y2b + this.getTextSize(); } else if(sConf.equals(StereoConfiguration.Nonchiral)) { y2b = y1; yt2 = y2b + this.getTextSize() / 2; x2b = x1 + this.lineLength; xt2 = x2b + 2; } this.drawLine(x1, y1, x2b, y2b); if(msPos == 2) { //*** only C1 to be added *** if(ms.isAldaric() || ms.isAldonic()) { ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(1); Substitution subst = null; if(substList != null && substList.size() > 0) { subst = substList.get(0); if(!subst.getLinkagetype1().equals(LinkageType.H_AT_OH)) { throw new ResourcesDbException("cannot draw haworth projection for monosaccharide with substitution at acid group and linkage type " + subst.getLinkagetypeStr1()); } } if(subst == null) { substLabelC1 = COOH; } else { substLabelC1 = COO + "-" + subst.getTemplate().getHaworthName(); } } else { if(!ms.hasCoreModification(CoreModificationTemplate.DEOXY, 1)) { if(sConf.equals(StereoConfiguration.Nonchiral)) { this.drawLine(x2b, y2b, x2b, y2b - this.lineLength); xt2 = x2b + this.getCharacterCenterXOffset(substLabelC1, false); yt2 = y2b - this.lineLength - 2; } else { this.drawLine(x1, y2b, x1 + this.lineLength, y2b); xt2 = x1 + this.lineLength + 2; if(sConf.equals(StereoConfiguration.Dexter)) { yt2 = yt2 + this.getTextSize() / 2 + 2; } else if(sConf.equals(StereoConfiguration.Laevus)) { yt2 = yt2 - this.getTextSize() / 2 - 2; } } substLabelC1 = Haworth.OH; ArrayList<Substitution> substList = ms.getSubstitutionsByPosition(1); if(substList != null && substList.size() > 0) { substLabelC1 = substList.get(0).getTemplate().getHaworthName(); } } } } else { //*** more than one atom to be added *** if(ms.getSize() - ms.getRingEnd() > 1) { substLabelC1 = "R1"; } else { substLabelC1 = "R"; } } if(substLabelC1 != null) { if(xt2 == x1) { xt2 += this.getCharacterCenterXOffset(substLabelC1, false); } this.drawString(substLabelC1, xt2, yt2); } } } /** * Draw a furanose residue in Haworth projection * @throws ResourcesDbException */ private void drawFuranose() throws ResourcesDbException { this.setFuranoseBasepoints(); this.calculateBasecenter(); this.drawFuranoseRingTemplate(); //*** draw modifications / OH groups at ring carbons: *** for(int i = 1; i < 5; i++) { this.drawFuranoseRingPosition(i); } } /** * Add a single position to a furanose ring graphic * If exocyclic carbons are present at ring positions 1 or 4, these are drawn together with these positions (represented by an "R" in case more than one exocyclic carbon is present at a position) * @param ringPos the carbon position within the furanose ring (1 to 4, i.e. C1 to C5 of an aldose or e.g. C2 to C6 of a 2-ketose) * @throws ResourcesDbException */ private void drawFuranoseRingPosition(int rPos) throws ResourcesDbException { this.drawRingPosition(rPos); } /** * Draw a line to indicate a double bond within a ring * @param pos the first position of the double bond */ private void drawRingDoubleBond(int pos) { int xc = this.getBaseCenter().x; int yc = this.getBaseCenter().y; int lx1 = this.getBasepoint(pos).x; int ly1 = this.getBasepoint(pos).y; int lx2 = this.getBasepoint(pos + 1).x; int ly2 = this.getBasepoint(pos + 1).y; int dx1 = Math.abs(lx1 - xc); int dy1 = Math.abs(ly1 - yc); int dx2 = Math.abs(lx2 - xc); int dy2 = Math.abs(ly2 - yc); if(lx1 < xc) lx1 = (int) (lx1 + 0.2 * dx1); if(lx1 > xc) lx1 = (int) (lx1 - 0.2 * dx1); if(ly1 < yc) ly1 = (int) (ly1 + 0.2 * dy1); if(ly1 > yc) ly1 = (int) (ly1 - 0.2 * dy1); if(lx2 < xc) lx2 = (int) (lx2 + 0.2 * dx2); if(lx2 > xc) lx2 = (int) (lx2 - 0.2 * dx2); if(ly2 < yc) ly2 = (int) (ly2 + 0.2 * dy2); if(ly2 > yc) ly2 = (int) (ly2 - 0.2 * dy2); this.drawLine(lx1, ly1, lx2, ly2); } private void addRests() { SvgFactory r1 = null; SvgFactory r2 = null; if(this.getMonosacc().getRingStart() > 2) { r1 = this.drawRest(this.getMonosacc().getRingStart(), 1); } if(this.getMonosacc().getSize() - this.getMonosacc().getRingEnd() > 1) { r2 = this.drawRest(this.getMonosacc().getRingEnd(), this.getMonosacc().getSize()); } int rx = this.getXMax() + 5; int ry = 0; if(r1 != null) { String rLabel; int rx1, ry1; if(r2 == null) { rLabel = "R="; rx1 = rx; ry1 = ry + this.getTextSize(); } else { rLabel = "R1="; rx1 = rx + this.getStringWidth(rLabel); ry1 = ry; } this.drawString(rLabel, rx, ry + this.getTextSize()); this.addSubGraphic(r1, rx1, ry1); ry = r1.getYMax() + 5; //TODO: add r1 subgraph to svg tree } if(r2 != null) { //TODO: add r2 subgraph to svg tree String rLabel; int rx2, ry2; if(r1 == null) { rLabel = "R="; rx2 = rx; ry2 = ry + this.getTextSize(); } else { rLabel = "R2="; rx2 = rx + this.getStringWidth(rLabel); ry2 = ry; } this.drawString(rLabel, rx2, ry2); this.addSubGraphic(r2, rx2, ry2); } } private SvgFactory drawRest(int msStartPos, int msEndPos) { SvgFactory rest = new SvgFactory(); Monosaccharide ms = this.getMonosacc(); int msPos; int currentY = 0; if(msStartPos > msEndPos) { msPos = msStartPos; while(msPos >= msEndPos) { msPos --; rest.drawLine(0, currentY, 0, currentY + this.lineLength); currentY += this.lineLength; if(!ms.hasCoreModification(CoreModificationTemplate.DEOXY, msPos)) { } } } else { msPos = msStartPos; while(msPos <= msEndPos) { msPos ++; rest.drawLine(0, currentY, 0, currentY + this.lineLength); currentY += this.lineLength; if(!ms.hasCoreModification(CoreModificationTemplate.DEOXY, msPos)) { } } } return rest; } public void drawMonosaccharide(Monosaccharide ms) throws ResourcesDbException { if(MonosaccharideValidation.checkFuzziness(ms)) { throw new ResourcesDbException("Cannot draw Haworth projection for monosaccharide with uncertain / fuzzy properties."); } if(ms.hasCoreModification(CoreModificationTemplate.ANHYDRO)) { throw new ResourcesDbException("Cannot draw Haworth projection for monosaccharide with anhydro modification."); } /*for(CoreModification mod : ms.getCoreModifications(CoreModificationTemplate.ACID.getName())) { if(ms.getSubstitutionsByPosition(mod.getIntValuePosition1()).size() > 0) { throw new ResourcesDbException("Cannot (yet) draw Haworth projection for monosaccharide with substitution at acid modification."); } } */ this.setMonosacc(ms); if(ms.getRingtype().equals(Ringtype.PYRANOSE)) { this.drawPyranose(); } else if(ms.getRingtype().equals(Ringtype.FURANOSE)) { this.drawFuranose(); } else { throw new ResourcesDbException("Cannot draw Haworth projection for monosaccharide with ring type " + ms.getRingtype().getName()); } this.addRests(); //*** add exocyclic parts, if necessary *** this.checkSize(); //*** check, if all elements of the graphic are within the visible area, rescale or resize if not *** } //***************************************************************************** //*** other methods: ********************************************************** //***************************************************************************** private void calculateBasecenter() throws MonosaccharideException { if(this.getBasepoints() == null) { throw new MonosaccharideException("Cannot calculate basecenter: basepoints not set"); } int size = this.getBasepoints().size(); if(size == 0) { throw new MonosaccharideException("Cannot calculate basecenter: basepoints not set"); } else { int xSum = 0; int ySum = 0; for(Point p : this.getBasepoints()) { xSum += p.getX(); ySum += p.getY(); } this.setBaseCenter(new Point(xSum / size, ySum / size)); } } }