Package com.bbn.openmap.dataAccess.shape.output

Source Code of com.bbn.openmap.dataAccess.shape.output.ShpOutputStream

// **********************************************************************
//
// <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/output/ShpOutputStream.java,v $
// $RCSfile: ShpOutputStream.java,v $
// $Revision: 1.3.2.3 $
// $Date: 2007/01/30 18:36:29 $
// $Author: dietrick $
//
// **********************************************************************

package com.bbn.openmap.dataAccess.shape.output;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.logging.Logger;

import com.bbn.openmap.LatLonPoint;
import com.bbn.openmap.dataAccess.shape.EsriGraphic;
import com.bbn.openmap.dataAccess.shape.EsriGraphicList;
import com.bbn.openmap.dataAccess.shape.EsriPointList;
import com.bbn.openmap.dataAccess.shape.EsriPolygonList;
import com.bbn.openmap.dataAccess.shape.EsriPolylineList;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.omGraphics.OMPoint;
import com.bbn.openmap.omGraphics.OMPoly;

/**
* Writes data to a .shp file
*
* @author Doug Van Auken
*/
public class ShpOutputStream {

    public static Logger logger = Logger.getLogger("com.bbn.openmap.dataAccess.shape.output.ShpOutputStream");

    /**
     * An outputstream that writes primitive data types in little endian or big
     * endian
     */
    private LittleEndianOutputStream _leos = null;

    /**
     * Creates an outputstream to write to
     *
     * @param os The output stream to write to
     */
    public ShpOutputStream(OutputStream os) {
        BufferedOutputStream bos = new BufferedOutputStream(os);
        _leos = new LittleEndianOutputStream(bos);
    }

    /**
     * Determine what type of list is given and write it out.
     *
     * @param list The EsriGraphicList to write
     * @return The index data that is used to create the .shx file
     */
    public int[][] writeGeometry(EsriGraphicList list) throws IOException {
        if (list instanceof EsriPolygonList || list instanceof EsriPolylineList) {
            return writePolyGeometry(list);
        } else if (list instanceof EsriPointList) {
            return writePointGeometry(list);
        }
        return null;
    }

    /**
     * Calculates the content length for each record, in terms of words as
     * defined by ESRI documentation. A word is 16 bits, so a double is 4 words
     * and an int is 2 words.
     *
     * @param list The EsriGraphicList to write
     * @return The index data that is used to create the .shx file
     */
    protected int[][] createPointIndex(OMGraphicList list) {
        int[][] indexData = new int[2][list.size()];

        int pos = 50;
        for (int i = 0; i < list.size(); i++) {
            // OMGraphicList sublist =
            // (OMGraphicList)list.getOMGraphicAt(i);
            int contentLength = 0;
            contentLength += 2; // Shape Type
            contentLength += 4; // X
            contentLength += 4; // Y
            indexData[1][i] = contentLength;
            indexData[0][i] = pos;
            pos += contentLength + 4;
        }
        return indexData;
    }

    /**
     * Creates a two dimensional array holding a list of shape content lengths
     * and shape content length offsets, as defined in Esri shape file
     * documentation. This array is used to create the .shx file
     *
     * @param list The list from which to create the respective array
     * @return The index data that is used to create the .shx file
     */
    protected int[][] createPolyIndex(EsriGraphicList list) {
        float[] data;

        int[][] indexData = new int[2][list.size()];
        int pos = 50;

        for (int i = 0; i < list.size(); i++) {
            int contentLength = 0;
            OMGraphic graphic = (OMGraphic) list.getOMGraphicAt(i);

            contentLength += 2; // Shape Type
            contentLength += 16; // Box
            contentLength += 2; // NumParts
            contentLength += 2; // NumPoints

            if (graphic instanceof OMGraphicList) {
                OMGraphicList sublist = (OMGraphicList) graphic;
                contentLength += sublist.size() * 2; // offsets?

                for (int j = 0; j < sublist.size(); j++) {
                    OMPoly poly = (OMPoly) sublist.getOMGraphicAt(j);
                    data = poly.getLatLonArray();

                    // each value equals 4 words
                    contentLength += data.length * 4;
                }
            } else {
                contentLength += 2; // offset?

                // Should be an EsriPolyline
                data = ((OMPoly) graphic).getLatLonArray();
                // each value equals 4 words
                contentLength += data.length * 4;
            }

            indexData[1][i] = contentLength;
            indexData[0][i] = pos;
            pos += contentLength + 4;
        }
        return indexData;
    }

