diff --git a/autotest/ogr/data/utm31.DAT b/autotest/ogr/data/utm31.DAT new file mode 100644 index 000000000..b0695179c Binary files /dev/null and b/autotest/ogr/data/utm31.DAT differ diff --git a/autotest/ogr/data/utm31.ID b/autotest/ogr/data/utm31.ID new file mode 100644 index 000000000..cd47ed5fc Binary files /dev/null and b/autotest/ogr/data/utm31.ID differ diff --git a/autotest/ogr/data/utm31.MAP b/autotest/ogr/data/utm31.MAP new file mode 100644 index 000000000..0d175d3e2 Binary files /dev/null and b/autotest/ogr/data/utm31.MAP differ diff --git a/autotest/ogr/data/utm31.TAB b/autotest/ogr/data/utm31.TAB new file mode 100644 index 000000000..ffa6e14f5 --- /dev/null +++ b/autotest/ogr/data/utm31.TAB @@ -0,0 +1,13 @@ +!table +!version 300 +!charset WindowsLatin1 + +Definition Table + Type NATIVE Charset "WindowsLatin1" + Fields 1 + id Integer ; +begin_metadata +"\IsReadOnly" = "FALSE" +"\MapInfo" = "" +"\MapInfo\TableID" = "f0bbc21d-6931-48be-b3f1-91f14480e738" +end_metadata diff --git a/autotest/ogr/ogr_mitab.py b/autotest/ogr/ogr_mitab.py index 21741d16f..08a041b45 100755 --- a/autotest/ogr/ogr_mitab.py +++ b/autotest/ogr/ogr_mitab.py @@ -595,6 +595,7 @@ def ogr_mitab_18(): wkt = sr_got.ExportToWkt() if wkt.find('2154') < 0: gdaltest.post_reason('failure') + print(filename) print(sr_got) return 'fail' proj4 = sr_got.ExportToProj4() @@ -607,6 +608,26 @@ def ogr_mitab_18(): ogr.GetDriverByName('MapInfo File').DeleteDataSource('/vsimem/ogr_mitab_18.tab') return 'success' + +############################################################################### +# Check that we correctly round coordinate to the appropriate precision +# (https://github.com/mapgears/mitab/issues/2) + +def ogr_mitab_19(): + + if gdaltest.mapinfo_drv is None: + return 'skip' + + ds = ogr.Open('data/utm31.TAB') + lyr = ds.GetLayer(0) + feat = lyr.GetNextFeature() + # Strict text comparison to check precision + if feat.GetGeometryRef().ExportToWkt() != 'POINT (485248.12 2261.45)': + feat.DumpReadable() + return 'fail' + + return 'success' + ############################################################################### # @@ -640,6 +661,7 @@ def ogr_mitab_cleanup(): ogr_mitab_16, ogr_mitab_17, ogr_mitab_18, + ogr_mitab_19, ogr_mitab_cleanup ] diff --git a/gdal/ogr/ogrsf_frmts/mitab/GNUmakefile b/gdal/ogr/ogrsf_frmts/mitab/GNUmakefile index 79435429d..b6e3afc17 100644 --- a/gdal/ogr/ogrsf_frmts/mitab/GNUmakefile +++ b/gdal/ogr/ogrsf_frmts/mitab/GNUmakefile @@ -21,6 +21,8 @@ default: $(O_OBJ:.o=.$(OBJ_EXT)) clean: rm -f *.o $(O_OBJ) +$(O_OBJ): mitab.h mitab_priv.h + update: copymatch.sh ~/pkg/mitab *.TXT copymatch.sh ~/pkg/mitab/mitab *.cpp *.h diff --git a/gdal/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp b/gdal/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp index c593f0697..dba4413b3 100644 --- a/gdal/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp +++ b/gdal/ogr/ogrsf_frmts/mitab/mitab_mapheaderblock.cpp @@ -138,6 +138,12 @@ #include "mitab.h" +#ifdef WIN32 +inline double round(double r) { + return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); +} +#endif + /*--------------------------------------------------------------------- * Set various constants used in generating the header block. *--------------------------------------------------------------------*/ @@ -178,6 +184,27 @@ static GByte gabyObjLenArray[ HDR_OBJ_LEN_ARRAY_SIZE ] = { **********************************************************************/ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/): TABRawBinBlock(eAccessMode, TRUE) +{ + InitMembersWithDefaultValues(); + + /* We don't want to reset it once it is set */ + m_bIntBoundsOverflow = FALSE; +} + +/********************************************************************** + * TABMAPHeaderBlock::~TABMAPHeaderBlock() + * + * Destructor. + **********************************************************************/ +TABMAPHeaderBlock::~TABMAPHeaderBlock() +{ + +} + +/********************************************************************** + * TABMAPHeaderBlock::InitMembersWithDefaultValues() + **********************************************************************/ +void TABMAPHeaderBlock::InitMembersWithDefaultValues() { int i; @@ -207,7 +234,7 @@ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/): m_nDistUnitsCode = 7; // Meters m_nMaxSpIndexDepth = 0; m_nCoordPrecision = 3; // ??? 3 Digits of precision - m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? + m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? N-E quadrant m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS; m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1; // See gabyObjLenArray[] m_numPenDefs = 0; @@ -219,10 +246,13 @@ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/): m_sProj.nProjId = 0; m_sProj.nEllipsoidId = 0; m_sProj.nUnitsId = 7; + m_sProj.nDatumId = 0; m_XScale = 1000.0; // Default coord range (before SetCoordSysBounds()) m_YScale = 1000.0; // will be [-1000000.000 .. 1000000.000] m_XDispl = 0.0; m_YDispl = 0.0; + m_XPrecision = 0.0; // not specified + m_YPrecision = 0.0; // not specified for(i=0; i<6; i++) m_sProj.adProjParams[i] = 0.0; @@ -243,16 +273,6 @@ TABMAPHeaderBlock::TABMAPHeaderBlock(TABAccess eAccessMode /*= TABRead*/): m_sProj.dAffineParamF = 0.0; } -/********************************************************************** - * TABMAPHeaderBlock::~TABMAPHeaderBlock() - * - * Destructor. - **********************************************************************/ -TABMAPHeaderBlock::~TABMAPHeaderBlock() -{ - -} - /********************************************************************** * TABMAPHeaderBlock::InitBlockFromData() @@ -405,6 +425,8 @@ int TABMAPHeaderBlock::InitBlockFromData(GByte *pabyBuf, } } + UpdatePrecision(); + return 0; } @@ -444,6 +466,12 @@ int TABMAPHeaderBlock::Int2Coordsys(GInt32 nX, GInt32 nY, else dY = (nY - m_YDispl) / m_YScale; + // Round coordinates to the desired precision + if (m_XPrecision > 0 && m_YPrecision > 0) + { + dX = round(dX*m_XPrecision)/m_XPrecision; + dY = round(dY*m_YPrecision)/m_YPrecision; + } //printf("Int2Coordsys: (%d, %d) -> (%.10g, %.10g)\n", nX, nY, dX, dY); return 0; @@ -664,6 +692,8 @@ int TABMAPHeaderBlock::SetCoordsysBounds(double dXMin, double dYMin, m_nXMax = 1000000000; m_nYMax = 1000000000; + UpdatePrecision(); + return 0; } @@ -912,7 +942,6 @@ int TABMAPHeaderBlock::CommitToFile() int TABMAPHeaderBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, int nFileOffset /* = 0*/) { - int i; /*----------------------------------------------------------------- * Start with the default initialisation *----------------------------------------------------------------*/ @@ -922,56 +951,7 @@ int TABMAPHeaderBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, /*----------------------------------------------------------------- * Set acceptable default values for member vars. *----------------------------------------------------------------*/ - m_nMAPVersionNumber = HDR_VERSION_NUMBER; - m_nBlockSize = HDR_DATA_BLOCK_SIZE; - - m_dCoordsys2DistUnits = 1.0; - m_nXMin = -1000000000; - m_nYMin = -1000000000; - m_nXMax = 1000000000; - m_nYMax = 1000000000; - - m_nFirstIndexBlock = 0; - m_nFirstGarbageBlock = 0; - m_nFirstToolBlock = 0; - - m_numPointObjects = 0; - m_numLineObjects = 0; - m_numRegionObjects = 0; - m_numTextObjects = 0; - m_nMaxCoordBufSize = 0; - - m_nDistUnitsCode = 7; // Meters - m_nMaxSpIndexDepth = 0; - m_nCoordPrecision = 3; // ??? 3 digits of precision - m_nCoordOriginQuadrant = HDR_DEF_ORG_QUADRANT; // ??? N-E quadrant - m_nReflectXAxisCoord = HDR_DEF_REFLECTXAXIS; - m_nMaxObjLenArrayId = HDR_OBJ_LEN_ARRAY_SIZE-1; // See gabyObjLenArray[] - m_numPenDefs = 0; - m_numBrushDefs = 0; - m_numSymbolDefs = 0; - m_numFontDefs = 0; - m_numMapToolBlocks = 0; - - m_sProj.nProjId = 0; - m_sProj.nEllipsoidId = 0; - m_sProj.nUnitsId = 7; - m_sProj.nDatumId = 0; - m_XScale = 1000.0; // Default coord range (before SetCoordSysBounds()) - m_YScale = 1000.0; // will be [-1000000.000 .. 1000000.000] - m_XDispl = 0.0; - m_YDispl = 0.0; - - for(i=0; i<6; i++) - m_sProj.adProjParams[i] = 0.0; - - m_sProj.dDatumShiftX = 0.0; - m_sProj.dDatumShiftY = 0.0; - m_sProj.dDatumShiftZ = 0.0; - for(i=0; i<5; i++) - m_sProj.adDatumParams[i] = 0.0; - - m_sProj.nAffineFlag = 0; + InitMembersWithDefaultValues(); /*----------------------------------------------------------------- * And Set the map object length array in the buffer... @@ -988,6 +968,17 @@ int TABMAPHeaderBlock::InitNewBlock(VSILFILE *fpSrc, int nBlockSize, return 0; } +/********************************************************************** + * TABMAPHeaderBlock::UpdatePrecision() + * + * Update x and y maximum achievable precision given current scales + * (m_XScale and m_YScale) + **********************************************************************/ +void TABMAPHeaderBlock::UpdatePrecision() +{ + m_XPrecision = pow(10.0, round(log10(m_XScale))); + m_YPrecision = pow(10.0, round(log10(m_YScale))); +} /********************************************************************** * TABMAPHeaderBlock::Dump() diff --git a/gdal/ogr/ogrsf_frmts/mitab/mitab_priv.h b/gdal/ogr/ogrsf_frmts/mitab/mitab_priv.h index 43df9e862..a8f30604b 100644 --- a/gdal/ogr/ogrsf_frmts/mitab/mitab_priv.h +++ b/gdal/ogr/ogrsf_frmts/mitab/mitab_priv.h @@ -877,6 +877,9 @@ class TABRawBinBlock class TABMAPHeaderBlock: public TABRawBinBlock { + void InitMembersWithDefaultValues(); + void UpdatePrecision(); + protected: TABProjInfo m_sProj; @@ -955,7 +958,8 @@ class TABMAPHeaderBlock: public TABRawBinBlock double m_YScale; double m_XDispl; double m_YDispl; - + double m_XPrecision; // maximum achievable precision along X axis depending on bounds extent + double m_YPrecision; // maximum achievable precision along Y axis depending on bounds extent }; /*---------------------------------------------------------------------