|
From: Benjamin S. <ben...@da...> - 2020-07-30 08:54:26
|
Hi all,
I have a self-written ShapefileWriter which uses the ShapefileDatastore.
Every time I want to write float or double values greater 10 into the
shapefile the schema isn't correct. I always want to have 4 decimal
places.
E.g. I have the value 12.1234, which has a length of 7 (because of the
decimal point) and 4 decimal places. But the ShapefileDatastore calculates
5 decimal places. If I change the value in debug mode the correct decimal
places are written.
My questions:
1. Why are the decimal places always fieldlength minus 2? (see arrows
ShapefileDataStore below)
2. What do I have to do to get the correct decimal places in the
shapefile?
Best regards
Benjamin Sokolowski
relevant code of ShapefileWriter:
private void writeShapeFile( final SimpleFeatureCollection fc, final
String fileName ) throws IOException {
URL shpURL = createURL( fc.getSchema(), fileName );
HashMap<String, Serializable> parameters = getDataStoreParameter(
shpURL );
ShapefileDataStoreFactory dataStoreFactory = new
ShapefileDataStoreFactory();
ShapefileDataStore newDataStore = (ShapefileDataStore)
dataStoreFactory
.createNewDataStore( parameters );
try {
newDataStore.createSchema( fc.getSchema() );
}
catch ( IOException e ) {
throw e;
}
CoordinateReferenceSystem crs = getCRS( fc );
if ( crs != null )
newDataStore.forceSchemaCRS( crs );
try ( Transaction transaction = new DefaultTransaction( "create" ) ) {
String typeName = newDataStore.getTypeNames()[0];
SimpleFeatureSource featureSource = newDataStore.getFeatureSource(
typeName );
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource
;
featureStore.setTransaction( transaction );
try {
featureStore.addFeatures( fc );
transaction.commit();
}
catch ( Exception e ) {
e.printStackTrace();
transaction.rollback();
}
}
newDataStore.dispose();
relevant code of ShapefileDatastore:
/**
* Attempt to create a DbaseFileHeader for the FeatureType. Note, we
cannot set the number of
* records until the write has completed.
*/
protected static DbaseFileHeader createDbaseHeader(SimpleFeatureType
featureType)
throws IOException, DbaseFileException {
DbaseFileHeader header = new DbaseFileHeader();
for (int i = 0, ii = featureType.getAttributeCount(); i < ii; i++)
{
AttributeDescriptor type = featureType.getDescriptor(i);
Class<?> colType = type.getType().getBinding();
String colName = type.getLocalName();
int fieldLen = FeatureTypes.getFieldLength(type);
if (fieldLen == FeatureTypes.ANY_LENGTH) fieldLen = 255;
if ((colType == Integer.class) || (colType == Short.class) ||
(colType == Byte.class)) {
header.addColumn(colName, 'N', Math.min(fieldLen, 9), 0);
} else if (colType == Long.class) {
header.addColumn(colName, 'N', Math.min(fieldLen, 19), 0);
} else if (colType == BigInteger.class) {
header.addColumn(colName, 'N', Math.min(fieldLen, 33), 0);
--> } else if (colType == Float.class) {
int l = Math.min(fieldLen, 24);
// GDAL format default is 15 decimal places of precision
// http://www.gdal.org/drv_shapefile.html
int d = Math.min(Math.max(l - 2, 0), 15);
header.addColumn(colName, 'N', l, d);
--> } else if (colType == Double.class) {
int l = Math.min(fieldLen, 33);
int d = Math.min(Math.max(l - 2, 0), 15);
header.addColumn(colName, 'N', l, d);
} else if (Number.class.isAssignableFrom(colType)) {
int l = Math.min(fieldLen, 33);
int d = Math.max(l - 2, 0);
header.addColumn(colName, 'N', l, d);
// This check has to come before the Date one or it is
never reached
// also, this field is only activated with the following
system property:
// org.geotools.shapefile.datetime=true
} else if (java.util.Date.class.isAssignableFrom(colType)
&& Boolean.getBoolean(
"org.geotools.shapefile.datetime")) {
header.addColumn(colName, '@', fieldLen, 0);
} else if (java.util.Date.class.isAssignableFrom(colType)
|| Calendar.class.isAssignableFrom(colType)) {
header.addColumn(colName, 'D', fieldLen, 0);
} else if (colType == Boolean.class) {
header.addColumn(colName, 'L', 1, 0);
} else if (CharSequence.class.isAssignableFrom(colType)
|| colType == java.util.UUID.class) {
// Possible fix for GEOT-42 : ArcExplorer doesn't like 0
length
// ensure that maxLength is at least 1
header.addColumn(colName, 'C', Math.min(254, fieldLen),
0);
} else if (Geometry.class.isAssignableFrom(colType)) {
continue;
// skip binary data types
} else if (colType == byte[].class) {
continue;
} else {
// Fallback to char columns
header.addColumn(colName, 'C', Math.min(254, fieldLen),
0);
}
}
return header;
}
|