    /**
     * Creates an array whose elements specify at what index a shapes geometry
     * begins
     *
     * @param contentLengths The array for which to get offsets from
     * @return An array of record offsets
     */
    protected int[] getRecordOffsets(int[] contentLengths) {
        int[] offsets = new int[contentLengths.length];
        int pos = 50;
        for (int i = 0; i < contentLengths.length; i++) {
            offsets[i] = pos;
            pos += contentLengths[i] + 4;
        }
        return offsets;
    }

    /**
     * Creates an array whose elements specifies at what index a parts geometry
     * begins
     *
     * @param sublist A list of shapes
     * @return An array of part offsets
     */
    protected int[] getPartOffsets(OMGraphicList sublist) {
        int pos = 0;
        int[] offsets = new int[sublist.size()];
        for (int j = 0; j < sublist.size(); j++) {
            OMPoly poly = (OMPoly) sublist.getOMGraphicAt(j);
            float[] data = poly.getLatLonArray();
            offsets[j] = pos / 2;
            pos += data.length;
        }
        return offsets;
    }

    /**
     * Iterates through a list of shapes, summing the points per part to
     * determine the number of points per shape
     *
     * @param sublist A list of shapes
     * @return The number of points for a given shape
     */
    protected int getPointsPerShape(OMGraphicList sublist) {
        int numPoints = 0;
        for (int i = 0; i < sublist.size(); i++) {
            OMPoly poly = (OMPoly) sublist.getOMGraphicAt(i);
            float[] data = poly.getLatLonArray();
            numPoints += data.length;
        }
        numPoints /= 2;
        return numPoints;
    }

    protected void writeExtents(float[] extents) throws IOException {

        if (_leos == null) {
            return;
        }

        if (extents[0] == 90f && extents[1] == 180f && extents[2] == -90f
                && extents[3] == -180f) {

            // Whoa! not set from defaults correctly!
            // use old, hardcoded way.
            _leos.writeLEDouble(-180.0);
            _leos.writeLEDouble(-90.0);
            _leos.writeLEDouble(180.0);
            _leos.writeLEDouble(90.0);

        } else {
            _leos.writeLEDouble((float) extents[1]);
            _leos.writeLEDouble((float) extents[0]);
            _leos.writeLEDouble((float) extents[3]);
            _leos.writeLEDouble((float) extents[2]);
        }

    }

