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.contact;
022
023import org.biojava.nbio.structure.Atom;
024
025import java.io.Serializable;
026import java.util.*;
027
028
029/**
030 * A set of atom-atom contacts to hold the results of intra and inter-chain contact calculations
031 *
032 * @author duarte_j
033 *
034 */
035public class AtomContactSet implements Serializable, Iterable<AtomContact> {
036
037
038        private static final long serialVersionUID = 1L;
039
040        private HashMap<Pair<AtomIdentifier>, AtomContact> contacts;
041        private double cutoff;
042
043        public AtomContactSet(double cutoff) {
044                this.cutoff = cutoff;
045                this.contacts = new HashMap<Pair<AtomIdentifier>,AtomContact>();
046        }
047
048        public void add(AtomContact contact) {
049                this.contacts.put(getAtomIdPairFromContact(contact), contact);
050        }
051
052        public void addAll(Collection<AtomContact> list) {
053                for (AtomContact contact:list) {
054                        this.contacts.put(getAtomIdPairFromContact(contact), contact);
055                }
056        }
057
058        public boolean hasContact(Atom atom1, Atom atom2) {
059                return hasContact(
060                                        new AtomIdentifier(atom1.getPDBserial(),atom1.getGroup().getChainId()),
061                                        new AtomIdentifier(atom2.getPDBserial(),atom2.getGroup().getChainId()) );
062        }
063
064        public boolean hasContact(AtomIdentifier atomId1, AtomIdentifier atomId2) {
065                return contacts.containsKey(new Pair<AtomIdentifier>(atomId1,atomId2));
066        }
067
068        /**
069         * Returns the corresponding AtomContact or null if no contact exists between the 2 given atoms
070         * @param atom1
071         * @param atom2
072         * @return
073         */
074        public AtomContact getContact(Atom atom1, Atom atom2) {
075                return contacts.get(new Pair<AtomIdentifier>(
076                                new AtomIdentifier(atom1.getPDBserial(),atom1.getGroup().getChainId()),
077                                new AtomIdentifier(atom2.getPDBserial(),atom2.getGroup().getChainId()) ));
078        }
079
080        public int size() {
081                return contacts.size();
082        }
083
084        @Override
085        public Iterator<AtomContact> iterator() {
086                return contacts.values().iterator();
087        }
088
089        private Pair<AtomIdentifier> getAtomIdPairFromContact(AtomContact contact) {
090                Pair<AtomIdentifier> pair = new Pair<AtomIdentifier>(
091                                new AtomIdentifier(contact.getPair().getFirst().getPDBserial(),contact.getPair().getFirst().getGroup().getChainId()),
092                                new AtomIdentifier(contact.getPair().getSecond().getPDBserial(),contact.getPair().getSecond().getGroup().getChainId()));
093
094                return pair;
095        }
096
097        /**
098         * Returns true if at least 1 contact from this set is within the given distance.
099         * Note that if the distance given is larger than the distance cutoff used to
100         * calculate the contacts then nothing will be found.
101         * @param distance
102         * @return
103         * @throws IllegalArgumentException if given distance is larger than distance cutoff
104         * used for calculation of contacts
105         */
106        public boolean hasContactsWithinDistance(double distance) {
107
108                if (distance>=cutoff)
109                        throw new IllegalArgumentException("Given distance "+
110                                        String.format("%.2f", distance)+" is larger than contacts' distance cutoff "+
111                                        String.format("%.2f", cutoff));
112
113                for (AtomContact contact:this.contacts.values()) {
114                        if (contact.getDistance()<distance) {
115                                return true;
116                        }
117                }
118                return false;
119        }
120
121        /**
122         * Returns the list of contacts from this set that are within the given distance.
123         * @param distance
124         * @return
125         * @throws IllegalArgumentException if given distance is larger than distance cutoff
126         * used for calculation of contacts
127         */
128        public List<AtomContact> getContactsWithinDistance(double distance) {
129
130                if (distance>=cutoff)
131                        throw new IllegalArgumentException("Given distance "+
132                                        String.format("%.2f", distance)+" is larger than contacts' distance cutoff "+
133                                        String.format("%.2f", cutoff));
134
135                List<AtomContact> list = new ArrayList<AtomContact>();
136                for (AtomContact contact:this.contacts.values()) {
137                        if (contact.getDistance()<distance) {
138                                list.add(contact);
139                        }
140                }
141                return list;
142        }
143}