www.pudn.com > mitab.rar > mitab_feature_mif.cpp
/**********************************************************************
* $Id: mitab_feature_mif.cpp,v 1.31 2006/01/27 13:44:44 fwarmerdam Exp $
*
* Name: mitab_feature.cpp
* Project: MapInfo TAB Read/Write library
* Language: C++
* Purpose: Implementation of R/W Fcts for (Mid/Mif) in feature classes
* specific to MapInfo files.
* Author: Stephane Villeneuve, stephane.v@videotron.ca
*
**********************************************************************
* Copyright (c) 1999-2002, Stephane Villeneuve
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
**********************************************************************
*
* $Log: mitab_feature_mif.cpp,v $
* Revision 1.31 2006/01/27 13:44:44 fwarmerdam
* fixed Mills.mif reading, crash at file end
*
* Revision 1.30 2006/01/26 21:26:36 fwarmerdam
* fixed bug with multi character delimeters in .mid file
*
* Revision 1.29 2005/10/04 19:36:10 dmorissette
* Added support for reading collections from MIF files (bug 1126)
*
* Revision 1.28 2005/10/04 15:44:31 dmorissette
* First round of support for Collection objects. Currently supports reading
* from .TAB/.MAP and writing to .MIF. Still lacks symbol support and write
* support. (Based in part on patch and docs from Jim Hope, bug 1126)
*
* Revision 1.27 2005/10/04 15:35:52 dmorissette
* Fixed an instance of hardcoded delimiter (",") in WriteRecordToMIDFile()
* (patch by KB Kieron, bug 1126)
*
* Revision 1.26 2005/07/14 16:15:05 jlacroix
* \n and \ are now unescaped internally.
*
* Revision 1.25 2003/12/19 07:52:34 fwarmerdam
* write 3d as 2d
*
* Revision 1.24 2002/11/27 22:51:52 daniel
* Bug 1631:Do not produce an error if .mid data records end with a stray ','
* Treat tabs (\t) as a blank space delimiter when reading .mif coordinates
*
* Revision 1.23 2002/10/29 21:09:20 warmerda
* Ensure that a blank line in a mid file is treated as one field containing
* an empty string.
*
* Revision 1.22 2002/04/26 14:16:49 julien
* Finishing the implementation of Multipoint (support for MIF)
*
* Revision 1.21 2002/03/26 01:48:40 daniel
* Added Multipoint object type (V650)
*
* Revision 1.20 2002/01/23 20:31:21 daniel
* Fixed warning produced by CPLAssert() in non-DEBUG mode.
*
* Revision 1.19 2001/06/25 01:50:42 daniel
* Fixed MIF Text object output: negative text angles were lost. Also use
* TABText::SetTextAngle() when reading MIF instead of setting class members
* directly so that negative angles get converted to the [0..360] range.
*
* Revision 1.18 2001/02/28 07:15:09 daniel
* Added support for text label line end point
*
* Revision 1.17 2001/01/22 16:03:58 warmerda
* expanded tabs
*
* Revision 1.16 2000/10/03 19:29:51 daniel
* Include OGR StyleString stuff (implemented by Stephane)
*
* Revision 1.15 2000/09/28 16:39:44 warmerda
* avoid warnings for unused, and unitialized variables
*
* Revision 1.14 2000/09/19 17:23:53 daniel
* Maintain and/or compute valid region and polyline center/label point
*
* Revision 1.13 2000/03/27 03:33:45 daniel
* Treat SYMBOL line as optional when reading TABPoint
*
* Revision 1.12 2000/02/28 16:56:32 daniel
* Support pen width in points (width values 11 to 2047)
*
* Revision 1.11 2000/01/15 22:30:44 daniel
* Switch to MIT/X-Consortium OpenSource license
*
* Revision 1.10 2000/01/14 23:51:37 daniel
* Fixed handling of "\n" in TABText strings... now the external interface
* of the lib returns and expects escaped "\"+"n" as described in MIF specs
*
* Revision 1.9 1999/12/19 17:37:14 daniel
* Fixed memory leaks
*
* Revision 1.8 1999/12/19 01:02:50 stephane
* Add a test on the CENTER information
*
* Revision 1.7 1999/12/18 23:23:23 stephane
* Change the format of the output double from %g to %.16g
*
* Revision 1.6 1999/12/18 08:22:57 daniel
* Removed stray break statement in PLINE MULTIPLE write code
*
* Revision 1.5 1999/12/18 07:21:30 daniel
* Fixed test on geometry type when writing OGRMultiLineStrings
*
* Revision 1.4 1999/12/18 07:11:57 daniel
* Return regions as OGRMultiPolygons instead of multiple rings OGRPolygons
*
* Revision 1.3 1999/12/16 17:16:44 daniel
* Use addRing/GeometryDirectly() (prevents leak), and rounded rectangles
* always return real corner radius from file even if it is bigger than MBR
*
* Revision 1.2 1999/11/11 01:22:05 stephane
* Remove DebugFeature call, Point Reading error, add IsValidFeature() to
* test correctly if we are on a feature
*
* Revision 1.1 1999/11/08 19:20:30 stephane
* First version
*
* Revision 1.1 1999/11/08 04:16:07 stephane
* First Revision
*
*
**********************************************************************/
#include "mitab.h"
#include "mitab_utils.h"
#include
/*=====================================================================
* class TABFeature
*====================================================================*/
/************************************************************************/
/* MIDTokenize() */
/* */
/* We implement a special tokenize function so we can handle */
/* multibyte delimeters (ie. MITAB bug 1266). */
/* */
/* http://bugzilla.maptools.org/show_bug.cgi?id=1266 */
/************************************************************************/
static char **MIDTokenize( const char *pszLine, const char *pszDelim )
{
char **papszResult = NULL;
int iChar, iTokenChar = 0, bInQuotes = FALSE;
char *pszToken = (char *) CPLMalloc(strlen(pszLine)+1);
int nDelimLen = strlen(pszDelim);
for( iChar = 0; pszLine[iChar] != '\0'; iChar++ )
{
if( bInQuotes && pszLine[iChar] == '\\' && pszLine[iChar+1] == '"' )
{
pszToken[iTokenChar++] = '"';
iChar++;
}
else if( pszLine[iChar] == '"' )
{
bInQuotes = !bInQuotes;
}
else if( !bInQuotes && strncmp(pszLine+iChar,pszDelim,nDelimLen) == 0 )
{
pszToken[iTokenChar++] = '\0';
papszResult = CSLAddString( papszResult, pszToken );
iChar += strlen(pszDelim) - 1;
iTokenChar = 0;
}
else
{
pszToken[iTokenChar++] = pszLine[iChar];
}
}
pszToken[iTokenChar++] = '\0';
papszResult = CSLAddString( papszResult, pszToken );
CPLFree( pszToken );
return papszResult;
}
/**********************************************************************
* TABFeature::ReadRecordFromMIDFile()
*
* This method is used to read the Record (Attributs) for all type of
* feature included in a mid/mif file.
*
* Returns 0 on success, -1 on error, in which case CPLError() will have
* been called.
**********************************************************************/
int TABFeature::ReadRecordFromMIDFile(MIDDATAFile *fp)
{
const char *pszLine;
char **papszToken;
int nFields,i;
nFields = GetFieldCount();
pszLine = fp->GetLastLine();
if (pszLine == NULL)
{
CPLError(CE_Failure, CPLE_FileIO,
"Unexpected EOF while reading attribute record from MID file.");
return -1;
}
papszToken = MIDTokenize( pszLine, fp->GetDelimiter() );
// Ensure that a blank line in a mid file is treated as one field
// containing an empty string.
if( nFields == 1 && CSLCount(papszToken) == 0 && pszLine[0] == '\0' )
papszToken = CSLAddString(papszToken,"");
// Make sure we found at least the expected number of field values.
// Note that it is possible to have a stray delimiter at the end of
// the line (mif/mid files from Geomedia), so don't produce an error
// if we find more tokens than expected.
if (CSLCount(papszToken) < nFields)
{
CSLDestroy(papszToken);
return -1;
}
for (i=0;iGetLine();
CSLDestroy(papszToken);
return 0;
}
/**********************************************************************
* TABFeature::WriteRecordToMIDFile()
*
* This methode is used to write the Record (Attributs) for all type
* of feature included in a mid file.
*
* Return 0 on success, -1 on error
**********************************************************************/
int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
{
int iField, numFields;
OGRFieldDefn *poFDefn = NULL;
CPLAssert(fp);
const char *delimiter = fp->GetDelimiter();
numFields = GetFieldCount();
for(iField=0; iFieldWriteLine(delimiter);
poFDefn = GetFieldDefnRef( iField );
switch(poFDefn->GetType())
{
case OFTString:
fp->WriteLine("\"%s\"",GetFieldAsString(iField));
break;
default:
fp->WriteLine("%s",GetFieldAsString(iField));
}
}
fp->WriteLine("\n");
return 0;
}
/**********************************************************************
* TABFeature::ReadGeometryFromMIFFile()
*
* In derived classes, this method should be reimplemented to
* fill the geometry and representation (color, etc...) part of the
* feature from the contents of the .MAP object pointed to by poMAPFile.
*
* It is assumed that before calling ReadGeometryFromMAPFile(), poMAPFile
* currently points to the beginning of a map object.
*
* The current implementation does nothing since instances of TABFeature
* objects contain no geometry (i.e. TAB_GEOM_NONE).
*
* Returns 0 on success, -1 on error, in which case CPLError() will have
* been called.
**********************************************************************/
int TABFeature::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
const char *pszLine;
/* Go to the first line of the next feature */
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
;
return 0;
}
/**********************************************************************
* TABFeature::WriteGeometryToMIFFile()
*
*
* In derived classes, this method should be reimplemented to
* write the geometry and representation (color, etc...) part of the
* feature to the .MAP object pointed to by poMAPFile.
*
* It is assumed that before calling WriteGeometryToMAPFile(), poMAPFile
* currently points to a valid map object.
*
* The current implementation does nothing since instances of TABFeature
* objects contain no geometry.
*
* Returns 0 on success, -1 on error, in which case CPLError() will have
* been called.
**********************************************************************/
int TABFeature::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
fp->WriteLine("NONE\n");
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeometry;
char **papszToken;
const char *pszLine;
double dfX,dfY;
papszToken = CSLTokenizeString2(fp->GetSavedLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=3)
{
CSLDestroy(papszToken);
return -1;
}
dfX = fp->GetXTrans(atof(papszToken[1]));
dfY = fp->GetYTrans(atof(papszToken[2]));
CSLDestroy(papszToken);
papszToken = NULL;
// Read optional SYMBOL line...
pszLine = fp->GetLastLine();
if( pszLine != NULL )
papszToken = CSLTokenizeStringComplex(pszLine," ,()\t",
TRUE,FALSE);
if (CSLCount(papszToken) == 4 && EQUAL(papszToken[0], "SYMBOL") )
{
SetSymbolNo(atoi(papszToken[1]));
SetSymbolColor(atoi(papszToken[2]));
SetSymbolSize(atoi(papszToken[3]));
}
CSLDestroy(papszToken);
papszToken = NULL;
// scan until we reach 1st line of next feature
// Since SYMBOL is optional, we have to test IsValidFeature() on that
// line as well.
while (pszLine && fp->IsValidFeature(pszLine) == FALSE)
{
pszLine = fp->GetLine();
}
poGeometry = new OGRPoint(dfX, dfY);
SetGeometryDirectly(poGeometry);
SetMBR(dfX, dfY, dfX, dfY);
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGRPoint *poPoint;
/*-----------------------------------------------------------------
* Fetch and validate geometry
*----------------------------------------------------------------*/
poGeom = GetGeometryRef();
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
poPoint = (OGRPoint*)poGeom;
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABPoint: Missing or Invalid Geometry!");
return -1;
}
fp->WriteLine("Point %.16g %.16g\n",poPoint->getX(),poPoint->getY());
fp->WriteLine(" Symbol (%d,%d,%d)\n",GetSymbolNo(),GetSymbolColor(),
GetSymbolSize());
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABFontPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeometry;
char **papszToken;
const char *pszLine;
double dfX,dfY;
papszToken = CSLTokenizeString2(fp->GetSavedLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=3)
{
CSLDestroy(papszToken);
return -1;
}
dfX = fp->GetXTrans(atof(papszToken[1]));
dfY = fp->GetYTrans(atof(papszToken[2]));
CSLDestroy(papszToken);
papszToken = CSLTokenizeStringComplex(fp->GetLastLine()," ,()\t",
TRUE,FALSE);
if (CSLCount(papszToken) !=7)
{
CSLDestroy(papszToken);
return -1;
}
SetSymbolNo(atoi(papszToken[1]));
SetSymbolColor(atoi(papszToken[2]));
SetSymbolSize(atoi(papszToken[3]));
SetFontName(papszToken[4]);
SetFontStyleMIFValue(atoi(papszToken[5]));
SetSymbolAngle(atof(papszToken[6]));
CSLDestroy(papszToken);
poGeometry = new OGRPoint(dfX, dfY);
SetGeometryDirectly(poGeometry);
SetMBR(dfX, dfY, dfX, dfY);
/* Go to the first line of the next feature */
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
;
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABFontPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGRPoint *poPoint;
/*-----------------------------------------------------------------
* Fetch and validate geometry
*----------------------------------------------------------------*/
poGeom = GetGeometryRef();
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
poPoint = (OGRPoint*)poGeom;
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABFontPoint: Missing or Invalid Geometry!");
return -1;
}
fp->WriteLine("Point %.16g %.16g\n",poPoint->getX(),poPoint->getY());
fp->WriteLine(" Symbol (%d,%d,%d,\"%s\",%d,%.16g)\n",
GetSymbolNo(),GetSymbolColor(),
GetSymbolSize(),GetFontNameRef(),GetFontStyleMIFValue(),
GetSymbolAngle());
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABCustomPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeometry;
char **papszToken;
const char *pszLine;
double dfX,dfY;
papszToken = CSLTokenizeString2(fp->GetSavedLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=3)
{
CSLDestroy(papszToken);
return -1;
}
dfX = fp->GetXTrans(atof(papszToken[1]));
dfY = fp->GetYTrans(atof(papszToken[2]));
CSLDestroy(papszToken);
papszToken = CSLTokenizeStringComplex(fp->GetLastLine()," ,()\t",
TRUE,FALSE);
if (CSLCount(papszToken) !=5)
{
CSLDestroy(papszToken);
return -1;
}
SetFontName(papszToken[1]);
SetSymbolColor(atoi(papszToken[2]));
SetSymbolSize(atoi(papszToken[3]));
m_nCustomStyle = atoi(papszToken[4]);
CSLDestroy(papszToken);
poGeometry = new OGRPoint(dfX, dfY);
SetGeometryDirectly(poGeometry);
SetMBR(dfX, dfY, dfX, dfY);
/* Go to the first line of the next feature */
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
;
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABCustomPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGRPoint *poPoint;
/*-----------------------------------------------------------------
* Fetch and validate geometry
*----------------------------------------------------------------*/
poGeom = GetGeometryRef();
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
poPoint = (OGRPoint*)poGeom;
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABCustomPoint: Missing or Invalid Geometry!");
return -1;
}
fp->WriteLine("Point %.16g %.16g\n",poPoint->getX(),poPoint->getY());
fp->WriteLine(" Symbol (\"%s\",%d,%d,%d)\n",GetFontNameRef(),
GetSymbolColor(), GetSymbolSize(),m_nCustomStyle);
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABPolyline::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
const char *pszLine;
char **papszToken;
OGRLineString *poLine;
OGRMultiLineString *poMultiLine;
GBool bMultiple = FALSE;
int nNumPoints,nNumSec=0,i,j;
OGREnvelope sEnvelope;
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) < 1)
{
CSLDestroy(papszToken);
return -1;
}
if (EQUALN(papszToken[0],"LINE",4))
{
if (CSLCount(papszToken) != 5)
return -1;
poLine = new OGRLineString();
poLine->setNumPoints(2);
poLine->setPoint(0, fp->GetXTrans(atof(papszToken[1])),
fp->GetYTrans(atof(papszToken[2])));
poLine->setPoint(1, fp->GetXTrans(atof(papszToken[3])),
fp->GetYTrans(atof(papszToken[4])));
SetGeometryDirectly(poLine);
poLine->getEnvelope(&sEnvelope);
SetMBR(sEnvelope.MinX, sEnvelope.MinY,sEnvelope.MaxX,sEnvelope.MaxY);
}
else if (EQUALN(papszToken[0],"PLINE",5))
{
switch (CSLCount(papszToken))
{
case 1:
bMultiple = FALSE;
pszLine = fp->GetLine();
nNumPoints = atoi(pszLine);
break;
case 2:
bMultiple = FALSE;
nNumPoints = atoi(papszToken[1]);
break;
case 3:
if (EQUALN(papszToken[1],"MULTIPLE",8))
{
bMultiple = TRUE;
nNumSec = atoi(papszToken[2]);
pszLine = fp->GetLine();
nNumPoints = atoi(pszLine);
break;
}
else
{
CSLDestroy(papszToken);
return -1;
}
break;
case 4:
if (EQUALN(papszToken[1],"MULTIPLE",8))
{
bMultiple = TRUE;
nNumSec = atoi(papszToken[2]);
nNumPoints = atoi(papszToken[3]);
break;
}
else
{
CSLDestroy(papszToken);
return -1;
}
break;
default:
CSLDestroy(papszToken);
return -1;
break;
}
if (bMultiple)
{
poMultiLine = new OGRMultiLineString();
for (j=0;jGetLine());
if (nNumPoints < 2)
{
CPLError(CE_Failure, CPLE_FileIO,
"Invalid number of vertices (%d) in PLINE "
"MULTIPLE segment.", nNumPoints);
return -1;
}
poLine->setNumPoints(nNumPoints);
for (i=0;iGetLine(),
" \t", CSLT_HONOURSTRINGS);
poLine->setPoint(i,fp->GetXTrans(atof(papszToken[0])),
fp->GetYTrans(atof(papszToken[1])));
}
if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
{
CPLAssert(FALSE); // Just in case OGR is modified
}
}
if (SetGeometryDirectly(poMultiLine) != OGRERR_NONE)
{
CPLAssert(FALSE); // Just in case OGR is modified
}
poMultiLine->getEnvelope(&sEnvelope);
SetMBR(sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX,sEnvelope.MaxY);
}
else
{
poLine = new OGRLineString();
poLine->setNumPoints(nNumPoints);
for (i=0;iGetLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) != 2)
return -1;
poLine->setPoint(i,fp->GetXTrans(atof(papszToken[0])),
fp->GetYTrans(atof(papszToken[1])));
}
SetGeometryDirectly(poLine);
poLine->getEnvelope(&sEnvelope);
SetMBR(sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX,sEnvelope.MaxY);
}
}
CSLDestroy(papszToken);
papszToken = NULL;
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
TRUE,FALSE);
if (CSLCount(papszToken) >= 1)
{
if (EQUALN(papszToken[0],"PEN",3))
{
if (CSLCount(papszToken) == 4)
{
SetPenWidthMIF(atoi(papszToken[1]));
SetPenPattern(atoi(papszToken[2]));
SetPenColor(atoi(papszToken[3]));
}
}
else if (EQUALN(papszToken[0],"SMOOTH",6))
{
m_bSmooth = TRUE;
}
}
CSLDestroy(papszToken);
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABPolyline::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGRMultiLineString *poMultiLine = NULL;
OGRLineString *poLine = NULL;
int nNumPoints,i;
/*-----------------------------------------------------------------
* Fetch and validate geometry
*----------------------------------------------------------------*/
poGeom = GetGeometryRef();
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
{
/*-------------------------------------------------------------
* Simple polyline
*------------------------------------------------------------*/
poLine = (OGRLineString*)poGeom;
nNumPoints = poLine->getNumPoints();
if (nNumPoints == 2)
{
fp->WriteLine("Line %.16g %.16g %.16g %.16g\n",poLine->getX(0),poLine->getY(0),
poLine->getX(1),poLine->getY(1));
}
else
{
fp->WriteLine("Pline %d\n",nNumPoints);
for (i=0;iWriteLine("%.16g %.16g\n",poLine->getX(i),poLine->getY(i));
}
}
}
else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
{
/*-------------------------------------------------------------
* Multiple polyline... validate all components
*------------------------------------------------------------*/
int iLine, numLines;
poMultiLine = (OGRMultiLineString*)poGeom;
numLines = poMultiLine->getNumGeometries();
fp->WriteLine("PLINE MULTIPLE %d\n", numLines);
for(iLine=0; iLine < numLines; iLine++)
{
poGeom = poMultiLine->getGeometryRef(iLine);
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
{
poLine = (OGRLineString*)poGeom;
nNumPoints = poLine->getNumPoints();
fp->WriteLine(" %d\n",nNumPoints);
for (i=0;iWriteLine("%.16g %.16g\n",poLine->getX(i),poLine->getY(i));
}
}
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABPolyline: Object contains an invalid Geometry!");
}
}
}
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABPolyline: Missing or Invalid Geometry!");
}
if (GetPenPattern())
fp->WriteLine(" Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
GetPenColor());
if (m_bSmooth)
fp->WriteLine(" Smooth\n");
return 0;
}
/**********************************************************************
* TABRegion::ReadGeometryFromMIFFile()
*
* Fill the geometry and representation (color, etc...) part of the
* feature from the contents of the .MIF file
*
* Returns 0 on success, -1 on error, in which case CPLError() will have
* been called.
**********************************************************************/
int TABRegion::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
double dX, dY;
OGRLinearRing *poRing;
OGRGeometry *poGeometry = NULL;
OGRPolygon *poPolygon = NULL;
OGRMultiPolygon *poMultiPolygon = NULL;
int i,iSection, numLineSections=0;
char **papszToken;
const char *pszLine;
OGREnvelope sEnvelope;
m_bSmooth = FALSE;
/*=============================================================
* REGION (Similar to PLINE MULTIPLE)
*============================================================*/
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) ==2)
numLineSections = atoi(papszToken[1]);
CSLDestroy(papszToken);
papszToken = NULL;
/*-------------------------------------------------------------
* For 1-ring regions, we return an OGRPolygon with one single
* OGRLinearRing geometry.
*
* REGIONs with multiple rings are returned as OGRMultiPolygon
* instead of as OGRPolygons since OGRPolygons require that the
* first ring be the outer ring, and the other all be inner
* rings, but this is not guaranteed inside MapInfo files.
*------------------------------------------------------------*/
if (numLineSections > 1)
poGeometry = poMultiPolygon = new OGRMultiPolygon;
else
poGeometry = NULL; // Will be set later
for(iSection=0; iSectionGetLine()) != NULL)
{
numSectionVertices = atoi(pszLine);
}
poRing = new OGRLinearRing();
poRing->setNumPoints(numSectionVertices);
for(i=0; iGetLine();
if (pszLine)
{
papszToken = CSLTokenizeStringComplex(pszLine," ,\t",
TRUE,FALSE);
if (CSLCount(papszToken) == 2)
{
dX = fp->GetXTrans(atof(papszToken[0]));
dY = fp->GetYTrans(atof(papszToken[1]));
poRing->setPoint(i, dX, dY);
}
CSLDestroy(papszToken);
papszToken = NULL;
}
}
poPolygon->addRingDirectly(poRing);
poRing = NULL;
if (numLineSections > 1)
poMultiPolygon->addGeometryDirectly(poPolygon);
else
poGeometry = poPolygon;
poPolygon = NULL;
}
SetGeometryDirectly(poGeometry);
poGeometry->getEnvelope(&sEnvelope);
SetMBR(sEnvelope.MinX, sEnvelope.MinY, sEnvelope.MaxX, sEnvelope.MaxY);
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
TRUE,FALSE);
if (CSLCount(papszToken) > 1)
{
if (EQUALN(papszToken[0],"PEN",3))
{
if (CSLCount(papszToken) == 4)
{
SetPenWidthMIF(atoi(papszToken[1]));
SetPenPattern(atoi(papszToken[2]));
SetPenColor(atoi(papszToken[3]));
}
}
else if (EQUALN(papszToken[0],"BRUSH", 5))
{
if (CSLCount(papszToken) >= 3)
{
SetBrushFGColor(atoi(papszToken[2]));
SetBrushPattern(atoi(papszToken[1]));
if (CSLCount(papszToken) == 4)
SetBrushBGColor(atoi(papszToken[3]));
else
SetBrushTransparent(TRUE);
}
}
else if (EQUALN(papszToken[0],"CENTER",6))
{
if (CSLCount(papszToken) == 3)
{
SetCenter(fp->GetXTrans(atof(papszToken[1])),
fp->GetYTrans(atof(papszToken[2])) );
}
}
}
CSLDestroy(papszToken);
papszToken = NULL;
}
return 0;
}
/**********************************************************************
* TABRegion::WriteGeometryToMIFFile()
*
* Write the geometry and representation (color, etc...) part of the
* feature to the .MIF file
*
* Returns 0 on success, -1 on error, in which case CPLError() will have
* been called.
**********************************************************************/
int TABRegion::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
poGeom = GetGeometryRef();
if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon ) )
{
/*=============================================================
* REGIONs are similar to PLINE MULTIPLE
*
* We accept both OGRPolygons (with one or multiple rings) and
* OGRMultiPolygons as input.
*============================================================*/
int i, iRing, numRingsTotal, numPoints;
numRingsTotal = GetNumRings();
fp->WriteLine("Region %d\n",numRingsTotal);
for(iRing=0; iRing < numRingsTotal; iRing++)
{
OGRLinearRing *poRing;
poRing = GetRingRef(iRing);
if (poRing == NULL)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABRegion: Object Geometry contains NULL rings!");
return -1;
}
numPoints = poRing->getNumPoints();
fp->WriteLine(" %d\n",numPoints);
for(i=0; iWriteLine("%.16g %.16g\n",poRing->getX(i), poRing->getY(i));
}
}
if (GetPenPattern())
fp->WriteLine(" Pen (%d,%d,%d)\n",
GetPenWidthMIF(),GetPenPattern(),
GetPenColor());
if (GetBrushPattern())
{
if (GetBrushTransparent() == 0)
fp->WriteLine(" Brush (%d,%d,%d)\n",GetBrushPattern(),
GetBrushFGColor(),GetBrushBGColor());
else
fp->WriteLine(" Brush (%d,%d)\n",GetBrushPattern(),
GetBrushFGColor());
}
if (m_bCenterIsSet)
{
fp->WriteLine(" Center %.16g %.16g\n", m_dCenterX, m_dCenterY);
}
}
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABRegion: Object contains an invalid Geometry!");
return -1;
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABRectangle::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
const char *pszLine;
char **papszToken;
double dXMin, dYMin, dXMax, dYMax;
OGRPolygon *poPolygon;
OGRLinearRing *poRing;
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) < 5)
{
CSLDestroy(papszToken);
return -1;
}
dXMin = fp->GetXTrans(atof(papszToken[1]));
dXMax = fp->GetXTrans(atof(papszToken[3]));
dYMin = fp->GetYTrans(atof(papszToken[2]));
dYMax = fp->GetYTrans(atof(papszToken[4]));
/*-----------------------------------------------------------------
* Call SetMBR() and GetMBR() now to make sure that min values are
* really smaller than max values.
*----------------------------------------------------------------*/
SetMBR(dXMin, dYMin, dXMax, dYMax);
GetMBR(dXMin, dYMin, dXMax, dYMax);
m_bRoundCorners = FALSE;
m_dRoundXRadius = 0.0;
m_dRoundYRadius = 0.0;
if (EQUALN(papszToken[0],"ROUNDRECT",9))
{
m_bRoundCorners = TRUE;
if (CSLCount(papszToken) == 6)
m_dRoundXRadius = m_dRoundYRadius = atof(papszToken[5])/2.0;
else
{
CSLDestroy(papszToken);
papszToken = CSLTokenizeString2(fp->GetLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=1 )
m_dRoundXRadius = m_dRoundYRadius = atof(papszToken[1])/2.0;
}
}
CSLDestroy(papszToken);
papszToken = NULL;
/*-----------------------------------------------------------------
* Create and fill geometry object
*----------------------------------------------------------------*/
poPolygon = new OGRPolygon;
poRing = new OGRLinearRing();
if (m_bRoundCorners && m_dRoundXRadius != 0.0 && m_dRoundYRadius != 0.0)
{
/*-------------------------------------------------------------
* For rounded rectangles, we generate arcs with 45 line
* segments for each corner. We start with lower-left corner
* and proceed counterclockwise
* We also have to make sure that rounding radius is not too
* large for the MBR however, we
* always return the true X/Y radius (not adjusted) since this
* is the way MapInfo seems to do it when a radius bigger than
* the MBR is passed from TBA to MIF.
*------------------------------------------------------------*/
double dXRadius = MIN(m_dRoundXRadius, (dXMax-dXMin)/2.0);
double dYRadius = MIN(m_dRoundYRadius, (dYMax-dYMin)/2.0);
TABGenerateArc(poRing, 45,
dXMin + dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
PI, 3.0*PI/2.0);
TABGenerateArc(poRing, 45,
dXMax - dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
3.0*PI/2.0, 2.0*PI);
TABGenerateArc(poRing, 45,
dXMax - dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
0.0, PI/2.0);
TABGenerateArc(poRing, 45,
dXMin + dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
PI/2.0, PI);
TABCloseRing(poRing);
}
else
{
poRing->addPoint(dXMin, dYMin);
poRing->addPoint(dXMax, dYMin);
poRing->addPoint(dXMax, dYMax);
poRing->addPoint(dXMin, dYMax);
poRing->addPoint(dXMin, dYMin);
}
poPolygon->addRingDirectly(poRing);
SetGeometryDirectly(poPolygon);
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
TRUE,FALSE);
if (CSLCount(papszToken) > 1)
{
if (EQUALN(papszToken[0],"PEN",3))
{
if (CSLCount(papszToken) == 4)
{
SetPenWidthMIF(atoi(papszToken[1]));
SetPenPattern(atoi(papszToken[2]));
SetPenColor(atoi(papszToken[3]));
}
}
else if (EQUALN(papszToken[0],"BRUSH", 5))
{
if (CSLCount(papszToken) >=3)
{
SetBrushFGColor(atoi(papszToken[2]));
SetBrushPattern(atoi(papszToken[1]));
if (CSLCount(papszToken) == 4)
SetBrushBGColor(atoi(papszToken[3]));
else
SetBrushTransparent(TRUE);
}
}
}
CSLDestroy(papszToken);
papszToken = NULL;
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABRectangle::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGRPolygon *poPolygon;
OGREnvelope sEnvelope;
/*-----------------------------------------------------------------
* Fetch and validate geometry
*----------------------------------------------------------------*/
poGeom = GetGeometryRef();
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
poPolygon = (OGRPolygon*)poGeom;
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABRectangle: Missing or Invalid Geometry!");
return -1;
}
/*-----------------------------------------------------------------
* Note that we will simply use the rectangle's MBR and don't really
* read the polygon geometry... this should be OK unless the
* polygon geometry was not really a rectangle.
*----------------------------------------------------------------*/
poPolygon->getEnvelope(&sEnvelope);
if (m_bRoundCorners == TRUE)
{
fp->WriteLine("Roundrect %.16g %.16g %.16g %.16g %.16g\n",
sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX, sEnvelope.MaxY, m_dRoundXRadius*2.0);
}
else
{
fp->WriteLine("Rect %.16g %.16g %.16g %.16g\n",
sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX, sEnvelope.MaxY);
}
if (GetPenPattern())
fp->WriteLine(" Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
GetPenColor());
if (GetBrushPattern())
{
if (GetBrushTransparent() == 0)
fp->WriteLine(" Brush (%d,%d,%d)\n",GetBrushPattern(),
GetBrushFGColor(),GetBrushBGColor());
else
fp->WriteLine(" Brush (%d,%d)\n",GetBrushPattern(),
GetBrushFGColor());
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABEllipse::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
const char *pszLine;
char **papszToken;
double dXMin, dYMin, dXMax, dYMax;
OGRPolygon *poPolygon;
OGRLinearRing *poRing;
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) != 5)
{
CSLDestroy(papszToken);
return -1;
}
dXMin = fp->GetXTrans(atof(papszToken[1]));
dXMax = fp->GetXTrans(atof(papszToken[3]));
dYMin = fp->GetYTrans(atof(papszToken[2]));
dYMax = fp->GetYTrans(atof(papszToken[4]));
CSLDestroy(papszToken);
papszToken = NULL;
/*-----------------------------------------------------------------
* Save info about the ellipse def. inside class members
*----------------------------------------------------------------*/
m_dCenterX = (dXMin + dXMax) / 2.0;
m_dCenterY = (dYMin + dYMax) / 2.0;
m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
SetMBR(dXMin, dYMin, dXMax, dYMax);
/*-----------------------------------------------------------------
* Create and fill geometry object
*----------------------------------------------------------------*/
poPolygon = new OGRPolygon;
poRing = new OGRLinearRing();
/*-----------------------------------------------------------------
* For the OGR geometry, we generate an ellipse with 2 degrees line
* segments.
*----------------------------------------------------------------*/
TABGenerateArc(poRing, 180,
m_dCenterX, m_dCenterY,
m_dXRadius, m_dYRadius,
0.0, 2.0*PI);
TABCloseRing(poRing);
poPolygon->addRingDirectly(poRing);
SetGeometryDirectly(poPolygon);
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
TRUE,FALSE);
if (CSLCount(papszToken) > 1)
{
if (EQUALN(papszToken[0],"PEN",3))
{
if (CSLCount(papszToken) == 4)
{
SetPenWidthMIF(atoi(papszToken[1]));
SetPenPattern(atoi(papszToken[2]));
SetPenColor(atoi(papszToken[3]));
}
}
else if (EQUALN(papszToken[0],"BRUSH", 5))
{
if (CSLCount(papszToken) >= 3)
{
SetBrushFGColor(atoi(papszToken[2]));
SetBrushPattern(atoi(papszToken[1]));
if (CSLCount(papszToken) == 4)
SetBrushBGColor(atoi(papszToken[3]));
else
SetBrushTransparent(TRUE);
}
}
}
CSLDestroy(papszToken);
papszToken = NULL;
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABEllipse::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGREnvelope sEnvelope;
poGeom = GetGeometryRef();
if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
(poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
poGeom->getEnvelope(&sEnvelope);
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABEllipse: Missing or Invalid Geometry!");
return -1;
}
fp->WriteLine("Ellipse %.16g %.16g %.16g %.16g\n",sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX,sEnvelope.MaxY);
if (GetPenPattern())
fp->WriteLine(" Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
GetPenColor());
if (GetBrushPattern())
{
if (GetBrushTransparent() == 0)
fp->WriteLine(" Brush (%d,%d,%d)\n",GetBrushPattern(),
GetBrushFGColor(),GetBrushBGColor());
else
fp->WriteLine(" Brush (%d,%d)\n",GetBrushPattern(),
GetBrushFGColor());
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABArc::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
const char *pszLine;
OGRLineString *poLine;
char **papszToken;
double dXMin,dXMax, dYMin,dYMax;
int numPts;
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) == 5)
{
dXMin = fp->GetXTrans(atof(papszToken[1]));
dXMax = fp->GetXTrans(atof(papszToken[3]));
dYMin = fp->GetYTrans(atof(papszToken[2]));
dYMax = fp->GetYTrans(atof(papszToken[4]));
CSLDestroy(papszToken);
papszToken = CSLTokenizeString2(fp->GetLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) != 2)
{
CSLDestroy(papszToken);
return -1;
}
m_dStartAngle = atof(papszToken[0]);
m_dEndAngle = atof(papszToken[1]);
}
else if (CSLCount(papszToken) == 7)
{
dXMin = fp->GetXTrans(atof(papszToken[1]));
dXMax = fp->GetXTrans(atof(papszToken[3]));
dYMin = fp->GetYTrans(atof(papszToken[2]));
dYMax = fp->GetYTrans(atof(papszToken[4]));
m_dStartAngle = atof(papszToken[5]);
m_dEndAngle = atof(papszToken[6]);
}
else
{
CSLDestroy(papszToken);
return -1;
}
CSLDestroy(papszToken);
papszToken = NULL;
/*-------------------------------------------------------------
* Start/End angles
* Since the angles are specified for integer coordinates, and
* that these coordinates can have the X axis reversed, we have to
* adjust the angle values for the change in the X axis
* direction.
*
* This should be necessary only when X axis is flipped.
* __TODO__ Why is order of start/end values reversed as well???
*------------------------------------------------------------*/
if (fp->GetXMultiplier() <= 0.0)
{
m_dStartAngle = 360.0 - m_dStartAngle;
m_dEndAngle = 360.0 - m_dEndAngle;
}
m_dCenterX = (dXMin + dXMax) / 2.0;
m_dCenterY = (dYMin + dYMax) / 2.0;
m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
/*-----------------------------------------------------------------
* Create and fill geometry object
* For the OGR geometry, we generate an arc with 2 degrees line
* segments.
*----------------------------------------------------------------*/
poLine = new OGRLineString;
if (m_dEndAngle < m_dStartAngle)
numPts = (int) ABS( ((m_dEndAngle+360.0)-m_dStartAngle)/2.0 ) + 1;
else
numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2.0 ) + 1;
numPts = MAX(2, numPts);
TABGenerateArc(poLine, numPts,
m_dCenterX, m_dCenterY,
m_dXRadius, m_dYRadius,
m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
SetMBR(dXMin, dYMin, dXMax, dYMax);
SetGeometryDirectly(poLine);
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
TRUE,FALSE);
if (CSLCount(papszToken) > 1)
{
if (EQUALN(papszToken[0],"PEN",3))
{
if (CSLCount(papszToken) == 4)
{
SetPenWidthMIF(atoi(papszToken[1]));
SetPenPattern(atoi(papszToken[2]));
SetPenColor(atoi(papszToken[3]));
}
}
}
CSLDestroy(papszToken);
papszToken = NULL;
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABArc::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
/*-------------------------------------------------------------
* Start/End angles
* Since we ALWAYS produce files in quadrant 1 then we can
* ignore the special angle conversion required by flipped axis.
*------------------------------------------------------------*/
// Write the Arc's actual MBR
fp->WriteLine("Arc %.16g %.16g %.16g %.16g\n", m_dCenterX-m_dXRadius,
m_dCenterY-m_dYRadius, m_dCenterX+m_dXRadius,
m_dCenterY+m_dYRadius);
fp->WriteLine(" %.16g %.16g\n",m_dStartAngle,m_dEndAngle);
if (GetPenPattern())
fp->WriteLine(" Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
GetPenColor());
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABText::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
double dXMin, dYMin, dXMax, dYMax;
OGRGeometry *poGeometry;
const char *pszLine;
char **papszToken;
const char *pszString;
char *pszTmpString;
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) == 1)
{
CSLDestroy(papszToken);
papszToken = CSLTokenizeString2(fp->GetLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) != 1)
{
CSLDestroy(papszToken);
return -1;
}
else
pszString = papszToken[0];
}
else if (CSLCount(papszToken) == 2)
{
pszString = papszToken[1];
}
else
{
CSLDestroy(papszToken);
return -1;
}
/*-------------------------------------------------------------
* Note: The text string may contain escaped "\n" chars, and we
* sstore them in memory in the UnEscaped form to be OGR
* compliant. See Maptools bug 1107 for more details.
*------------------------------------------------------------*/
pszTmpString = CPLStrdup(pszString);
m_pszString = TABUnEscapeString(pszTmpString, TRUE);
if (pszTmpString != m_pszString)
CPLFree(pszTmpString);
CSLDestroy(papszToken);
papszToken = CSLTokenizeString2(fp->GetLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) != 4)
{
CSLDestroy(papszToken);
return -1;
}
else
{
dXMin = fp->GetXTrans(atof(papszToken[0]));
dXMax = fp->GetXTrans(atof(papszToken[2]));
dYMin = fp->GetYTrans(atof(papszToken[1]));
dYMax = fp->GetYTrans(atof(papszToken[3]));
m_dHeight = dYMax - dYMin; //SetTextBoxHeight(dYMax - dYMin);
m_dWidth = dXMax - dXMin; //SetTextBoxWidth(dXMax - dXMin);
if (m_dHeight <0.0)
m_dHeight*=-1.0;
if (m_dWidth <0.0)
m_dWidth*=-1.0;
}
CSLDestroy(papszToken);
papszToken = NULL;
/* Set/retrieve the MBR to make sure Mins are smaller than Maxs
*/
SetMBR(dXMin, dYMin, dXMax, dYMax);
GetMBR(dXMin, dYMin, dXMax, dYMax);
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
TRUE,FALSE);
if (CSLCount(papszToken) > 1)
{
if (EQUALN(papszToken[0],"FONT",4))
{
if (CSLCount(papszToken) >= 5)
{
SetFontName(papszToken[1]);
SetFontFGColor(atoi(papszToken[4]));
if (CSLCount(papszToken) ==6)
{
SetFontBGColor(atoi(papszToken[5]));
SetFontStyleMIFValue(atoi(papszToken[2]),TRUE);
}
else
SetFontStyleMIFValue(atoi(papszToken[2]));
// papsztoken[3] = Size ???
}
}
else if (EQUALN(papszToken[0],"SPACING",7))
{
if (CSLCount(papszToken) >= 2)
{
if (EQUALN(papszToken[1],"2",1))
{
SetTextSpacing(TABTSDouble);
}
else if (EQUALN(papszToken[1],"1.5",3))
{
SetTextSpacing(TABTS1_5);
}
}
if (CSLCount(papszToken) == 7)
{
if (EQUALN(papszToken[2],"LAbel",5))
{
if (EQUALN(papszToken[4],"simple",6))
{
SetTextLineType(TABTLSimple);
SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[5])),
fp->GetYTrans(atof(papszToken[6])));
}
else if (EQUALN(papszToken[4],"arrow", 5))
{
SetTextLineType(TABTLArrow);
SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[5])),
fp->GetYTrans(atof(papszToken[6])));
}
}
}
}
else if (EQUALN(papszToken[0],"Justify",7))
{
if (CSLCount(papszToken) == 2)
{
if (EQUALN( papszToken[1],"Center",6))
{
SetTextJustification(TABTJCenter);
}
else if (EQUALN( papszToken[1],"Right",5))
{
SetTextJustification(TABTJRight);
}
}
}
else if (EQUALN(papszToken[0],"Angle",5))
{
if (CSLCount(papszToken) == 2)
{
SetTextAngle(atof(papszToken[1]));
}
}
else if (EQUALN(papszToken[0],"LAbel",5))
{
if (CSLCount(papszToken) == 5)
{
if (EQUALN(papszToken[2],"simple",6))
{
SetTextLineType(TABTLSimple);
SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[3])),
fp->GetYTrans(atof(papszToken[4])));
}
else if (EQUALN(papszToken[2],"arrow", 5))
{
SetTextLineType(TABTLArrow);
SetTextLineEndPoint(fp->GetXTrans(atof(papszToken[3])),
fp->GetYTrans(atof(papszToken[4])));
}
}
// What I do with the XY coordonate
}
}
CSLDestroy(papszToken);
papszToken = NULL;
}
/*-----------------------------------------------------------------
* Create an OGRPoint Geometry...
* The point X,Y values will be the coords of the lower-left corner before
* rotation is applied. (Note that the rotation in MapInfo is done around
* the upper-left corner)
* We need to calculate the true lower left corner of the text based
* on the MBR after rotation, the text height and the rotation angle.
*---------------------------------------------------------------- */
double dCos, dSin, dX, dY;
dSin = sin(m_dAngle*PI/180.0);
dCos = cos(m_dAngle*PI/180.0);
if (dSin > 0.0 && dCos > 0.0)
{
dX = dXMin + m_dHeight * dSin;
dY = dYMin;
}
else if (dSin > 0.0 && dCos < 0.0)
{
dX = dXMax;
dY = dYMin - m_dHeight * dCos;
}
else if (dSin < 0.0 && dCos < 0.0)
{
dX = dXMax + m_dHeight * dSin;
dY = dYMax;
}
else // dSin < 0 && dCos > 0
{
dX = dXMin;
dY = dYMax - m_dHeight * dCos;
}
poGeometry = new OGRPoint(dX, dY);
SetGeometryDirectly(poGeometry);
/*-----------------------------------------------------------------
* Compute Text Width: the width of the Text MBR before rotation
* in ground units... unfortunately this value is not stored in the
* file, so we have to compute it with the MBR after rotation and
* the height of the MBR before rotation:
* With W = Width of MBR before rotation
* H = Height of MBR before rotation
* dX = Width of MBR after rotation
* dY = Height of MBR after rotation
* teta = rotation angle
*
* For [-PI/4..teta..+PI/4] or [3*PI/4..teta..5*PI/4], we'll use:
* W = H * (dX - H * sin(teta)) / (H * cos(teta))
*
* and for other teta values, use:
* W = H * (dY - H * cos(teta)) / (H * sin(teta))
*---------------------------------------------------------------- */
dSin = ABS(dSin);
dCos = ABS(dCos);
if (m_dHeight == 0.0)
m_dWidth = 0.0;
else if ( dCos > dSin )
m_dWidth = m_dHeight * ((dXMax-dXMin) - m_dHeight*dSin) /
(m_dHeight*dCos);
else
m_dWidth = m_dHeight * ((dYMax-dYMin) - m_dHeight*dCos) /
(m_dHeight*dSin);
m_dWidth = ABS(m_dWidth);
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABText::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
double dXMin,dYMin,dXMax,dYMax;
char *pszTmpString;
/*-------------------------------------------------------------
* Note: The text string may contain unescaped "\n" chars or
* "\\" chars and we expect to receive them in an unescaped
* form. Those characters are unescaped in memory to be like
* other OGR drivers. See MapTools bug 1107 for more details.
*------------------------------------------------------------*/
pszTmpString = TABEscapeString(m_pszString);
if(pszTmpString == NULL)
fp->WriteLine("Text \"\"\n" );
else
fp->WriteLine("Text \"%s\"\n", pszTmpString );
if (pszTmpString != m_pszString)
CPLFree(pszTmpString);
// UpdateTextMBR();
GetMBR(dXMin, dYMin, dXMax, dYMax);
fp->WriteLine(" %.16g %.16g %.16g %.16g\n",dXMin, dYMin,dXMax, dYMax);
if (IsFontBGColorUsed())
fp->WriteLine(" Font (\"%s\",%d,%d,%d,%d)\n", GetFontNameRef(),
GetFontStyleMIFValue(),0,GetFontFGColor(),
GetFontBGColor());
else
fp->WriteLine(" Font (\"%s\",%d,%d,%d)\n", GetFontNameRef(),
GetFontStyleMIFValue(),0,GetFontFGColor());
switch (GetTextSpacing())
{
case TABTS1_5:
fp->WriteLine(" Spacing 1.5\n");
break;
case TABTSDouble:
fp->WriteLine(" Spacing 2.0\n");
break;
case TABTSSingle:
default:
break;
}
switch (GetTextJustification())
{
case TABTJCenter:
fp->WriteLine(" Justify Center\n");
break;
case TABTJRight:
fp->WriteLine(" Justify Right\n");
break;
case TABTJLeft:
default:
break;
}
if (ABS(GetTextAngle()) > 0.000001)
fp->WriteLine(" Angle %.16g\n",GetTextAngle());
switch (GetTextLineType())
{
case TABTLSimple:
if (m_bLineEndSet)
fp->WriteLine(" Label Line Simple %.16g %.16g \n",
m_dfLineEndX, m_dfLineEndY );
break;
case TABTLArrow:
if (m_bLineEndSet)
fp->WriteLine(" Label Line Arrow %.16g %.16g \n",
m_dfLineEndX, m_dfLineEndY );
break;
case TABTLNoLine:
default:
break;
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABMultiPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
OGRPoint *poPoint;
OGRMultiPoint *poMultiPoint;
char **papszToken;
const char *pszLine;
int nNumPoint, i;
double dfX,dfY;
OGREnvelope sEnvelope;
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=2)
{
CSLDestroy(papszToken);
return -1;
}
nNumPoint = atoi(papszToken[1]);
poMultiPoint = new OGRMultiPoint;
CSLDestroy(papszToken);
papszToken = NULL;
// Get each point and add them to the multipoint feature
for(i=0; iGetLine();
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=2)
{
CSLDestroy(papszToken);
return -1;
}
dfX = fp->GetXTrans(atof(papszToken[0]));
dfY = fp->GetXTrans(atof(papszToken[1]));
poPoint = new OGRPoint(dfX, dfY);
if ( poMultiPoint->addGeometryDirectly( poPoint ) != OGRERR_NONE)
{
CPLAssert(FALSE); // Just in case OGR is modified
}
// Set center
if(i == 0)
{
SetCenter( dfX, dfY );
}
}
if( SetGeometryDirectly( poMultiPoint ) != OGRERR_NONE)
{
CPLAssert(FALSE); // Just in case OGR is modified
}
poMultiPoint->getEnvelope(&sEnvelope);
SetMBR(sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX,sEnvelope.MaxY);
// Read optional SYMBOL line...
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
{
papszToken = CSLTokenizeStringComplex(pszLine," ,()\t",
TRUE,FALSE);
if (CSLCount(papszToken) == 4 && EQUAL(papszToken[0], "SYMBOL") )
{
SetSymbolNo(atoi(papszToken[1]));
SetSymbolColor(atoi(papszToken[2]));
SetSymbolSize(atoi(papszToken[3]));
}
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABMultiPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
OGRGeometry *poGeom;
OGRPoint *poPoint;
OGRMultiPoint *poMultiPoint;
int nNumPoints, iPoint;
/*-----------------------------------------------------------------
* Fetch and validate geometry
*----------------------------------------------------------------*/
poGeom = GetGeometryRef();
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
{
poMultiPoint = (OGRMultiPoint*)poGeom;
nNumPoints = poMultiPoint->getNumGeometries();
fp->WriteLine("MultiPoint %d\n", nNumPoints);
for(iPoint=0; iPoint < nNumPoints; iPoint++)
{
/*------------------------------------------------------------
* Validate each point
*-----------------------------------------------------------*/
poGeom = poMultiPoint->getGeometryRef(iPoint);
if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
{
poPoint = (OGRPoint*)poGeom;
fp->WriteLine("%.16g %.16g\n",poPoint->getX(),poPoint->getY());
}
else
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABMultiPoint: Missing or Invalid Geometry!");
return -1;
}
}
// Write symbol
fp->WriteLine(" Symbol (%d,%d,%d)\n",GetSymbolNo(),GetSymbolColor(),
GetSymbolSize());
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABCollection::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
char **papszToken;
const char *pszLine;
int numParts, i;
OGREnvelope sEnvelope;
/*-----------------------------------------------------------------
* Fetch number of parts in "COLLECTION %d" line
*----------------------------------------------------------------*/
papszToken = CSLTokenizeString2(fp->GetLastLine(),
" \t", CSLT_HONOURSTRINGS);
if (CSLCount(papszToken) !=2)
{
CSLDestroy(papszToken);
return -1;
}
numParts = atoi(papszToken[1]);
CSLDestroy(papszToken);
papszToken = NULL;
// Make sure collection is empty
EmptyCollection();
pszLine = fp->GetLine();
/*-----------------------------------------------------------------
* Read each part and add them to the feature
*----------------------------------------------------------------*/
for (i=0; i < numParts; i++)
{
if (pszLine == NULL)
{
CPLError(CE_Failure, CPLE_FileIO,
"Unexpected EOF while reading TABCollection from MIF file.");
return -1;
}
while(*pszLine == ' ' || *pszLine == '\t')
pszLine++; // skip leading spaces
if (*pszLine == '\0')
continue; // Skip blank lines
if (EQUALN(pszLine,"REGION",6))
{
m_poRegion = new TABRegion(GetDefnRef());
if (m_poRegion->ReadGeometryFromMIFFile(fp) != 0)
{
CPLError(CE_Failure, CPLE_NotSupported,
"TABCollection: Error reading REGION part.");
delete m_poRegion;
m_poRegion = NULL;
return -1;
}
}
else if (EQUALN(pszLine,"LINE",4) ||
EQUALN(pszLine,"PLINE",5))
{
m_poPline = new TABPolyline(GetDefnRef());
if (m_poPline->ReadGeometryFromMIFFile(fp) != 0)
{
CPLError(CE_Failure, CPLE_NotSupported,
"TABCollection: Error reading PLINE part.");
delete m_poPline;
m_poPline = NULL;
return -1;
}
}
else if (EQUALN(pszLine,"MULTIPOINT",10))
{
m_poMpoint = new TABMultiPoint(GetDefnRef());
if (m_poMpoint->ReadGeometryFromMIFFile(fp) != 0)
{
CPLError(CE_Failure, CPLE_NotSupported,
"TABCollection: Error reading MULTIPOINT part.");
delete m_poMpoint;
m_poMpoint = NULL;
return -1;
}
}
else
{
CPLError(CE_Failure, CPLE_FileIO,
"Reading TABCollection from MIF failed, expecting one "
"of REGION, PLINE or MULTIPOINT, got: '%s'",
pszLine);
return -1;
}
pszLine = fp->GetLastLine();
}
/*-----------------------------------------------------------------
* Set the main OGRFeature Geometry
* (this is actually duplicating geometries from each member)
*----------------------------------------------------------------*/
// use addGeometry() rather than addGeometryDirectly() as this clones
// the added geometry so won't leave dangling ptrs when the above features
// are deleted
OGRGeometryCollection *poGeomColl = new OGRGeometryCollection();
if(m_poRegion && m_poRegion->GetGeometryRef() != NULL)
poGeomColl->addGeometry(m_poRegion->GetGeometryRef());
if(m_poPline && m_poPline->GetGeometryRef() != NULL)
poGeomColl->addGeometry(m_poPline->GetGeometryRef());
if(m_poMpoint && m_poMpoint->GetGeometryRef() != NULL)
poGeomColl->addGeometry(m_poMpoint->GetGeometryRef());
this->SetGeometryDirectly(poGeomColl);
poGeomColl->getEnvelope(&sEnvelope);
SetMBR(sEnvelope.MinX, sEnvelope.MinY,
sEnvelope.MaxX, sEnvelope.MaxY);
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABCollection::WriteGeometryToMIFFile(MIDDATAFile *fp)
{
int numParts = 0;
if (m_poRegion) numParts++;
if (m_poPline) numParts++;
if (m_poMpoint) numParts++;
fp->WriteLine("COLLECTION %d\n", numParts);
if (m_poRegion)
{
if (m_poRegion->WriteGeometryToMIFFile(fp) != 0)
return -1;
}
if (m_poPline)
{
if (m_poPline->WriteGeometryToMIFFile(fp) != 0)
return -1;
}
if (m_poMpoint)
{
if (m_poMpoint->WriteGeometryToMIFFile(fp) != 0)
return -1;
}
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABDebugFeature::ReadGeometryFromMIFFile(MIDDATAFile *fp)
{
const char *pszLine;
/* Go to the first line of the next feature */
printf("%s\n", fp->GetLastLine());
while (((pszLine = fp->GetLine()) != NULL) &&
fp->IsValidFeature(pszLine) == FALSE)
;
return 0;
}
/**********************************************************************
*
**********************************************************************/
int TABDebugFeature::WriteGeometryToMIFFile(MIDDATAFile *fp){ return -1; }