    /**
     * Writes polygon geometry to the class scope LittleEndianInputStream.
     *
     * @param list The list of geometry objects to save
     * @return A two dimensional array containing shape offsets and content
     *         lengths
     */
    public int[][] writePolyGeometry(EsriGraphicList list) throws IOException {

        OMPoly poly;

        _leos.writeInt(9994); // Byte 0 File Code
        _leos.writeInt(0); // Byte 4 Unused
        _leos.writeInt(0); // Byte 8 Unused
        _leos.writeInt(0); // Byte 12 Unused
        _leos.writeInt(0); // Byte 16 Unused
        _leos.writeInt(0); // Byte 20 Unused

        int[][] indexData = createPolyIndex(list);
        int contentLength = 50;

        if (list.size() > 0) {
            contentLength = indexData[0][indexData[0].length - 1]
                    + indexData[1][indexData[0].length - 1];
        }

        _leos.writeInt(contentLength); // Byte 24 File Length
        _leos.writeLEInt(1000); // Byte 28 Version
        _leos.writeLEInt(list.getType()); // Byte 32 Shape Type

        // Writes bounding box.
        float[] extents = list.getExtents();
        writeExtents(extents);

        _leos.writeDouble(0.0); // Byte 68
        _leos.writeDouble(0.0); // Byte 76
        _leos.writeDouble(0.0); // Byte 84
        _leos.writeDouble(0.0); // Byte 92

        // Iterate through the list
        for (int i = 0; i < list.size(); i++) {

            OMGraphic graphic = list.getOMGraphicAt(i);

            // Record header
            _leos.writeInt(i + 1); // Record numbers start with 1
            _leos.writeInt(indexData[1][i]);

            // Beginning of Geometry data
            _leos.writeLEInt(list.getType()); // Little endian

            // More stuff needs to be written out for just the OMPoly
            // case...
            // Single part, etc.

            if (graphic instanceof EsriGraphicList) {

                // Assumes that the elements of the top level list are
                // EsriGraphicLists, too. This will probably be
                // changing.
                EsriGraphicList sublist = (EsriGraphicList) graphic;

                // Writes bounding box.
                extents = sublist.getExtents();
                writeExtents(extents);

                // Writes number of parts
                int numParts = sublist.size();
                _leos.writeLEInt(numParts);

                // Write number of points per shape
                int numPoints = getPointsPerShape(sublist);
                _leos.writeLEInt(numPoints);

                // Write the offsets to each part for a given shape
                int[] offsets = getPartOffsets(sublist);

                for (int j = 0; j < offsets.length; j++) {
                    _leos.writeLEInt(offsets[j]);
                }

                // Write the geometry for each part
                for (int j = 0; j < sublist.size(); j++) {
                    poly = (OMPoly) sublist.getOMGraphicAt(j);
                    float[] data = poly.getLatLonArray();
                    int n = 0;
                    while (n < data.length) {
                        Float lat = new Float(data[n++]);
                        Float lon = new Float(data[n++]);
                        _leos.writeLEDouble(Math.toDegrees(lon.doubleValue()));
                        _leos.writeLEDouble(Math.toDegrees(lat.doubleValue()));
                    }
                }
            } else {
                extents = ((EsriGraphic) graphic).getExtents();
                writeExtents(extents);

                // Writes number of parts for shape (1)
                _leos.writeLEInt(1);

                poly = (OMPoly) graphic;
                float[] data = poly.getLatLonArray();

                // Write number of points for shape
                _leos.writeLEInt(data.length / 2);

                // Write the offsets to this shape
                _leos.writeLEInt(0);

                int n = 0;
                while (n < data.length) {
                    Float lat = new Float(data[n++]);
                    Float lon = new Float(data[n++]);
                    _leos.writeLEDouble(Math.toDegrees(lon.doubleValue()));
                    _leos.writeLEDouble(Math.toDegrees(lat.doubleValue()));
                }
            }
        }
        _leos.flush();
        _leos.close();
        return indexData;
    }

    /**
     * Writes point geometry to the class scope LittleEndianOutputStream.
     *
     * @param list An EsriGraphicList of points
     * @return A two dimensional array containing shape offsets and content
     *         lengths
     */
    public int[][] writePointGeometry(EsriGraphicList list) throws IOException {
        _leos.writeInt(9994); // Big
        _leos.writeInt(0); // Big
        _leos.writeInt(0); // Big
        _leos.writeInt(0); // Big
        _leos.writeInt(0); // Big
        _leos.writeInt(0); // Big

        int[][] indexData = createPointIndex(list);
        int contentLength = 50;

        if (list.size() > 0) {
            contentLength = indexData[0][indexData[0].length - 1]
                    + indexData[1][indexData[0].length - 1];
        }

        _leos.writeInt(contentLength); // Big
        _leos.writeLEInt(1000); // Little
        _leos.writeLEInt(list.getType());

        // Writes bounding box.
        float[] extents = list.getExtents();
        writeExtents(extents);

        _leos.writeDouble(0.0);
        _leos.writeDouble(0.0);
        _leos.writeDouble(0.0);
        _leos.writeDouble(0.0);

        for (int i = 0; i < list.size(); i++) {
            OMPoint point = (OMPoint) list.getOMGraphicAt(i);
            LatLonPoint pt = new LatLonPoint(point.getLat(), point.getLon());

            // Record header...
            _leos.writeInt(i + 1); // Record numbers start with 1
            _leos.writeInt(indexData[1][i]);

            // Beginning of Geometry data
            _leos.writeLEInt(list.getType());

            Float lat = new Float(pt.getLatitude());
            Float lon = new Float(pt.getLongitude());

            _leos.writeLEDouble(lon.doubleValue());
            _leos.writeLEDouble(lat.doubleValue());
        }
        _leos.flush();
        _leos.close();

        return indexData;
    }
}
TOP

Related Classes of com.bbn.openmap.dataAccess.shape.output.ShpOutputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.