/*
* This file is part of MoleculeViewer.
*
* MoleculeViewer is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MoleculeViewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with MoleculeViewer. If not, see <http://www.gnu.org/licenses/>.
*/
package astex;
import it.unimi.dsi.fastutil.ints.IntArrayList;
class NeighbourGrid2D {
/** The maximum number of cells along an edge. */
private static final int MaxDim = 64;
/** The minimum coordinate of the box.. */
private double xmin = 0.0;
private double ymin = 0.0;
/** The maximum coordinate of the box. */
private double xmax = 0.0;
private double ymax = 0.0;
/** The minimum distance we wish to search. */
private double spacing = 0.0;
/** The number of boxes along each edge. */
private int nx = 0;
private int ny = 0;
/** The total number of grid boxes. */
private int ncell = 0;
/** The list of cell positions for atoms. */
private IntArrayList list = new IntArrayList();
/** The head pointers for each cell. */
private int head[] = null;
/**
* Construct a neighbour grid with the following specification.
*/
public NeighbourGrid2D(){
}
/** Get the spacing. */
public double getSpacing(){
return spacing;
}
/** Reset and reuse a neighbour grid. */
public void reset(double xmin, double ymin,
double xmax, double ymax,
double dmin){
this.xmin = xmin;
this.ymin = ymin;
this.xmax = xmax;
this.ymax = ymax;
this.spacing = dmin;
nx = 1 + (int)((xmax - xmin) / dmin);
ny = 1 + (int)((ymax - ymin) / dmin);
if(nx > MaxDim || ny > MaxDim){
double biggest = xmax - xmin;
if(ymax - ymin > biggest) biggest = ymax - ymin;
spacing = biggest / (MaxDim + 1);
nx = 1 + (int)((xmax - xmin) / spacing);
ny = 1 + (int)((ymax - ymin) / spacing);
}
ncell = nx * ny;
// make sure we have room
if(head == null || head.length < ncell){
head = new int[ncell];
}
// initialise cell head pointers
// -1 shows that the cell is empty
for(int i = 0; i < ncell; i++){
head[i] = -1;
}
list.clear();
}
/** Add an object to the appropriate cell. */
public void add(int i, double x, double y){
if(x < xmin || y < ymin ||
x > xmax || y > ymax){
System.out.println("NeighbourGrid.add(): unable to add " + i +
" coordinate outside of box");
FILE.out.print("x %8.3f, ", x);
FILE.out.print("y %8.3f\n", y);
return;
}
int ix = (int)((x - xmin)/spacing);
int iy = (int)((y - ymin)/spacing);
int icell = findcell(ix, iy);
if(icell < 0 || icell >= ncell){
System.out.println("invalid cell " + icell + " for object " + i);
return;
}
list.add(head[icell]);
head[icell] = i;
}
/**
* Return the possible neighbours of the point.
* d - is the distance we want to find neighbours out to.
*/
public int getPossibleNeighbours(int id,
double x, double y,
double d,
IntArrayList neighbours,
boolean allNeighbours){
int ibox = ((int)((x - xmin)/spacing));
int jbox = ((int)((y - ymin)/spacing));
int offset = 0 + (int)(0.5 + d/spacing);
int l[] = list.toIntArray();
for(int i = -offset; i <= offset; i++){
int ii = ibox + i;
for(int j = -offset; j <= offset; j++){
int jj = jbox + j;
int c = findcell(ii, jj);
if(c != -1){
int iobj = head[c];
if(iobj != -1){
if(allNeighbours){
if(id == -1){
while(iobj >= 0){
neighbours.add(iobj);
iobj = l[iobj];
}
}else{
while(iobj >= 0){
// don't put ourselves
// in the list of neighbours
if(iobj != id){
neighbours.add(iobj);
}
iobj = l[iobj];
}
}
}else{
while(iobj >= 0){
// don't put things less than us
// in the list of neighbours
if(iobj > id){
neighbours.add(iobj);
}
iobj = l[iobj];
}
}
}
}
}
}
return neighbours.size();
}
/** Find the cell that corresponds to the id's. */
private int findcell(int i, int j){
if(i < 0 || j < 0 || i >= nx || j >= ny) return -1;
return i + j * nx;
}
}