Package org.geotools.data.ogr

Source Code of org.geotools.data.ogr.FeatureMapper

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2007-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.data.ogr;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DateFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.TimeZone;

import org.geotools.data.DataSourceException;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.util.Converters;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Polygon;

/**
* Maps OGR features into Geotools ones, and vice versa. Chances are that if you need to update a
* decode method a simmetric modification will be needed in the encode method. This class is not
* thread safe, so each thread should create its own instance.
*
* @author Andrea Aime - OpenGeo
*
*/
class FeatureMapper {

    SimpleFeatureBuilder builder;
   
    SimpleFeatureType schema;
   
    GeometryMapper geomMapper;
   
    GeometryFactory geomFactory;

    /**
     * The date time format used by OGR when getting/setting times using strings
     */
    DateFormat dateTimeFormat = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss");

    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");

    DateFormat timeFormat = new SimpleDateFormat("hh:mm:ss");

    HashMap<String, Integer> attributeIndexes;

    OGR ogr;

    /**
     * TODO: this is subscepitble to changes to the Locale in Java that might not affect
     * the C code... we should probably figure out a way to get the OS level locale?
     */
    static final DecimalFormatSymbols DECIMAL_SYMBOLS = new DecimalFormatSymbols();

    public FeatureMapper(SimpleFeatureType targetSchema, Object layer, GeometryFactory geomFactory, OGR ogr) {
        this.schema = targetSchema;
        this.builder = new SimpleFeatureBuilder(schema);
        this.geomMapper = new GeometryMapper.WKB(geomFactory, ogr);
        this.geomFactory = geomFactory;
        this.ogr = ogr;

        attributeIndexes = new HashMap<String, Integer>();
        Object layerDefinition = ogr.LayerGetLayerDefn(layer);
        int size = ogr.LayerGetFieldCount(layerDefinition);
        for(int i = 0; i < size; i++) {
            Object field = ogr.LayerGetFieldDefn(layerDefinition, i);
            String name = ogr.FieldGetName(field);
            if(targetSchema.getDescriptor(name) != null) {
                attributeIndexes.put(name, i);
            }
        }
    }

    /**
     * Converts an OGR feature into a GeoTools one
     *
     * @param schema
     * @param ogrFeature
     * @return
     * @throws IOException
     */
    SimpleFeature convertOgrFeature(Object ogrFeature)
            throws IOException {
        // Extract all attributes (do not assume any specific order, the feature
        // type may have been re-ordered by the Query)
        Object[] attributes = new Object[schema.getAttributeCount()];

        // .. then extract each attribute using the attribute type to determine
        // which extraction method to call
        for (int i = 0; i < attributes.length; i++) {
            AttributeDescriptor at = schema.getDescriptor(i);
            builder.add(getOgrField(at, ogrFeature));
        }

        // .. gather the FID
        String fid = convertOGRFID(schema, ogrFeature);

        // .. finally create the feature
        return builder.buildFeature(fid);
    }

    /**
     * Turns a GeoTools feature into an OGR one
     *
     * @param feature
     * @return
     * @throws DataSourceException
     */
    Object convertGTFeature(Object featureDefinition, SimpleFeature feature)
            throws IOException {
        // create a new empty OGR feature
        Object ogrFeature = ogr.LayerNewFeature(featureDefinition);
               
        // go thru GeoTools feature attributes, and convert
        SimpleFeatureType schema = feature.getFeatureType();
        for (int i = 0, j = 0; i < schema.getAttributeCount(); i++) {
            Object attribute = feature.getAttribute(i);
            if (attribute instanceof Geometry) {
                // using setGeoemtryDirectly the feature becomes the owner of the generated
                // OGR geometry and we don't have to .delete() it (it's faster, too)
                Object geometry = geomMapper.parseGTGeometry((Geometry) attribute);
                ogr.FeatureSetGeometryDirectly(ogrFeature, geometry);
            } else {
                setFieldValue(featureDefinition, ogrFeature, j, attribute, ogr);
                j++;
            }
        }

        return ogrFeature;
    }

