All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xmlcml.cml.chemdraw.components.CDXFragment Maven / Gradle / Ivy

/**
 * Copyright (C) 2001 Peter Murray-Rust ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.xmlcml.cml.chemdraw.components;

import java.util.List;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.xmlcml.cml.base.CMLConstants;
import org.xmlcml.cml.element.CMLAtom;
import org.xmlcml.cml.element.CMLBond;
import org.xmlcml.cml.element.CMLBondStereo;
import org.xmlcml.cml.element.CMLLabel;
import org.xmlcml.cml.element.CMLMolecule;
import org.xmlcml.euclid.Real2;
import org.xmlcml.euclid.Vector2;

import nu.xom.Element;
import nu.xom.Elements;
import nu.xom.Nodes;
/**
 * 
 * @author pm286
 *
 */
public class CDXFragment extends CDXObject {

    static Logger LOG = Logger.getLogger(CDXFragment.class);
	static {
		LOG.setLevel(Level.INFO);
	}

    public final static int CODE = 0x8003;
    public final static String NAME = "Fragment";
    public final static String CDXNAME = "fragment";
	private static final double SCALE_GROUPS = 0.3;

    public CDXFragment() {
        super(CODE, NAME, CDXNAME);
	}
	
    /**
     * copy node .
     * @return Element
     */
    public Element copy() {
        return new CDXFragment(this);
    }
    
    /**
     * copy constructor
     * @param old
     */
    public CDXFragment(CDXFragment old) {
    	super(old);
    }

    
	void process2CML(CMLMolecule molecule) {
//      
//      
//       
//      
//      
//      
//       
//      
//      
//       
//      
//      
//       
//      
//      
//       
//      
//      
//      
//      
//     
	   	Elements childElements = this.getChildElements();
	   	for (int i = 0; i < childElements.size(); i++) {
	   		CDXObject child = (CDXObject) childElements.get(i);
	   		if (child instanceof CDXNode) {
	   			((CDXNode)child).process2CML(molecule);
	   		} else if (child instanceof CDXBond) {
	   			((CDXBond)child).process2CML(molecule);
	   		} else if (child instanceof CDXGraphic) {
	   			LOG.debug("Skipped graphic");
	   			((CDXGraphic)child).process2CML(molecule);
	   		} else if (child instanceof CDXText) {
	   			((CDXText)child).process2CML(molecule);
			} else {
				LOG.error("Cannot parse fragment child: "+child);
			}
	    }
	   	// flatten subgroups
	   	flattenSubGroups(molecule);
	}

	void flattenSubGroups(CMLMolecule molecule) {

//	    
//	    
//	    
//	      
//	  
//	  
//	    
//	    
//	    
//	    
//	    
//	    
//	    
//	  
		List atomList = molecule.getAtoms();
		for (CMLAtom replacedAtom : atomList) {
			Nodes subMolecules = replacedAtom.query("cml:molecule", CML_XPATH);
			if (subMolecules.size() == 0) {
				continue;
			} else if (subMolecules.size() > 1) {
				throw new RuntimeException("too many molecule children");
			}
			List parentReplacedAtoms = replacedAtom.getLigandAtoms();
			CMLAtom replacedAtomParent = null;
			if (parentReplacedAtoms.size() == 0) {
				LOG.warn("too few ligands of replaced atom");
			} else if (parentReplacedAtoms.size() > 1) {
				replacedAtomParent = parentReplacedAtoms.get(0);
				LOG.warn("too many ligands of replaced atom: "+replacedAtom.getId());
			} else {
				replacedAtomParent = parentReplacedAtoms.get(0);
			}
			
			CMLMolecule subMolecule = (CMLMolecule) subMolecules.get(0);
			Nodes atoms = subMolecule.query(
					"cml:atomArray/cml:atom[@*[local-name()='NodeType' and .='ExternalConnectionPoint']]", CML_XPATH);
			CMLAtom extensionAtom = null;
			if (atoms.size() == 0) {
				LOG.warn("too few extension points");
			} else if (atoms.size() > 1) {
				LOG.warn("too many extension points: "+atoms.size());
			} 
			if (atoms.size() > 0) {
				extensionAtom = (CMLAtom) atoms.get(0);
				List extensionLigandAtoms = extensionAtom.getLigandAtoms();
				if (extensionLigandAtoms.size() == 0 || extensionLigandAtoms.size() > 1) {
					throw new RuntimeException("too few/many ligands of extension points");
				}
				CMLAtom replacingAtom = extensionLigandAtoms.get(0);
				replaceAtomsAndBonds(molecule, replacedAtom, replacedAtomParent, subMolecule, extensionAtom, replacingAtom);
			}
		}
	}
	
