/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2008, Open Source Geospatial Foundation (OSGeo) * * This library 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; * version 2.1 of the License. * * This library 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. */ package org.geotools.renderer.shape; import static org.geotools.data.shapefile.ShpFileType.QIX; import static org.geotools.data.shapefile.ShpFileType.SHX; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.Collection; import java.util.Iterator; import java.util.logging.Level; import org.geotools.data.DataSourceException; import org.geotools.data.DataUtilities; import org.geotools.data.shapefile.FileReader; import org.geotools.data.shapefile.ShpFiles; import org.geotools.data.shapefile.indexed.IndexType; import org.geotools.data.shapefile.indexed.RecordNumberTracker; import org.geotools.data.shapefile.shp.IndexFile; import org.geotools.data.shapefile.shp.ShapefileReader; import org.geotools.index.CloseableIterator; import org.geotools.index.Data; import org.geotools.index.TreeException; import org.geotools.index.quadtree.QuadTree; import org.geotools.index.quadtree.StoreException; import org.geotools.index.quadtree.fs.FileSystemIndexStore; import com.vividsolutions.jts.geom.Envelope; /** * Encapsulates index information for a layer in the MapContext. The associated * layer can be obtained by * * @author jones * * * @source $URL$ */ public class IndexInfo implements FileReader { final IndexType treeType; private QuadTree qtree; private ShpFiles shpFiles; public IndexInfo(IndexType treeType, ShpFiles shpFiles) { this.treeType = treeType; this.shpFiles = shpFiles; } /** * QuadTree Query * * @param bbox * @return * @throws DataSourceException * @throws IOException * @throws TreeException * DOCUMENT ME! */ CloseableIterator<Data> queryQuadTree(Envelope bbox) throws DataSourceException, IOException, TreeException { try { // old code was checking the resulting collection wasn't empty and // it that // case it closed the qtree straight away. qtree gets closed anyways // with // this code path, but it's quite a bit faster because it avoid one // disk access // just to check the collection is not empty if ((qtree != null) && !bbox.contains(qtree.getRoot().getBounds())) return qtree.search(bbox); } catch (Exception e) { ShapefileRenderer.LOGGER.warning(e.getLocalizedMessage()); } return null; } /** * Convenience method for opening a QuadTree index. * * @return A new QuadTree * @throws StoreException */ QuadTree openQuadTree() throws StoreException { URL url = shpFiles.acquireRead(QIX, this); try { File file = DataUtilities.urlToFile(url); FileSystemIndexStore store = new FileSystemIndexStore(file); try { return store.load(openIndexFile(), false); } catch (IOException e) { throw new StoreException(e); } } finally { shpFiles.unlockRead(url, this); } } /** * Convenience method for opening a ShapefileReader. * * @return An IndexFile * @throws IOException */ IndexFile openIndexFile() throws IOException { if (shpFiles.get(SHX) == null || (shpFiles.isLocal() && !shpFiles.exists(SHX))) { return null; } try{ return new IndexFile(shpFiles, false); }catch (Exception e) { return null; } } private CloseableIterator<Data> queryTree(Envelope bbox) throws IOException, TreeException { if (treeType == IndexType.QIX) { return queryQuadTree(bbox); } // should not happen return null; } static class Reader implements RecordNumberTracker { private ShapefileReader shp; Iterator goodRecs; private int recno = 1; private Data next; private IndexInfo info; public Reader(IndexInfo info, ShapefileReader reader, Envelope bbox) throws IOException { shp = reader; try { if (info.treeType == IndexType.QIX) { info.qtree = info.openQuadTree(); } goodRecs = info.queryTree(bbox); } catch (Exception e) { ShapefileRenderer.LOGGER.log(Level.FINE, "Exception occured attempting to use indexing:", e); goodRecs = null; } this.info = info; } public int getRecordNumber() { return this.recno; } public boolean hasNext() throws IOException { if (this.goodRecs != null) { if (next != null) return true; if (this.goodRecs.hasNext()) { next = (Data) goodRecs.next(); this.recno = ((Integer) next.getValue(0)).intValue(); return true; } return false; } return shp.hasNext(); } public ShapefileReader.Record next() throws IOException { if (!hasNext()) throw new IndexOutOfBoundsException( "No more features in reader"); if (this.goodRecs != null) { Long l = (Long) next.getValue(1); ShapefileReader.Record record = shp.recordAt(l.intValue()); next = null; return record; } recno++; return shp.nextRecord(); } public void close() throws IOException { shp.close(); try { if (info.qtree != null) { info.qtree.close(goodRecs); info.qtree.close(); } } catch (StoreException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public String id() { return getClass().getName(); } }