    static void setFieldValue(Object featureDefinition, Object ogrFeature, int fieldIdx,
            Object value, OGR ogr) throws IOException {
         if (value == null) {
             ogr.FeatureUnsetField(ogrFeature, fieldIdx);
        } else {
            Object fieldDefinition = ogr.LayerGetFieldDefn(featureDefinition, fieldIdx);
            long ogrType = ogr.FieldGetType(fieldDefinition);
            if (ogr.FieldIsIntegerType(ogrType)) {
                ogr.FeatureSetFieldInteger(ogrFeature, fieldIdx, ((Number)value).intValue());
            } else if (ogr.FieldIsRealType(ogrType)) {
                ogr.FeatureSetFieldDouble(ogrFeature, fieldIdx, ((Number) value).doubleValue());
            } else if (ogr.FieldIsBinaryType(ogrType)) {
                byte[] attValue = (byte[]) value;
                ogr.FeatureSetFieldBinary(ogrFeature, fieldIdx, attValue.length, attValue);
            } else if (ogr.FieldIsDateType(ogrType)) {
                Calendar cal = Calendar.getInstance();
                cal.setTime((Date) value);
                int year = cal.get(Calendar.YEAR);
                int month = cal.get(Calendar.MONTH);
                int day = cal.get(Calendar.DAY_OF_MONTH);
                ogr.FeatureSetFieldDateTime(ogrFeature, fieldIdx, year, month, day, 0, 0, 0, 0);
            } else if (ogr.FieldIsTimeType(ogrType)) {
                Calendar cal = Calendar.getInstance();
                cal.setTime((Date) value);
                int hour = cal.get(Calendar.HOUR_OF_DAY);
                int minute = cal.get(Calendar.MINUTE);
                int second = cal.get(Calendar.SECOND);
                ogr.FeatureSetFieldDateTime(ogrFeature, fieldIdx, 0, 0, 0, hour, minute, second, 0);
            } else if (ogr.FieldIsDateTimeType(ogrType)) {
                Calendar cal = Calendar.getInstance();
                cal.setTime((Date) value);
                int year = cal.get(Calendar.YEAR);
                int month = cal.get(Calendar.MONTH);
                int day = cal.get(Calendar.DAY_OF_MONTH);
                int hour = cal.get(Calendar.HOUR_OF_DAY);
                int minute = cal.get(Calendar.MINUTE);
                int second = cal.get(Calendar.SECOND);
                ogr.FeatureSetFieldDateTime(ogrFeature, fieldIdx, year, month, day, hour, minute, second, 0);
            } else {
                // anything else we treat as a string
                String str = Converters.convert(value, String.class);
                ogr.FeatureSetFieldString(ogrFeature, fieldIdx, str);
            }
        }
    }

    /**
     * Turns line and polygon into multiline and multipolygon. This is a stop-gap measure to make
     * things works against shapefiles, I've asked the GDAL mailing list on how to properly handle
     * this in the meantime
     *
     * @param ogrGeometry
     * @param ad
     * @return
     */
    Geometry fixGeometryType(Geometry ogrGeometry, AttributeDescriptor ad) {
        if (MultiPolygon.class.equals(ad.getType())) {
            if (ogrGeometry instanceof MultiPolygon)
                return ogrGeometry;
            else
                return geomFactory.createMultiPolygon(new Polygon[] { (Polygon) ogrGeometry });
        } else if (MultiLineString.class.equals(ad.getType())) {
            if (ogrGeometry instanceof MultiLineString)
                return ogrGeometry;
            else
                return geomFactory
                        .createMultiLineString(new LineString[] { (LineString) ogrGeometry });
        }
        return ogrGeometry;

    }