	private void replaceAtomsAndBonds(CMLMolecule molecule, CMLAtom replacedAtom, CMLAtom replacedAtomParent,
			CMLMolecule subMolecule, CMLAtom extensionAtom, CMLAtom replacingAtom) {
		moveLabelFromStaticAtomToGroup(replacedAtom, replacingAtom);
		scaleAndMoveGroup(replacedAtomParent, subMolecule, replacingAtom);
		CMLBond replacedBond = transferAtomsAndBondsFromGroup(molecule,
				replacedAtom, replacedAtomParent, subMolecule, extensionAtom,
				replacingAtom);
		createAndAddNewBond(molecule, replacedAtomParent, replacingAtom,
				replacedBond);
	}

	private void createAndAddNewBond(CMLMolecule molecule,
			CMLAtom replacedAtomParent, CMLAtom replacingAtom,
			CMLBond replacedBond) {
		if (replacedBond != null) {
			CMLBondStereo bondStereo = replacedBond.getBondStereo();
			String order = replacedBond.getOrder();
			
			if (replacedAtomParent != null) {
		//		make new bond and copy properties
				CMLBond newBond = new CMLBond();
				newBond.setAtomRefs2(new String[]{replacedAtomParent.getId(), replacingAtom.getId()});
				if (bondStereo != null) {
					newBond.addBondStereo(bondStereo);
				}
				newBond.setOrder(order);
				molecule.addBond(newBond);
			}
		}
	}

	private CMLBond transferAtomsAndBondsFromGroup(CMLMolecule molecule,
			CMLAtom replacedAtom, CMLAtom replacedAtomParent,
			CMLMolecule subMolecule, CMLAtom extensionAtom,
			CMLAtom replacingAtom) {
		CMLBond replacedBond = molecule.getBond(replacedAtom, replacedAtomParent);
		CMLBond extensionBond = subMolecule.getBond(extensionAtom, replacingAtom);
		// delete everything from subMolecule
		// delete bonds first
		List subMoleculeBonds = subMolecule.getBonds();
		List subMoleculeAtoms = subMolecule.getAtoms();
		for (CMLBond subMoleculeBond : subMoleculeBonds) {
			subMolecule.deleteBond(subMoleculeBond);
		}
		for (CMLAtom subMoleculeAtom : subMoleculeAtoms) {
			subMolecule.deleteAtom(subMoleculeAtom);
		}

		// replace bonds in target
		molecule.deleteBond(replacedBond);
		molecule.deleteAtom(replacedAtom);
		// transfer atoms
		for (CMLAtom subMoleculeAtom : subMoleculeAtoms) {
			if (subMoleculeAtom.equals(extensionAtom)) {
				continue;
			}
			molecule.addAtom(subMoleculeAtom);
		}
		// and bonds
		for (CMLBond subMoleculeBond : subMoleculeBonds) {
			if (subMoleculeBond.equals(extensionBond)) {
				continue;
			}
			molecule.addBond(subMoleculeBond);
		}
		return replacedBond;
	}

	private void moveLabelFromStaticAtomToGroup(CMLAtom replacedAtom,
			CMLAtom replacingAtom) {
		Nodes labelNodes = replacedAtom.query("./cml:label", CMLConstants.CML_XPATH);
		CMLLabel label = (labelNodes.size() >= 1) ? (CMLLabel) labelNodes.get(0) : null;
		if (label != null) {
			label.detach();
			replacingAtom.addLabel(label);
		}
	}

	private void scaleAndMoveGroup(CMLAtom replacedAtomParent,
			CMLMolecule subMolecule, CMLAtom replacingAtom) {
		if (replacedAtomParent != null) {
			Real2 replacedXY2 = replacedAtomParent.getXY2();
			Real2 replacingXY2 = replacingAtom.getXY2();
			Vector2 bondVector = new Vector2(replacedXY2.subtract(replacingXY2));
			bondVector = new Vector2(bondVector.multiplyBy(SCALE_GROUPS));
			Real2 newXY2 = replacingXY2.plus(bondVector);
			subMolecule.multiply2DCoordsBy(SCALE_GROUPS);
			Real2 newReplacingXY2 = replacingAtom.getXY2();
			Vector2 translateXY2 = new Vector2(newXY2.subtract(newReplacingXY2));
			subMolecule.translate2D(translateXY2);
		}
	}
};