/** * Adds a LonePair to this Atom. * * @param atomID The atom number to which the LonePair is added in [0,..] */ public void addLonePair(int atomID) { ILonePair lonePair = getBuilder().newInstance(ILonePair.class, atoms[atomID]); lonePair.addListener(this); addLonePair(lonePair); /* no notifyChanged() here because addElectronContainer() does it already */ }
/** * Removes the lone pair at the given position from the AtomContainer. * * @param position The position of the LonePair to be removed. */ public ILonePair removeLonePair(int position) { ILonePair lp = lonePairs[position]; lp.removeListener(this); for (int i = position; i < lonePairCount - 1; i++) { lonePairs[i] = lonePairs[i + 1]; } lonePairs[lonePairCount - 1] = null; lonePairCount--; notifyChanged(); return lp; }
/** * Clones this AtomContainer object and its content. * * @return The cloned object * @see #shallowCopy */ public IAtomContainer clone() throws CloneNotSupportedException { // this is pretty wasteful as we need to delete most the data // we can't simply create an empty instance as the sub classes (e.g. AminoAcid) // would have a ClassCastException when they invoke clone IAtomContainer clone = (IAtomContainer) super.clone(); // remove existing elements - we need to set the stereo elements list as list.clone() doesn't // work as expected and will also remove all elements from the original clone.setStereoElements(new ArrayList<IStereoElement>(stereoElements.size())); clone.removeAllElements(); // create a mapping of the original atoms/bonds to the cloned atoms/bonds // we need this mapping to correctly clone bonds, single/paired electrons // and stereo elements // - the expected size stop the map be resized - method from Google Guava Map<IAtom, IAtom> atomMap = new HashMap<IAtom, IAtom>(atomCount >= 3 ? atomCount + atomCount / 3 : atomCount + 1); Map<IBond, IBond> bondMap = new HashMap<IBond, IBond>(bondCount >= 3 ? bondCount + bondCount / 3 : bondCount + 1); // clone atoms IAtom[] atoms = new IAtom[this.atomCount]; for (int i = 0; i < atoms.length; i++) { atoms[i] = (IAtom) this.atoms[i].clone(); atomMap.put(this.atoms[i], atoms[i]); } clone.setAtoms(atoms); // clone bonds using a the mappings from the original to the clone IBond[] bonds = new IBond[this.bondCount]; for (int i = 0; i < bonds.length; i++) { IBond original = this.bonds[i]; IBond bond = (IBond) original.clone(); int n = bond.getAtomCount(); IAtom[] members = new IAtom[n]; for (int j = 0; j < n; j++) { members[j] = atomMap.get(original.getAtom(j)); } bond.setAtoms(members); bondMap.put(this.bonds[i], bond); bonds[i] = bond; } clone.setBonds(bonds); // clone lone pairs (we can't use an array to buffer as there is no setLonePairs()) for (int i = 0; i < lonePairCount; i++) { ILonePair original = this.lonePairs[i]; ILonePair pair = (ILonePair) original.clone(); if (pair.getAtom() != null) pair.setAtom(atomMap.get(original.getAtom())); clone.addLonePair(pair); } // clone single electrons (we can't use an array to buffer as there is no setSingleElectrons()) for (int i = 0; i < singleElectronCount; i++) { ISingleElectron original = this.singleElectrons[i]; ISingleElectron electron = (ISingleElectron) original.clone(); if (electron.getAtom() != null) electron.setAtom(atomMap.get(original.getAtom())); clone.addSingleElectron(electron); } // map each stereo element to a new instance in the clone for (IStereoElement element : stereoElements) { clone.addStereoElement(element.map(atomMap, bondMap)); } return clone; }
@Override public BoundsTree layout(IAtom atom, Graphics2D g) { Rectangle2D idBounds; this.currentObject = atom; String id = atom.getID(); IAtomContainer molecule = null; if (this.parent != null) { molecule = (IAtomContainer) this.parent.getCurrentObject(); } this.boundsTree = new BoundsTree(atom.getID()); if (molecule == null || this.shouldDraw(atom, molecule)) { Integer implicitHydrogenCount; this.boundsTree.add(id + ":symbol", this.layoutAtomSymbol(atom, g)); if (this.isCharged(atom)) { Rectangle2D chargeBounds = this.layoutCharge(atom, g); this.boundsTree.add(id + ":charge", chargeBounds); } if (this.params.drawImplicitHydrogens && (implicitHydrogenCount = atom.getImplicitHydrogenCount()) != null && implicitHydrogenCount > 0) { int align = 1; if (molecule != null) { GeometryTools.getBestAlignmentForLabel((IAtomContainer) molecule, (IAtom) atom); } LabelManager.AnnotationPosition suggestedPosition = this.labelManager.alignmentToAnnotationPosition(align); if (atom.getSymbol().equals("O") && (molecule == null || molecule.getConnectedAtomsCount(atom) == 0)) { suggestedPosition = LabelManager.AnnotationPosition.W; } if (this.labelManager.isUsed(atom, suggestedPosition)) { suggestedPosition = this.labelManager.getNextSparePosition(atom); } this.labelManager.setUsedPosition(atom, suggestedPosition); Rectangle2D hBounds = this.layoutImplicitHydrogens(atom, implicitHydrogenCount, suggestedPosition, g); if (hBounds != null) { this.boundsTree.add(id + ":hs", hBounds); } } } else if (this.params.drawRS && this.chiralMap.containsKey(atom)) { this.boundsTree.add( id + ":chiral", this.layoutChiralSymbol(atom, this.chiralMap.get(atom), g)); } else { Point2d p = atom.getPoint2d(); this.boundsTree.add(id + ":symbol", new Point2D.Double(p.x, p.y)); } if (this.params.drawAtomID && molecule != null && (idBounds = this.layoutAtomID(atom, molecule, g)) != null) { this.boundsTree.add(id + ":id", idBounds); } if (this.params.drawLonePairs && molecule != null) { int lonePairCount = 0; for (ILonePair lonePair : molecule.lonePairs()) { if (!lonePair.contains(atom)) { continue; } ++lonePairCount; } if (lonePairCount > 0) { Stroke stroke = g.getStroke(); g.setStroke(new BasicStroke(0.05f)); this.layoutElectronPairs(atom, molecule, lonePairCount, g); g.setStroke(stroke); } } return this.boundsTree; }