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.slf4j.Logger; 024import org.slf4j.LoggerFactory; 025 026import javax.vecmath.Point3d; 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 Jose Duarte 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 (Point3d[] atoms) { 076 077 if (atoms.length==0) logger.error("Error! Empty list of atoms"); 078 079 xmax = atoms[0].x; 080 xmin = xmax; 081 ymax = atoms[0].y; 082 ymin = ymax; 083 zmax = atoms[0].z; 084 zmin = zmax; 085 086 for(int i=1;i<atoms.length;i++) { 087 if(atoms[i].x > xmax) xmax = atoms[i].x; 088 else if(atoms[i].x < xmin) xmin = atoms[i].x; 089 090 if(atoms[i].y > ymax) ymax = atoms[i].y; 091 else if(atoms[i].y < ymin) ymin = atoms[i].y; 092 093 if(atoms[i].z > zmax) zmax = atoms[i].z; 094 else if(atoms[i].z < zmin) zmin = atoms[i].z; 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 /** 204 * Check if a given point falls within this box 205 * @param atom 206 * @return 207 */ 208 public boolean contains(Point3d atom) { 209 double x = atom.x; 210 double y = atom.y; 211 double z = atom.z; 212 return xmin <= x && x <= xmax 213 && ymin <= y && y <= ymax 214 && zmin <= z && z <= zmax; 215 } 216 217 public void translate(Vector3d translation) { 218 xmin+=translation.x; 219 xmax+=translation.x; 220 ymin+=translation.y; 221 ymax+=translation.y; 222 zmin+=translation.z; 223 zmax+=translation.z; 224 } 225 226 /** 227 * Returns an array of size 2 with min and max values of given double array 228 * @param array 229 * @return 230 */ 231 public double[] getMinMax(double[] array) { 232 double[] minmax = new double[2]; 233 234 double max = Double.MIN_VALUE; 235 double min = Double.MAX_VALUE; 236 237 for(double value : array) { 238 if(value > max) max = value; 239 if(value < min) min = value; 240 } 241 242 minmax[0] = min; 243 minmax[1] = max; 244 return minmax; 245 } 246 247 @Override 248 public String toString() { 249 return String.format("[(%7.2f,%7.2f),(%7.2f,%7.2f),(%7.2f,%7.2f)]", xmin,xmax,ymin,ymax,zmin,zmax); 250 } 251}