/** * Index the triangulation using a grid index * * @param xCellCount * number of grid cells in a row * @param yCellCount * number of grid cells in a column */ public void indexData(int xCellCount, int yCellCount) { gridIndex = new GridIndex(this, xCellCount, yCellCount); }
/** * Constructs a grid index holding the triangles of a delaunay * triangulation. The grid will be made of (xCellCount * yCellCount) cells. * The smaller the cells the less triangles that fall in them, whuch means * better indexing, but also more cells in the index, which mean more * storage. The smaller the indexed region is, the smaller the cells can be * and still maintain the same capacity, but adding geometries outside the * initial region will invalidate the index ! * * @param delaunay * delaunay triangulation to index * @param xCellCount * number of grid cells in a row * @param yCellCount * number of grid cells in a column * @param region * geographic region to index */ public GridIndex(DelaunayTriangulation delaunay, int xCellCount, int yCellCount, BoundingBox region) { init(delaunay, xCellCount, yCellCount, region); }
private void updateCellValues(int startXCell, int startYCell, int lastXCell, int lastYCell, Triangle startTriangle) { // Go over each grid cell and locate a triangle in it to be the cell's // starting search triangle. Since we only pass between adjacent cells // we can search from the last triangle found and not from the start. // Add triangles for each column cells for (int i = startXCell; i <= lastXCell; i++) { // Find a triangle at the begining of the current column startTriangle = indexDelaunay.find(middleOfCell(i, startYCell), startTriangle); grid[i][startYCell] = startTriangle; Triangle prevRowTriangle = startTriangle; // Add triangles for the next row cells for (int j = startYCell + 1; j <= lastYCell; j++) { grid[i][j] = indexDelaunay.find(middleOfCell(i, j), prevRowTriangle); prevRowTriangle = grid[i][j]; } } }
init(indexDelaunay, (int) (indexRegion.getWidth() / xSize), (int) (indexRegion.getHeight() / ySize), indexRegion.unionWith(updatedRegion)); } else { PointInt minInvalidCell = getCellOf(updatedRegion.getMinPoint()); PointInt maxInvalidCell = getCellOf(updatedRegion.getMaxPoint()); Triangle adjacentValidTriangle = findValidTriangle(minInvalidCell); updateCellValues(minInvalidCell.x, minInvalidCell.y, maxInvalidCell.x, maxInvalidCell.y, adjacentValidTriangle);
/** * Initialize the grid index * * @param delaunay * delaunay triangulation to index * @param xCellCount * number of grid cells in a row * @param yCellCount * number of grid cells in a column * @param region * geographic region to index */ private void init(DelaunayTriangulation delaunay, int xCellCount, int yCellCount, BoundingBox region) { indexDelaunay = delaunay; indexRegion = region; xSize = region.getWidth() / yCellCount; ySize = region.getHeight() / xCellCount; // The grid will hold a trinagle for each cell, so a point (x,y) will // lie // in the cell representing the grid partition of region to a // xCellCount on yCellCount grid grid = new Triangle[xCellCount][yCellCount]; Triangle colStartTriangle = indexDelaunay.find(middleOfCell(0, 0)); updateCellValues(0, 0, xCellCount - 1, yCellCount - 1, colStartTriangle); }
private void deleteUpdate(Point pointToDelete) { for (Triangle addedTriangle1 : addedTriangles) { // update between addedd triangles and deleted triangles for (Triangle deletedTriangle : deletedTriangles) { if (shareSegment(addedTriangle1, deletedTriangle)) { updateNeighbor(addedTriangle1, deletedTriangle, pointToDelete); } } } for (Triangle addedTriangle1 : addedTriangles) { // update between added triangles for (Triangle addedTriangle2 : addedTriangles) { if ((addedTriangle1 != addedTriangle2) && (shareSegment(addedTriangle1, addedTriangle2))) { updateNeighbor(addedTriangle1, addedTriangle2); } } } // Update index with changed triangles if (gridIndex != null) gridIndex.updateIndex(addedTriangles.iterator()); }
/** * finds the triangle the query point falls in, note if out-side of this * triangulation a half plane triangle will be returned (see contains), the * search has expected time of O(n^0.5), and it starts form a fixed triangle * (this.startTriangle), * * @param p * query point * @return the triangle that point p is in. */ public Triangle find(Point p) { // If triangulation has a spatial index try to use it as the starting // triangle Triangle searchTriangle = startTriangle; if (gridIndex != null) { Triangle indexTriangle = gridIndex.findCellTriangleOf(p); if (indexTriangle != null) searchTriangle = indexTriangle; } // Search for the point's triangle starting from searchTriangle return find(searchTriangle, p); }
/** * insert the point to this Delaunay Triangulation. Note: if p is null or * already exist in this triangulation p is ignored. * * @param p * new vertex to be inserted the triangulation. */ public void insertPoint(Point p) { if (vertices.contains(p)) return; modCount++; updateBoundingBox(p); vertices.add(p); Triangle t = insertPointSimple(p); if (t == null) // return; Triangle tt = t; currT = t; // recall the last point for - fast (last) update iterator. do { flip(tt, modCount); tt = tt.getCaTriangle(); } while (tt != t && !tt.isHalfplane()); // Update index with changed triangles if (gridIndex != null) gridIndex.updateIndex(getLastUpdatedTriangles()); }
/** * Finds a valid (existing) trinagle adjacent to a given invalid cell * * @param minInvalidCell * minimum bounding box invalid cell * @return a valid triangle adjacent to the invalid cell */ private Triangle findValidTriangle(PointInt minInvalidCell) { // If the invalid cell is the minimal one in the grid we are forced to // search the // triangulation for a trinagle at that location if (minInvalidCell.x == 0 && minInvalidCell.y == 0) return indexDelaunay.find(middleOfCell(minInvalidCell.getX(), minInvalidCell.getY()), null); else // Otherwise we can take an adjacent cell triangle that is still // valid return grid[Math.min(0, minInvalidCell.getX())][Math.min(0, minInvalidCell.getY())]; }