/* $Revision$ $Author$ $Date$
*
* Copyright (C) 2005-2007 Stefan Kuhn <shk3@users.sf.net>
* 2008 Aleksey Tarkhov <bayern7105@yahoo.de>
*
* Contact: jchempaint-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
* All we ask is that proper credit is given for our work, which includes
* - but is not limited to - adding the above copyright notice to the beginning
* of your source code files, and to any copyright notice that you may distribute
* with programs based on this work.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.openscience.cdk.libio.cml;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.dict.DictRef;
import org.openscience.cdk.dict.DictionaryDatabase;
import org.openscience.cdk.geometry.CrystalGeometryTools;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemFile;
import org.openscience.cdk.interfaces.IChemModel;
import org.openscience.cdk.interfaces.IChemObject;
import org.openscience.cdk.interfaces.IChemSequence;
import org.openscience.cdk.interfaces.ICrystal;
import org.openscience.cdk.interfaces.IIsotope;
import org.openscience.cdk.interfaces.IMolecularFormula;
import org.openscience.cdk.interfaces.IMolecularFormulaSet;
import org.openscience.cdk.interfaces.IMolecule;
import org.openscience.cdk.interfaces.IMoleculeSet;
import org.openscience.cdk.interfaces.IMonomer;
import org.openscience.cdk.interfaces.IPDBPolymer;
import org.openscience.cdk.interfaces.IPseudoAtom;
import org.openscience.cdk.interfaces.IReaction;
import org.openscience.cdk.interfaces.IReactionScheme;
import org.openscience.cdk.interfaces.IReactionSet;
import org.openscience.cdk.interfaces.IStrand;
import org.openscience.cdk.tools.IDCreator;
import org.openscience.cdk.tools.ILoggingTool;
import org.openscience.cdk.tools.LoggingToolFactory;
import org.openscience.cdk.tools.manipulator.MolecularFormulaManipulator;
import org.openscience.cdk.tools.manipulator.ReactionSchemeManipulator;
import org.xmlcml.cml.base.CMLElement;
import org.xmlcml.cml.element.CMLAtom;
import org.xmlcml.cml.element.CMLBond;
import org.xmlcml.cml.element.CMLBondStereo;
import org.xmlcml.cml.element.CMLBondType;
import org.xmlcml.cml.element.CMLCml;
import org.xmlcml.cml.element.CMLCrystal;
import org.xmlcml.cml.element.CMLFormula;
import org.xmlcml.cml.element.CMLIdentifier;
import org.xmlcml.cml.element.CMLList;
import org.xmlcml.cml.element.CMLMolecule;
import org.xmlcml.cml.element.CMLMoleculeList;
import org.xmlcml.cml.element.CMLProduct;
import org.xmlcml.cml.element.CMLProductList;
import org.xmlcml.cml.element.CMLReactant;
import org.xmlcml.cml.element.CMLReactantList;
import org.xmlcml.cml.element.CMLReaction;
import org.xmlcml.cml.element.CMLReactionList;
import org.xmlcml.cml.element.CMLReactionScheme;
import org.xmlcml.cml.element.CMLReactionStep;
import org.xmlcml.cml.element.CMLScalar;
import org.xmlcml.cml.element.CMLSubstance;
import org.xmlcml.cml.element.CMLSubstanceList;
/**
* @cdk.module libiocml
* @cdk.githash
* @cdk.keyword CML
* @cdk.keyword class convertor
* @cdk.builddepends jumbo52.jar
* @cdk.require java1.5+
*/
public class Convertor {
public final static String NS_CML = "http://www.xml-cml.org/schema";
private static ILoggingTool logger =
LoggingToolFactory.createLoggingTool(Convertor.class);
private final static String CUSTOMIZERS_LIST = "libio-cml-customizers.set";
private static Map<String, ICMLCustomizer> customizers = null;
private boolean useCMLIDs;
private String prefix;
/**
* Constructs a CML convertor.
*
* @param useCMLIDs Uses object IDs like 'a1' instead of 'a<hash>'.
* @param prefix Namespace prefix to use. If null, then no prefix is used;
*/
public Convertor(boolean useCMLIDs, String prefix) {
this.useCMLIDs = useCMLIDs;
this.prefix = prefix;
setupCustomizers();
}
public void registerCustomizer(ICMLCustomizer customizer) {
if (customizers == null) customizers = new HashMap<String, ICMLCustomizer>();
if (!customizers.containsKey(customizer.getClass().getName())) {
customizers.put(customizer.getClass().getName(), customizer);
logger.info("Loaded Customizer: ", customizer.getClass().getName());
} else {
logger.warn("Duplicate attempt to register a customizer");
}
}
private void setupCustomizers() {
if (customizers == null) customizers = new HashMap<String, ICMLCustomizer>();
try {
logger.debug("Starting loading Customizers...");
BufferedReader reader = new BufferedReader(new InputStreamReader(
this.getClass().getClassLoader().getResourceAsStream(CUSTOMIZERS_LIST)
));
int customizerCount = 0;
while (reader.ready()) {
// load them one by one
String customizerName = reader.readLine();
customizerCount++;
if (customizers.containsKey(customizerName)) {
try {
ICMLCustomizer customizer = (ICMLCustomizer) this.getClass().getClassLoader().
loadClass(customizerName).newInstance();
customizers.put(customizer.getClass().getName(), customizer);
logger.info("Loaded Customizer: ", customizer.getClass().getName());
} catch (ClassNotFoundException exception) {
logger.info("Could not find this Customizer: ", customizerName);
logger.debug(exception);
} catch (Exception exception) {
logger.warn("Could not load this Customizer: ", customizerName);
logger.warn(exception.getMessage());
logger.debug(exception);
}
} else {
logger.warn("Duplicate attempt to register a customizer");
}
}
logger.info("Number of loaded customizers: ", customizerCount);
} catch (Exception exception) {
logger.error("Could not load this list: ", CUSTOMIZERS_LIST);
logger.debug(exception);
}
}
public CMLCml cdkChemFileToCMLList(IChemFile file) {
return cdkChemFileToCMLList(file, true);
}
private CMLCml cdkChemFileToCMLList(IChemFile file, boolean setIDs) {
CMLCml cmlList = new CMLCml();
cmlList.setConvention("cdk:document");
if (useCMLIDs && setIDs) {
IDCreator.createIDs(file);
}
if (file.getID() != null && !file.getID().equals(""))
cmlList.setId(file.getID());
if (file.getChemSequenceCount() > 0) {
Iterator<IChemSequence> sequences = file.chemSequences().iterator();
while (sequences.hasNext()) {
cmlList.appendChild(cdkChemSequenceToCMLList(sequences.next()));
}
}
return cmlList;
}
public CMLList cdkChemSequenceToCMLList(IChemSequence sequence) {
return cdkChemSequenceToCMLList(sequence, true);
}
private CMLList cdkChemSequenceToCMLList(IChemSequence sequence, boolean setIDs) {
CMLList cmlList = new CMLList();
cmlList.setConvention("cdk:sequence");
if (useCMLIDs && setIDs) {
IDCreator.createIDs(sequence);
}
if (sequence.getID() != null && !sequence.getID().equals(""))
cmlList.setId(sequence.getID());
if (sequence.getChemModelCount() > 0) {
for (int i = 0; i < sequence.getChemModelCount(); i++) {
cmlList.appendChild(cdkChemModelToCMLList(sequence.getChemModel(i)));
}
}
return cmlList;
}
public CMLList cdkChemModelToCMLList(IChemModel model) {
return cdkChemModelToCMLList(model, true);
}
private CMLList cdkChemModelToCMLList(IChemModel model, boolean setIDs) {
CMLList cmlList = new CMLList();
cmlList.setConvention("cdk:model");
if (useCMLIDs && setIDs) {
IDCreator.createIDs(model);
}
if (model.getID() != null && !model.getID().equals(""))
cmlList.setId(model.getID());
if (model.getCrystal() != null) {
cmlList.appendChild(cdkCrystalToCMLMolecule(model.getCrystal(), false));
}
if (model.getReactionSet() != null) {
cmlList.appendChild(cdkReactionSetToCMLReactionList(model.getReactionSet(), false));
}
if (model.getMoleculeSet() != null) {
cmlList.appendChild(cdkMoleculeSetToCMLList(model.getMoleculeSet(), false));
}
return cmlList;
}
public CMLCml cdkReactionSchemeToCMLReactionSchemeAndMoleculeList(IReactionScheme cdkScheme){
CMLCml cml = new CMLCml();
cml.appendChild(cdkMoleculeSetToCMLList(ReactionSchemeManipulator.getAllMolecules(cdkScheme)));
cml.appendChild(cdkReactionSchemeToCMLReactionScheme(cdkScheme, true, true));
return cml;
}
public CMLReactionScheme cdkReactionSchemeToCMLReactionScheme(IReactionScheme cdkScheme){
return cdkReactionSchemeToCMLReactionScheme(cdkScheme, true, false);
}
private CMLReactionScheme cdkReactionSchemeToCMLReactionScheme(
IReactionScheme cdkScheme, boolean setIDs, boolean isRef) {
CMLReactionScheme reactionScheme = new CMLReactionScheme();
if (useCMLIDs && setIDs) {
IDCreator.createIDs(cdkScheme);
}
if (cdkScheme.getID() != null && !cdkScheme.getID().equals(""))
reactionScheme.setId(cdkScheme.getID());
for(Iterator<IReaction> it = cdkScheme.reactions().iterator(); it.hasNext();){
reactionScheme.appendChild(cdkReactionToCMLReaction(it.next(), true));
}
for(IReactionScheme intScheme : cdkScheme.reactionSchemes()){
reactionScheme.appendChild(cdkReactionSchemeToCMLReactionScheme(intScheme));
}
return reactionScheme;
}
public CMLReactionStep cdkReactionToCMLReactionStep(IReaction reaction){
return cdkReactionToCMLReactionStep(reaction, true);
}
private CMLReactionStep cdkReactionToCMLReactionStep(IReaction reaction, boolean setIDs){
CMLReactionStep reactionStep = new CMLReactionStep();
reactionStep.appendChild(cdkReactionToCMLReaction(reaction, true));
return reactionStep;
}
public CMLReactionList cdkReactionSetToCMLReactionList(IReactionSet reactionSet) {
return cdkReactionSetToCMLReactionList(reactionSet, true);
}
private CMLReactionList cdkReactionSetToCMLReactionList(IReactionSet reactionSet, boolean setIDs) {
CMLReactionList reactionList = new CMLReactionList();
if (useCMLIDs && setIDs) {
IDCreator.createIDs(reactionSet);
}
if (reactionSet.getID() != null && !reactionSet.getID().equals(""))
reactionList.setId(reactionSet.getID());
Iterator<IReaction> reactionIter = reactionSet.reactions().iterator();
while (reactionIter.hasNext()) {
reactionList.appendChild(cdkReactionToCMLReaction(reactionIter.next(), false));
}
return reactionList;
}
public CMLMoleculeList cdkMoleculeSetToCMLList(IMoleculeSet moleculeSet) {
return cdkMoleculeSetToCMLList(moleculeSet, true);
}
private CMLMoleculeList cdkMoleculeSetToCMLList(IMoleculeSet moleculeSet, boolean setIDs) {
CMLMoleculeList cmlList = new CMLMoleculeList();
cmlList.setConvention("cdk:moleculeSet");
if (useCMLIDs && setIDs) {
IDCreator.createIDs(moleculeSet);
}
if (moleculeSet.getID() != null && !moleculeSet.getID().equals(""))
cmlList.setId(moleculeSet.getID());
for (int i = 0; i < moleculeSet.getAtomContainerCount(); i++) {
IAtomContainer container = moleculeSet.getMolecule(i);
if (container instanceof IMolecule) {
cmlList.appendChild(
cdkMoleculeToCMLMolecule((IMolecule)container, false)
);
} else {
cmlList.appendChild(
cdkAtomContainerToCMLMolecule(container, false, false)
);
}
}
return cmlList;
}
public CMLReaction cdkReactionToCMLReaction(IReaction reaction) {
return cdkReactionToCMLReaction(reaction, true);
}
private CMLReaction cdkReactionToCMLReaction(IReaction reaction, boolean setIDs) {
CMLReaction cmlReaction = new CMLReaction();
if (useCMLIDs && setIDs) {
IDCreator.createIDs(reaction);
}
if (reaction.getID() != null && !reaction.getID().equals(""))
cmlReaction.setId(reaction.getID());
Map<Object, Object> props = reaction.getProperties();
Iterator<Object> keys = props.keySet().iterator();
while (keys.hasNext()) {
Object key = keys.next();
if (key instanceof String &&
props.get(key) instanceof String) {
Object value = props.get(key);
if (!key.toString().equals(CDKConstants.TITLE)) {
CMLScalar scalar = new CMLScalar();
this.checkPrefix(scalar);
scalar.setDictRef("cdk:reactionProperty");
scalar.setTitle(key.toString());
scalar.setValue(value.toString());
cmlReaction.appendChild(scalar);
}
}
}
// reactants
CMLReactantList cmlReactants = new CMLReactantList();
Iterator<IAtomContainer> reactants = reaction.getReactants().molecules().iterator();
while (reactants.hasNext()) {
CMLReactant cmlReactant = new CMLReactant();
cmlReactant.addMolecule(cdkMoleculeToCMLMolecule((IMolecule)reactants.next(), false));
cmlReactants.addReactant(cmlReactant);
}
// products
CMLProductList cmlProducts = new CMLProductList();
Iterator<IAtomContainer> products = reaction.getProducts().molecules().iterator();
while (products.hasNext()) {
CMLProduct cmlProduct = new CMLProduct();
cmlProduct.addMolecule(cdkMoleculeToCMLMolecule((IMolecule)products.next(), false));
cmlProducts.addProduct(cmlProduct);
}
// substance
CMLSubstanceList cmlSubstances = new CMLSubstanceList();
Iterator<IAtomContainer> substance = reaction.getAgents().molecules().iterator();
while (substance.hasNext()) {
CMLSubstance cmlSubstance = new CMLSubstance();
cmlSubstance.addMolecule(cdkMoleculeToCMLMolecule((IMolecule)substance.next(), false));
cmlSubstances.addSubstance(cmlSubstance);
}
if (reaction.getID() != null)
cmlReaction.setId(reaction.getID());
cmlReaction.addReactantList(cmlReactants);
cmlReaction.addProductList(cmlProducts);
cmlReaction.addSubstanceList(cmlSubstances);
return cmlReaction;
}
public CMLMolecule cdkCrystalToCMLMolecule(ICrystal crystal) {
return cdkCrystalToCMLMolecule(crystal, true);
}
private CMLMolecule cdkCrystalToCMLMolecule(ICrystal crystal, boolean setIDs) {
CMLMolecule molecule = cdkAtomContainerToCMLMolecule(crystal, false, false);
CMLCrystal cmlCrystal = new CMLCrystal();
if (useCMLIDs && setIDs) {
IDCreator.createIDs(crystal);
}
if (crystal.getID() != null && !crystal.getID().equals(""))
cmlCrystal.setId(crystal.getID());
this.checkPrefix(cmlCrystal);
cmlCrystal.setZ(crystal.getZ());
double[] params = CrystalGeometryTools.cartesianToNotional(
crystal.getA(), crystal.getB(), crystal.getC()
);
logger.debug("Number of cell params: ", params.length);
cmlCrystal.setCellParameters(params);
molecule.appendChild(cmlCrystal);
return molecule;
}
public CMLMolecule cdkPDBPolymerToCMLMolecule(IPDBPolymer pdbPolymer) {
return cdkPDBPolymerToCMLMolecule(pdbPolymer, true);
}
private CMLMolecule cdkPDBPolymerToCMLMolecule(IPDBPolymer pdbPolymer, boolean setIDs) {
CMLMolecule cmlMolecule = new CMLMolecule();
cmlMolecule.setConvention("PDB");
cmlMolecule.setDictRef("pdb:model");
Map<String, IStrand> mapS = pdbPolymer.getStrands();
Iterator<String> iter = mapS.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
IStrand strand = mapS.get(key);
Map<String, IMonomer> mapM = strand.getMonomers();
Iterator<String> iterM = mapM.keySet().iterator();
while (iterM.hasNext()) {
IMonomer monomer = mapM.get(iterM.next());
CMLMolecule clmono = cdkMonomerToCMLMolecule(monomer, true);
cmlMolecule.appendChild(clmono);
}
}
return cmlMolecule;
}
public CMLMolecule cdkMonomerToCMLMolecule(IMonomer monomer) {
return cdkMonomerToCMLMolecule(monomer, true);
}
private CMLMolecule cdkMonomerToCMLMolecule(IMonomer monomer, boolean setIDs) {
CMLMolecule cmlMolecule = new CMLMolecule();
cmlMolecule.setDictRef("pdb:sequence");
if (monomer.getMonomerName() != null && !monomer.getMonomerName().equals(""))
cmlMolecule.setId(monomer.getMonomerName());
for(int i = 0 ; i < monomer.getAtomCount(); i++){
IAtom cdkAtom = monomer.getAtom(i);
CMLAtom cmlAtom = cdkAtomToCMLAtom(monomer, cdkAtom);
if (monomer.getConnectedSingleElectronsCount(cdkAtom) > 0) {
cmlAtom.setSpinMultiplicity(monomer.getConnectedSingleElectronsCount(cdkAtom) + 1);
}
cmlMolecule.addAtom(cmlAtom);
}
return cmlMolecule;
}
public CMLMolecule cdkMoleculeToCMLMolecule(IMolecule structure) {
return cdkMoleculeToCMLMolecule(structure, true);
}
private CMLMolecule cdkMoleculeToCMLMolecule(IMolecule structure, boolean setIDs) {
return cdkAtomContainerToCMLMolecule(structure, setIDs, false);
}
public CMLMolecule cdkAtomContainerToCMLMolecule(IAtomContainer structure) {
return cdkAtomContainerToCMLMolecule(structure, true, false);
}
private CMLMolecule cdkAtomContainerToCMLMolecule(
IAtomContainer structure, boolean setIDs, boolean isRef) {
CMLMolecule cmlMolecule = new CMLMolecule();
if (useCMLIDs && setIDs) {
IDCreator.createIDs(structure);
}
this.checkPrefix(cmlMolecule);
if (structure.getID() != null && !structure.getID().equals(""))
if(!isRef) cmlMolecule.setId(structure.getID());
else cmlMolecule.setRef(structure.getID());
if (structure.getProperty(CDKConstants.TITLE) != null) {
cmlMolecule.setTitle((String) structure.getProperty(CDKConstants.TITLE));
}
if (structure.getProperty(CDKConstants.INCHI) != null) {
CMLIdentifier ident = new CMLIdentifier();
ident.setConvention("iupac:inchi");
ident.setCMLValue(structure.getProperty(CDKConstants.INCHI).toString());
cmlMolecule.appendChild(ident);
}
if(!isRef){
for (int i = 0; i < structure.getAtomCount(); i++) {
IAtom cdkAtom = structure.getAtom(i);
CMLAtom cmlAtom = cdkAtomToCMLAtom(structure, cdkAtom);
if (structure.getConnectedSingleElectronsCount(cdkAtom) > 0) {
cmlAtom.setSpinMultiplicity(structure.getConnectedSingleElectronsCount(cdkAtom) + 1);
}
cmlMolecule.addAtom(cmlAtom);
}
for (int i = 0; i < structure.getBondCount(); i++) {
CMLBond cmlBond = cdkBondToCMLBond(structure.getBond(i));
cmlMolecule.addBond(cmlBond);
}
}
// ok, output molecular properties, but not TITLE, INCHI, or DictRef's
Map<Object, Object> props = structure.getProperties();
Iterator<Object> keys = props.keySet().iterator();
while (keys.hasNext()) {
Object key = keys.next();
// but only if a String
if (key instanceof String && !isRef &&
props.get(key) instanceof String) {
Object value = props.get(key);
if (!key.toString().equals(CDKConstants.TITLE) &&
!key.toString().equals(CDKConstants.INCHI)) {
// ok, should output this
CMLScalar scalar = new CMLScalar();
this.checkPrefix(scalar);
scalar.setDictRef("cdk:molecularProperty");
scalar.setTitle(key.toString());
scalar.setValue(value.toString());
cmlMolecule.addScalar(scalar);
}
}
// FIXME: At the moment the order writing the formula is into properties
// but it should be that IMolecularFormula is a extension of IAtomContainer
if (key instanceof String && !isRef &&
key.toString().equals(CDKConstants.FORMULA)){
if(props.get(key) instanceof IMolecularFormula){
IMolecularFormula cdkFormula = (IMolecularFormula)props.get(key);
CMLFormula cmlFormula = new CMLFormula();
List<IIsotope> isotopesList = MolecularFormulaManipulator.putInOrder(MolecularFormulaManipulator.generateOrderEle(),cdkFormula);
for(int i = 0; i< isotopesList.size(); i++){
cmlFormula.add(isotopesList.get(i).getSymbol(), cdkFormula.getIsotopeCount(isotopesList.get(i)));
}
cmlMolecule.appendChild(cmlFormula);
}else if (props.get(key) instanceof IMolecularFormulaSet){
IMolecularFormulaSet cdkFormulaSet = (IMolecularFormulaSet)props.get(key);
for(Iterator<IMolecularFormula> it = cdkFormulaSet.molecularFormulas().iterator(); it.hasNext();){
IMolecularFormula cdkFormula = it.next();
List<IIsotope> isotopesList = MolecularFormulaManipulator.putInOrder(MolecularFormulaManipulator.generateOrderEle(),cdkFormula);
CMLFormula cmlFormula = new CMLFormula();
cmlFormula.setDictRef("cdk:possibleMachts");
for(int i = 0; i< isotopesList.size(); i++){
cmlFormula.add(isotopesList.get(i).getSymbol(), cdkFormula.getIsotopeCount(isotopesList.get(i)));
}
cmlMolecule.appendChild(cmlFormula);
}
}
}
}
Iterator<String> elements = customizers.keySet().iterator();
while (elements.hasNext()) {
ICMLCustomizer customizer = customizers.get(elements.next());
try {
customizer.customize(structure, cmlMolecule);
} catch (Exception exception) {
logger.error("Error while customizing CML output with customizer: ",
customizer.getClass().getName());
logger.debug(exception);
}
}
return cmlMolecule;
}
private boolean addDictRef(IChemObject object, CMLElement cmlElement) {
Map<Object,Object> properties = object.getProperties();
Iterator<Object> iter = properties.keySet().iterator();
while (iter.hasNext()) {
Object key = iter.next();
if (key instanceof String) {
String keyName = (String) key;
if (keyName.startsWith(DictionaryDatabase.DICTREFPROPERTYNAME)) {
String dictRef = (String) properties.get(keyName);
cmlElement.setProperty("dictRef", dictRef);
return true;
}
}
}
return false;
}
private boolean addAtomID(IAtom cdkAtom, CMLAtom cmlAtom) {
if (cdkAtom.getID() != null && !cdkAtom.getID().equals("")) {
cmlAtom.setId(cdkAtom.getID());
} else {
cmlAtom.setId("a" + Integer.valueOf(cdkAtom.hashCode()).toString());
}
return true;
}
public CMLAtom cdkAtomToCMLAtom(IAtom cdkAtom) {
return cdkAtomToCMLAtom(null, cdkAtom);
}
public CMLAtom cdkAtomToCMLAtom(IAtomContainer container, IAtom cdkAtom) {
CMLAtom cmlAtom = new CMLAtom();
this.checkPrefix(cmlAtom);
addAtomID(cdkAtom, cmlAtom);
addDictRef(cdkAtom, cmlAtom);
cmlAtom.setElementType(cdkAtom.getSymbol());
if (cdkAtom instanceof IPseudoAtom) {
String label = ((IPseudoAtom) cdkAtom).getLabel();
if (label != null) cmlAtom.setTitle(label);
cmlAtom.setElementType("Du");
}
map2DCoordsToCML(cmlAtom, cdkAtom);
map3DCoordsToCML(cmlAtom, cdkAtom);
mapFractionalCoordsToCML(cmlAtom, cdkAtom);
Integer formalCharge = cdkAtom.getFormalCharge();
if (formalCharge != null) cmlAtom.setFormalCharge(formalCharge);
// CML's hydrogen count consists of the sum of implicit and explicit
// hydrogens (see bug #1655045).
Integer totalHydrogen = cdkAtom.getHydrogenCount();
if (totalHydrogen != null) {
if (container != null) {
Iterator<IBond> bonds = container.getConnectedBondsList(cdkAtom).iterator();
while (bonds.hasNext()) {
Iterator<IAtom> atoms = (bonds.next()).atoms().iterator();
while (atoms.hasNext()) {
IAtom atom= atoms.next();
if ("H".equals(atom.getSymbol()) && atom!=cdkAtom) totalHydrogen++;
}
}
} // else: it is the implicit hydrogen count
cmlAtom.setHydrogenCount(totalHydrogen);
} // else: don't report it, people can count the explicit Hs themselves
Integer massNumber = cdkAtom.getMassNumber();
if (!(cdkAtom instanceof IPseudoAtom)) {
if (massNumber != null) {
cmlAtom.setIsotopeNumber(massNumber);
}
}
if (cdkAtom.getCharge() != CDKConstants.UNSET) {
CMLScalar scalar = new CMLScalar();
this.checkPrefix(scalar);
// scalar.setDataType("xsd:float");
scalar.setDictRef("cdk:partialCharge");
scalar.setValue(cdkAtom.getCharge());
cmlAtom.addScalar(scalar);
}
writeProperties(cdkAtom, cmlAtom);
Iterator<String> elements = customizers.keySet().iterator();
while (elements.hasNext()) {
ICMLCustomizer customizer = (ICMLCustomizer)customizers.get(elements.next());
try {
customizer.customize(cdkAtom, cmlAtom);
} catch (Exception exception) {
logger.error("Error while customizing CML output with customizer: ",
customizer.getClass().getName());
logger.debug(exception);
}
}
return cmlAtom;
}
public CMLBond cdkBondToCMLBond(IBond cdkBond) {
CMLBond cmlBond = new CMLBond();
this.checkPrefix(cmlBond);
if (cdkBond.getID() == null || cdkBond.getID().length() == 0) {
cmlBond.setId("b" + cdkBond.hashCode());
} else {
cmlBond.setId(cdkBond.getID());
}
String[] atomRefArray = new String[cdkBond.getAtomCount()];
for (int i = 0; i < cdkBond.getAtomCount(); i++) {
String atomID = cdkBond.getAtom(i).getID();
if (atomID == null || atomID.length() == 0) {
atomRefArray[i] = "a" + Integer.valueOf(cdkBond.getAtom(i).hashCode()).toString();
} else {
atomRefArray[i] = atomID;
}
}
if (atomRefArray.length == 2) {
cmlBond.setAtomRefs2(atomRefArray);
} else {
cmlBond.setAtomRefs(atomRefArray);
}
IBond.Order border = cdkBond.getOrder();
if (border == CDKConstants.BONDORDER_SINGLE) {
cmlBond.setOrder("S");
} else if (border == CDKConstants.BONDORDER_DOUBLE) {
cmlBond.setOrder("D");
} else if (border == CDKConstants.BONDORDER_TRIPLE) {
cmlBond.setOrder("T");
} else {
CMLScalar scalar = new CMLScalar();
this.checkPrefix(scalar);
// scalar.setDataType("xsd:float");
scalar.setDictRef("cdk:bondOrder");
scalar.setTitle("order");
scalar.setValue(cdkBond.getOrder().ordinal()+1);
cmlBond.appendChild(scalar);
}
if (cdkBond.getFlag(CDKConstants.ISAROMATIC)) {
CMLBondType bType = new CMLBondType();
bType.setDictRef("cdk:aromaticBond");
cmlBond.appendChild(bType);
}
if (cdkBond.getStereo() == IBond.Stereo.UP ||
cdkBond.getStereo() == IBond.Stereo.DOWN) {
CMLBondStereo bondStereo = new CMLBondStereo();
this.checkPrefix(bondStereo);
if (cdkBond.getStereo() == IBond.Stereo.UP) {
bondStereo.setDictRef("cml:W");
} else {
bondStereo.setDictRef("cml:H");
}
cmlBond.appendChild(bondStereo);
}
if (cdkBond.getProperties().size() > 0) writeProperties(cdkBond, cmlBond);
Iterator<String> elements = customizers.keySet().iterator();
while (elements.hasNext()) {
ICMLCustomizer customizer = customizers.get(elements.next());
try {
customizer.customize(cdkBond, cmlBond);
} catch (Exception exception) {
logger.error("Error while customizing CML output with customizer: ",
customizer.getClass().getName());
logger.debug(exception);
}
}
return cmlBond;
}
private void writeProperties(IChemObject object, CMLElement cmlElement) {
Map<Object,Object> props = object.getProperties();
Iterator<Object> keys = props.keySet().iterator();
CMLElement propList = null;
while (keys.hasNext()) {
Object key = keys.next();
if (key instanceof DictRef) {
Object value = props.get(key);
CMLScalar scalar = new CMLScalar();
this.checkPrefix(scalar);
scalar.setDictRef(((DictRef) key).getType());
scalar.setValue(value.toString());
cmlElement.appendChild(scalar);
} else if (key instanceof String) {
String stringKey = (String) key;
if (stringKey.equals(CDKConstants.TITLE)) {
// don't output this one. It's covered by addTitle()
} else if (!(stringKey.startsWith("org.openscience.cdk"))) {
Object value = props.get(key);
CMLScalar scalar = new CMLScalar();
this.checkPrefix(scalar);
scalar.setTitle((String) key);
scalar.setValue(value.toString());
cmlElement.appendChild(scalar);
}
}
}
if (propList != null) {
cmlElement.appendChild(propList);
}
}
private void mapFractionalCoordsToCML(CMLAtom cmlAtom, IAtom cdkAtom) {
if (cdkAtom.getFractionalPoint3d() != null) {
cmlAtom.setXFract(cdkAtom.getFractionalPoint3d().x);
cmlAtom.setYFract(cdkAtom.getFractionalPoint3d().y);
cmlAtom.setZFract(cdkAtom.getFractionalPoint3d().z);
}
}
private void map3DCoordsToCML(CMLAtom cmlAtom, IAtom cdkAtom) {
if (cdkAtom.getPoint3d() != null) {
cmlAtom.setX3(cdkAtom.getPoint3d().x);
cmlAtom.setY3(cdkAtom.getPoint3d().y);
cmlAtom.setZ3(cdkAtom.getPoint3d().z);
}
}
private void map2DCoordsToCML(CMLAtom cmlAtom, IAtom cdkAtom) {
if (cdkAtom.getPoint2d() != null) {
cmlAtom.setX2(cdkAtom.getPoint2d().x);
cmlAtom.setY2(cdkAtom.getPoint2d().y);
}
}
private void checkPrefix(CMLElement element) {
if (this.prefix != null) {
this.prefix.trim();
if (this.prefix.length() == 0) prefix = null;
}
if (this.prefix != null) element.setNamespacePrefix(this.prefix);
}
}