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; 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027import javax.vecmath.Vector3d; 028import java.io.Serializable; 029import java.util.Arrays; 030 031 032/** 033 * A bounding box for short cutting some geometrical calculations. 034 * 035 * See http://en.wikipedia.org/wiki/Bounding_volume 036 * 037 * @author duarte_j 038 * 039 */ 040public class BoundingBox implements Serializable { 041 042 private static final long serialVersionUID = 1L; 043 private static final Logger logger = LoggerFactory.getLogger(StructureInterfaceList.class); 044 045 046 public double xmin; 047 public double xmax; 048 public double ymin; 049 public double ymax; 050 public double zmin; 051 public double zmax; 052 053 public BoundingBox(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { 054 this.xmin = xmin; 055 this.xmax = xmax; 056 this.ymin = ymin; 057 this.ymax = ymax; 058 this.zmin = zmin; 059 this.zmax = zmax; 060 } 061 062 public BoundingBox(BoundingBox bb) { 063 this.xmin = bb.xmin; 064 this.xmax = bb.xmax; 065 this.ymin = bb.ymin; 066 this.ymax = bb.ymax; 067 this.zmin = bb.zmin; 068 this.zmax = bb.zmax; 069 } 070 071 /** 072 * Constructs a BoundingBox by calculating maxs and mins of given array of atoms. 073 * @param atoms 074 */ 075 public BoundingBox (Atom[] atoms) { 076 077 if (atoms.length==0) logger.error("Error! Empty list of atoms"); 078 079 xmax = atoms[0].getX(); 080 xmin = xmax; 081 ymax = atoms[0].getY(); 082 ymin = ymax; 083 zmax = atoms[0].getZ(); 084 zmin = zmax; 085 086 for(int i=1;i<atoms.length;i++) { 087 if(atoms[i].getX() > xmax) xmax = atoms[i].getX(); 088 else if(atoms[i].getX() < xmin) xmin = atoms[i].getX(); 089 090 if(atoms[i].getY() > ymax) ymax = atoms[i].getY(); 091 else if(atoms[i].getY() < ymin) ymin = atoms[i].getY(); 092 093 if(atoms[i].getZ() > zmax) zmax = atoms[i].getZ(); 094 else if(atoms[i].getZ() < zmin) zmin = atoms[i].getZ(); 095 } 096 097 } 098 099 100 /** Returns the dimensions of this bounding box. 101 * 102 * @return a double array (x,y,z) with the dimensions of the box. 103 */ 104 public double[] getDimensions(){ 105 106 double[] dim = new double[3]; 107 108 dim[0] = xmax-xmin; 109 dim[1] = ymax-ymin; 110 dim[2] = zmax-zmin; 111 112 return dim; 113 114 } 115 116 /** 117 * Given a set of bounding boxes returns a bounding box that bounds all of them. 118 * @param boxes 119 */ 120 public BoundingBox(BoundingBox[] boxes) { 121 122 if (boxes.length==0) logger.error("Error! Empty list of bounding boxes"); 123 124 xmax = boxes[0].xmax; 125 xmin = boxes[0].xmin; 126 ymax = boxes[0].ymax; 127 ymin = boxes[0].ymin; 128 zmax = boxes[0].zmax; 129 zmin = boxes[0].zmin; 130 131 for (int i=1;i<boxes.length;i++) { 132 if(boxes[i].xmax > xmax) xmax = boxes[i].xmax; 133 else if(boxes[i].xmin < xmin) xmin = boxes[i].xmin; 134 if(boxes[i].ymax > ymax) ymax = boxes[i].ymax; 135 else if(boxes[i].ymin < ymin) ymin = boxes[i].ymin; 136 if(boxes[i].zmax > zmax) zmax = boxes[i].zmax; 137 else if(boxes[i].zmin < zmin) zmin = boxes[i].zmin; 138 } 139 140 } 141 142 private class Bound implements Comparable<Bound> { 143 int cardinal; 144 double value; 145 public Bound(int cardinal,double value) { 146 this.cardinal = cardinal; 147 this.value = value; 148 } 149 @Override 150 public int compareTo(Bound o) { 151 return Double.compare(this.value,o.value); 152 } 153 @Override 154 public String toString() { 155 return "["+cardinal+","+value+"]"; 156 } 157 } 158 159 /** 160 * Returns true if this bounding box overlaps given one, i.e. they are within 161 * one cutoff distance in one of their 3 dimensions. 162 * @param cutoff 163 * @return 164 */ 165 public boolean overlaps(BoundingBox o, double cutoff) { 166 if (this==o) return true; 167 // x dimension 168 if (!areOverlapping(xmin,xmax,o.xmin,o.xmax,cutoff)) { 169 return false; 170 } 171 // y dimension 172 if (!areOverlapping(ymin,ymax,o.ymin,o.ymax,cutoff)) { 173 return false; 174 } 175 // z dimension 176 if (!areOverlapping(zmin,zmax,o.zmin,o.zmax,cutoff)) { 177 return false; 178 } 179 return true; 180 } 181 182 private boolean areOverlapping(double imin, double imax, double jmin, double jmax, double cutoff) { 183 184 Bound[] bounds = {new Bound(0,imin), new Bound(1,imax), 185 new Bound(2,jmin), new Bound(3,jmax)}; 186 187 Arrays.sort(bounds); 188 189 if ((bounds[0].cardinal==0 && bounds[1].cardinal==1)) { 190 if ((bounds[2].value-bounds[1].value)>cutoff) { 191 return false; 192 } 193 } else if (bounds[0].cardinal==2 && bounds[1].cardinal==3) { 194 if ((bounds[2].value-bounds[1].value)>cutoff) { 195 return false; 196 } 197 } 198 199 return true; 200 201 } 202 203 public void translate(Vector3d translation) { 204 xmin+=translation.x; 205 xmax+=translation.x; 206 ymin+=translation.y; 207 ymax+=translation.y; 208 zmin+=translation.z; 209 zmax+=translation.z; 210 } 211 212 /** 213 * Returns an array of size 2 with min and max values of given double array 214 * @param array 215 * @return 216 */ 217 public double[] getMinMax(double[] array) { 218 double[] minmax = new double[2]; 219 220 double max = Double.MIN_VALUE; 221 double min = Double.MAX_VALUE; 222 223 for(double value : array) { 224 if(value > max) max = value; 225 if(value < min) min = value; 226 } 227 228 minmax[0] = min; 229 minmax[1] = max; 230 return minmax; 231 } 232 233 @Override 234 public String toString() { 235 return String.format("[(%7.2f,%7.2f),(%7.2f,%7.2f),(%7.2f,%7.2f)]", xmin,xmax,ymin,ymax,zmin,zmax); 236 } 237}