001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.io;
022
023import java.text.DecimalFormat;
024import java.util.ArrayList;
025import java.util.List;
026import org.biojava.nbio.structure.Atom;
027import org.biojava.nbio.structure.Bond;
028import org.biojava.nbio.structure.Group;
029
030
031public class GroupToSDF {
032
033
034        public String getText(Group thisGroup) {
035                // Fuction to convert a Group to a strign of  the MDL molnlock
036                StringBuilder sb = new StringBuilder();
037                sb.append(getHeader(thisGroup));
038                sb.append(getCtab(thisGroup));
039                return sb.toString();
040        }
041
042        private String getCtab(Group thisGroup){
043                DecimalFormat df = new DecimalFormat("0.0000");
044                // The thre string builders for the three parts of the MDL block
045                StringBuilder header = new StringBuilder();
046                StringBuilder atomList = new StringBuilder();
047                StringBuilder bondOrders = new StringBuilder();
048                int numBonds = 0;
049                List<Atom> atoms = thisGroup.getAtoms();
050                for(Atom a: thisGroup.getAtoms()){
051                        /// ALL SHOULD BE TO FOUR DECIMAL PLACES WITH A CERTAIN NUMBER OF SPACES BEFOREa
052                        String spaceX = getSpace(10, df.format(a.getX()));
053                        String spaceY = getSpace(10, df.format(a.getY()));
054                        String spaceZ = getSpace(10, df.format(a.getZ()));
055                        String spaceEle = getSpace(4, a.getElement().toString());
056                        atomList.append(spaceX+df.format(a.getX())+spaceY+df.format(a.getY())+spaceZ+df.format(a.getZ())+" "+a.getElement().toString()+spaceEle+"0  0  0  0  0  0  0  0  0  0  0  0\n");
057                        for(Bond b: a.getBonds()){
058                                Atom otherAtom = b.getOther(a);
059                                if(atoms.indexOf(otherAtom)>=atoms.indexOf(a)){
060                                        continue;
061                                }
062                                if(atoms.indexOf(otherAtom)<0){
063                                        continue;
064                                }
065                                if(atoms.indexOf(a)<0){
066                                        continue;
067                                }
068                                numBonds++;
069                                // Deal with the index infromation
070                                String indexOther = Integer.toString(atoms.indexOf(otherAtom)+1);
071                                String index = Integer.toString(atoms.indexOf(a)+1);
072                                String order = Integer.toString(b.getBondOrder());
073                                String spaceIndOne = getSpace(3, index);
074                                String spaceIndTwo = getSpace(3, indexOther);
075                                String spaceOrder = getSpace(3, order);
076                                bondOrders.append(spaceIndOne+index+spaceIndTwo+indexOther+spaceOrder+order+"  0\n");
077                        }
078                }
079                StringBuilder outString = new  StringBuilder();
080                // Add the first line now
081                String spaceNumAtoms = getSpace(3, Integer.toString(thisGroup.getAtoms().size()));
082                String spaceNumBonds = getSpace(3, Integer.toString(numBonds));
083                header.append("\n");
084                header.append(spaceNumAtoms+thisGroup.getAtoms().size()+spaceNumBonds+numBonds+"  0  0  0  0  0  0  0  0999 V2000\n");
085                // Now add the header, atom, bond and charge information togeyher
086                outString.append(header.toString());
087                outString.append(atomList.toString());
088                outString.append(bondOrders.toString());
089                outString.append(getCharges(thisGroup));
090                // Add the final line and the $$$$ delimiter
091                outString.append("M  END\n$$$$");
092                // Get the string and return it
093                return outString.toString();
094        }
095
096        private Object getCharges(Group thisGroup) {
097                // Get the array of charges
098                List<Number> chargeList = getAtomCharges(thisGroup);
099                // Build the string
100                StringBuilder outS = new StringBuilder();
101                int chargeCount=0;
102                // Loop through the charges -> maximum 8 charges per line
103                for(int i =0; i<chargeList.size();i++){
104                        short charge = (Short) chargeList.get(i);
105                        if(charge!=0){
106                                if(chargeCount==0){
107                                        outS.append("M  CHG   N");
108                                }
109                                outS.append(getSpace(4, Integer.toString(i))+(i+1));
110                                outS.append(getSpace(4, Short.toString(charge))+charge);
111                                chargeCount++;
112                        }
113                        //
114                        if(chargeCount==8){
115                                outS.append("\n");
116                                outS.replace(0, 10, "M  CHG   "+chargeCount);
117                                chargeCount=0;
118                        }
119
120                }
121                if(chargeCount==0){
122                        return "";
123                }
124                // Now add the charge count
125                outS.replace(0, 10, "M  CHG  "+chargeCount);
126                outS.append("\n");
127                // Now return the string
128                return outS.toString();
129        }
130
131        private static List<Number> getAtomCharges(Group group) {
132                // The list to store the answer
133                List<Number> outArr = new ArrayList<Number>();
134                // Get the atom charge Information
135                for(Atom a: group.getAtoms()){
136                        outArr.add(a.getCharge());
137                }
138                return outArr;
139        }
140
141        private String getSpace(int inputNum, String format) {
142                // Function to get the spaces between numbers
143                StringBuilder sb = new StringBuilder();
144                for(int i=0; i<(inputNum-format.length());i++){
145                        sb.append(" ");
146                }
147                return sb.toString();
148        }
149
150        private String getHeader(Group thisGroup) {
151                // Make the header info for the start of the block
152                StringBuilder sb = new StringBuilder();
153                sb.append(thisGroup.getPDBName()+"\n");
154                sb.append("Made by BioJava");
155                sb.append("\n");
156                return sb.toString();
157        }
158}