Permalink
Browse files

1005: Added ability to use different TypeCharacters for numeric types…

… when saving out a shape file. (#1159)
  • Loading branch information...
southernprogrammer authored and mogikanin committed May 5, 2018
1 parent a12686a commit e5793160258f705887ed3033947ad88a468c7d18
@@ -145,4 +145,5 @@ Be aware that code written for 1.9 will not work out of the box because DotSpati
- assign "D_ITRF_1997" to ITRF1997.GeographicInfo.Datum.Name instead of ITRF1997.GeographicInfo.Name because this is the name of the datum and not the GeographicInfo (#1090)
- Update Brutile version in Webmap? (#800)
- SetSelectable Plugin Not Included in Release Build (#1106)
- Error on OpenFile with special SPHEROID string (#1142)
- Error on OpenFile with special SPHEROID string (#1142)
- Shape File Saves with Wrong DataTypes (#1005)
@@ -53,3 +53,4 @@ Trent Muhr
Joe Houghton
Matthias Schider <matthias.schilder1@gmail.com>
Ilya Sosnovsky <yakrewedko@ya.ru>
Bryan Price <southernprogrammer@gmail.com>
@@ -0,0 +1,26 @@
using System;
namespace DotSpatial.Data.Tests
{
class CustomTestFieldMapper : IFieldTypeCharacterMapper
{
public char Map(Type type)
{
if (type == typeof(bool)) return FieldTypeCharacters.Logic;
if (type == typeof(DateTime)) return FieldTypeCharacters.DateTime;
// We are using numeric in most cases here, because that is the format most compatible with other
// Applications
if (type == typeof(float)) return FieldTypeCharacters.Double;
if (type == typeof(double)) return FieldTypeCharacters.Double;
if (type == typeof(decimal)) return FieldTypeCharacters.Double;
if (type == typeof(byte)) return FieldTypeCharacters.Number;
if (type == typeof(short)) return FieldTypeCharacters.Number;
if (type == typeof(int)) return FieldTypeCharacters.Number;
if (type == typeof(long)) return FieldTypeCharacters.Number;
// The default is to store it as a string type
return FieldTypeCharacters.Text;
}
}
}
@@ -99,6 +99,7 @@
<Compile Include="AffineCoefficientsTests.cs" />
<Compile Include="AttributeTableTests.cs" />
<Compile Include="BinaryRasterProviderTests.cs" />
<Compile Include="CustomTestFieldMapper.cs" />
<Compile Include="DataManagerTests.cs" />
<Compile Include="DoubleRasterTest.cs" />
<Compile Include="ExtentTests.cs" />
@@ -456,6 +456,80 @@ public void SavePointToShapefileWithMandZ(CoordinateType c)
}
}
/// <summary>
/// Tests whether or not the field mapper is saving the TypeCharacter correctly to shape files
/// Note that the TypeCharacter is derived from a field's DataType
/// When a shape file is read from disk, DataType is derived from the typeCode stored in the file.
/// So when read from disk the translation goes as follows [file typeCode]->[DataType]->TypeCharacter
/// So there could be something lost in this translation
/// </summary>
/// <param name="customFieldMapper">Whether or not to run the test with the Custom Field Mapper defined at the bottom of this document.</param>
[TestCase(true)]
[TestCase(false)]
public void SaveShapeFileCustomFieldMappings(bool customFieldMapper)
{
if (customFieldMapper)
FieldTypeCharacterMapperManager.Mapper = new CustomTestFieldMapper();
var featureType = FeatureType.Line;
var coordinateType = CoordinateType.Regular;
var fileName = FileTools.GetTempFileName(".shp");
try
{
var coords = new List<Coordinate>
{
new Coordinate(1, 2),
new Coordinate(3, 4),
new Coordinate(5, 6),
new Coordinate(7, 8),
new Coordinate(1, 2)
};
var fs = new FeatureSet(featureType)
{
Projection = KnownCoordinateSystems.Geographic.World.WGS1984,
CoordinateType = coordinateType
};
fs.DataTable.Columns.Add(new DataColumn("doublefield", typeof(double)));
fs.DataTable.Columns.Add(new DataColumn("decimalfield", typeof(decimal)));
fs.DataTable.Columns.Add(new DataColumn("floatfield", typeof(float)));
fs.DataTable.Columns.Add(new DataColumn("stringfield", typeof(string)));
var feature = fs.AddFeature(new LineString(coords.ToArray()));
feature.DataRow.BeginEdit();
feature.DataRow["doublefield"] = 0.05d;
feature.DataRow["decimalfield"] = 0.05m;
feature.DataRow["floatfield"] = 0.05f;
feature.DataRow["stringfield"] = "hello world";
feature.DataRow.EndEdit();
Assert.DoesNotThrow(() => fs.SaveAs(fileName, true));
var loaded = FeatureSet.Open(fileName);
if (customFieldMapper)
{
Assert.True(new Field(loaded.DataTable.Columns[0]).TypeCharacter == FieldTypeCharacters.Double);
Assert.True(new Field(loaded.DataTable.Columns[1]).TypeCharacter == FieldTypeCharacters.Double);
Assert.True(new Field(loaded.DataTable.Columns[2]).TypeCharacter == FieldTypeCharacters.Double);
}
else
{
Assert.True(new Field(loaded.DataTable.Columns[0]).TypeCharacter == FieldTypeCharacters.Number);
Assert.True(new Field(loaded.DataTable.Columns[1]).TypeCharacter == FieldTypeCharacters.Number);
Assert.True(new Field(loaded.DataTable.Columns[2]).TypeCharacter == FieldTypeCharacters.Number);
}
Assert.True(((Field)loaded.DataTable.Columns[3]).TypeCharacter == FieldTypeCharacters.Text);
}
finally
{
FileTools.DeleteShapeFile(fileName);
FieldTypeCharacterMapperManager.Mapper = new FieldTypeCharacterMapper();
}
}
/// <summary>
/// Checks that FeatureSet.UnionShapes is not null and contains features.
/// </summary>
@@ -131,12 +131,16 @@
</Compile>
<Compile Include="FeatureType.cs" />
<Compile Include="Fields.cs" />
<Compile Include="FieldTypeCharacterMapper.cs" />
<Compile Include="FieldTypeCharacterMapperManager.cs" />
<Compile Include="FieldTypeCharacters.cs" />
<Compile Include="IContainRasterBounds.cs" />
<Compile Include="IDisposeLock.cs" />
<Compile Include="IExtent.cs" />
<Compile Include="IExtentM.cs" />
<Compile Include="IExtentZ.cs" />
<Compile Include="IFeatureRow.cs" />
<Compile Include="IFieldTypeCharacterMapper.cs" />
<Compile Include="IGetBitmap.cs" />
<Compile Include="Endian.cs" />
<Compile Include="ImageBandType.cs" />
@@ -214,35 +214,9 @@ public Field(string columnName, char typeCode, byte length, byte decimalCount)
/// <summary>
/// Gets the single character dBase code. Only some of these are supported with Esri.
/// C - Character (Chars, Strings, objects - as ToString(), and structs - as )
/// D - Date (DateTime)
/// T - Time (DateTime)
/// N - Number (Short, Integer, Long, Float, Double, byte)
/// L - Logic (True-False, Yes-No)
/// F - Float
/// B - Double
/// The possible values are defined in FieldTypeCharacters.
/// </summary>
public char TypeCharacter
{
get
{
if (DataType == typeof(bool)) return 'L';
if (DataType == typeof(DateTime)) return 'D';
// We are using numeric in most cases here, because that is the format most compatible with other
// Applications
if (DataType == typeof(float)) return 'N';
if (DataType == typeof(double)) return 'N';
if (DataType == typeof(decimal)) return 'N';
if (DataType == typeof(byte)) return 'N';
if (DataType == typeof(short)) return 'N';
if (DataType == typeof(int)) return 'N';
if (DataType == typeof(long)) return 'N';
// The default is to store it as a string type
return 'C';
}
}
public char TypeCharacter => FieldTypeCharacterMapperManager.Mapper.Map(DataType);
/// <summary>
/// Gets or sets the number of places to keep after the 0 in number formats.
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DotSpatial.Data
{
/// <summary>
/// Default FieldTypeCharacterMapper that is responsible for mapping a Type to a FieldTypeCharacter
/// </summary>
public class FieldTypeCharacterMapper : IFieldTypeCharacterMapper
{
/// <summary>
/// Maps a Type to a FieldTypeCharacter
/// </summary>
/// <param name="type">A Type to convert to the char FieldTypeCharacter</param>
/// <returns></returns>
public char Map(Type type)
{
if (type == typeof(bool)) return FieldTypeCharacters.Logic;
if (type == typeof(DateTime)) return FieldTypeCharacters.DateTime;
// We are using numeric in most cases here, because that is the format most compatible with other
// Applications
if (type == typeof(float)) return FieldTypeCharacters.Number;
if (type == typeof(double)) return FieldTypeCharacters.Number;
if (type == typeof(decimal)) return FieldTypeCharacters.Number;
if (type == typeof(byte)) return FieldTypeCharacters.Number;
if (type == typeof(short)) return FieldTypeCharacters.Number;
if (type == typeof(int)) return FieldTypeCharacters.Number;
if (type == typeof(long)) return FieldTypeCharacters.Number;
// The default is to store it as a string type
return FieldTypeCharacters.Text;
}
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DotSpatial.Data
{
/// <summary>
/// Manages the Default Mappings of Fields
/// </summary>
public class FieldTypeCharacterMapperManager
{
/// <summary>
/// The IFieldTypeCharacterMapper that the Field will use to Map a Type to a FieldTypeCharacter
/// </summary>
public static IFieldTypeCharacterMapper Mapper { get; set; } = new FieldTypeCharacterMapper();
}
}
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DotSpatial.Data
{
/// <summary>
/// Specifies the Constant TypeCharacters used for Field.TypeCharacter
/// </summary>
public static class FieldTypeCharacters
{
/// <summary>
/// Use for Floats, Number is used by default for Floats
/// </summary>
public const char Float = 'F';
/// <summary>
/// Use for Doubles, Number is used by default for Doubles
/// </summary>
public const char Double = 'B';
/// <summary>
/// Logic (True-False, Yes-No)
/// </summary>
public const char Logic = 'L';
/// <summary>
/// Number (Short, Integer, Long, Float, Double, byte)
/// </summary>
public const char Number = 'N';
/// <summary>
/// Use for DateTimes where you just need the time
/// </summary>
public const char Time = 'T'; // DateTime
/// Use for DateTimes
public const char DateTime = 'D'; // DateTime
/// <summary>
/// Use for Chars, Strings, objects - as ToString(), and structs - as
/// </summary>
public const char Text = 'C';
}
}
@@ -0,0 +1,17 @@
using System;
namespace DotSpatial.Data
{
/// <summary>
/// Responsible for mapping a Type to a FieldTypeCharacter
/// </summary>
public interface IFieldTypeCharacterMapper
{
/// <summary>
/// Maps a Type to a FieldTypeCharacter
/// </summary>
/// <param name="type">A Type to convert to the char FieldTypeCharacter</param>
/// <returns></returns>
char Map(Type type);
}
}

0 comments on commit e579316

Please sign in to comment.