    /**
     * Reads the current feature's specified field using the most appropriate OGR field extraction
     * method
     *
     * @param ad
     * @return
     */
    Object getOgrField(AttributeDescriptor ad, Object ogrFeature) throws IOException {
        if(ad instanceof GeometryDescriptor) {
            // gets the geometry as a reference, we don't own it, we should not deallocate it
            Object ogrGeometry = ogr.FeatureGetGeometry(ogrFeature);
            return fixGeometryType(geomMapper.parseOgrGeometry(ogrGeometry), ad);
        }
       
        Integer idx = attributeIndexes.get(ad.getLocalName());

        // check for null fields
        if (idx == null || !ogr.FeatureIsFieldSet(ogrFeature, idx)) {
            return null;
        }

        // hum, ok try and parse it
        Class clazz = ad.getType().getBinding();
        if (clazz.equals(String.class)) {
            return  ogr.FeatureGetFieldAsString(ogrFeature, idx);
        } else if (clazz.equals(Byte.class)) {
            return (byte) ogr.FeatureGetFieldAsInteger(ogrFeature, idx);
        } else if (clazz.equals(Short.class)) {
            //return (short) OGR_F_GetFieldAsInteger(ogrFeature, idx);
            return (short) ogr.FeatureGetFieldAsInteger(ogrFeature, idx);
        } else if (clazz.equals(Integer.class)) {
            return ogr.FeatureGetFieldAsInteger(ogrFeature, idx);
        } else if (clazz.equals(Long.class)) {
            String value = ogr.FeatureGetFieldAsString(ogrFeature, idx);
            return new Long(value);
        } else if (clazz.equals(BigInteger.class)) {
            String value = ogr.FeatureGetFieldAsString(ogrFeature, idx);
            return new BigInteger(value);
        } else if (clazz.equals(Double.class)) {
            return ogr.FeatureGetFieldAsDouble(ogrFeature, idx);
        } else if (clazz.equals(Float.class)) {
            return (float) ogr.FeatureGetFieldAsDouble(ogrFeature, idx);
        } else if (clazz.equals(BigDecimal.class)) {
            String value = ogr.FeatureGetFieldAsString(ogrFeature, idx).trim();
            char separator = DECIMAL_SYMBOLS.getDecimalSeparator();
            if(separator != '.') {
                value = value.replace(separator, '.');
            }
            return new BigDecimal(value);
        } else if (clazz.equals(java.sql.Date.class)) {
            Calendar cal = getDateField(ogrFeature, idx);
            cal.clear(Calendar.HOUR_OF_DAY);
            cal.clear(Calendar.MINUTE);
            cal.clear(Calendar.SECOND);
            return new java.sql.Date(cal.getTimeInMillis());
        } else if (clazz.equals(java.sql.Time.class)) {
            Calendar cal = getDateField(ogrFeature, idx);
            cal.clear(Calendar.YEAR);
            cal.clear(Calendar.MONTH);
            cal.clear(Calendar.DAY_OF_MONTH);
            return new java.sql.Time(cal.getTimeInMillis());
        } else if (clazz.equals(java.sql.Timestamp.class)) {
            Calendar cal = getDateField(ogrFeature, idx);
            return new java.sql.Time(cal.getTimeInMillis());
        } else if (clazz.equals(java.util.Date.class)) {
            Calendar cal = getDateField(ogrFeature, idx);
            return cal.getTime();
        } else {
            throw new IllegalArgumentException("Don't know how to read " + clazz.getName()
                    + " fields");
        }
    }

    /**
     * Reads a date field from the OGR api
     * @param ogrFeature
     * @param idx
     * @return
     */
    private Calendar getDateField(Object ogrFeature, Integer idx) {
        int[] year = new int[1];
        int[] month = new int[1];
        int[] day = new int[1];
        int[] hour = new int[1];
        int[] minute = new int[1];
        int[] second = new int[1];
        int[] timeZone = new int[1];

        ogr.FeatureGetFieldAsDateTime(ogrFeature, idx, year, month, day, hour, minute, second, timeZone);

        Calendar cal = Calendar.getInstance();
        // from ogr_core.h
        // 0=unknown, 1=localtime(ambiguous), 100=GMT, 104=GMT+1, 80=GMT-5, etc
        int tz = timeZone[0];
        if(tz != 0 && tz != 1) {
            int offset = tz - 100 / 4;
            if(offset < 0) {
                cal.setTimeZone(TimeZone.getTimeZone("GMT" + offset));
            } else if(offset == 0) {
                cal.setTimeZone(TimeZone.getTimeZone("GMT"));
            } else {
                cal.setTimeZone(TimeZone.getTimeZone("GMT+" + offset));
            }              
        }
        cal.clear();
        cal.set(Calendar.YEAR, year[0]);
        cal.set(Calendar.MONTH, month[0]);
        cal.set(Calendar.DAY_OF_MONTH, day[0]);
        cal.set(Calendar.HOUR_OF_DAY, hour[0]);
        cal.set(Calendar.MINUTE, minute[0]);
        cal.set(Calendar.SECOND, second[0]);
        return cal;
    }

    /**
     * Generates a GT2 feature id given its feature type and an OGR feature
     *
     * @param schema
     * @param ogrFeature
     * @return
     */
    String convertOGRFID(SimpleFeatureType schema, Object ogrFeature) {
        long id = ogr.FeatureGetFID(ogrFeature);
        return schema.getTypeName() + "." + id;
    }

    /**
     * Decodes a GT2 feature id into an OGR one
     *
     * @param feature
     * @return
     */
    long convertGTFID(SimpleFeature feature) {
        String id = feature.getID();
        return Long.parseLong(id.substring(id.indexOf(".") + 1));
    }

}
TOP

Related Classes of org.geotools.data.ogr.FeatureMapper

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.