// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/dataAccess/shape/EsriGraphicList.java,v $ // $RCSfile: EsriGraphicList.java,v $ // $Revision: 1.11 $ // $Date: 2009/01/21 01:24:41 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.dataAccess.shape; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import com.bbn.openmap.dataAccess.shape.input.ShpInputStream; import com.bbn.openmap.dataAccess.shape.input.ShxInputStream; import com.bbn.openmap.io.FormatException; import com.bbn.openmap.omGraphics.DrawingAttributes; import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.proj.coords.GeoCoordTransformation; import com.bbn.openmap.util.ArgParser; import com.bbn.openmap.util.PropUtils; /** * EsriGraphicList ensures that only supported geometry types are added to its * list. Each subclass of this EsriGraphicList list will hold polyline, polygon, * or point geometry -- other types of geometry are not supported. As shapes are * added to the list, EsriGraphicList will ensure that the type of geometry * being added is the same type of geometry as specified by the subclass list * type. * * @author Doug Van Auken * @author Don Dietrick */ public abstract class EsriGraphicList extends OMGraphicList implements ShapeConstants, EsriGraphic { public static Logger logger = Logger.getLogger("com.bbn.openmap.dataAccess.shape.EsriGraphicList"); protected double[] extents; protected int type; /** * Over-ride the add( ) method to trap for inconsistent shape geometry. If * you are adding a OMGraphic that is not a list, make sure this list is a * sub-list containing multiple geometry parts. Only add another list to a * top level EsriGraphicList. * * @param shape the non-null OMGraphic to add */ public boolean add(OMGraphic shape) { return super.add(shape); } /** * Add an OMGraphic to the GraphicList. The OMGraphic must not be null. * * @param g the non-null OMGraphic to add * @return true if addition is successful. * @exception IllegalArgumentException if OMGraphic is null */ public boolean addOMGraphic(OMGraphic g) { return add(g); } public void setType(int type) { this.type = type; } /** * Get the list type in ESRI type number form */ public int getType() { return type; } /** * Construct an EsriGraphicList. */ public EsriGraphicList() { super(); } /** * Construct an EsriGraphicList with an initial capacity. * * @param initialCapacity the initial capacity of the list */ public EsriGraphicList(int initialCapacity) { super(initialCapacity); } /** * Construct an EsriGraphicList with an initial capacity and a standard * increment value. * * @param initialCapacity the initial capacity of the list * @param capacityIncrement the capacityIncrement for resizing * @deprecated capacityIncrement doesn't do anything. */ public EsriGraphicList(int initialCapacity, int capacityIncrement) { super(initialCapacity); } /** * The lat/lon extent of the EsriGraphicList contents, assumed to contain * miny, minx, maxy maxx in order of the array. */ public void setExtents(double[] extents) { this.extents = extents; } /** * The lat/lon extent of the EsriGraphicList contents, returned as miny, * minx, maxy maxx in order of the array. */ public double[] getExtents() { if (extents == null) { // These are set to their opposites to guarantee some // movement. extents = new double[] { 90f, 180f, -90f, -180f }; } return extents; } public void addExtents(double[] graphicExtents) { double[] ex = getExtents(); // Check both graphic extents in case they are inadvertently // switched. for (int i = 0; i < graphicExtents.length; i += 2) { if (ex[0] > graphicExtents[i]) ex[0] = graphicExtents[i]; if (ex[1] > graphicExtents[i + 1]) ex[1] = graphicExtents[i + 1]; if (ex[2] < graphicExtents[i]) ex[2] = graphicExtents[i]; if (ex[3] < graphicExtents[i + 1]) ex[3] = graphicExtents[i + 1]; } // System.out.println("extents of list: " + // ex[1] + ", " + // ex[0] + ", " + // ex[3] + ", " + // ex[2]); } /** * Set the DbfTableModel in the AppObject of this list that holds the * attribute information about this list's objects. */ public void setTable(DbfTableModel dtm) { if (dtm != null) { putAttribute(DBF_ATTRIBUTE, dtm); } else { removeAttribute(DBF_ATTRIBUTE); } } /** * Get the DbfTableModel object from the AppObject of this list. */ public DbfTableModel getTable() { Object obj = getAttribute(DBF_ATTRIBUTE); if (obj instanceof DbfTableModel) { return (DbfTableModel) obj; } else { return null; } } /** * Create a generic DbfTableModel for the contents of this list, where the * attributes hold rendering properties for the list contents. The table is * stored in the AppObject member variable of the list. */ public void createTable() { // lineWidth, lineColor, fillColor, selectColor We could do // stroke info. Toss space in there for name, or general // attribute for later. // this.setAppObject(EsriShapeExport.createDefaultModel(this)); putAttribute(DBF_ATTRIBUTE, EsriShapeExport.createDefaultModel(this)); } /** * Reads the contents of the SHX and SHP files. The SHX file will be read * first by utilizing the ShapeIndex.open method. This method will return a * list of offsets, which the AbstractSupport.open method will use to * iterate through the contents of the SHP file. * * @param shp The url of the SHP file * @param shx The url of the SHX file * @param drawingAttributes a DrawingAttributes object containing the * rendering parameters you might want on the OMGraphics. The * OMGraphic default (black edge, clear fill) will be used if this is * null. * @param dbf a DbfTableModel, if you want each row of objects from the * table (an array), inserted into their associated OMGraphic's * appObject. The dbf will be added to the list appObject, so you can * ask it questions later. If null, no problem. If the number of * records doesn't match the OMGraphic list length, nothing will be * done. * @return A new EsriGraphicList, null if there is a problem. * * @deprecated use getGraphicList(URL, DrawingAttributes, DbfTableModel) */ public static EsriGraphicList getEsriGraphicList(URL shp, URL shx, DrawingAttributes drawingAttributes, DbfTableModel dbf) { return getEsriGraphicList(shp, drawingAttributes, dbf, null); } /** * Reads the contents of the SHP files. * * @param shp The url of the SHP file * @param drawingAttributes a DrawingAttributes object containing the * rendering parameters you might want on the OMGraphics. The * OMGraphic default (black edge, clear fill) will be used if this is * null. * @param dbf a DbfTableModel. The dbf will be added to the list appObject, * so you can ask it questions later. If null, no problem. If the * number of records doesn't match the OMGraphic list length, nothing * will be done. * @param coordTranslator a GeoCoordTransformation to use to convert * coordinates to decimal degree lat/lon data. * @return A new EsriGraphicList, null if there is a problem. */ public static EsriGraphicList getEsriGraphicList(URL shp, DrawingAttributes drawingAttributes, DbfTableModel dbf, GeoCoordTransformation coordTranslator) { EsriGraphicList list = null; // Open and stream shp file try { InputStream is = shp.openStream(); ShpInputStream pis = new ShpInputStream(is); if (drawingAttributes != null) { pis.setDrawingAttributes(drawingAttributes); } EsriGraphicFactory egf = new EsriGraphicFactory(OMGraphic.LINETYPE_GREATCIRCLE, coordTranslator); list = pis.getGeometry(egf); is.close(); } catch (Exception e) { logger.warning("Not able to stream SHP file"); if (logger.isLoggable(Level.FINE)) { e.printStackTrace(); } return null; } if (list != null && dbf != null && dbf.getRowCount() == list.size()) { list.setTable(dbf); } return list; } /** * Reads the contents of the SHP files, including the DBF file, based on the * location of the shape file. The dbf will be added to the list appObject, * so you can ask it questions later. If null, no problem. If the number of * records doesn't match the OMGraphic list length, the dbf information * won't be added to the list. * * @param shp The url of the SHP file * @param drawingAttributes a DrawingAttributes object containing the * rendering parameters you might want on the OMGraphics. The * OMGraphic default (black edge, clear fill) will be used if this is * null. * @param coordTranslator used to transform coordinates to lat/lon decimal * degrees for OpenMap. * @return A new EsriGraphicList, null if there is a problem. */ public static EsriGraphicList getEsriGraphicList(URL shp, DrawingAttributes drawingAttributes, GeoCoordTransformation coordTranslator) { DbfTableModel dbf = null; if (shp != null) { String shpPath = shp.getFile(); String protocol = shp.getProtocol(); String host = shp.getHost(); if (shpPath != null && shpPath.endsWith(".shp")) { String dbfPath = shpPath.replace(".shp", ".dbf"); URL dbfURL; try { dbfURL = new URL(protocol, host, dbfPath); dbf = DbfTableModel.getDbfTableModel(dbfURL); dbfURL = null; } catch (MalformedURLException e) { e.printStackTrace(); } } } return getEsriGraphicList(shp, drawingAttributes, dbf, coordTranslator); } /** * Find EsriGraphics with a certain attribute * * @param value the value of the desired attribute. * @param columnName the columnName in the dbf * @return new List of EsriGraphic shapes with value in column * @throws FormatException thrown if columnName isn't found. */ public List<EsriGraphic> getGraphicsWithValueInColumn(Object value, String columnName) throws FormatException { List<EsriGraphic> ret = new ArrayList<EsriGraphic>(); DbfTableModel dbf = getTable(); int colIndex = dbf.findColumn(columnName); if (colIndex != -1) { for (OMGraphic eg : this) { Integer index = (Integer) eg.getAttribute(ShapeConstants.SHAPE_INDEX_ATTRIBUTE); List<Object> atts = dbf.getRecord(index); if (atts.get(colIndex).equals(value)) { ret.add((EsriGraphic) eg); } } } else { throw new FormatException("Column " + columnName + " not found"); } return ret; } public static void main(String[] args) { ArgParser ap = new ArgParser("EsriGraphicList"); ap.add("fixcl", "Check and fix content length of Shape file", 1); ap.add("print", "Display text structure of shapes in Shape file", 1); if (!ap.parse(args)) { ap.printUsage(); System.exit(0); } String[] fixit = ap.getArgValues("fixcl"); if (fixit != null) { String shape = fixit[0]; if (shape.endsWith(".shp")) { shape = shape.substring(0, shape.length() - 4); try { URL shx = PropUtils.getResourceOrFileOrURL(shape + ".shx"); InputStream is = shx.openStream(); ShxInputStream pis = new ShxInputStream(is); int[][] index = pis.getIndex(); is.close(); RandomAccessFile raf = new RandomAccessFile(shape + ".shp", "rw"); raf.seek(24); int contentLength = raf.readInt(); int indexedContentLength = index[0][index[0].length - 1] + index[1][index[1].length - 1]; if (contentLength != indexedContentLength) { System.out.println(shape + " content length - shp: " + contentLength + ", shx: " + indexedContentLength); raf.seek(24); raf.writeInt(indexedContentLength); } raf.close(); } catch (Exception e) { e.printStackTrace(); } } else { System.out.println("Shape " + shape + " doesn't look like a shape file"); } } String[] printit = ap.getArgValues("print"); if (printit != null) { try { EsriGraphicList.logger.setLevel(Level.FINER); EsriGraphicFactory.logger.setLevel(Level.FINER); URL eglURL = PropUtils.getResourceOrFileOrURL(printit[0]); EsriGraphicList egl = EsriGraphicList.getEsriGraphicList(eglURL, null, null); if (egl != null) { System.out.println(egl.getDescription()); } } catch (Exception e) { logger.warning(e.getMessage()); e.printStackTrace(); } } } }