LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_feature.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 2974
Code covered: 14.4 % Executed lines: 427

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_feature.cpp,v 1.94 2008/11/18 16:47:44 dmorissette Exp $
       3                 :  *
       4                 :  * Name:     mitab_feature.cpp
       5                 :  * Project:  MapInfo TAB Read/Write library
       6                 :  * Language: C++
       7                 :  * Purpose:  Implementation of the feature classes specific to MapInfo files.
       8                 :  * Author:   Daniel Morissette, dmorissette@dmsolutions.ca
       9                 :  *
      10                 :  **********************************************************************
      11                 :  * Copyright (c) 1999-2002, Daniel Morissette
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  * 
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  * 
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      24                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  **********************************************************************
      31                 :  *
      32                 :  * $Log: mitab_feature.cpp,v $
      33                 :  * Revision 1.94  2008/11/18 16:47:44  dmorissette
      34                 :  * Fixed compile warning when MITAB_USE_OFTDATETIME is set
      35                 :  *
      36                 :  * Revision 1.93  2008/11/17 22:06:21  aboudreault
      37                 :  * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
      38                 :  * OGR and fixed reading/writing support for these types.
      39                 :  *
      40                 :  * Revision 1.92  2008/07/29 13:06:17  aboudreault
      41                 :  * Added Font Point styles support (halo, border) (bug 1925)
      42                 :  *
      43                 :  * Revision 1.91  2008/07/21 19:23:03  aboudreault
      44                 :  * Fixed another small error with expanded text.
      45                 :  *
      46                 :  * Revision 1.90  2008/07/21 18:17:19  dmorissette
      47                 :  * Fixed a few compile warnings
      48                 :  *
      49                 :  * Revision 1.89  2008/07/21 17:59:28  aboudreault
      50                 :  * Fixed error in GetLabelStyleString() function: when text style expanded is
      51                 :  * set, no space is needed after the last char.
      52                 :  *
      53                 :  * Revision 1.88  2008/07/21 14:09:41  aboudreault
      54                 :  * Add font text styles support (bold, italic, etc.) (bug 1922)
      55                 :  *
      56                 :  * Revision 1.87  2008/07/17 14:09:30  aboudreault
      57                 :  * Add text outline color support (halo background in MapInfo)
      58                 :  *
      59                 :  * Revision 1.86  2008/07/14 17:51:21  aboudreault
      60                 :  * Fixed the text font size problem (bug 1918)
      61                 :  *
      62                 :  * Revision 1.85  2008/07/14 16:09:10  aboudreault
      63                 :  * Fixed multi-line text height problem (bug 1919)
      64                 :  *
      65                 :  * Revision 1.84  2008/07/14 14:39:52  aboudreault
      66                 :  * Fixed multi-line text rendering by adding support of the end of line char
      67                 :  * "\n" as well as the "\\n".
      68                 :  *
      69                 :  * Revision 1.83  2008/07/01 14:33:17  aboudreault
      70                 :  * * Fixed deprecated warnings generated by mitab.h by moving SetFontName to
      71                 :  *   mitab_feature.cpp.
      72                 :  *
      73                 :  * Revision 1.82  2008/02/22 20:20:44  dmorissette
      74                 :  * Fixed the internal compressed coordinate range detection test to prevent
      75                 :  * possible overflow of the compressed integer coordinate values leading
      76                 :  * to some coord. errors in very rare cases while writing to TAB (bug 1854)
      77                 :  *
      78                 :  * Revision 1.81  2008/02/20 21:35:30  dmorissette
      79                 :  * Added support for V800 COLLECTION of large objects (bug 1496)
      80                 :  *
      81                 :  * Revision 1.80  2008/02/05 22:22:48  dmorissette
      82                 :  * Added support for TAB_GEOM_V800_MULTIPOINT (bug 1496)
      83                 :  *
      84                 :  * Revision 1.79  2008/02/01 19:36:31  dmorissette
      85                 :  * Initial support for V800 REGION and MULTIPLINE (bug 1496)
      86                 :  *
      87                 :  * Revision 1.78  2008/01/29 20:46:32  dmorissette
      88                 :  * Added support for v9 Time and DateTime fields (byg 1754)
      89                 :  *
      90                 :  * Revision 1.77  2007/12/11 04:21:54  dmorissette
      91                 :  * Fixed leaks in ITABFeature???::Set???FromStyleString() (GDAL ticket 1696)
      92                 :  *
      93                 :  * Revision 1.76  2007/09/18 17:43:56  dmorissette
      94                 :  * Fixed another index splitting issue: compr coordinates origin was not
      95                 :  * stored in the TABFeature in ReadGeometry... (bug 1732)
      96                 :  *
      97                 :  * Revision 1.75  2007/09/14 19:29:24  dmorissette
      98                 :  * Completed handling of bCoordBlockDataOnly arg to Read/WriteGeometry()
      99                 :  * functions to avoid screwing up pen/brush ref counters (bug 1732)
     100                 :  *
     101                 :  * Revision 1.74  2007/09/14 18:30:19  dmorissette
     102                 :  * Fixed the splitting of object blocks with the optimized spatial
     103                 :  * index mode that was producing files with misaligned bytes that
     104                 :  * confused MapInfo (bug 1732)
     105                 :  *
     106                 :  * Revision 1.73  2007/09/12 20:22:31  dmorissette
     107                 :  * Added TABFeature::CreateFromMapInfoType()
     108                 :  *
     109                 :  * Revision 1.72  2007/06/12 14:17:16  dmorissette
     110                 :  * Added TABFile::TwoPointLineAsPolyline() to allow writing two point lines
     111                 :  * as polylines (bug 1735)
     112                 :  *
     113                 :  * Revision 1.71  2007/06/11 17:57:06  dmorissette
     114                 :  * Removed stray calls to poMapFile->GetCurObjBlock()
     115                 :  *
     116                 :  * Revision 1.70  2007/06/11 14:52:30  dmorissette
     117                 :  * Return a valid m_nCoordDatasize value for Collection objects to prevent
     118                 :  * trashing of collection data during object splitting (bug 1728)
     119                 :  *
     120                 :  * Revision 1.69  2007/02/28 20:41:40  dmorissette
     121                 :  * Added missing NULL pointer checks in SetPenFromStyleString(),
     122                 :  * SetBrushFromStyleString() and SetSymbolFromStyleString() (bug 1670)
     123                 :  *
     124                 :  * Revision 1.68  2007/02/22 18:35:53  dmorissette
     125                 :  * Fixed problem writing collections where MITAB was sometimes trying to
     126                 :  * read past EOF in write mode (bug 1657).
     127                 :  *
     128                 :  * Revision 1.67  2006/11/28 18:49:07  dmorissette
     129                 :  * Completed changes to split TABMAPObjectBlocks properly and produce an
     130                 :  * optimal spatial index (bug 1585)
     131                 :  *
     132                 :  * Revision 1.66  2006/10/17 14:34:31  dmorissette
     133                 :  * Fixed problem with null brush bg color (bug 1603)
     134                 :  *
     135                 :  * Revision 1.65  2006/07/25 13:22:58  dmorissette
     136                 :  * Fixed initialization of MBR of TABCollection members (bug 1520)
     137                 :  *
     138                 :  * Revision 1.64  2006/06/29 19:49:35  dmorissette
     139                 :  * Fixed problem writing PLINE MULTIPLE to TAB format introduced in
     140                 :  * MITAB 1.5.0 (bug 1466).
     141                 :  *
     142                 :  * Revision 1.63  2006/02/08 05:02:57  dmorissette
     143                 :  * Fixed crash when attempting to write TABPolyline object with an invalid
     144                 :  * geometry (GDAL bug 1059)
     145                 :  *
     146                 :  * ...
     147                 :  *
     148                 :  * Revision 1.1  1999/07/12 04:18:24  daniel
     149                 :  * Initial checkin
     150                 :  *
     151                 :  **********************************************************************/
     152                 : 
     153                 : #include "mitab.h"
     154                 : #include "mitab_utils.h"
     155                 : #include "mitab_geometry.h"
     156                 : 
     157                 : /*=====================================================================
     158                 :  *                      class TABFeature
     159                 :  *====================================================================*/
     160                 : 
     161                 : 
     162                 : /**********************************************************************
     163                 :  *                   TABFeature::TABFeature()
     164                 :  *
     165                 :  * Constructor.
     166                 :  **********************************************************************/
     167             130 : TABFeature::TABFeature(OGRFeatureDefn *poDefnIn):
     168             130 :                OGRFeature(poDefnIn)
     169                 : {
     170             130 :     m_nMapInfoType = TAB_GEOM_NONE;
     171             130 :     m_bDeletedFlag = FALSE;
     172                 : 
     173             130 :     SetMBR(0.0, 0.0, 0.0, 0.0);
     174             130 : }
     175                 : 
     176                 : /**********************************************************************
     177                 :  *                   TABFeature::~TABFeature()
     178                 :  *
     179                 :  * Destructor.
     180                 :  **********************************************************************/
     181             130 : TABFeature::~TABFeature()
     182                 : {
     183             130 : }
     184                 : 
     185                 : 
     186                 : /**********************************************************************
     187                 :  *                     TABFeature::CreateFromMapInfoType()
     188                 :  *
     189                 :  * Factory that creates a TABFeature of the right class for the specified
     190                 :  * MapInfo Type
     191                 :  *
     192                 :  **********************************************************************/
     193                 : TABFeature *TABFeature::CreateFromMapInfoType(int nMapInfoType,
     194              53 :                                               OGRFeatureDefn *poDefn)
     195                 : {
     196              53 :     TABFeature *poFeature = NULL;
     197                 : 
     198                 :     /*-----------------------------------------------------------------
     199                 :      * Create new feature object of the right type
     200                 :      *----------------------------------------------------------------*/
     201              53 :     switch(nMapInfoType)
     202                 :     {
     203                 :       case TAB_GEOM_NONE:
     204               1 :         poFeature = new TABFeature(poDefn);
     205               1 :         break;
     206                 :       case TAB_GEOM_SYMBOL_C:
     207                 :       case TAB_GEOM_SYMBOL:
     208               0 :         poFeature = new TABPoint(poDefn);
     209               0 :         break;
     210                 :       case TAB_GEOM_FONTSYMBOL_C:
     211                 :       case TAB_GEOM_FONTSYMBOL:
     212               0 :         poFeature = new TABFontPoint(poDefn);
     213               0 :         break;
     214                 :       case TAB_GEOM_CUSTOMSYMBOL_C:
     215                 :       case TAB_GEOM_CUSTOMSYMBOL:
     216               0 :         poFeature = new TABCustomPoint(poDefn);
     217               0 :         break;
     218                 :       case TAB_GEOM_LINE_C:
     219                 :       case TAB_GEOM_LINE:
     220                 :       case TAB_GEOM_PLINE_C:
     221                 :       case TAB_GEOM_PLINE:
     222                 :       case TAB_GEOM_MULTIPLINE_C:
     223                 :       case TAB_GEOM_MULTIPLINE:
     224                 :       case TAB_GEOM_V450_MULTIPLINE_C:
     225                 :       case TAB_GEOM_V450_MULTIPLINE:
     226                 :       case TAB_GEOM_V800_MULTIPLINE_C:
     227                 :       case TAB_GEOM_V800_MULTIPLINE:
     228               1 :        poFeature = new TABPolyline(poDefn);
     229               1 :         break;
     230                 :       case TAB_GEOM_ARC_C:
     231                 :       case TAB_GEOM_ARC:
     232               0 :         poFeature = new TABArc(poDefn);
     233               0 :         break;
     234                 : 
     235                 :       case TAB_GEOM_REGION_C:
     236                 :       case TAB_GEOM_REGION:
     237                 :       case TAB_GEOM_V450_REGION_C:
     238                 :       case TAB_GEOM_V450_REGION:
     239                 :       case TAB_GEOM_V800_REGION_C:
     240                 :       case TAB_GEOM_V800_REGION:
     241              51 :         poFeature = new TABRegion(poDefn);
     242              51 :         break;
     243                 :       case TAB_GEOM_RECT_C:
     244                 :       case TAB_GEOM_RECT:
     245                 :       case TAB_GEOM_ROUNDRECT_C:
     246                 :       case TAB_GEOM_ROUNDRECT:
     247               0 :         poFeature = new TABRectangle(poDefn);
     248               0 :         break;
     249                 :       case TAB_GEOM_ELLIPSE_C:
     250                 :       case TAB_GEOM_ELLIPSE:
     251               0 :         poFeature = new TABEllipse(poDefn);
     252               0 :         break;
     253                 :       case TAB_GEOM_TEXT_C:
     254                 :       case TAB_GEOM_TEXT:
     255               0 :         poFeature = new TABText(poDefn);
     256               0 :         break;
     257                 :       case TAB_GEOM_MULTIPOINT_C:
     258                 :       case TAB_GEOM_MULTIPOINT:
     259                 :       case TAB_GEOM_V800_MULTIPOINT_C:
     260                 :       case TAB_GEOM_V800_MULTIPOINT:
     261               0 :         poFeature = new TABMultiPoint(poDefn);
     262               0 :         break;
     263                 :       case TAB_GEOM_COLLECTION_C:
     264                 :       case TAB_GEOM_COLLECTION:
     265                 :       case TAB_GEOM_V800_COLLECTION_C:
     266                 :       case TAB_GEOM_V800_COLLECTION:
     267               0 :         poFeature = new TABCollection(poDefn);  
     268               0 :         break;
     269                 :       default:
     270                 :         /*-------------------------------------------------------------
     271                 :          * Unsupported feature type... we still return a valid feature
     272                 :          * with NONE geometry after producing a Warning.
     273                 :          * Callers can trap that case by checking CPLGetLastErrorNo() 
     274                 :          * against TAB_WarningFeatureTypeNotSupported
     275                 :          *------------------------------------------------------------*/
     276                 : //        poFeature = new TABDebugFeature(poDefn);
     277               0 :         poFeature = new TABFeature(poDefn);
     278                 : 
     279                 :         CPLError(CE_Warning, TAB_WarningFeatureTypeNotSupported,
     280                 :                  "Unsupported object type %d (0x%2.2x).  Feature will be "
     281                 :                  "returned with NONE geometry.",
     282               0 :                  nMapInfoType, nMapInfoType);
     283                 :     }
     284                 : 
     285              53 :     return poFeature;
     286                 : }
     287                 : 
     288                 : 
     289                 : /**********************************************************************
     290                 :  *                     TABFeature::CopyTABFeatureBase()
     291                 :  *
     292                 :  * Used by CloneTABFeature() to copy the basic (fields, geometry, etc.)
     293                 :  * TABFeature members.
     294                 :  *
     295                 :  * The newly created feature is owned by the caller, and will have it's own
     296                 :  * reference to the OGRFeatureDefn.
     297                 :  *
     298                 :  * It is possible to create the clone with a different OGRFeatureDefn,
     299                 :  * in this case, the fields won't be copied of course.
     300                 :  *
     301                 :  **********************************************************************/
     302               0 : void TABFeature::CopyTABFeatureBase(TABFeature *poDestFeature)
     303                 : {
     304                 :     /*-----------------------------------------------------------------
     305                 :      * Copy fields only if OGRFeatureDefn is the same
     306                 :      *----------------------------------------------------------------*/
     307               0 :     OGRFeatureDefn *poThisDefnRef = GetDefnRef();
     308                 : 
     309               0 :     if (poThisDefnRef == poDestFeature->GetDefnRef())
     310                 :     {
     311               0 :         for( int i = 0; i < poThisDefnRef->GetFieldCount(); i++ )
     312                 :         {
     313               0 :             poDestFeature->SetField( i, GetRawFieldRef( i ) );
     314                 :         }
     315                 :     }
     316                 : 
     317                 :     /*-----------------------------------------------------------------
     318                 :      * Copy the geometry
     319                 :      *----------------------------------------------------------------*/
     320               0 :     poDestFeature->SetGeometry( GetGeometryRef() );
     321                 : 
     322                 :     double dXMin, dYMin, dXMax, dYMax;
     323               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
     324               0 :     poDestFeature->SetMBR(dXMin, dYMin, dXMax, dYMax);
     325                 : 
     326                 :     GInt32 nXMin, nYMin, nXMax, nYMax;
     327               0 :     GetIntMBR(nXMin, nYMin, nXMax, nYMax);
     328               0 :     poDestFeature->SetIntMBR(nXMin, nYMin, nXMax, nYMax);
     329                 : 
     330                 :     // m_nMapInfoType is not carried but it is not required anyways.
     331                 :     // it will default to TAB_GEOM_NONE
     332               0 : }
     333                 : 
     334                 : 
     335                 : /**********************************************************************
     336                 :  *                     TABFeature::CloneTABFeature()
     337                 :  *
     338                 :  * Duplicate feature, including stuff specific to each TABFeature type.
     339                 :  *
     340                 :  * The newly created feature is owned by the caller, and will have it's own
     341                 :  * reference to the OGRFeatureDefn.
     342                 :  *
     343                 :  * It is possible to create the clone with a different OGRFeatureDefn,
     344                 :  * in this case, the fields won't be copied of course.
     345                 :  *
     346                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
     347                 :  * then copies any members specific to its own type.
     348                 :  **********************************************************************/
     349               0 : TABFeature *TABFeature::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
     350                 : {
     351                 :     /*-----------------------------------------------------------------
     352                 :      * Alloc new feature and copy the base stuff
     353                 :      *----------------------------------------------------------------*/
     354               0 :     TABFeature *poNew = new TABFeature(poNewDefn ? poNewDefn : GetDefnRef());
     355                 : 
     356               0 :     CopyTABFeatureBase(poNew);
     357                 : 
     358                 :     /*-----------------------------------------------------------------
     359                 :      * And members specific to this class
     360                 :      *----------------------------------------------------------------*/
     361                 :     // Nothing to do for this class
     362                 : 
     363               0 :     return poNew;
     364                 : }
     365                 : 
     366                 : /**********************************************************************
     367                 :  *                   TABFeature::SetMBR()
     368                 :  *
     369                 :  * Set the values for the MBR corners for this feature.
     370                 :  **********************************************************************/
     371                 : void TABFeature::SetMBR(double dXMin, double dYMin, 
     372             214 :                         double dXMax, double dYMax)
     373                 : {
     374             214 :     m_dXMin = MIN(dXMin, dXMax);
     375             214 :     m_dYMin = MIN(dYMin, dYMax);
     376             214 :     m_dXMax = MAX(dXMin, dXMax);
     377             214 :     m_dYMax = MAX(dYMin, dYMax);
     378             214 : }
     379                 : 
     380                 : /**********************************************************************
     381                 :  *                   TABFeature::GetMBR()
     382                 :  *
     383                 :  * Return the values for the MBR corners for this feature.
     384                 :  **********************************************************************/
     385                 : void TABFeature::GetMBR(double &dXMin, double &dYMin, 
     386               0 :                         double &dXMax, double &dYMax)
     387                 : {
     388               0 :     dXMin = m_dXMin;
     389               0 :     dYMin = m_dYMin;
     390               0 :     dXMax = m_dXMax;
     391               0 :     dYMax = m_dYMax;
     392               0 : }
     393                 : 
     394                 : /**********************************************************************
     395                 :  *                   TABFeature::SetIntMBR()
     396                 :  *
     397                 :  * Set the integer coordinates values of the MBR of this feature.
     398                 :  **********************************************************************/
     399                 : void TABFeature::SetIntMBR(GInt32 nXMin, GInt32 nYMin, 
     400              52 :                            GInt32 nXMax, GInt32 nYMax)
     401                 : {
     402              52 :     m_nXMin = nXMin;
     403              52 :     m_nYMin = nYMin;
     404              52 :     m_nXMax = nXMax;
     405              52 :     m_nYMax = nYMax;
     406              52 : }
     407                 : 
     408                 : /**********************************************************************
     409                 :  *                   TABFeature::GetIntMBR()
     410                 :  *
     411                 :  * Return the integer coordinates values of the MBR of this feature.
     412                 :  **********************************************************************/
     413                 : void TABFeature::GetIntMBR(GInt32 &nXMin, GInt32 &nYMin, 
     414              12 :                            GInt32 &nXMax, GInt32 &nYMax)
     415                 : {
     416              12 :     nXMin = m_nXMin;
     417              12 :     nYMin = m_nYMin;
     418              12 :     nXMax = m_nXMax;
     419              12 :     nYMax = m_nYMax;
     420              12 : }
     421                 : 
     422                 : /**********************************************************************
     423                 :  *                   TABFeature::ReadRecordFromDATFile()
     424                 :  *
     425                 :  * Fill the fields part of the feature from the contents of the 
     426                 :  * table record pointed to by poDATFile.
     427                 :  *
     428                 :  * It is assumed that poDATFile currently points to the beginning of
     429                 :  * the table record and that this feature's OGRFeatureDefn has been 
     430                 :  * properly initialized for this table.
     431                 :  **********************************************************************/
     432              53 : int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
     433                 : {
     434                 :     int         iField, numFields, nValue;
     435                 :     double      dValue;
     436                 :     const char *pszValue;
     437                 : #ifdef MITAB_USE_OFTDATETIME
     438                 :     int nYear, nMonth, nDay, nHour, nMin, nSec, nMS;
     439              53 :     nYear = nMonth = nDay = nHour = nMin = nSec = nMS = 0;
     440                 : #endif
     441                 : 
     442              53 :     CPLAssert(poDATFile);
     443                 : 
     444              53 :     numFields = poDATFile->GetNumFields();
     445                 : 
     446             206 :     for(iField=0; iField<numFields; iField++)
     447                 :     {
     448             153 :         switch(poDATFile->GetFieldType(iField))
     449                 :         {
     450                 :           case TABFChar:
     451                 :             pszValue = poDATFile->ReadCharField(poDATFile->
     452              53 :                                                 GetFieldWidth(iField));
     453              53 :             SetField(iField, pszValue);
     454              53 :             break;
     455                 :           case TABFDecimal:
     456                 :             dValue = poDATFile->ReadDecimalField(poDATFile->
     457               0 :                                                  GetFieldWidth(iField));
     458               0 :             SetField(iField, dValue);
     459               0 :             break;
     460                 :           case TABFInteger:
     461                 :             nValue = poDATFile->ReadIntegerField(poDATFile->
     462              50 :                                                  GetFieldWidth(iField));
     463              50 :             SetField(iField, nValue);
     464              50 :             break;
     465                 :           case TABFSmallInt:
     466                 :             nValue = poDATFile->ReadSmallIntField(poDATFile->
     467               0 :                                                  GetFieldWidth(iField));
     468               0 :             SetField(iField, nValue);
     469               0 :             break;
     470                 :           case TABFFloat:
     471                 :             dValue = poDATFile->ReadFloatField(poDATFile->
     472              50 :                                                  GetFieldWidth(iField));
     473              50 :             SetField(iField, dValue);
     474              50 :             break;
     475                 :           case TABFLogical:
     476                 :             pszValue = poDATFile->ReadLogicalField(poDATFile->
     477               0 :                                                  GetFieldWidth(iField));
     478               0 :             SetField(iField, pszValue);
     479               0 :             break;
     480                 :           case TABFDate:
     481                 :             pszValue = poDATFile->ReadDateField(poDATFile->
     482               0 :                                                  GetFieldWidth(iField));
     483                 : #ifdef MITAB_USE_OFTDATETIME
     484                 :             sscanf(pszValue, "%4d%2d%2d",
     485               0 :                     &nYear, &nMonth, &nDay);
     486               0 :             SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
     487                 : #else
     488                 :             SetField(iField, pszValue);
     489                 : #endif
     490               0 :             break;
     491                 :           case TABFTime:
     492                 :              pszValue = poDATFile->ReadTimeField(poDATFile->
     493               0 :                                                      GetFieldWidth(iField));
     494                 : #ifdef MITAB_USE_OFTDATETIME
     495                 :              sscanf(pszValue,"%2d%2d%2d%3d",
     496               0 :                     &nHour, &nMin, &nSec, &nMS);
     497                 :              
     498               0 :             SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
     499                 : #else
     500                 :             SetField(iField, pszValue);
     501                 : #endif
     502               0 :             break;
     503                 :           case TABFDateTime:
     504                 :             pszValue = poDATFile->ReadDateTimeField(poDATFile->
     505               0 :                                                     GetFieldWidth(iField));
     506                 : #ifdef MITAB_USE_OFTDATETIME
     507                 :             sscanf(pszValue, "%4d%2d%2d%2d%2d%2d%3d",
     508               0 :                    &nYear, &nMonth, &nDay, &nHour, &nMin, &nSec, &nMS);
     509               0 :             SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
     510                 : #else
     511                 :             SetField(iField, pszValue);
     512                 : #endif
     513               0 :             break;
     514                 :           default:
     515                 :             // Other type???  Impossible!
     516                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     517               0 :                      "Unsupported field type!");
     518                 :         }
     519                 :         
     520                 :     }
     521                 : 
     522              53 :     return 0;
     523                 : }
     524                 : 
     525                 : /**********************************************************************
     526                 :  *                   TABFeature::WriteRecordToDATFile()
     527                 :  *
     528                 :  * Write the attribute part of the feature to the .DAT file.
     529                 :  *
     530                 :  * It is assumed that poDATFile currently points to the beginning of
     531                 :  * the table record and that this feature's OGRFeatureDefn has been 
     532                 :  * properly initialized for this table.
     533                 :  *
     534                 :  * Returns 0 on success, -1 on error.
     535                 :  **********************************************************************/
     536                 : int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
     537              13 :                                      TABINDFile *poINDFile, int *panIndexNo)
     538                 : {
     539              13 :     int         iField, numFields, nStatus=0;
     540                 : #ifdef MITAB_USE_OFTDATETIME
     541                 :     int         nYear, nMon, nDay, nHour, nMin, nSec;
     542                 :     const char  *pszValue;
     543                 :     char        *pszBuffer;
     544                 : #endif
     545                 : 
     546              13 :     CPLAssert(poDATFile);
     547              13 :     CPLAssert(panIndexNo || GetDefnRef()->GetFieldCount() == 0);
     548                 : 
     549              13 :     numFields = poDATFile->GetNumFields();
     550                 : 
     551              46 :     for(iField=0; nStatus == 0 && iField<numFields; iField++)
     552                 :     {
     553                 :         // Hack for "extra" introduced field.
     554              33 :         if( iField >= GetDefnRef()->GetFieldCount() )
     555                 :         {
     556               0 :             CPLAssert( poDATFile->GetFieldType(iField) == TABFInteger 
     557                 :                        && iField == 0 );
     558               0 :             nStatus = poDATFile->WriteIntegerField( GetFID(), poINDFile, 0 );
     559               0 :             continue;
     560                 :         }
     561                 : 
     562              33 :         switch(poDATFile->GetFieldType(iField))
     563                 :         {
     564                 :           case TABFChar:
     565                 :             nStatus = poDATFile->WriteCharField(GetFieldAsString(iField),
     566                 :                                       poDATFile->GetFieldWidth(iField),
     567              13 :                                                 poINDFile, panIndexNo[iField]);
     568              13 :             break;
     569                 :           case TABFDecimal:
     570                 :             nStatus = poDATFile->WriteDecimalField(GetFieldAsDouble(iField),
     571                 :                                       poDATFile->GetFieldWidth(iField),
     572                 :                                       poDATFile->GetFieldPrecision(iField),
     573               0 :                                              poINDFile, panIndexNo[iField]);
     574               0 :             break;
     575                 :           case TABFInteger:
     576                 :             nStatus = poDATFile->WriteIntegerField(GetFieldAsInteger(iField),
     577              10 :                                                 poINDFile, panIndexNo[iField]);
     578              10 :             break;
     579                 :           case TABFSmallInt:
     580                 :             nStatus = poDATFile->WriteSmallIntField(GetFieldAsInteger(iField),
     581               0 :                                                 poINDFile, panIndexNo[iField]);
     582               0 :             break;
     583                 :           case TABFFloat:
     584                 :             nStatus = poDATFile->WriteFloatField(GetFieldAsDouble(iField),
     585              10 :                                                 poINDFile, panIndexNo[iField]);
     586              10 :             break;
     587                 :           case TABFLogical:
     588                 :             nStatus = poDATFile->WriteLogicalField(GetFieldAsString(iField),
     589               0 :                                                 poINDFile, panIndexNo[iField]);
     590               0 :             break;
     591                 :           case TABFDate:
     592                 :             nStatus = poDATFile->WriteDateField(GetFieldAsString(iField),
     593               0 :                                                 poINDFile, panIndexNo[iField]);
     594               0 :             break;
     595                 :           case TABFTime:
     596                 : #ifdef MITAB_USE_OFTDATETIME
     597                 :              /* Fix Time string returned by OGR: the hour must be 2 char */
     598               0 :              pszValue = GetFieldAsString(iField);
     599               0 :              pszBuffer = (char*)CPLMalloc((8+1)*sizeof(char));
     600               0 :              sscanf(pszValue, "%d:%d:%d", &nHour, &nMin, &nSec);
     601               0 :              sprintf(pszBuffer, "%02d:%02d:%02d", nHour, nMin, nSec); 
     602                 :              nStatus = poDATFile->WriteTimeField(pszBuffer,
     603               0 :                                                  poINDFile, panIndexNo[iField]);
     604               0 :              CPLFree(pszBuffer);
     605                 : #else
     606                 :              nStatus = poDATFile->WriteTimeField(GetFieldAsString(iField),
     607                 :                                                  poINDFile, panIndexNo[iField]);
     608                 : #endif
     609               0 :             break;
     610                 :           case TABFDateTime:
     611                 : #ifdef MITAB_USE_OFTDATETIME
     612                 :              /* Fix DateTime string returned by OGR: the hour must be 2 char */
     613               0 :              pszValue = GetFieldAsString(iField);
     614               0 :              pszBuffer = (char*)CPLMalloc((19+1)*sizeof(char));
     615                 :              sscanf(pszValue, "%4d/%2d/%2d %2d:%2d:%2d", 
     616               0 :                     &nYear,&nMon, &nDay, &nHour, &nMin, &nSec);
     617                 :              sprintf(pszBuffer, "%04d/%02d/%02d %02d:%02d:%02d", 
     618               0 :                      nYear, nMon, nDay, nHour, nMin, nSec); 
     619                 :              nStatus = poDATFile->WriteDateTimeField(pszBuffer,
     620               0 :                                                      poINDFile, panIndexNo[iField]);
     621               0 :              CPLFree(pszBuffer);
     622                 : #else
     623                 :              nStatus = poDATFile->WriteDateTimeField(GetFieldAsString(iField),
     624                 :                                                      poINDFile, panIndexNo[iField]);
     625                 : #endif
     626               0 :             break;
     627                 :           default:
     628                 :             // Other type???  Impossible!
     629                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     630               0 :                      "Unsupported field type!");
     631                 :         }
     632                 : 
     633                 :     }
     634                 : 
     635              13 :     if (poDATFile->CommitRecordToFile() != 0)
     636               0 :         return -1;
     637                 : 
     638              13 :     return 0;
     639                 : }
     640                 : 
     641                 : /**********************************************************************
     642                 :  *                   TABFeature::ReadGeometryFromMAPFile()
     643                 :  *
     644                 :  * In derived classes, this method should be reimplemented to
     645                 :  * fill the geometry and representation (color, etc...) part of the
     646                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
     647                 :  *
     648                 :  * It is assumed that before calling ReadGeometryFromMAPFile(), poMAPFile
     649                 :  * currently points to the beginning of a map object.
     650                 :  *
     651                 :  * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
     652                 :  * the CoordBlock data during splitting of object blocks. In this case we
     653                 :  * need to process only the information related to the CoordBlock. One 
     654                 :  * important thing to avoid is reading/writing pen/brush/symbol definitions
     655                 :  * as that would screw up their ref counters.
     656                 :  *
     657                 :  * ppoCoordBlock is used by TABCollection and by index splitting code
     658                 :  * to provide a CoordBlock to use instead of the one from the poMAPFile and
     659                 :  * return the current pointer at the end of the call.
     660                 :  *
     661                 :  * The current implementation does nothing since instances of TABFeature
     662                 :  * objects contain no geometry (i.e. TAB_GEOM_NONE).
     663                 :  * 
     664                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
     665                 :  * been called.
     666                 :  **********************************************************************/
     667                 : int TABFeature::ReadGeometryFromMAPFile(TABMAPFile * /*poMapFile*/,
     668                 :                                         TABMAPObjHdr * /*poObjHdr*/,
     669                 :                                         GBool /*bCoordBlockDataOnly=FALSE*/, 
     670               1 :                                         TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
     671                 : {
     672                 :     /*-----------------------------------------------------------------
     673                 :      * Nothing to do... instances of TABFeature objects contain no geometry.
     674                 :      *----------------------------------------------------------------*/
     675                 : 
     676               1 :     return 0;
     677                 : }
     678                 : 
     679                 : 
     680                 : /**********************************************************************
     681                 :  *                   TABFeature::UpdateMBR()
     682                 :  *
     683                 :  * Fetch envelope of poGeom and update MBR.
     684                 :  * Integer coord MBR is updated only if poMapFile is not NULL.
     685                 :  *
     686                 :  * Returns 0 on success, or -1 if there is no geometry in object
     687                 :  **********************************************************************/
     688              12 : int TABFeature::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
     689                 : {
     690                 :     OGRGeometry *poGeom;
     691                 : 
     692              12 :     poGeom = GetGeometryRef();
     693                 : 
     694              12 :     if (poGeom)
     695                 :     {
     696              12 :         OGREnvelope oEnv;
     697              12 :         poGeom->getEnvelope(&oEnv);
     698                 : 
     699              12 :         m_dXMin = oEnv.MinX;
     700              12 :         m_dYMin = oEnv.MinY;
     701              12 :         m_dXMax = oEnv.MaxX;
     702              12 :         m_dYMax = oEnv.MaxY;
     703                 : 
     704              12 :         if (poMapFile)
     705                 :         {
     706              12 :             poMapFile->Coordsys2Int(oEnv.MinX, oEnv.MinY, m_nXMin, m_nYMin);
     707              12 :             poMapFile->Coordsys2Int(oEnv.MaxX, oEnv.MaxY, m_nXMax, m_nYMax);
     708                 :         }
     709                 : 
     710              12 :         return 0;
     711                 :     }
     712                 : 
     713               0 :     return -1;
     714                 : }
     715                 : 
     716                 : /**********************************************************************
     717                 :  *                   TABFeature::ValidateCoordType()
     718                 :  *
     719                 :  * Checks the feature envelope to establish if the feature should be
     720                 :  * written using Compressed coordinates or not and adjust m_nMapInfoType
     721                 :  * accordingly. Calling this method also sets (initializes) m_nXMin, m_nYMin, 
     722                 :  * m_nXMax, m_nYMax
     723                 :  *
     724                 :  * This function should be used only by the ValidateMapInfoType() 
     725                 :  * implementations.
     726                 :  *
     727                 :  * Returns TRUE if coord. should be compressed, FALSE otherwise
     728                 :  **********************************************************************/
     729              11 : GBool TABFeature::ValidateCoordType(TABMAPFile * poMapFile)
     730                 : {
     731              11 :     GBool bCompr = FALSE;
     732                 : 
     733                 :     /*-------------------------------------------------------------
     734                 :      * Decide if coordinates should be compressed or not.
     735                 :      *------------------------------------------------------------*/
     736              11 :     if (UpdateMBR(poMapFile) == 0)
     737                 :     {
     738                 :         /* Test for max range < 65535 here instead of < 65536 to avoid
     739                 :          * compressed coordinate overflows in some boundary situations
     740                 :          */
     741              11 :         if ((m_nXMax - m_nXMin) < 65535 && (m_nYMax-m_nYMin) < 65535)
     742                 :         {
     743              10 :             bCompr = TRUE;
     744                 :         }
     745              11 :         m_nComprOrgX = (m_nXMin + m_nXMax) / 2;
     746              11 :         m_nComprOrgY = (m_nYMin + m_nYMax) / 2;
     747                 :     }
     748                 : 
     749                 :     /*-------------------------------------------------------------
     750                 :      * Adjust native type
     751                 :      *------------------------------------------------------------*/
     752              21 :     if (bCompr && ((m_nMapInfoType%3) == 2))
     753              10 :         m_nMapInfoType--;  // compr = 1, 4, 7, ...
     754               1 :     else if (!bCompr && ((m_nMapInfoType%3) == 1))
     755               0 :         m_nMapInfoType++;  // non-compr = 2, 5, 8, ...
     756                 : 
     757              11 :     return bCompr;
     758                 : }
     759                 : 
     760                 : /**********************************************************************
     761                 :  *                   TABFeature::ForceCoordTypeAndOrigin()
     762                 :  *
     763                 :  * This function is used by TABCollection::ValidateMapInfoType() to force 
     764                 :  * the coord type and compressed origin of all members of a collection 
     765                 :  * to be the same. (A replacement for ValidateCoordType() for this 
     766                 :  * specific case)
     767                 :  **********************************************************************/
     768                 : void TABFeature::ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
     769                 :                                          GInt32 nComprOrgX, GInt32 nComprOrgY,
     770                 :                                          GInt32 nXMin, GInt32 nYMin, 
     771               0 :                                          GInt32 nXMax, GInt32 nYMax)
     772                 : {
     773                 :     /*-------------------------------------------------------------
     774                 :      * Set Compressed Origin and adjust native type
     775                 :      *------------------------------------------------------------*/
     776               0 :     m_nComprOrgX = nComprOrgX;
     777               0 :     m_nComprOrgY = nComprOrgY;
     778                 : 
     779               0 :     m_nMapInfoType = nMapInfoType;
     780                 : 
     781               0 :     if (bCompr && ((m_nMapInfoType%3) == 2))
     782               0 :         m_nMapInfoType--;  // compr = 1, 4, 7, ...
     783               0 :     else if (!bCompr && ((m_nMapInfoType%3) == 1))
     784               0 :         m_nMapInfoType++;  // non-compr = 2, 5, 8, ...
     785                 : 
     786               0 :     m_nXMin = nXMin;
     787               0 :     m_nYMin = nYMin;
     788               0 :     m_nXMax = nXMax;
     789               0 :     m_nYMax = nYMax;
     790               0 : }
     791                 : 
     792                 : /**********************************************************************
     793                 :  *                   TABFeature::WriteGeometryToMAPFile()
     794                 :  *
     795                 :  *
     796                 :  * In derived classes, this method should be reimplemented to
     797                 :  * write the geometry and representation (color, etc...) part of the
     798                 :  * feature to the .MAP object pointed to by poMAPFile.
     799                 :  *
     800                 :  * It is assumed that before calling WriteGeometryToMAPFile(), poMAPFile
     801                 :  * currently points to a valid map object.
     802                 :  *
     803                 :  * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
     804                 :  * the CoordBlock data during splitting of object blocks. In this case we
     805                 :  * need to process only the information related to the CoordBlock. One 
     806                 :  * important thing to avoid is reading/writing pen/brush/symbol definitions
     807                 :  * as that would screw up their ref counters.
     808                 :  *
     809                 :  * ppoCoordBlock is used by TABCollection and by index splitting code
     810                 :  * to provide a CoordBlock to use instead of the one from the poMAPFile and
     811                 :  * return the current pointer at the end of the call.
     812                 :  *
     813                 :  * The current implementation does nothing since instances of TABFeature
     814                 :  * objects contain no geometry (i.e. TAB_GEOM_NONE).
     815                 :  * 
     816                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
     817                 :  * been called.
     818                 :  **********************************************************************/
     819                 : int TABFeature::WriteGeometryToMAPFile(TABMAPFile * /* poMapFile*/,
     820                 :                                        TABMAPObjHdr * /*poObjHdr*/,
     821                 :                                        GBool /*bCoordBlockDataOnly=FALSE*/, 
     822               1 :                                        TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
     823                 : {
     824                 :     /*-----------------------------------------------------------------
     825                 :      * Nothing to do... instances of TABFeature objects contain no geometry.
     826                 :      *----------------------------------------------------------------*/
     827                 : 
     828               1 :     return 0;
     829                 : }
     830                 : 
     831                 : /**********************************************************************
     832                 :  *                   TABFeature::DumpMID()
     833                 :  *
     834                 :  * Dump feature attributes in a format similar to .MID data records.
     835                 :  **********************************************************************/
     836               0 : void TABFeature::DumpMID(FILE *fpOut /*=NULL*/)
     837                 : {
     838               0 :     OGRFeatureDefn      *poDefn = GetDefnRef();
     839                 : 
     840               0 :     if (fpOut == NULL)
     841               0 :         fpOut = stdout;
     842                 : 
     843               0 :     for( int iField = 0; iField < GetFieldCount(); iField++ )
     844                 :     {
     845               0 :         OGRFieldDefn    *poFDefn = poDefn->GetFieldDefn(iField);
     846                 :         
     847                 :         fprintf( fpOut, "  %s (%s) = %s\n",
     848                 :                  poFDefn->GetNameRef(),
     849                 :                  OGRFieldDefn::GetFieldTypeName(poFDefn->GetType()),
     850               0 :                  GetFieldAsString( iField ) );
     851                 :     }
     852                 : 
     853               0 :     fflush(fpOut);
     854               0 : }
     855                 : 
     856                 : /**********************************************************************
     857                 :  *                   TABFeature::DumpMIF()
     858                 :  *
     859                 :  * Dump feature geometry in a format similar to .MIF files.
     860                 :  **********************************************************************/
     861               0 : void TABFeature::DumpMIF(FILE *fpOut /*=NULL*/)
     862                 : {
     863               0 :     if (fpOut == NULL)
     864               0 :         fpOut = stdout;
     865                 : 
     866                 :     /*-----------------------------------------------------------------
     867                 :      * Generate output... not much to do, feature contains no geometry.
     868                 :      *----------------------------------------------------------------*/
     869               0 :     fprintf(fpOut, "NONE\n" );
     870                 : 
     871               0 :     fflush(fpOut);
     872               0 : }
     873                 : 
     874                 : 
     875                 : /*=====================================================================
     876                 :  *                      class TABPoint
     877                 :  *====================================================================*/
     878                 : 
     879                 : 
     880                 : /**********************************************************************
     881                 :  *                   TABPoint::TABPoint()
     882                 :  *
     883                 :  * Constructor.
     884                 :  **********************************************************************/
     885               8 : TABPoint::TABPoint(OGRFeatureDefn *poDefnIn):
     886               8 :               TABFeature(poDefnIn)
     887                 : {
     888               8 : }
     889                 : 
     890                 : /**********************************************************************
     891                 :  *                   TABPoint::~TABPoint()
     892                 :  *
     893                 :  * Destructor.
     894                 :  **********************************************************************/
     895               8 : TABPoint::~TABPoint()
     896                 : {
     897               8 : }
     898                 : 
     899                 : /**********************************************************************
     900                 :  *                     TABPoint::CloneTABFeature()
     901                 :  *
     902                 :  * Duplicate feature, including stuff specific to each TABFeature type.
     903                 :  *
     904                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
     905                 :  * then copies any members specific to its own type.
     906                 :  **********************************************************************/
     907               0 : TABFeature *TABPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
     908                 : {
     909                 :     /*-----------------------------------------------------------------
     910                 :      * Alloc new feature and copy the base stuff
     911                 :      *----------------------------------------------------------------*/
     912               0 :     TABPoint *poNew = new TABPoint(poNewDefn ? poNewDefn : GetDefnRef());
     913                 : 
     914               0 :     CopyTABFeatureBase(poNew);
     915                 : 
     916                 :     /*-----------------------------------------------------------------
     917                 :      * And members specific to this class
     918                 :      *----------------------------------------------------------------*/
     919                 :     // ITABFeatureSymbol
     920               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
     921                 : 
     922               0 :     return poNew;
     923                 : }
     924                 : 
     925                 : 
     926                 : /**********************************************************************
     927                 :  *                   TABPoint::ValidateMapInfoType()
     928                 :  *
     929                 :  * Check the feature's geometry part and return the corresponding
     930                 :  * mapinfo object type code.  The m_nMapInfoType member will also
     931                 :  * be updated for further calls to GetMapInfoType();
     932                 :  *
     933                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
     934                 :  * is expected for this object class.
     935                 :  **********************************************************************/
     936               0 : int  TABPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
     937                 : {
     938                 :     OGRGeometry *poGeom;
     939                 : 
     940                 :     /*-----------------------------------------------------------------
     941                 :      * Fetch and validate geometry 
     942                 :      * __TODO__ For now we always write in uncompressed format (until we 
     943                 :      * find that this is not correct... note that at this point the
     944                 :      * decision to use compressed/uncompressed will likely be based on
     945                 :      * the distance between the point and the object block center in
     946                 :      * integer coordinates being > 32767 or not... remains to be verified)
     947                 :      *----------------------------------------------------------------*/
     948               0 :     poGeom = GetGeometryRef();
     949               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
     950                 :     {
     951               0 :         switch(GetFeatureClass())
     952                 :         {
     953                 :           case TABFCFontPoint:
     954               0 :             m_nMapInfoType = TAB_GEOM_FONTSYMBOL;
     955               0 :             break;
     956                 :           case TABFCCustomPoint:
     957               0 :             m_nMapInfoType = TAB_GEOM_CUSTOMSYMBOL;
     958               0 :             break;
     959                 :           case TABFCPoint:
     960                 :           default:
     961               0 :             m_nMapInfoType = TAB_GEOM_SYMBOL;
     962                 :             break;
     963                 :         }
     964                 :     }
     965                 :     else
     966                 :     {
     967                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
     968               0 :                  "TABPoint: Missing or Invalid Geometry!");
     969               0 :         m_nMapInfoType = TAB_GEOM_NONE;
     970                 :     }
     971                 : 
     972               0 :     UpdateMBR(poMapFile);
     973                 : 
     974               0 :     return m_nMapInfoType;
     975                 : }
     976                 : 
     977                 : /**********************************************************************
     978                 :  *                   TABPoint::ReadGeometryFromMAPFile()
     979                 :  *
     980                 :  * Fill the geometry and representation (color, etc...) part of the
     981                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
     982                 :  *
     983                 :  * It is assumed that poMAPFile currently points to the beginning of
     984                 :  * a map object.
     985                 :  *
     986                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
     987                 :  * been called.
     988                 :  **********************************************************************/
     989                 : int TABPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
     990                 :                                       TABMAPObjHdr *poObjHdr,
     991                 :                                       GBool bCoordBlockDataOnly /*=FALSE*/, 
     992               0 :                                       TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
     993                 : {
     994                 :     double              dX, dY;
     995                 :     OGRGeometry         *poGeometry;
     996                 : 
     997                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
     998               0 :     if (bCoordBlockDataOnly)
     999               0 :         return 0;
    1000                 : 
    1001                 :     /*-----------------------------------------------------------------
    1002                 :      * Fetch and validate geometry type
    1003                 :      *----------------------------------------------------------------*/
    1004               0 :     m_nMapInfoType = poObjHdr->m_nType;
    1005                 : 
    1006               0 :     if (m_nMapInfoType != TAB_GEOM_SYMBOL &&
    1007                 :         m_nMapInfoType != TAB_GEOM_SYMBOL_C )
    1008                 :     {
    1009                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1010                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    1011               0 :                  m_nMapInfoType, m_nMapInfoType);
    1012               0 :         return -1;
    1013                 :     }
    1014                 : 
    1015                 :     /*-----------------------------------------------------------------
    1016                 :      * Read object information
    1017                 :      *----------------------------------------------------------------*/
    1018               0 :     TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
    1019                 : 
    1020               0 :     m_nSymbolDefIndex = poPointHdr->m_nSymbolId;   // Symbol index
    1021                 : 
    1022               0 :     poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
    1023                 :     
    1024                 :     /*-----------------------------------------------------------------
    1025                 :      * Create and fill geometry object
    1026                 :      *----------------------------------------------------------------*/
    1027               0 :     poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
    1028               0 :     poGeometry = new OGRPoint(dX, dY);
    1029                 :     
    1030               0 :     SetGeometryDirectly(poGeometry);
    1031                 : 
    1032               0 :     SetMBR(dX, dY, dX, dY);
    1033                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    1034               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    1035                 : 
    1036               0 :     return 0;
    1037                 : }
    1038                 : 
    1039                 : /**********************************************************************
    1040                 :  *                   TABPoint::WriteGeometryToMAPFile()
    1041                 :  *
    1042                 :  * Write the geometry and representation (color, etc...) part of the
    1043                 :  * feature to the .MAP object pointed to by poMAPFile.
    1044                 :  *
    1045                 :  * It is assumed that poMAPFile currently points to a valid map object.
    1046                 :  *
    1047                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1048                 :  * been called.
    1049                 :  **********************************************************************/
    1050                 : int TABPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    1051                 :                                      TABMAPObjHdr *poObjHdr,
    1052                 :                                      GBool bCoordBlockDataOnly /*=FALSE*/, 
    1053               0 :                                      TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1054                 : {
    1055                 :     GInt32              nX, nY;
    1056                 :     OGRGeometry         *poGeom;
    1057                 :     OGRPoint            *poPoint;
    1058                 : 
    1059                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1060               0 :     if (bCoordBlockDataOnly)
    1061               0 :         return 0;
    1062                 : 
    1063                 :     /*-----------------------------------------------------------------
    1064                 :      * We assume that ValidateMapInfoType() was called already and that
    1065                 :      * the type in poObjHdr->m_nType is valid.
    1066                 :      *----------------------------------------------------------------*/
    1067               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    1068                 : 
    1069                 :     /*-----------------------------------------------------------------
    1070                 :      * Fetch and validate geometry
    1071                 :      *----------------------------------------------------------------*/
    1072               0 :     poGeom = GetGeometryRef();
    1073               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1074               0 :         poPoint = (OGRPoint*)poGeom;
    1075                 :     else
    1076                 :     {
    1077                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1078               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1079               0 :         return -1;
    1080                 :     }
    1081                 : 
    1082               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    1083                 : 
    1084                 :     /*-----------------------------------------------------------------
    1085                 :      * Copy object information
    1086                 :      *----------------------------------------------------------------*/
    1087               0 :     TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
    1088                 : 
    1089               0 :     poPointHdr->m_nX = nX;
    1090               0 :     poPointHdr->m_nY = nY;
    1091               0 :     poPointHdr->SetMBR(nX, nY, nX, nY);
    1092                 : 
    1093               0 :     m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
    1094               0 :     poPointHdr->m_nSymbolId = m_nSymbolDefIndex;      // Symbol index
    1095                 : 
    1096               0 :     if (CPLGetLastErrorNo() != 0)
    1097               0 :         return -1;
    1098                 : 
    1099               0 :     return 0;
    1100                 : }
    1101                 : 
    1102                 : 
    1103                 : /**********************************************************************
    1104                 :  *                   TABPoint::GetX()
    1105                 :  *
    1106                 :  * Return this point's X coordinate.
    1107                 :  **********************************************************************/
    1108               0 : double TABPoint::GetX()
    1109                 : {
    1110                 :     OGRGeometry *poGeom;
    1111               0 :     OGRPoint    *poPoint=NULL;
    1112                 : 
    1113                 :     /*-----------------------------------------------------------------
    1114                 :      * Fetch and validate geometry
    1115                 :      *----------------------------------------------------------------*/
    1116               0 :     poGeom = GetGeometryRef();
    1117               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1118               0 :         poPoint = (OGRPoint*)poGeom;
    1119                 :     else
    1120                 :     {
    1121                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1122               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1123               0 :         return 0.0;
    1124                 :     }
    1125                 : 
    1126               0 :     return poPoint->getX();
    1127                 : }
    1128                 : 
    1129                 : /**********************************************************************
    1130                 :  *                   TABPoint::GetY()
    1131                 :  *
    1132                 :  * Return this point's Y coordinate.
    1133                 :  **********************************************************************/
    1134               0 : double TABPoint::GetY()
    1135                 : {
    1136                 :     OGRGeometry *poGeom;
    1137               0 :     OGRPoint    *poPoint=NULL;
    1138                 : 
    1139                 :     /*-----------------------------------------------------------------
    1140                 :      * Fetch and validate geometry
    1141                 :      *----------------------------------------------------------------*/
    1142               0 :     poGeom = GetGeometryRef();
    1143               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1144               0 :         poPoint = (OGRPoint*)poGeom;
    1145                 :     else
    1146                 :     {
    1147                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1148               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1149               0 :         return 0.0;
    1150                 :     }
    1151                 : 
    1152               0 :     return poPoint->getY();
    1153                 : }
    1154                 : 
    1155                 : 
    1156                 : /**********************************************************************
    1157                 :  *                   TABPoint::GetStyleString()
    1158                 :  *
    1159                 :  * Return style string for this feature.
    1160                 :  *
    1161                 :  * Style String is built only once during the first call to GetStyleString().
    1162                 :  **********************************************************************/
    1163               0 : const char *TABPoint::GetStyleString()
    1164                 : {
    1165               0 :     if (m_pszStyleString == NULL)
    1166                 :     {
    1167               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    1168                 :     }
    1169                 : 
    1170               0 :     return m_pszStyleString;
    1171                 : }
    1172                 : 
    1173                 : 
    1174                 : /**********************************************************************
    1175                 :  *                   TABPoint::DumpMIF()
    1176                 :  *
    1177                 :  * Dump feature geometry in a format similar to .MIF POINTs.
    1178                 :  **********************************************************************/
    1179               0 : void TABPoint::DumpMIF(FILE *fpOut /*=NULL*/)
    1180                 : {
    1181                 :     OGRGeometry *poGeom;
    1182                 :     OGRPoint    *poPoint;
    1183                 : 
    1184               0 :     if (fpOut == NULL)
    1185               0 :         fpOut = stdout;
    1186                 : 
    1187                 :     /*-----------------------------------------------------------------
    1188                 :      * Fetch and validate geometry
    1189                 :      *----------------------------------------------------------------*/
    1190               0 :     poGeom = GetGeometryRef();
    1191               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1192               0 :         poPoint = (OGRPoint*)poGeom;
    1193                 :     else
    1194                 :     {
    1195                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1196               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1197               0 :         return;
    1198                 :     }
    1199                 : 
    1200                 :     /*-----------------------------------------------------------------
    1201                 :      * Generate output
    1202                 :      *----------------------------------------------------------------*/
    1203               0 :     fprintf(fpOut, "POINT %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
    1204                 : 
    1205               0 :     DumpSymbolDef(fpOut);
    1206                 : 
    1207                 :     /*-----------------------------------------------------------------
    1208                 :      * Handle stuff specific to derived classes
    1209                 :      *----------------------------------------------------------------*/
    1210               0 :     if (GetFeatureClass() == TABFCFontPoint)
    1211                 :     {
    1212               0 :         TABFontPoint *poFeature = (TABFontPoint *)this;
    1213                 :         fprintf(fpOut, "  m_nFontStyle     = 0x%2.2x (%d)\n", 
    1214                 :                 poFeature->GetFontStyleTABValue(),
    1215               0 :                 poFeature->GetFontStyleTABValue());
    1216                 : 
    1217               0 :         poFeature->DumpFontDef(fpOut);
    1218                 :     }
    1219               0 :     if (GetFeatureClass() == TABFCCustomPoint)
    1220                 :     {
    1221               0 :         TABCustomPoint *poFeature = (TABCustomPoint *)this;
    1222                 : 
    1223                 :         fprintf(fpOut, "  m_nUnknown_      = 0x%2.2x (%d)\n", 
    1224               0 :                 poFeature->m_nUnknown_, poFeature->m_nUnknown_);
    1225                 :         fprintf(fpOut, "  m_nCustomStyle   = 0x%2.2x (%d)\n", 
    1226                 :                 poFeature->GetCustomSymbolStyle(), 
    1227               0 :                 poFeature->GetCustomSymbolStyle());
    1228                 : 
    1229               0 :         poFeature->DumpFontDef(fpOut);
    1230                 :     }
    1231                 : 
    1232               0 :     fflush(fpOut);
    1233                 : }
    1234                 : 
    1235                 : /*=====================================================================
    1236                 :  *                      class TABFontPoint
    1237                 :  *====================================================================*/
    1238                 : 
    1239                 : 
    1240                 : /**********************************************************************
    1241                 :  *                   TABFontPoint::TABFontPoint()
    1242                 :  *
    1243                 :  * Constructor.
    1244                 :  **********************************************************************/
    1245               0 : TABFontPoint::TABFontPoint(OGRFeatureDefn *poDefnIn):
    1246               0 :               TABPoint(poDefnIn)
    1247                 : {
    1248               0 :     m_nFontStyle = 0;
    1249               0 :     m_dAngle = 0.0;
    1250               0 : }
    1251                 : 
    1252                 : /**********************************************************************
    1253                 :  *                   TABFontPoint::~TABFontPoint()
    1254                 :  *
    1255                 :  * Destructor.
    1256                 :  **********************************************************************/
    1257               0 : TABFontPoint::~TABFontPoint()
    1258                 : {
    1259               0 : }
    1260                 : 
    1261                 : /**********************************************************************
    1262                 :  *                     TABFontPoint::CloneTABFeature()
    1263                 :  *
    1264                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    1265                 :  *
    1266                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    1267                 :  * then copies any members specific to its own type.
    1268                 :  **********************************************************************/
    1269               0 : TABFeature *TABFontPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
    1270                 : {
    1271                 :     /*-----------------------------------------------------------------
    1272                 :      * Alloc new feature and copy the base stuff
    1273                 :      *----------------------------------------------------------------*/
    1274                 :     TABFontPoint *poNew = new TABFontPoint(poNewDefn ? poNewDefn : 
    1275               0 :                                                        GetDefnRef());
    1276                 : 
    1277               0 :     CopyTABFeatureBase(poNew);
    1278                 : 
    1279                 :     /*-----------------------------------------------------------------
    1280                 :      * And members specific to this class
    1281                 :      *----------------------------------------------------------------*/
    1282                 :     // ITABFeatureSymbol
    1283               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
    1284                 : 
    1285                 :     // ITABFeatureFont
    1286               0 :     *(poNew->GetFontDefRef()) = *GetFontDefRef();
    1287                 : 
    1288               0 :     poNew->SetSymbolAngle( GetSymbolAngle() );
    1289               0 :     poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
    1290                 : 
    1291               0 :     return poNew;
    1292                 : }
    1293                 : 
    1294                 : /**********************************************************************
    1295                 :  *                   TABFontPoint::ReadGeometryFromMAPFile()
    1296                 :  *
    1297                 :  * Fill the geometry and representation (color, etc...) part of the
    1298                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    1299                 :  *
    1300                 :  * It is assumed that poMAPFile currently points to the beginning of
    1301                 :  * a map object.
    1302                 :  *
    1303                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1304                 :  * been called.
    1305                 :  **********************************************************************/
    1306                 : int TABFontPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    1307                 :                                           TABMAPObjHdr *poObjHdr,
    1308                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    1309               0 :                                           TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1310                 : {
    1311                 :     double              dX, dY;
    1312                 :     OGRGeometry         *poGeometry;
    1313                 : 
    1314                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1315               0 :     if (bCoordBlockDataOnly)
    1316               0 :         return 0;
    1317                 : 
    1318                 :     /*-----------------------------------------------------------------
    1319                 :      * Fetch and validate geometry type
    1320                 :      *----------------------------------------------------------------*/
    1321               0 :     m_nMapInfoType = poObjHdr->m_nType;
    1322                 : 
    1323               0 :     if (m_nMapInfoType != TAB_GEOM_FONTSYMBOL &&
    1324                 :         m_nMapInfoType != TAB_GEOM_FONTSYMBOL_C )
    1325                 :     {
    1326                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1327                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    1328               0 :                  m_nMapInfoType, m_nMapInfoType);
    1329               0 :         return -1;
    1330                 :     }
    1331                 : 
    1332                 :     /*-----------------------------------------------------------------
    1333                 :      * Read object information
    1334                 :      * NOTE: This symbol type does not contain a reference to a
    1335                 :      * SymbolDef block in the file, but we still use the m_sSymbolDef
    1336                 :      * structure to store the information inside the class so that the
    1337                 :      * ITABFeatureSymbol methods work properly for the class user.
    1338                 :      *----------------------------------------------------------------*/
    1339               0 :     TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
    1340                 : 
    1341               0 :     m_nSymbolDefIndex = -1;
    1342               0 :     m_sSymbolDef.nRefCount = 0;
    1343                 : 
    1344               0 :     m_sSymbolDef.nSymbolNo  = poPointHdr->m_nSymbolId;  // shape
    1345               0 :     m_sSymbolDef.nPointSize = poPointHdr->m_nPointSize; // point size
    1346                 : 
    1347               0 :     m_nFontStyle            = poPointHdr->m_nFontStyle; // font style
    1348                 : 
    1349                 :     m_sSymbolDef.rgbColor   = (poPointHdr->m_nR*256*256 +
    1350                 :                                poPointHdr->m_nG*256 +
    1351               0 :                                poPointHdr->m_nB);
    1352                 : 
    1353                 :     /*-------------------------------------------------------------
    1354                 :      * Symbol Angle, in thenths of degree.
    1355                 :      * Contrary to arc start/end angles, no conversion based on 
    1356                 :      * origin quadrant is required here
    1357                 :      *------------------------------------------------------------*/
    1358               0 :     m_dAngle       = poPointHdr->m_nAngle/10.0;
    1359                 : 
    1360               0 :     m_nFontDefIndex = poPointHdr->m_nFontId;      // Font name index
    1361                 : 
    1362               0 :     poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
    1363                 : 
    1364                 :     /*-----------------------------------------------------------------
    1365                 :      * Create and fill geometry object
    1366                 :      *----------------------------------------------------------------*/
    1367               0 :     poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
    1368               0 :     poGeometry = new OGRPoint(dX, dY);
    1369                 :     
    1370               0 :     SetGeometryDirectly(poGeometry);
    1371                 : 
    1372               0 :     SetMBR(dX, dY, dX, dY);
    1373                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    1374               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    1375                 : 
    1376               0 :     return 0;
    1377                 : }
    1378                 : 
    1379                 : /**********************************************************************
    1380                 :  *                   TABFontPoint::WriteGeometryToMAPFile()
    1381                 :  *
    1382                 :  * Write the geometry and representation (color, etc...) part of the
    1383                 :  * feature to the .MAP object pointed to by poMAPFile.
    1384                 :  *
    1385                 :  * It is assumed that poMAPFile currently points to a valid map object.
    1386                 :  *
    1387                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1388                 :  * been called.
    1389                 :  **********************************************************************/
    1390                 : int TABFontPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    1391                 :                                          TABMAPObjHdr *poObjHdr,
    1392                 :                                          GBool bCoordBlockDataOnly /*=FALSE*/, 
    1393               0 :                                          TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1394                 : {
    1395                 :     GInt32              nX, nY;
    1396                 :     OGRGeometry         *poGeom;
    1397                 :     OGRPoint            *poPoint;
    1398                 : 
    1399                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1400               0 :     if (bCoordBlockDataOnly)
    1401               0 :         return 0;
    1402                 : 
    1403                 :     /*-----------------------------------------------------------------
    1404                 :      * We assume that ValidateMapInfoType() was called already and that
    1405                 :      * the type in poObjHdr->m_nType is valid.
    1406                 :      *----------------------------------------------------------------*/
    1407               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    1408                 : 
    1409                 :     /*-----------------------------------------------------------------
    1410                 :      * Fetch and validate geometry
    1411                 :      *----------------------------------------------------------------*/
    1412               0 :     poGeom = GetGeometryRef();
    1413               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1414               0 :         poPoint = (OGRPoint*)poGeom;
    1415                 :     else
    1416                 :     {
    1417                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1418               0 :                  "TABFontPoint: Missing or Invalid Geometry!");
    1419               0 :         return -1;
    1420                 :     }
    1421                 : 
    1422               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    1423                 : 
    1424                 :     /*-----------------------------------------------------------------
    1425                 :      * Copy object information
    1426                 :      * NOTE: This symbol type does not contain a reference to a
    1427                 :      * SymbolDef block in the file, but we still use the m_sSymbolDef
    1428                 :      * structure to store the information inside the class so that the
    1429                 :      * ITABFeatureSymbol methods work properly for the class user.
    1430                 :      *----------------------------------------------------------------*/
    1431               0 :     TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
    1432                 : 
    1433               0 :     poPointHdr->m_nX = nX;
    1434               0 :     poPointHdr->m_nY = nY;
    1435               0 :     poPointHdr->SetMBR(nX, nY, nX, nY);
    1436                 : 
    1437               0 :     poPointHdr->m_nSymbolId = (GByte)m_sSymbolDef.nSymbolNo;    // shape
    1438               0 :     poPointHdr->m_nPointSize = (GByte)m_sSymbolDef.nPointSize;  // point size
    1439               0 :     poPointHdr->m_nFontStyle = m_nFontStyle;                    // font style
    1440                 : 
    1441               0 :     poPointHdr->m_nR = COLOR_R(m_sSymbolDef.rgbColor);
    1442               0 :     poPointHdr->m_nG = COLOR_G(m_sSymbolDef.rgbColor);
    1443               0 :     poPointHdr->m_nB = COLOR_B(m_sSymbolDef.rgbColor);
    1444                 : 
    1445                 :     /*-------------------------------------------------------------
    1446                 :      * Symbol Angle, in thenths of degree.
    1447                 :      * Contrary to arc start/end angles, no conversion based on 
    1448                 :      * origin quadrant is required here
    1449                 :      *------------------------------------------------------------*/
    1450               0 :     poPointHdr->m_nAngle = ROUND_INT(m_dAngle * 10.0);
    1451                 : 
    1452                 :     // Write Font Def
    1453               0 :     m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
    1454               0 :     poPointHdr->m_nFontId = m_nFontDefIndex;      // Font name index
    1455                 : 
    1456               0 :     if (CPLGetLastErrorNo() != 0)
    1457               0 :         return -1;
    1458                 : 
    1459               0 :     return 0;
    1460                 : }
    1461                 : 
    1462                 : /**********************************************************************
    1463                 :  *                   TABFontPoint::QueryFontStyle()
    1464                 :  *
    1465                 :  * Return TRUE if the specified font style attribute is turned ON,
    1466                 :  * or FALSE otherwise.  See enum TABFontStyle for the list of styles
    1467                 :  * that can be queried on.
    1468                 :  **********************************************************************/
    1469               0 : GBool TABFontPoint::QueryFontStyle(TABFontStyle eStyleToQuery)
    1470                 : {
    1471               0 :     return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
    1472                 : }
    1473                 : 
    1474               0 : void TABFontPoint::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
    1475                 : {
    1476               0 :     if (bStyleOn)
    1477               0 :         m_nFontStyle |=  (int)eStyleToToggle;
    1478                 :     else
    1479               0 :         m_nFontStyle &=  ~(int)eStyleToToggle;
    1480               0 : }
    1481                 : 
    1482                 : /**********************************************************************
    1483                 :  *                   TABFontPoint::GetFontStyleMIFValue()
    1484                 :  *
    1485                 :  * Return the Font Style value for this object using the style values
    1486                 :  * that are used in a MIF FONT() clause.  See MIF specs (appendix A).
    1487                 :  *
    1488                 :  * The reason why we have to differentiate between the TAB and the MIF font
    1489                 :  * style values is that in TAB, TABFSBox is included in the style value
    1490                 :  * as code 0x100, but in MIF it is not included, instead it is implied by
    1491                 :  * the presence of the BG color in the FONT() clause (the BG color is 
    1492                 :  * present only when TABFSBox or TABFSHalo is set).
    1493                 :  * This also has the effect of shifting all the other style values > 0x100
    1494                 :  * by 1 byte.
    1495                 :  *
    1496                 :  * NOTE: Even if there is no BG color for font symbols, we inherit this
    1497                 :  * problem because Font Point styles use the same codes as Text Font styles.
    1498                 :  **********************************************************************/
    1499               0 : int TABFontPoint::GetFontStyleMIFValue()
    1500                 : {
    1501                 :     // The conversion is simply to remove bit 0x100 from the value and shift
    1502                 :     // down all values past this bit.
    1503               0 :     return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
    1504                 : }
    1505                 : 
    1506               0 : void TABFontPoint:: SetFontStyleMIFValue(int nStyle)
    1507                 : {
    1508               0 :     m_nFontStyle = (nStyle & 0xff) + (nStyle & 0x7f00)*2;
    1509               0 : }
    1510                 : 
    1511                 : /**********************************************************************
    1512                 :  *                   TABFontPoint::SetSymbolAngle()
    1513                 :  *
    1514                 :  * Set the symbol angle value in degrees, making sure the value is
    1515                 :  * always in the range [0..360]
    1516                 :  **********************************************************************/
    1517               0 : void TABFontPoint::SetSymbolAngle(double dAngle)
    1518                 : {
    1519               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    1520               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    1521                 : 
    1522               0 :     m_dAngle = dAngle;
    1523               0 : }
    1524                 : 
    1525                 : 
    1526                 : /**********************************************************************
    1527                 :  *                   TABFontPoint::GetStyleString()
    1528                 :  *
    1529                 :  * Return style string for this feature.
    1530                 :  *
    1531                 :  * Style String is built only once during the first call to GetStyleString().
    1532                 :  **********************************************************************/
    1533               0 : const char *TABFontPoint::GetStyleString()
    1534                 : {
    1535               0 :     if (m_pszStyleString == NULL)
    1536                 :     {
    1537                 :         /* Get the SymbolStyleString, and add the outline Color 
    1538                 :            (halo/border in MapInfo Symbol terminology) */
    1539               0 :         char *pszSymbolStyleString = CPLStrdup(GetSymbolStyleString(GetSymbolAngle()));
    1540               0 :         int nStyleStringlen = strlen(pszSymbolStyleString);
    1541               0 :         pszSymbolStyleString[nStyleStringlen-1] = '\0';
    1542                 : 
    1543                 :         const char *outlineColor;
    1544               0 :         if (m_nFontStyle & 16)
    1545               0 :             outlineColor = ",o:#000000";
    1546               0 :         else if (m_nFontStyle & 512)
    1547               0 :             outlineColor = ",o:#ffffff";
    1548                 :         else
    1549               0 :             outlineColor = "";
    1550                 : 
    1551                 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s%s)",
    1552                 :                                                 pszSymbolStyleString,
    1553               0 :                                                 outlineColor));
    1554               0 :         CPLFree(pszSymbolStyleString);
    1555                 :     }
    1556                 : 
    1557               0 :     return m_pszStyleString;
    1558                 : }
    1559                 : 
    1560                 : 
    1561                 : /*=====================================================================
    1562                 :  *                      class TABCustomPoint
    1563                 :  *====================================================================*/
    1564                 : 
    1565                 : 
    1566                 : /**********************************************************************
    1567                 :  *                   TABCustomPoint::TABCustomPoint()
    1568                 :  *
    1569                 :  * Constructor.
    1570                 :  **********************************************************************/
    1571               0 : TABCustomPoint::TABCustomPoint(OGRFeatureDefn *poDefnIn):
    1572               0 :                     TABPoint(poDefnIn)
    1573                 : {
    1574               0 :     m_nUnknown_ = m_nCustomStyle = 0;
    1575               0 : }
    1576                 : 
    1577                 : /**********************************************************************
    1578                 :  *                   TABCustomPoint::~TABCustomPoint()
    1579                 :  *
    1580                 :  * Destructor.
    1581                 :  **********************************************************************/
    1582               0 : TABCustomPoint::~TABCustomPoint()
    1583                 : {
    1584               0 : }
    1585                 : 
    1586                 : /**********************************************************************
    1587                 :  *                     TABCustomPoint::CloneTABFeature()
    1588                 :  *
    1589                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    1590                 :  *
    1591                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    1592                 :  * then copies any members specific to its own type.
    1593                 :  **********************************************************************/
    1594               0 : TABFeature *TABCustomPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    1595                 : {
    1596                 :     /*-----------------------------------------------------------------
    1597                 :      * Alloc new feature and copy the base stuff
    1598                 :      *----------------------------------------------------------------*/
    1599                 :     TABCustomPoint *poNew = new TABCustomPoint(poNewDefn ? poNewDefn : 
    1600               0 :                                                            GetDefnRef());
    1601                 : 
    1602               0 :     CopyTABFeatureBase(poNew);
    1603                 : 
    1604                 :     /*-----------------------------------------------------------------
    1605                 :      * And members specific to this class
    1606                 :      *----------------------------------------------------------------*/
    1607                 :     // ITABFeatureSymbol
    1608               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
    1609                 : 
    1610                 :     // ITABFeatureFont
    1611               0 :     *(poNew->GetFontDefRef()) = *GetFontDefRef();
    1612                 : 
    1613               0 :     poNew->SetCustomSymbolStyle( GetCustomSymbolStyle() );
    1614                 : 
    1615               0 :     return poNew;
    1616                 : }
    1617                 : 
    1618                 : /**********************************************************************
    1619                 :  *                   TABCustomPoint::ReadGeometryFromMAPFile()
    1620                 :  *
    1621                 :  * Fill the geometry and representation (color, etc...) part of the
    1622                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    1623                 :  *
    1624                 :  * It is assumed that poMAPFile currently points to the beginning of
    1625                 :  * a map object.
    1626                 :  *
    1627                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1628                 :  * been called.
    1629                 :  **********************************************************************/
    1630                 : int TABCustomPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    1631                 :                                             TABMAPObjHdr *poObjHdr,
    1632                 :                                             GBool bCoordBlockDataOnly /*=FALSE*/,
    1633               0 :                                             TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1634                 : {
    1635                 :     double              dX, dY;
    1636                 :     OGRGeometry         *poGeometry;
    1637                 : 
    1638                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1639               0 :     if (bCoordBlockDataOnly)
    1640               0 :         return 0;
    1641                 : 
    1642                 :     /*-----------------------------------------------------------------
    1643                 :      * Fetch and validate geometry type
    1644                 :      *----------------------------------------------------------------*/
    1645               0 :     m_nMapInfoType = poObjHdr->m_nType;
    1646                 : 
    1647               0 :     if (m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL &&
    1648                 :         m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL_C )
    1649                 :     {
    1650                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1651                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    1652               0 :                  m_nMapInfoType, m_nMapInfoType);
    1653               0 :         return -1;
    1654                 :     }
    1655                 : 
    1656                 :     /*-----------------------------------------------------------------
    1657                 :      * Read object information
    1658                 :      *----------------------------------------------------------------*/
    1659               0 :     TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
    1660                 : 
    1661               0 :     m_nUnknown_    = poPointHdr->m_nUnknown_;   // ??? 
    1662               0 :     m_nCustomStyle = poPointHdr->m_nCustomStyle;// 0x01=Show BG,
    1663                 :                                                 // 0x02=Apply Color
    1664                 : 
    1665               0 :     m_nSymbolDefIndex = poPointHdr->m_nSymbolId;   // Symbol index
    1666               0 :     poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
    1667                 : 
    1668               0 :     m_nFontDefIndex = poPointHdr->m_nFontId;    // Font index
    1669               0 :     poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
    1670                 : 
    1671                 :     /*-----------------------------------------------------------------
    1672                 :      * Create and fill geometry object
    1673                 :      *----------------------------------------------------------------*/
    1674               0 :     poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
    1675               0 :     poGeometry = new OGRPoint(dX, dY);
    1676                 :     
    1677               0 :     SetGeometryDirectly(poGeometry);
    1678                 : 
    1679               0 :     SetMBR(dX, dY, dX, dY);
    1680                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    1681               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    1682                 : 
    1683               0 :     return 0;
    1684                 : }
    1685                 : 
    1686                 : /**********************************************************************
    1687                 :  *                   TABCustomPoint::WriteGeometryToMAPFile()
    1688                 :  *
    1689                 :  * Write the geometry and representation (color, etc...) part of the
    1690                 :  * feature to the .MAP object pointed to by poMAPFile.
    1691                 :  *
    1692                 :  * It is assumed that poMAPFile currently points to a valid map object.
    1693                 :  *
    1694                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1695                 :  * been called.
    1696                 :  **********************************************************************/
    1697                 : int TABCustomPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    1698                 :                                            TABMAPObjHdr *poObjHdr,
    1699                 :                                            GBool bCoordBlockDataOnly /*=FALSE*/,
    1700               0 :                                            TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1701                 : {
    1702                 :     GInt32              nX, nY;
    1703                 :     OGRGeometry         *poGeom;
    1704                 :     OGRPoint            *poPoint;
    1705                 : 
    1706                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1707               0 :     if (bCoordBlockDataOnly)
    1708               0 :         return 0;
    1709                 : 
    1710                 :     /*-----------------------------------------------------------------
    1711                 :      * We assume that ValidateMapInfoType() was called already and that
    1712                 :      * the type in poObjHdr->m_nType is valid.
    1713                 :      *----------------------------------------------------------------*/
    1714               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    1715                 : 
    1716                 :     /*-----------------------------------------------------------------
    1717                 :      * Fetch and validate geometry
    1718                 :      *----------------------------------------------------------------*/
    1719               0 :     poGeom = GetGeometryRef();
    1720               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1721               0 :         poPoint = (OGRPoint*)poGeom;
    1722                 :     else
    1723                 :     {
    1724                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1725               0 :                  "TABCustomPoint: Missing or Invalid Geometry!");
    1726               0 :         return -1;
    1727                 :     }
    1728                 : 
    1729               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    1730                 : 
    1731                 :     /*-----------------------------------------------------------------
    1732                 :      * Copy object information
    1733                 :      *----------------------------------------------------------------*/
    1734               0 :     TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
    1735                 : 
    1736               0 :     poPointHdr->m_nX = nX;
    1737               0 :     poPointHdr->m_nY = nY;
    1738               0 :     poPointHdr->SetMBR(nX, nY, nX, nY);
    1739               0 :     poPointHdr->m_nUnknown_ = m_nUnknown_;
    1740               0 :     poPointHdr->m_nCustomStyle = m_nCustomStyle;// 0x01=Show BG,
    1741                 :                                                // 0x02=Apply Color
    1742                 : 
    1743               0 :     m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
    1744               0 :     poPointHdr->m_nSymbolId = m_nSymbolDefIndex;      // Symbol index
    1745                 : 
    1746               0 :     m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
    1747               0 :     poPointHdr->m_nFontId = m_nFontDefIndex;      // Font index
    1748                 : 
    1749               0 :     if (CPLGetLastErrorNo() != 0)
    1750               0 :         return -1;
    1751                 : 
    1752               0 :     return 0;
    1753                 : }
    1754                 : 
    1755                 : 
    1756                 : /**********************************************************************
    1757                 :  *                   TABCustomPoint::GetStyleString()
    1758                 :  *
    1759                 :  * Return style string for this feature.
    1760                 :  *
    1761                 :  * Style String is built only once during the first call to GetStyleString().
    1762                 :  **********************************************************************/
    1763               0 : const char *TABCustomPoint::GetStyleString()
    1764                 : {
    1765               0 :     if (m_pszStyleString == NULL)
    1766                 :     {
    1767               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    1768                 :     }
    1769                 : 
    1770               0 :     return m_pszStyleString;
    1771                 : }
    1772                 : 
    1773                 : /*=====================================================================
    1774                 :  *                      class TABPolyline
    1775                 :  *====================================================================*/
    1776                 : 
    1777                 : 
    1778                 : /**********************************************************************
    1779                 :  *                   TABPolyline::TABPolyline()
    1780                 :  *
    1781                 :  * Constructor.
    1782                 :  **********************************************************************/
    1783               2 : TABPolyline::TABPolyline(OGRFeatureDefn *poDefnIn):
    1784               2 :               TABFeature(poDefnIn)
    1785                 : {
    1786               2 :     m_bCenterIsSet = FALSE;
    1787               2 :     m_bSmooth = FALSE;
    1788               2 :     m_bWriteTwoPointLineAsPolyline = FALSE;
    1789               2 : }
    1790                 : 
    1791                 : /**********************************************************************
    1792                 :  *                   TABPolyline::~TABPolyline()
    1793                 :  *
    1794                 :  * Destructor.
    1795                 :  **********************************************************************/
    1796               2 : TABPolyline::~TABPolyline()
    1797                 : {
    1798               2 : }
    1799                 : 
    1800                 : /**********************************************************************
    1801                 :  *                     TABPolyline::CloneTABFeature()
    1802                 :  *
    1803                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    1804                 :  *
    1805                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    1806                 :  * then copies any members specific to its own type.
    1807                 :  **********************************************************************/
    1808               0 : TABFeature *TABPolyline::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    1809                 : {
    1810                 :     /*-----------------------------------------------------------------
    1811                 :      * Alloc new feature and copy the base stuff
    1812                 :      *----------------------------------------------------------------*/
    1813               0 :     TABPolyline *poNew = new TABPolyline(poNewDefn ? poNewDefn : GetDefnRef());
    1814                 : 
    1815               0 :     CopyTABFeatureBase(poNew);
    1816                 : 
    1817                 :     /*-----------------------------------------------------------------
    1818                 :      * And members specific to this class
    1819                 :      *----------------------------------------------------------------*/
    1820                 :     // ITABFeaturePen
    1821               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    1822                 : 
    1823               0 :     poNew->m_bSmooth = m_bSmooth;
    1824               0 :     poNew->m_bCenterIsSet = m_bCenterIsSet;
    1825               0 :     poNew->m_dCenterX = m_dCenterX;
    1826               0 :     poNew->m_dCenterY = m_dCenterY;
    1827                 : 
    1828               0 :     return poNew;
    1829                 : }
    1830                 : 
    1831                 : /**********************************************************************
    1832                 :  *                   TABPolyline::GetNumParts()
    1833                 :  *
    1834                 :  * Return the total number of parts in this object.
    1835                 :  *
    1836                 :  * Returns 0 if the geometry contained in the object is invalid or missing.
    1837                 :  **********************************************************************/
    1838               0 : int TABPolyline::GetNumParts()
    1839                 : {
    1840                 :     OGRGeometry         *poGeom;
    1841               0 :     int                 numParts = 0;
    1842                 : 
    1843               0 :     poGeom = GetGeometryRef();
    1844               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    1845                 :     {
    1846                 :         /*-------------------------------------------------------------
    1847                 :          * Simple polyline
    1848                 :          *------------------------------------------------------------*/
    1849               0 :         numParts = 1;
    1850                 :     }
    1851               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    1852                 :     {
    1853                 :         /*-------------------------------------------------------------
    1854                 :          * Multiple polyline
    1855                 :          *------------------------------------------------------------*/
    1856               0 :         OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
    1857               0 :         numParts = poMultiLine->getNumGeometries();
    1858                 :     }
    1859                 : 
    1860               0 :     return numParts;
    1861                 : }
    1862                 : 
    1863                 : /**********************************************************************
    1864                 :  *                   TABPolyline::GetPartRef()
    1865                 :  *
    1866                 :  * Returns a reference to the specified OGRLineString number, hiding the
    1867                 :  * complexity of dealing with OGRMultiLineString vs OGRLineString cases.
    1868                 :  *
    1869                 :  * Returns NULL if the geometry contained in the object is invalid or 
    1870                 :  * missing or if the specified part index is invalid.
    1871                 :  **********************************************************************/
    1872               0 : OGRLineString *TABPolyline::GetPartRef(int nPartIndex)
    1873                 : {
    1874                 :     OGRGeometry         *poGeom;
    1875                 : 
    1876               0 :     poGeom = GetGeometryRef();
    1877               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString && nPartIndex==0)
    1878                 :     {
    1879                 :         /*-------------------------------------------------------------
    1880                 :          * Simple polyline
    1881                 :          *------------------------------------------------------------*/
    1882               0 :         return (OGRLineString *)poGeom;
    1883                 :     }
    1884               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    1885                 :     {
    1886                 :         /*-------------------------------------------------------------
    1887                 :          * Multiple polyline
    1888                 :          *------------------------------------------------------------*/
    1889               0 :         OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
    1890               0 :         if (nPartIndex >= 0 &&
    1891                 :             nPartIndex < poMultiLine->getNumGeometries())
    1892                 :         {
    1893               0 :             return (OGRLineString*)poMultiLine->getGeometryRef(nPartIndex);
    1894                 :         }
    1895                 :         else
    1896               0 :             return NULL;
    1897                 :     }
    1898                 : 
    1899               0 :     return NULL;
    1900                 : }
    1901                 : 
    1902                 : /**********************************************************************
    1903                 :  *                   TABPolyline::ValidateMapInfoType()
    1904                 :  *
    1905                 :  * Check the feature's geometry part and return the corresponding
    1906                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    1907                 :  * be updated for further calls to GetMapInfoType();
    1908                 :  *
    1909                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    1910                 :  * is expected for this object class.
    1911                 :  **********************************************************************/
    1912               1 : int  TABPolyline::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    1913                 : {
    1914                 :     OGRGeometry   *poGeom;
    1915               1 :     OGRMultiLineString *poMultiLine = NULL;
    1916                 : 
    1917                 :     /*-----------------------------------------------------------------
    1918                 :      * Fetch and validate geometry
    1919                 :      *----------------------------------------------------------------*/
    1920               1 :     poGeom = GetGeometryRef();
    1921               1 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    1922                 :     {
    1923                 :         /*-------------------------------------------------------------
    1924                 :          * Simple polyline
    1925                 :          *------------------------------------------------------------*/
    1926               1 :         OGRLineString *poLine = (OGRLineString*)poGeom;
    1927               1 :         if ( TAB_REGION_PLINE_REQUIRES_V800(1, poLine->getNumPoints()) )
    1928                 :         {
    1929               0 :             m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
    1930                 :         }
    1931               1 :         else if ( poLine->getNumPoints() > TAB_REGION_PLINE_300_MAX_VERTICES)
    1932                 :         {
    1933               0 :             m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
    1934                 :         }
    1935               1 :         else if ( poLine->getNumPoints() > 2 )
    1936                 :         {
    1937               0 :             m_nMapInfoType = TAB_GEOM_PLINE;
    1938                 :         }
    1939               1 :         else if ( (poLine->getNumPoints() == 2) && 
    1940                 :                   (m_bWriteTwoPointLineAsPolyline == TRUE) )
    1941                 :         {
    1942               0 :            m_nMapInfoType = TAB_GEOM_PLINE;
    1943                 :         }
    1944               1 :         else if ( (poLine->getNumPoints() == 2) && 
    1945                 :                   (m_bWriteTwoPointLineAsPolyline == FALSE) )
    1946                 :         {
    1947               1 :             m_nMapInfoType = TAB_GEOM_LINE;
    1948                 :         }
    1949                 :         else
    1950                 :         {
    1951                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1952               0 :                      "TABPolyline: Geometry must contain at least 2 points.");
    1953               0 :             m_nMapInfoType = TAB_GEOM_NONE;
    1954                 :         }
    1955                 :     }
    1956               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    1957                 :     {
    1958                 :         /*-------------------------------------------------------------
    1959                 :          * Multiple polyline... validate all components
    1960                 :          *------------------------------------------------------------*/
    1961                 :         int iLine, numLines;
    1962               0 :         GInt32 numPointsTotal = 0;
    1963               0 :         poMultiLine = (OGRMultiLineString*)poGeom;
    1964               0 :         numLines = poMultiLine->getNumGeometries();
    1965                 : 
    1966               0 :         m_nMapInfoType = TAB_GEOM_MULTIPLINE;
    1967                 : 
    1968               0 :         for(iLine=0; iLine < numLines; iLine++)
    1969                 :         {
    1970               0 :             poGeom = poMultiLine->getGeometryRef(iLine);
    1971               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) != wkbLineString)
    1972                 :             {
    1973                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    1974               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    1975               0 :                 m_nMapInfoType = TAB_GEOM_NONE;
    1976               0 :                 numPointsTotal = 0;
    1977               0 :                 break;
    1978                 :             }
    1979               0 :             OGRLineString *poLine = (OGRLineString*)poGeom;
    1980               0 :             numPointsTotal += poLine->getNumPoints();
    1981                 :         }
    1982                 : 
    1983               0 :         if ( TAB_REGION_PLINE_REQUIRES_V800(numLines, numPointsTotal) )
    1984               0 :             m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
    1985               0 :         else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
    1986               0 :             m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
    1987                 :     }
    1988                 :     else
    1989                 :     {
    1990                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1991               0 :                  "TABPolyline: Missing or Invalid Geometry!");
    1992               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    1993                 :     }
    1994                 : 
    1995                 :     /*-----------------------------------------------------------------
    1996                 :      * Decide if coordinates should be compressed or not.
    1997                 :      *
    1998                 :      * __TODO__ We never write type LINE (2 points line) as compressed
    1999                 :      * for the moment.  If we ever do it, then the decision to write
    2000                 :      * a 2 point line in compressed coordinates or not should take into
    2001                 :      * account the location of the object block MBR, so this would be
    2002                 :      * better handled directly by TABMAPObjLine::WriteObject() since the
    2003                 :      * object block center is not known until it is written to disk.
    2004                 :      *----------------------------------------------------------------*/
    2005               1 :     if (m_nMapInfoType != TAB_GEOM_LINE)
    2006                 :     {
    2007               0 :         ValidateCoordType(poMapFile);
    2008                 :     }
    2009                 :     else
    2010                 :     {
    2011               1 :         UpdateMBR(poMapFile);
    2012                 :     }
    2013                 : 
    2014               1 :     return m_nMapInfoType;
    2015                 : }
    2016                 : 
    2017                 : 
    2018                 : /**********************************************************************
    2019                 :  *                   TABPolyline::ReadGeometryFromMAPFile()
    2020                 :  *
    2021                 :  * Fill the geometry and representation (color, etc...) part of the
    2022                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    2023                 :  *
    2024                 :  * It is assumed that poMAPFile currently points to the beginning of
    2025                 :  * a map object.
    2026                 :  *
    2027                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    2028                 :  * been called.
    2029                 :  **********************************************************************/
    2030                 : int TABPolyline::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    2031                 :                                          TABMAPObjHdr *poObjHdr,
    2032                 :                                          GBool bCoordBlockDataOnly /*=FALSE*/,
    2033               1 :                                          TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    2034                 : {
    2035                 :     GInt32              nX, nY;
    2036                 :     double              dX, dY, dXMin, dYMin, dXMax, dYMax;
    2037                 :     OGRGeometry         *poGeometry;
    2038                 :     OGRLineString       *poLine;
    2039               1 :     GBool               bComprCoord = poObjHdr->IsCompressedType();
    2040               1 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    2041                 : 
    2042                 :     /*-----------------------------------------------------------------
    2043                 :      * Fetch and validate geometry type
    2044                 :      *----------------------------------------------------------------*/
    2045               1 :     m_nMapInfoType = poObjHdr->m_nType;
    2046                 : 
    2047               2 :     if (m_nMapInfoType == TAB_GEOM_LINE ||
    2048                 :         m_nMapInfoType == TAB_GEOM_LINE_C )
    2049                 :     {
    2050                 :         /*=============================================================
    2051                 :          * LINE (2 vertices)
    2052                 :          *============================================================*/
    2053               1 :         TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
    2054                 : 
    2055               1 :         m_bSmooth = FALSE;
    2056                 : 
    2057               1 :         poGeometry = poLine = new OGRLineString();
    2058               1 :         poLine->setNumPoints(2);
    2059                 : 
    2060                 :         poMapFile->Int2Coordsys(poLineHdr->m_nX1, poLineHdr->m_nY1, 
    2061               1 :                                 dXMin, dYMin);
    2062               1 :         poLine->setPoint(0, dXMin, dYMin);
    2063                 : 
    2064                 :         poMapFile->Int2Coordsys(poLineHdr->m_nX2, poLineHdr->m_nY2,
    2065               1 :                                 dXMax, dYMax);
    2066               1 :         poLine->setPoint(1, dXMax, dYMax);
    2067                 : 
    2068               1 :         if (!bCoordBlockDataOnly)
    2069                 :         {
    2070               1 :             m_nPenDefIndex = poLineHdr->m_nPenId;      // Pen index
    2071               1 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    2072                 :         }
    2073                 :     }
    2074               0 :     else if (m_nMapInfoType == TAB_GEOM_PLINE ||
    2075                 :              m_nMapInfoType == TAB_GEOM_PLINE_C )
    2076                 :     {
    2077                 :         /*=============================================================
    2078                 :          * PLINE ( > 2 vertices)
    2079                 :          *============================================================*/
    2080                 :         int     i, numPoints, nStatus;
    2081                 :         GUInt32 nCoordDataSize;
    2082                 :         GInt32  nCoordBlockPtr;
    2083                 : 
    2084                 :         /*-------------------------------------------------------------
    2085                 :          * Copy data from poObjHdr
    2086                 :          *------------------------------------------------------------*/
    2087               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2088                 : 
    2089               0 :         nCoordBlockPtr  = poPLineHdr->m_nCoordBlockPtr;
    2090               0 :         nCoordDataSize  = poPLineHdr->m_nCoordDataSize;
    2091                 :         //numLineSections = poPLineHdr->m_numLineSections; // Always 1
    2092               0 :         m_bSmooth       = poPLineHdr->m_bSmooth;
    2093                 : 
    2094                 :         // Centroid/label point
    2095                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY, 
    2096               0 :                                 dX, dY);
    2097               0 :         SetCenter(dX, dY);
    2098                 : 
    2099                 :         // Compressed coordinate origin (useful only in compressed case!)
    2100               0 :         m_nComprOrgX = poPLineHdr->m_nComprOrgX;
    2101               0 :         m_nComprOrgY = poPLineHdr->m_nComprOrgY;
    2102                 : 
    2103                 :         // MBR
    2104                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY, 
    2105               0 :                                 dXMin, dYMin);
    2106                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY, 
    2107               0 :                                 dXMax, dYMax);
    2108                 : 
    2109               0 :         if (!bCoordBlockDataOnly)
    2110                 :         {
    2111               0 :             m_nPenDefIndex = poPLineHdr->m_nPenId;        // Pen index
    2112               0 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    2113                 :         }
    2114                 : 
    2115                 :         /*-------------------------------------------------------------
    2116                 :          * Create Geometry and read coordinates
    2117                 :          *------------------------------------------------------------*/
    2118               0 :         numPoints = nCoordDataSize/(bComprCoord?4:8);
    2119                 : 
    2120               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2121               0 :             poCoordBlock = *ppoCoordBlock;
    2122                 :         else
    2123               0 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    2124               0 :         if (poCoordBlock == NULL)
    2125                 :         {
    2126                 :             CPLError(CE_Failure, CPLE_FileIO,
    2127                 :                      "Can't access coordinate block at offset %d", 
    2128               0 :                      nCoordBlockPtr);
    2129               0 :             return -1;
    2130                 :         }
    2131                 : 
    2132               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2133                 : 
    2134               0 :         poGeometry = poLine = new OGRLineString();
    2135               0 :         poLine->setNumPoints(numPoints);
    2136                 : 
    2137               0 :         nStatus = 0;
    2138               0 :         for(i=0; nStatus == 0 && i<numPoints; i++)
    2139                 :         {
    2140               0 :             nStatus = poCoordBlock->ReadIntCoord(bComprCoord, nX, nY);
    2141               0 :             if (nStatus != 0)
    2142               0 :                 break;
    2143               0 :             poMapFile->Int2Coordsys(nX, nY, dX, dY);
    2144               0 :             poLine->setPoint(i, dX, dY);
    2145                 :         }
    2146                 : 
    2147               0 :         if (nStatus != 0)
    2148                 :         {
    2149                 :             // Failed ... error message has already been produced
    2150               0 :             delete poGeometry;
    2151               0 :             return nStatus;
    2152                 :         }   
    2153                 : 
    2154                 :     }
    2155               0 :     else if (m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
    2156                 :              m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
    2157                 :              m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
    2158                 :              m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
    2159                 :              m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
    2160                 :              m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C )
    2161                 :     {
    2162                 :         /*=============================================================
    2163                 :          * PLINE MULTIPLE
    2164                 :          *============================================================*/
    2165                 :         int     i, iSection;
    2166                 :         GInt32  nCoordBlockPtr, numLineSections;
    2167                 :         GInt32  nCoordDataSize, numPointsTotal, *panXY;
    2168                 :         OGRMultiLineString      *poMultiLine;
    2169                 :         TABMAPCoordSecHdr       *pasSecHdrs;
    2170               0 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    2171                 : 
    2172                 :         /*-------------------------------------------------------------
    2173                 :          * Copy data from poObjHdr
    2174                 :          *------------------------------------------------------------*/
    2175               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2176                 : 
    2177               0 :         nCoordBlockPtr  = poPLineHdr->m_nCoordBlockPtr;
    2178               0 :         nCoordDataSize  = poPLineHdr->m_nCoordDataSize;
    2179               0 :         numLineSections = poPLineHdr->m_numLineSections;
    2180               0 :         m_bSmooth       = poPLineHdr->m_bSmooth;
    2181                 : 
    2182                 :         // Centroid/label point
    2183                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY, 
    2184               0 :                                 dX, dY);
    2185               0 :         SetCenter(dX, dY);
    2186                 : 
    2187                 :         // Compressed coordinate origin (useful only in compressed case!)
    2188               0 :         m_nComprOrgX = poPLineHdr->m_nComprOrgX;
    2189               0 :         m_nComprOrgY = poPLineHdr->m_nComprOrgY;
    2190                 : 
    2191                 :         // MBR
    2192                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY, 
    2193               0 :                                 dXMin, dYMin);
    2194                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY, 
    2195               0 :                                 dXMax, dYMax);
    2196                 : 
    2197               0 :         if (!bCoordBlockDataOnly)
    2198                 :         {
    2199               0 :             m_nPenDefIndex = poPLineHdr->m_nPenId;        // Pen index
    2200               0 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    2201                 :         }
    2202                 : 
    2203                 :         /*-------------------------------------------------------------
    2204                 :          * Read data from the coord. block
    2205                 :          *------------------------------------------------------------*/
    2206                 :         pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
    2207               0 :                                                    sizeof(TABMAPCoordSecHdr));
    2208                 : 
    2209               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2210               0 :             poCoordBlock = *ppoCoordBlock;
    2211                 :         else
    2212               0 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    2213                 : 
    2214               0 :         if (poCoordBlock == NULL ||
    2215                 :             poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion, 
    2216                 :                                            numLineSections,
    2217                 :                                            pasSecHdrs, numPointsTotal) != 0)
    2218                 :         {
    2219                 :             CPLError(CE_Failure, CPLE_FileIO,
    2220                 :                      "Failed reading coordinate data at offset %d", 
    2221               0 :                      nCoordBlockPtr);
    2222               0 :             CPLFree(pasSecHdrs);
    2223               0 :             return -1;
    2224                 :         }
    2225                 : 
    2226               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2227                 : 
    2228               0 :         panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
    2229                 : 
    2230               0 :         if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
    2231                 :         {
    2232                 :             CPLError(CE_Failure, CPLE_FileIO,
    2233                 :                      "Failed reading coordinate data at offset %d", 
    2234               0 :                      nCoordBlockPtr);
    2235               0 :             CPLFree(pasSecHdrs);
    2236               0 :             CPLFree(panXY);
    2237               0 :             return -1;
    2238                 :         }
    2239                 : 
    2240                 :         /*-------------------------------------------------------------
    2241                 :          * Create a Geometry collection with one line geometry for
    2242                 :          * each coordinates section
    2243                 :          * If object contains only one section, then return a simple LineString
    2244                 :          *------------------------------------------------------------*/
    2245               0 :         if (numLineSections > 1)
    2246               0 :             poGeometry = poMultiLine = new OGRMultiLineString();
    2247                 :         else
    2248               0 :             poGeometry = poMultiLine = NULL;
    2249                 : 
    2250               0 :         for(iSection=0; iSection<numLineSections; iSection++)
    2251                 :         {
    2252                 :             GInt32 *pnXYPtr;
    2253                 :             int     numSectionVertices;
    2254                 : 
    2255               0 :             numSectionVertices = pasSecHdrs[iSection].numVertices;
    2256               0 :             pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
    2257                 : 
    2258               0 :             poLine = new OGRLineString();
    2259               0 :             poLine->setNumPoints(numSectionVertices);
    2260                 : 
    2261               0 :             for(i=0; i<numSectionVertices; i++)
    2262                 :             {
    2263               0 :                 poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
    2264               0 :                 poLine->setPoint(i, dX, dY);
    2265               0 :                 pnXYPtr += 2;
    2266                 :             }
    2267                 : 
    2268               0 :             if (poGeometry==NULL)
    2269               0 :                 poGeometry = poLine;
    2270               0 :             else if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
    2271                 :             {
    2272               0 :                 CPLAssert(FALSE); // Just in case lower-level lib is modified
    2273                 :             }
    2274               0 :             poLine = NULL;
    2275                 :         }
    2276                 : 
    2277               0 :         CPLFree(pasSecHdrs);
    2278               0 :         CPLFree(panXY);
    2279                 :     }
    2280                 :     else
    2281                 :     {
    2282                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2283                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    2284               0 :                  m_nMapInfoType, m_nMapInfoType);
    2285               0 :         return -1;
    2286                 :     }
    2287                 : 
    2288               1 :     SetGeometryDirectly(poGeometry);
    2289                 : 
    2290               1 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    2291                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    2292               1 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    2293                 : 
    2294                 :     /* Return a ref to coord block so that caller can continue reading
    2295                 :      * after the end of this object (used by TABCollection and index splitting)
    2296                 :      */
    2297               1 :     if (ppoCoordBlock)
    2298               0 :         *ppoCoordBlock = poCoordBlock;
    2299                 : 
    2300               1 :     return 0;
    2301                 : }
    2302                 : 
    2303                 : /**********************************************************************
    2304                 :  *                   TABPolyline::WriteGeometryToMAPFile()
    2305                 :  *
    2306                 :  * Write the geometry and representation (color, etc...) part of the
    2307                 :  * feature to the .MAP object pointed to by poMAPFile.
    2308                 :  *
    2309                 :  * It is assumed that poMAPFile currently points to a valid map object.
    2310                 :  *
    2311                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    2312                 :  * been called.
    2313                 :  **********************************************************************/
    2314                 : int TABPolyline::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    2315                 :                                         TABMAPObjHdr *poObjHdr,
    2316                 :                                         GBool bCoordBlockDataOnly /*=FALSE*/,
    2317               1 :                                         TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    2318                 : {
    2319                 :     GInt32              nX, nY;
    2320                 :     OGRGeometry         *poGeom;
    2321               1 :     OGRLineString       *poLine=NULL;
    2322               1 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    2323                 : 
    2324                 :     /*-----------------------------------------------------------------
    2325                 :      * We assume that ValidateMapInfoType() was called already and that
    2326                 :      * the type in poObjHdr->m_nType is valid.
    2327                 :      *----------------------------------------------------------------*/
    2328               1 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    2329               1 :     CPLErrorReset();
    2330                 : 
    2331                 :     /*-----------------------------------------------------------------
    2332                 :      * Fetch and validate geometry
    2333                 :      *----------------------------------------------------------------*/
    2334               1 :     poGeom = GetGeometryRef();
    2335                 : 
    2336               1 :     if ((m_nMapInfoType == TAB_GEOM_LINE || 
    2337                 :          m_nMapInfoType == TAB_GEOM_LINE_C ) &&
    2338                 :         poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString &&
    2339                 :         (poLine = (OGRLineString*)poGeom)->getNumPoints() == 2)
    2340                 :     {
    2341                 :         /*=============================================================
    2342                 :          * LINE (2 vertices)
    2343                 :          *============================================================*/
    2344               1 :         TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
    2345                 : 
    2346                 :         poMapFile->Coordsys2Int(poLine->getX(0), poLine->getY(0), 
    2347               1 :                                 poLineHdr->m_nX1, poLineHdr->m_nY1);
    2348                 :         poMapFile->Coordsys2Int(poLine->getX(1), poLine->getY(1), 
    2349               1 :                                 poLineHdr->m_nX2, poLineHdr->m_nY2);
    2350                 :         poLineHdr->SetMBR(poLineHdr->m_nX1, poLineHdr->m_nY1,
    2351               1 :                           poLineHdr->m_nX2, poLineHdr->m_nY2 );
    2352                 : 
    2353               1 :         if (!bCoordBlockDataOnly)
    2354                 :         {
    2355               1 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    2356               1 :             poLineHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    2357                 :         }
    2358                 : 
    2359                 :     }
    2360               0 :     else if ((m_nMapInfoType == TAB_GEOM_PLINE ||
    2361                 :               m_nMapInfoType == TAB_GEOM_PLINE_C ) &&
    2362                 :              poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
    2363                 :     {
    2364                 :         /*=============================================================
    2365                 :          * PLINE ( > 2 vertices and less than 32767 vertices)
    2366                 :          *============================================================*/
    2367                 :         int     i, numPoints, nStatus;
    2368                 :         GUInt32 nCoordDataSize;
    2369                 :         GInt32  nCoordBlockPtr;
    2370               0 :         GBool   bCompressed = poObjHdr->IsCompressedType();
    2371                 : 
    2372                 :         /*-------------------------------------------------------------
    2373                 :          * Process geometry first...
    2374                 :          *------------------------------------------------------------*/
    2375               0 :         poLine = (OGRLineString*)poGeom;
    2376               0 :         numPoints = poLine->getNumPoints();
    2377               0 :         CPLAssert(numPoints <= TAB_REGION_PLINE_300_MAX_VERTICES);
    2378                 : 
    2379               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2380               0 :             poCoordBlock = *ppoCoordBlock;
    2381                 :         else
    2382               0 :             poCoordBlock = poMapFile->GetCurCoordBlock();
    2383               0 :         poCoordBlock->StartNewFeature();
    2384               0 :         nCoordBlockPtr = poCoordBlock->GetCurAddress();
    2385               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2386                 : 
    2387               0 :         nStatus = 0;
    2388               0 :         for(i=0; nStatus == 0 && i<numPoints; i++)
    2389                 :         {
    2390               0 :             poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i), nX, nY);
    2391               0 :             if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY, 
    2392                 :                                                        bCompressed)) != 0)
    2393                 :             {
    2394                 :                 // Failed ... error message has already been produced
    2395               0 :                 return nStatus;
    2396                 :             }   
    2397                 :         }
    2398                 : 
    2399               0 :         nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    2400                 : 
    2401                 :         /*-------------------------------------------------------------
    2402                 :          * Copy info to poObjHdr
    2403                 :          *------------------------------------------------------------*/
    2404               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2405                 : 
    2406               0 :         poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
    2407               0 :         poPLineHdr->m_nCoordDataSize = nCoordDataSize;
    2408               0 :         poPLineHdr->m_numLineSections = 1;
    2409                 : 
    2410               0 :         poPLineHdr->m_bSmooth = m_bSmooth;
    2411                 : 
    2412                 :         // MBR
    2413               0 :         poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    2414                 : 
    2415                 :         // Polyline center/label point
    2416                 :         double dX, dY;
    2417               0 :         if (GetCenter(dX, dY) != -1)
    2418                 :         {
    2419                 :             poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX, 
    2420               0 :                                     poPLineHdr->m_nLabelY);
    2421                 :         }
    2422                 :         else
    2423                 :         {
    2424               0 :             poPLineHdr->m_nLabelX = m_nComprOrgX;
    2425               0 :             poPLineHdr->m_nLabelY = m_nComprOrgY;
    2426                 :         }
    2427                 :         
    2428                 :         // Compressed coordinate origin (useful only in compressed case!)
    2429               0 :         poPLineHdr->m_nComprOrgX = m_nComprOrgX;
    2430               0 :         poPLineHdr->m_nComprOrgY = m_nComprOrgY;
    2431                 : 
    2432               0 :         if (!bCoordBlockDataOnly)
    2433                 :         {
    2434               0 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    2435               0 :             poPLineHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    2436                 :         }
    2437                 : 
    2438                 :     }
    2439               0 :     else if ((m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
    2440                 :               m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
    2441                 :               m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
    2442                 :               m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
    2443                 :               m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
    2444                 :               m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C) &&
    2445                 :              poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
    2446                 :                         wkbFlatten(poGeom->getGeometryType()) == wkbLineString) )
    2447                 :     {
    2448                 :         /*=============================================================
    2449                 :          * PLINE MULTIPLE (or single PLINE with more than 32767 vertices)
    2450                 :          *============================================================*/
    2451               0 :         int     nStatus=0, i, iLine;
    2452                 :         GInt32  numPointsTotal, numPoints;
    2453                 :         GUInt32 nCoordDataSize;
    2454                 :         GInt32  nCoordBlockPtr, numLines;
    2455               0 :         OGRMultiLineString      *poMultiLine=NULL;
    2456                 :         TABMAPCoordSecHdr       *pasSecHdrs;
    2457               0 :         OGREnvelope             sEnvelope;
    2458               0 :         GBool   bCompressed = poObjHdr->IsCompressedType();
    2459                 : 
    2460               0 :         CPLAssert(m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
    2461                 :                   m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
    2462                 :                   m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
    2463                 :                   m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
    2464                 :                   m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
    2465                 :                   m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C);
    2466                 :         /*-------------------------------------------------------------
    2467                 :          * Process geometry first...
    2468                 :          *------------------------------------------------------------*/
    2469               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2470               0 :             poCoordBlock = *ppoCoordBlock;
    2471                 :         else
    2472               0 :             poCoordBlock = poMapFile->GetCurCoordBlock();
    2473               0 :         poCoordBlock->StartNewFeature();
    2474               0 :         nCoordBlockPtr = poCoordBlock->GetCurAddress();
    2475               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2476                 : 
    2477               0 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2478                 :         {
    2479               0 :             poMultiLine = (OGRMultiLineString*)poGeom;
    2480               0 :             numLines = poMultiLine->getNumGeometries();
    2481                 :         }
    2482                 :         else
    2483                 :         {
    2484               0 :             poMultiLine = NULL;
    2485               0 :             numLines = 1;
    2486                 :         }
    2487                 : 
    2488                 :         /*-------------------------------------------------------------
    2489                 :          * Build and write array of coord sections headers
    2490                 :          *------------------------------------------------------------*/
    2491                 :         pasSecHdrs = (TABMAPCoordSecHdr*)CPLCalloc(numLines,
    2492               0 :                                                    sizeof(TABMAPCoordSecHdr));
    2493                 : 
    2494                 :         /*-------------------------------------------------------------
    2495                 :          * In calculation of nDataOffset, we have to take into account that
    2496                 :          * V450 header section uses int32 instead of int16 for numVertices
    2497                 :          * and we add another 2 bytes to align with a 4 bytes boundary.
    2498                 :          *------------------------------------------------------------*/
    2499               0 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    2500                 : 
    2501                 :         int nTotalHdrSizeUncompressed;
    2502               0 :         if (nVersion >= 450)
    2503               0 :             nTotalHdrSizeUncompressed = 28 * numLines;
    2504                 :         else
    2505               0 :             nTotalHdrSizeUncompressed = 24 * numLines;
    2506                 : 
    2507               0 :         numPointsTotal = 0;
    2508               0 :         for(iLine=0; iLine < numLines; iLine++)
    2509                 :         {
    2510               0 :             if (poMultiLine)
    2511               0 :                 poGeom = poMultiLine->getGeometryRef(iLine);
    2512                 :                 
    2513               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2514                 :             {
    2515               0 :                 poLine = (OGRLineString*)poGeom;
    2516               0 :                 numPoints = poLine->getNumPoints();
    2517               0 :                 poLine->getEnvelope(&sEnvelope);
    2518                 : 
    2519               0 :                 pasSecHdrs[iLine].numVertices = poLine->getNumPoints();
    2520               0 :                 pasSecHdrs[iLine].numHoles = 0; // It's a line!
    2521                 : 
    2522                 :                 poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
    2523                 :                                         pasSecHdrs[iLine].nXMin,
    2524               0 :                                         pasSecHdrs[iLine].nYMin);
    2525                 :                 poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
    2526                 :                                         pasSecHdrs[iLine].nXMax,
    2527               0 :                                         pasSecHdrs[iLine].nYMax);
    2528                 :                 pasSecHdrs[iLine].nDataOffset = nTotalHdrSizeUncompressed +
    2529               0 :                                                 numPointsTotal*4*2;
    2530               0 :                 pasSecHdrs[iLine].nVertexOffset = numPointsTotal;
    2531                 : 
    2532               0 :                 numPointsTotal += numPoints;
    2533                 :             }
    2534                 :             else
    2535                 :             {
    2536                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2537               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2538               0 :                 nStatus = -1;
    2539                 :             }
    2540                 : 
    2541                 :         }
    2542                 :          
    2543               0 :         if (nStatus == 0)
    2544                 :             nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numLines, 
    2545               0 :                                                       pasSecHdrs, bCompressed);
    2546                 : 
    2547               0 :         CPLFree(pasSecHdrs);
    2548               0 :         pasSecHdrs = NULL;
    2549                 : 
    2550               0 :         if (nStatus != 0)
    2551               0 :             return nStatus;  // Error has already been reported.
    2552                 : 
    2553                 :         /*-------------------------------------------------------------
    2554                 :          * Then write the coordinates themselves...
    2555                 :          *------------------------------------------------------------*/
    2556               0 :         for(iLine=0; nStatus == 0 && iLine < numLines; iLine++)
    2557                 :         {
    2558               0 :             if (poMultiLine)
    2559               0 :                 poGeom = poMultiLine->getGeometryRef(iLine);
    2560                 : 
    2561               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2562                 :             {
    2563               0 :                 poLine = (OGRLineString*)poGeom;
    2564               0 :                 numPoints = poLine->getNumPoints();
    2565                 : 
    2566               0 :                 for(i=0; nStatus == 0 && i<numPoints; i++)
    2567                 :                 {
    2568                 :                     poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i),
    2569               0 :                                             nX, nY);
    2570               0 :                     if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
    2571                 :                                                            bCompressed)) != 0)
    2572                 :                     {
    2573                 :                         // Failed ... error message has already been produced
    2574               0 :                         return nStatus;
    2575                 :                     }   
    2576                 :                 }
    2577                 :             }
    2578                 :             else
    2579                 :             {
    2580                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2581               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2582               0 :                 return -1;
    2583                 :             }
    2584                 : 
    2585                 :         }
    2586                 : 
    2587               0 :         nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    2588                 : 
    2589                 :         /*-------------------------------------------------------------
    2590                 :          * ... and finally copy info to poObjHdr
    2591                 :          *------------------------------------------------------------*/
    2592               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2593                 : 
    2594               0 :         poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
    2595               0 :         poPLineHdr->m_nCoordDataSize = nCoordDataSize;
    2596               0 :         poPLineHdr->m_numLineSections = numLines;
    2597                 : 
    2598               0 :         poPLineHdr->m_bSmooth = m_bSmooth;
    2599                 : 
    2600                 :         // MBR
    2601               0 :         poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    2602                 : 
    2603                 :         // Polyline center/label point
    2604                 :         double dX, dY;
    2605               0 :         if (GetCenter(dX, dY) != -1)
    2606                 :         {
    2607                 :             poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX, 
    2608               0 :                                     poPLineHdr->m_nLabelY);
    2609                 :         }
    2610                 :         else
    2611                 :         {
    2612               0 :             poPLineHdr->m_nLabelX = m_nComprOrgX;
    2613               0 :             poPLineHdr->m_nLabelY = m_nComprOrgY;
    2614                 :         }
    2615                 :         
    2616                 :         // Compressed coordinate origin (useful only in compressed case!)
    2617               0 :         poPLineHdr->m_nComprOrgX = m_nComprOrgX;
    2618               0 :         poPLineHdr->m_nComprOrgY = m_nComprOrgY;
    2619                 : 
    2620               0 :         if (!bCoordBlockDataOnly)
    2621                 :         {
    2622               0 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    2623               0 :             poPLineHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    2624                 :         }
    2625                 : 
    2626                 :     }
    2627                 :     else
    2628                 :     {
    2629                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2630               0 :                  "TABPolyline: Object contains an invalid Geometry!");
    2631               0 :         return -1;
    2632                 :     }
    2633                 : 
    2634               1 :     if (CPLGetLastErrorType() == CE_Failure )
    2635               0 :         return -1;
    2636                 : 
    2637                 :     /* Return a ref to coord block so that caller can continue writing
    2638                 :      * after the end of this object (used by index splitting)
    2639                 :      */
    2640               1 :     if (ppoCoordBlock)
    2641               0 :         *ppoCoordBlock = poCoordBlock;
    2642                 : 
    2643               1 :     return 0;
    2644                 : }
    2645                 : 
    2646                 : /**********************************************************************
    2647                 :  *                   TABPolyline::GetStyleString()
    2648                 :  *
    2649                 :  * Return style string for this feature.
    2650                 :  *
    2651                 :  * Style String is built only once during the first call to GetStyleString().
    2652                 :  **********************************************************************/
    2653               0 : const char *TABPolyline::GetStyleString()
    2654                 : {
    2655               0 :     if (m_pszStyleString == NULL)
    2656                 :     {
    2657               0 :         m_pszStyleString = CPLStrdup(GetPenStyleString());
    2658                 :     }
    2659                 : 
    2660               0 :     return m_pszStyleString;
    2661                 : }
    2662                 : 
    2663                 : 
    2664                 : /**********************************************************************
    2665                 :  *                   TABPolyline::DumpMIF()
    2666                 :  *
    2667                 :  * Dump feature geometry in a format similar to .MIF PLINEs.
    2668                 :  **********************************************************************/
    2669               0 : void TABPolyline::DumpMIF(FILE *fpOut /*=NULL*/)
    2670                 : {
    2671                 :     OGRGeometry   *poGeom;
    2672               0 :     OGRMultiLineString *poMultiLine = NULL;
    2673               0 :     OGRLineString *poLine = NULL;
    2674                 :     int i, numPoints;
    2675                 : 
    2676               0 :     if (fpOut == NULL)
    2677               0 :         fpOut = stdout;
    2678                 : 
    2679                 :     /*-----------------------------------------------------------------
    2680                 :      * Fetch and validate geometry
    2681                 :      *----------------------------------------------------------------*/
    2682               0 :     poGeom = GetGeometryRef();
    2683               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2684                 :     {
    2685                 :         /*-------------------------------------------------------------
    2686                 :          * Generate output for simple polyline
    2687                 :          *------------------------------------------------------------*/
    2688               0 :         poLine = (OGRLineString*)poGeom;
    2689               0 :         numPoints = poLine->getNumPoints();
    2690               0 :         fprintf(fpOut, "PLINE %d\n", numPoints);
    2691               0 :         for(i=0; i<numPoints; i++)
    2692               0 :             fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
    2693                 :     }
    2694               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2695                 :     {
    2696                 :         /*-------------------------------------------------------------
    2697                 :          * Generate output for multiple polyline
    2698                 :          *------------------------------------------------------------*/
    2699                 :         int iLine, numLines;
    2700               0 :         poMultiLine = (OGRMultiLineString*)poGeom;
    2701               0 :         numLines = poMultiLine->getNumGeometries();
    2702               0 :         fprintf(fpOut, "PLINE MULTIPLE %d\n", numLines);
    2703               0 :         for(iLine=0; iLine < numLines; iLine++)
    2704                 :         {
    2705               0 :             poGeom = poMultiLine->getGeometryRef(iLine);
    2706               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2707                 :             {
    2708               0 :                 poLine = (OGRLineString*)poGeom;
    2709               0 :                 numPoints = poLine->getNumPoints();
    2710               0 :                 fprintf(fpOut, " %d\n", numPoints);
    2711               0 :                 for(i=0; i<numPoints; i++)
    2712               0 :                     fprintf(fpOut, "%.15g %.15g\n",poLine->getX(i),poLine->getY(i));
    2713                 :             }
    2714                 :             else
    2715                 :             {
    2716                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2717               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2718               0 :                 return;
    2719                 :             }
    2720                 : 
    2721                 :         }
    2722                 :     }
    2723                 :     else
    2724                 :     {
    2725                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2726               0 :                  "TABPolyline: Missing or Invalid Geometry!");
    2727               0 :         return;
    2728                 :     }
    2729                 : 
    2730               0 :     if (m_bCenterIsSet)
    2731               0 :         fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
    2732                 : 
    2733                 :     // Finish with PEN/BRUSH/etc. clauses
    2734               0 :     DumpPenDef();
    2735                 : 
    2736               0 :     fflush(fpOut);
    2737                 : }
    2738                 : 
    2739                 : /**********************************************************************
    2740                 :  *                   TABPolyline::GetCenter()
    2741                 :  *
    2742                 :  * Returns the center point of the line.  Compute one if it was not 
    2743                 :  * explicitly set:
    2744                 :  *
    2745                 :  * In MapInfo, for a simple or multiple polyline (pline), the center point 
    2746                 :  * in the object definition is supposed to be either the center point of 
    2747                 :  * the pline or the first section of a multiple pline (if an odd number of 
    2748                 :  * points in the pline or first section), or the midway point between the 
    2749                 :  * two central points (if an even number of points involved). 
    2750                 :  *
    2751                 :  * Returns 0 on success, -1 on error.
    2752                 :  **********************************************************************/
    2753               0 : int TABPolyline::GetCenter(double &dX, double &dY)
    2754                 : {
    2755               0 :     if (!m_bCenterIsSet)
    2756                 :     {
    2757                 :         OGRGeometry     *poGeom;
    2758               0 :         OGRLineString   *poLine = NULL;
    2759                 : 
    2760               0 :         poGeom = GetGeometryRef();
    2761               0 :         if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2762                 :         {
    2763               0 :             poLine = (OGRLineString *)poGeom;
    2764                 :         }
    2765               0 :         else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2766                 :         {
    2767               0 :             OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
    2768               0 :             if (poMultiLine->getNumGeometries() > 0)
    2769               0 :                 poLine = (OGRLineString *)poMultiLine->getGeometryRef(0);
    2770                 :         }
    2771                 : 
    2772               0 :         if (poLine && poLine->getNumPoints() > 0)
    2773                 :         {
    2774               0 :             int i = poLine->getNumPoints()/2;
    2775               0 :             if (poLine->getNumPoints() % 2 == 0)
    2776                 :             {
    2777                 :                 // Return the midway between the 2 center points
    2778               0 :                 m_dCenterX = (poLine->getX(i-1) + poLine->getX(i))/2.0;
    2779               0 :                 m_dCenterY = (poLine->getY(i-1) + poLine->getY(i))/2.0;
    2780                 :             }
    2781                 :             else
    2782                 :             {
    2783                 :                 // Return the center point
    2784               0 :                 m_dCenterX = poLine->getX(i);
    2785               0 :                 m_dCenterY = poLine->getY(i);
    2786                 :             }
    2787               0 :             m_bCenterIsSet = TRUE;
    2788                 :         }
    2789                 :     }
    2790                 : 
    2791               0 :     if (!m_bCenterIsSet)
    2792               0 :         return -1;
    2793                 : 
    2794               0 :     dX = m_dCenterX;
    2795               0 :     dY = m_dCenterY;
    2796               0 :     return 0;
    2797                 : }
    2798                 : 
    2799                 : /**********************************************************************
    2800                 :  *                   TABPolyline::SetCenter()
    2801                 :  *
    2802                 :  * Set the X,Y coordinates to use as center point for the line.
    2803                 :  **********************************************************************/
    2804               0 : void TABPolyline::SetCenter(double dX, double dY)
    2805                 : {
    2806               0 :     m_dCenterX = dX;
    2807               0 :     m_dCenterY = dY;
    2808               0 :     m_bCenterIsSet = TRUE;
    2809               0 : }
    2810                 : 
    2811                 : /**********************************************************************
    2812                 :  *                   TABPolyline::TwoPointLineAsPolyline()
    2813                 :  *
    2814                 :  * Returns the value of m_bWriteTwoPointLineAsPolyline
    2815                 :  **********************************************************************/
    2816               0 : GBool TABPolyline::TwoPointLineAsPolyline()
    2817                 : {
    2818               0 :     return m_bWriteTwoPointLineAsPolyline;
    2819                 : }
    2820                 : 
    2821                 : /**********************************************************************
    2822                 : *                   TABPolyline::TwoPointLineAsPolyline()
    2823                 : *
    2824                 : * Sets the value of m_bWriteTwoPointLineAsPolyline
    2825                 : **********************************************************************/
    2826               0 : void TABPolyline::TwoPointLineAsPolyline(GBool bTwoPointLineAsPolyline)
    2827                 : {
    2828               0 :     m_bWriteTwoPointLineAsPolyline = bTwoPointLineAsPolyline;
    2829               0 : }
    2830                 : 
    2831                 : 
    2832                 : /*=====================================================================
    2833                 :  *                      class TABRegion
    2834                 :  *====================================================================*/
    2835                 : 
    2836                 : /**********************************************************************
    2837                 :  *                   TABRegion::TABRegion()
    2838                 :  *
    2839                 :  * Constructor.
    2840                 :  **********************************************************************/
    2841             100 : TABRegion::TABRegion(OGRFeatureDefn *poDefnIn):
    2842             100 :               TABFeature(poDefnIn)
    2843                 : {
    2844             100 :     m_bCenterIsSet = FALSE;
    2845             100 :     m_bSmooth = FALSE;
    2846             100 : }
    2847                 : 
    2848                 : /**********************************************************************
    2849                 :  *                   TABRegion::~TABRegion()
    2850                 :  *
    2851                 :  * Destructor.
    2852                 :  **********************************************************************/
    2853             100 : TABRegion::~TABRegion()
    2854                 : {
    2855             100 : }
    2856                 : 
    2857                 : /**********************************************************************
    2858                 :  *                     TABRegion::CloneTABFeature()
    2859                 :  *
    2860                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    2861                 :  *
    2862                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    2863                 :  * then copies any members specific to its own type.
    2864                 :  **********************************************************************/
    2865               0 : TABFeature *TABRegion::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    2866                 : {
    2867                 :     /*-----------------------------------------------------------------
    2868                 :      * Alloc new feature and copy the base stuff
    2869                 :      *----------------------------------------------------------------*/
    2870               0 :     TABRegion *poNew = new TABRegion(poNewDefn ? poNewDefn : GetDefnRef());
    2871                 : 
    2872               0 :     CopyTABFeatureBase(poNew);
    2873                 : 
    2874                 :     /*-----------------------------------------------------------------
    2875                 :      * And members specific to this class
    2876                 :      *----------------------------------------------------------------*/
    2877                 :     // ITABFeaturePen
    2878               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    2879                 : 
    2880                 :     // ITABFeatureBrush
    2881               0 :     *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
    2882                 : 
    2883               0 :     poNew->m_bSmooth = m_bSmooth;
    2884               0 :     poNew->m_bCenterIsSet = m_bCenterIsSet;
    2885               0 :     poNew->m_dCenterX = m_dCenterX;
    2886               0 :     poNew->m_dCenterY = m_dCenterY;
    2887                 : 
    2888               0 :     return poNew;
    2889                 : }
    2890                 : 
    2891                 : /**********************************************************************
    2892                 :  *                   TABRegion::ValidateMapInfoType()
    2893                 :  *
    2894                 :  * Check the feature's geometry part and return the corresponding
    2895                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    2896                 :  * be updated for further calls to GetMapInfoType();
    2897                 :  *
    2898                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    2899                 :  * is expected for this object class.
    2900                 :  **********************************************************************/
    2901              11 : int  TABRegion::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    2902                 : {
    2903                 :     OGRGeometry *poGeom;
    2904                 : 
    2905                 :     /*-----------------------------------------------------------------
    2906                 :      * Fetch and validate geometry
    2907                 :      *----------------------------------------------------------------*/
    2908              11 :     poGeom = GetGeometryRef();
    2909              11 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    2910                 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    2911                 :     {
    2912              11 :         GInt32 numPointsTotal=0, numRings=GetNumRings();
    2913              22 :         for(int i=0; i<numRings; i++)
    2914                 :         {
    2915              11 :             OGRLinearRing *poRing = GetRingRef(i);
    2916              11 :             if (poRing)
    2917              11 :                 numPointsTotal += poRing->getNumPoints();
    2918                 :         }
    2919              11 :         if ( TAB_REGION_PLINE_REQUIRES_V800(numRings, numPointsTotal) )
    2920               0 :             m_nMapInfoType = TAB_GEOM_V800_REGION;
    2921              11 :          else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
    2922               0 :             m_nMapInfoType = TAB_GEOM_V450_REGION;
    2923                 :         else
    2924              11 :             m_nMapInfoType = TAB_GEOM_REGION;
    2925                 : 
    2926                 :     }
    2927                 :     else
    2928                 :     {
    2929                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2930               0 :                  "TABRegion: Missing or Invalid Geometry!");
    2931               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    2932                 :     }
    2933                 : 
    2934                 :     /*-----------------------------------------------------------------
    2935                 :      * Decide if coordinates should be compressed or not.
    2936                 :      *----------------------------------------------------------------*/
    2937              11 :     ValidateCoordType(poMapFile);
    2938                 : 
    2939              11 :     return m_nMapInfoType;
    2940                 : }
    2941                 : 
    2942                 : /**********************************************************************
    2943                 :  *                   TABRegion::ReadGeometryFromMAPFile()
    2944                 :  *
    2945                 :  * Fill the geometry and representation (color, etc...) part of the
    2946                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    2947                 :  *
    2948                 :  * It is assumed that poMAPFile currently points to the beginning of
    2949                 :  * a map object.
    2950                 :  *
    2951                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    2952                 :  * been called.
    2953                 :  **********************************************************************/
    2954                 : int TABRegion::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    2955                 :                                        TABMAPObjHdr *poObjHdr,
    2956                 :                                        GBool bCoordBlockDataOnly /*=FALSE*/,
    2957              51 :                                        TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    2958                 : {
    2959                 :     double              dX, dY, dXMin, dYMin, dXMax, dYMax;
    2960                 :     OGRGeometry         *poGeometry;
    2961                 :     OGRLinearRing       *poRing;
    2962              51 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    2963                 : 
    2964                 :     /*-----------------------------------------------------------------
    2965                 :      * Fetch and validate geometry type
    2966                 :      *----------------------------------------------------------------*/
    2967              51 :     m_nMapInfoType = poObjHdr->m_nType;
    2968                 : 
    2969              51 :     if (m_nMapInfoType == TAB_GEOM_REGION ||
    2970                 :         m_nMapInfoType == TAB_GEOM_REGION_C ||
    2971                 :         m_nMapInfoType == TAB_GEOM_V450_REGION ||
    2972                 :         m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
    2973                 :         m_nMapInfoType == TAB_GEOM_V800_REGION ||
    2974                 :         m_nMapInfoType == TAB_GEOM_V800_REGION_C )
    2975                 :     {
    2976                 :         /*=============================================================
    2977                 :          * REGION (Similar to PLINE MULTIPLE)
    2978                 :          *============================================================*/
    2979                 :         int     i, iSection;
    2980                 :         GInt32  nCoordBlockPtr, numLineSections;
    2981                 :         GInt32  nCoordDataSize, numPointsTotal, *panXY;
    2982              51 :         OGRMultiPolygon         *poMultiPolygon = NULL;
    2983              51 :         OGRPolygon              *poPolygon = NULL;
    2984                 :         TABMAPCoordSecHdr       *pasSecHdrs;
    2985              51 :         GBool                   bComprCoord = poObjHdr->IsCompressedType();
    2986              51 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    2987                 : 
    2988                 :         /*-------------------------------------------------------------
    2989                 :          * Copy data from poObjHdr
    2990                 :          *------------------------------------------------------------*/
    2991              51 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2992                 : 
    2993              51 :         nCoordBlockPtr  = poPLineHdr->m_nCoordBlockPtr;
    2994              51 :         nCoordDataSize  = poPLineHdr->m_nCoordDataSize;
    2995              51 :         numLineSections = poPLineHdr->m_numLineSections;
    2996              51 :         m_bSmooth       = poPLineHdr->m_bSmooth;
    2997                 : 
    2998                 :         // Centroid/label point
    2999                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY, 
    3000              51 :                                 dX, dY);
    3001              51 :         SetCenter(dX, dY);
    3002                 : 
    3003                 :         // Compressed coordinate origin (useful only in compressed case!)
    3004              51 :         m_nComprOrgX = poPLineHdr->m_nComprOrgX;
    3005              51 :         m_nComprOrgY = poPLineHdr->m_nComprOrgY;
    3006                 : 
    3007                 :         // MBR
    3008                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY, 
    3009              51 :                                 dXMin, dYMin);
    3010                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY, 
    3011              51 :                                 dXMax, dYMax);
    3012                 : 
    3013              51 :         if (!bCoordBlockDataOnly)
    3014                 :         {
    3015              51 :             m_nPenDefIndex = poPLineHdr->m_nPenId;        // Pen index
    3016              51 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    3017              51 :             m_nBrushDefIndex = poPLineHdr->m_nBrushId;    // Brush index
    3018              51 :             poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
    3019                 :         }
    3020                 : 
    3021                 :         /*-------------------------------------------------------------
    3022                 :          * Read data from the coord. block
    3023                 :          *------------------------------------------------------------*/
    3024                 :         pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
    3025              51 :                                                    sizeof(TABMAPCoordSecHdr));
    3026                 : 
    3027              51 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    3028               0 :             poCoordBlock = *ppoCoordBlock;
    3029                 :         else
    3030              51 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    3031                 : 
    3032              51 :         if (poCoordBlock)
    3033              51 :             poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    3034                 : 
    3035              51 :         if (poCoordBlock == NULL ||
    3036                 :             poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion,
    3037                 :                                            numLineSections,
    3038                 :                                            pasSecHdrs, numPointsTotal) != 0)
    3039                 :         {
    3040                 :             CPLError(CE_Failure, CPLE_FileIO,
    3041                 :                      "Failed reading coordinate data at offset %d", 
    3042               0 :                      nCoordBlockPtr);
    3043               0 :             CPLFree(pasSecHdrs);
    3044               0 :             return -1;
    3045                 :         }
    3046                 : 
    3047              51 :         panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
    3048                 : 
    3049              51 :         if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
    3050                 :         {
    3051                 :             CPLError(CE_Failure, CPLE_FileIO,
    3052                 :                      "Failed reading coordinate data at offset %d", 
    3053               0 :                      nCoordBlockPtr);
    3054               0 :             CPLFree(pasSecHdrs);
    3055               0 :             CPLFree(panXY);
    3056               0 :             return -1;
    3057                 :         }
    3058                 : 
    3059                 :         /*-------------------------------------------------------------
    3060                 :          * Decide if we should return an OGRPolygon or an OGRMultiPolygon
    3061                 :          * depending on the number of outer rings found in CoordSecHdr blocks.
    3062                 :          * The CoodSecHdr block for each outer ring in the region has a flag
    3063                 :          * indicating the number of inner rings that follow.
    3064                 :          * In older versions of the format, the count of inner rings was 
    3065                 :          * always zero, so in this case we would always return MultiPolygons.
    3066                 :          *
    3067                 :          * Note: The current implementation assumes that there cannot be
    3068                 :          * holes inside holes (i.e. multiple levels of inner rings)... if
    3069                 :          * that case was encountered then we would return an OGRMultiPolygon
    3070                 :          * in which the topological relationship between the rings would
    3071                 :          * be lost.
    3072                 :          *------------------------------------------------------------*/
    3073              51 :         int numOuterRings = 0;
    3074             102 :         for(iSection=0; iSection<numLineSections; iSection++)
    3075                 :         {
    3076                 :             // Count this as an outer ring.
    3077              51 :             numOuterRings++;
    3078                 :             // Skip inner rings... so loop continues on an outer ring.
    3079              51 :             iSection += pasSecHdrs[iSection].numHoles;
    3080                 :         }
    3081                 : 
    3082              51 :         if (numOuterRings > 1)
    3083               0 :             poGeometry = poMultiPolygon = new OGRMultiPolygon;
    3084                 :         else
    3085              51 :             poGeometry = NULL;  // Will be set later
    3086                 : 
    3087                 :         /*-------------------------------------------------------------
    3088                 :          * OK, build the OGRGeometry object.
    3089                 :          *------------------------------------------------------------*/
    3090              51 :         int numHolesToRead = 0;
    3091              51 :         poPolygon = NULL;
    3092             102 :         for(iSection=0; iSection<numLineSections; iSection++)
    3093                 :         {
    3094                 :             GInt32 *pnXYPtr;
    3095                 :             int     numSectionVertices;
    3096                 : 
    3097              51 :             if (poPolygon == NULL)
    3098              51 :                 poPolygon = new OGRPolygon();
    3099                 : 
    3100              51 :             if (numHolesToRead < 1)
    3101              51 :                 numHolesToRead = pasSecHdrs[iSection].numHoles;
    3102                 :             else
    3103               0 :                 numHolesToRead--;
    3104                 : 
    3105              51 :             numSectionVertices = pasSecHdrs[iSection].numVertices;
    3106              51 :             pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
    3107                 : 
    3108              51 :             poRing = new OGRLinearRing();
    3109              51 :             poRing->setNumPoints(numSectionVertices);
    3110                 : 
    3111            1281 :             for(i=0; i<numSectionVertices; i++)
    3112                 :             {
    3113            1230 :                 poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
    3114            1230 :                 poRing->setPoint(i, dX, dY);
    3115            1230 :                 pnXYPtr += 2;
    3116                 :             }
    3117                 : 
    3118              51 :             poPolygon->addRingDirectly(poRing);
    3119              51 :             poRing = NULL;
    3120                 : 
    3121              51 :             if (numHolesToRead < 1)
    3122                 :             {
    3123              51 :                 if (numOuterRings > 1)
    3124                 :                 {
    3125               0 :                     poMultiPolygon->addGeometryDirectly(poPolygon);
    3126                 :                 }
    3127                 :                 else
    3128                 :                 {
    3129              51 :                     poGeometry = poPolygon;
    3130              51 :                     CPLAssert(iSection == numLineSections-1);
    3131                 :                 }
    3132                 : 
    3133              51 :                 poPolygon = NULL;  // We'll alloc a new polygon next loop.
    3134                 :             }
    3135                 : 
    3136                 :         }
    3137                 : 
    3138              51 :         CPLFree(pasSecHdrs);
    3139              51 :         CPLFree(panXY);
    3140                 :     }
    3141                 :     else
    3142                 :     {
    3143                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3144                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    3145               0 :                  m_nMapInfoType, m_nMapInfoType);
    3146               0 :         return -1;
    3147                 :     }
    3148                 : 
    3149              51 :     SetGeometryDirectly(poGeometry);
    3150                 : 
    3151              51 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    3152                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    3153              51 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    3154                 : 
    3155                 :     /* Return a ref to coord block so that caller can continue reading
    3156                 :      * after the end of this object (used by TABCollection and index splitting)
    3157                 :      */
    3158              51 :     if (ppoCoordBlock)
    3159               0 :         *ppoCoordBlock = poCoordBlock;
    3160                 : 
    3161              51 :     return 0;
    3162                 : }
    3163                 : 
    3164                 : /**********************************************************************
    3165                 :  *                   TABRegion::WriteGeometryToMAPFile()
    3166                 :  *
    3167                 :  * Write the geometry and representation (color, etc...) part of the
    3168                 :  * feature to the .MAP object pointed to by poMAPFile.
    3169                 :  *
    3170                 :  * It is assumed that poMAPFile currently points to a valid map object.
    3171                 :  *
    3172                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    3173                 :  * been called.
    3174                 :  **********************************************************************/
    3175                 : int TABRegion::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    3176                 :                                       TABMAPObjHdr *poObjHdr,
    3177                 :                                       GBool bCoordBlockDataOnly /*=FALSE*/,
    3178              11 :                                       TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    3179                 : {
    3180                 :     GInt32              nX, nY;
    3181                 :     OGRGeometry         *poGeom;
    3182              11 :     TABMAPCoordBlock    *poCoordBlock=NULL;
    3183                 : 
    3184                 :     /*-----------------------------------------------------------------
    3185                 :      * We assume that ValidateMapInfoType() was called already and that
    3186                 :      * the type in poObjHdr->m_nType is valid.
    3187                 :      *----------------------------------------------------------------*/
    3188              11 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    3189                 : 
    3190                 :     /*-----------------------------------------------------------------
    3191                 :      * Fetch and validate geometry
    3192                 :      *----------------------------------------------------------------*/
    3193              11 :     poGeom = GetGeometryRef();
    3194                 : 
    3195              11 :     if ((m_nMapInfoType == TAB_GEOM_REGION ||
    3196                 :          m_nMapInfoType == TAB_GEOM_REGION_C ||
    3197                 :          m_nMapInfoType == TAB_GEOM_V450_REGION ||
    3198                 :          m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
    3199                 :          m_nMapInfoType == TAB_GEOM_V800_REGION ||
    3200                 :          m_nMapInfoType == TAB_GEOM_V800_REGION_C) &&
    3201                 :         poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3202                 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3203                 :     {
    3204                 :         /*=============================================================
    3205                 :          * REGIONs are similar to PLINE MULTIPLE
    3206                 :          *
    3207                 :          * We accept both OGRPolygons (with one or multiple rings) and 
    3208                 :          * OGRMultiPolygons as input.
    3209                 :          *============================================================*/
    3210              11 :         int     nStatus=0, i, iRing;
    3211                 :         int     numRingsTotal;
    3212                 :         GUInt32 nCoordDataSize;
    3213                 :         GInt32  nCoordBlockPtr;
    3214              11 :         TABMAPCoordSecHdr       *pasSecHdrs = NULL;
    3215              11 :         GBool   bCompressed = poObjHdr->IsCompressedType();
    3216                 : 
    3217                 :         /*-------------------------------------------------------------
    3218                 :          * Process geometry first...
    3219                 :          *------------------------------------------------------------*/
    3220              11 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    3221               0 :             poCoordBlock = *ppoCoordBlock;
    3222                 :         else
    3223              11 :             poCoordBlock = poMapFile->GetCurCoordBlock();
    3224              11 :         poCoordBlock->StartNewFeature();
    3225              11 :         nCoordBlockPtr = poCoordBlock->GetCurAddress();
    3226              11 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    3227                 : 
    3228                 : #ifdef TABDUMP
    3229                 :     printf("TABRegion::WriteGeometryToMAPFile(): ComprOrgX,Y= (%d,%d)\n",
    3230                 :            m_nComprOrgX, m_nComprOrgY);
    3231                 : #endif
    3232                 :         /*-------------------------------------------------------------
    3233                 :          * Fetch total number of rings and build array of coord 
    3234                 :          * sections headers.
    3235                 :          *------------------------------------------------------------*/
    3236              11 :         numRingsTotal = ComputeNumRings(&pasSecHdrs, poMapFile);
    3237              11 :         if (numRingsTotal == 0)
    3238               0 :             nStatus = -1;
    3239                 : 
    3240                 :         /*-------------------------------------------------------------
    3241                 :          * Write the Coord. Section Header
    3242                 :          *------------------------------------------------------------*/
    3243              11 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    3244                 : 
    3245              11 :         if (nStatus == 0)
    3246                 :             nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numRingsTotal, 
    3247              11 :                                                       pasSecHdrs, bCompressed);
    3248                 : 
    3249              11 :         CPLFree(pasSecHdrs);
    3250              11 :         pasSecHdrs = NULL;
    3251                 : 
    3252              11 :         if (nStatus != 0)
    3253               0 :             return nStatus;  // Error has already been reported.
    3254                 : 
    3255                 :         /*-------------------------------------------------------------
    3256                 :          * Go through all the rings in our OGRMultiPolygon or OGRPolygon
    3257                 :          * to write the coordinates themselves...
    3258                 :          *------------------------------------------------------------*/
    3259                 : 
    3260              22 :         for(iRing=0; iRing < numRingsTotal; iRing++)
    3261                 :         {
    3262                 :             OGRLinearRing       *poRing;
    3263                 : 
    3264              11 :             poRing = GetRingRef(iRing);
    3265              11 :             if (poRing == NULL)
    3266                 :             {
    3267                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    3268               0 :                          "TABRegion: Object Geometry contains NULL rings!");
    3269               0 :                 return -1;
    3270                 :             }
    3271                 : 
    3272              11 :             int numPoints = poRing->getNumPoints();
    3273                 :             
    3274             261 :             for(i=0; nStatus == 0 && i<numPoints; i++)
    3275                 :             {
    3276                 :                 poMapFile->Coordsys2Int(poRing->getX(i), poRing->getY(i),
    3277             250 :                                         nX, nY);
    3278             250 :                 if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
    3279                 :                                                          bCompressed)) != 0)
    3280                 :                 {
    3281                 :                     // Failed ... error message has already been produced
    3282               0 :                     return nStatus;
    3283                 :                 }   
    3284                 :             }
    3285                 :         }/* for iRing*/
    3286                 : 
    3287              11 :         nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    3288                 : 
    3289                 :         /*-------------------------------------------------------------
    3290                 :          * ... and finally copy info to poObjHdr
    3291                 :          *------------------------------------------------------------*/
    3292              11 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    3293                 : 
    3294              11 :         poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
    3295              11 :         poPLineHdr->m_nCoordDataSize = nCoordDataSize;
    3296              11 :         poPLineHdr->m_numLineSections = numRingsTotal;
    3297                 : 
    3298              11 :         poPLineHdr->m_bSmooth = m_bSmooth;
    3299                 : 
    3300                 :         // MBR
    3301              11 :         poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    3302                 : 
    3303                 :         // Region center/label point
    3304                 :         double dX, dY;
    3305              11 :         if (GetCenter(dX, dY) != -1)
    3306                 :         {
    3307                 :             poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX, 
    3308              11 :                                     poPLineHdr->m_nLabelY);
    3309                 :         }
    3310                 :         else
    3311                 :         {
    3312               0 :             poPLineHdr->m_nLabelX = m_nComprOrgX;
    3313               0 :             poPLineHdr->m_nLabelY = m_nComprOrgY;
    3314                 :         }
    3315                 :         
    3316                 :         // Compressed coordinate origin (useful only in compressed case!)
    3317              11 :         poPLineHdr->m_nComprOrgX = m_nComprOrgX;
    3318              11 :         poPLineHdr->m_nComprOrgY = m_nComprOrgY;
    3319                 : 
    3320              11 :         if (!bCoordBlockDataOnly)
    3321                 :         {
    3322              11 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    3323              11 :             poPLineHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    3324                 : 
    3325              11 :             m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
    3326              11 :             poPLineHdr->m_nBrushId = m_nBrushDefIndex;  // Brush index
    3327                 :         }
    3328                 :     }
    3329                 :     else
    3330                 :     {
    3331                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3332               0 :                  "TABRegion: Object contains an invalid Geometry!");
    3333               0 :         return -1;
    3334                 :     }
    3335                 : 
    3336              11 :     if (CPLGetLastErrorNo() != 0)
    3337               0 :         return -1;
    3338                 : 
    3339                 :     /* Return a ref to coord block so that caller can continue writing
    3340                 :      * after the end of this object (used by index splitting)
    3341                 :      */
    3342              11 :     if (ppoCoordBlock)
    3343               0 :         *ppoCoordBlock = poCoordBlock;
    3344                 : 
    3345              11 :     return 0;
    3346                 : }
    3347                 : 
    3348                 : 
    3349                 : /**********************************************************************
    3350                 :  *                   TABRegion::GetNumRings()
    3351                 :  *
    3352                 :  * Return the total number of rings in this object making it look like
    3353                 :  * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
    3354                 :  * of rings... hides the complexity of handling OGRMultiPolygons vs 
    3355                 :  * OGRPolygons, etc.
    3356                 :  *
    3357                 :  * Returns 0 if the geometry contained in the object is invalid or missing.
    3358                 :  **********************************************************************/
    3359              21 : int TABRegion::GetNumRings()
    3360                 : {
    3361              21 :     return ComputeNumRings(NULL, NULL);
    3362                 : }
    3363                 : 
    3364                 : int TABRegion::ComputeNumRings(TABMAPCoordSecHdr **ppasSecHdrs,
    3365              32 :                                TABMAPFile *poMapFile)
    3366                 : {
    3367                 :     OGRGeometry         *poGeom;
    3368              32 :     int                 numRingsTotal = 0, iLastSect = 0;
    3369                 : 
    3370              32 :     if (ppasSecHdrs)
    3371              11 :         *ppasSecHdrs = NULL;
    3372              32 :     poGeom = GetGeometryRef();
    3373                 : 
    3374              32 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3375                 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3376                 :     {
    3377                 :         /*-------------------------------------------------------------
    3378                 :          * Calculate total number of rings...
    3379                 :          *------------------------------------------------------------*/
    3380              32 :         OGRPolygon      *poPolygon=NULL;
    3381              32 :         OGRMultiPolygon *poMultiPolygon = NULL;
    3382                 : 
    3383              32 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3384                 :         {
    3385               0 :             poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3386               0 :             for(int iPoly=0; iPoly<poMultiPolygon->getNumGeometries(); iPoly++)
    3387                 :             {
    3388                 :                 // We are guaranteed that all parts are OGRPolygons
    3389               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
    3390               0 :                 if (poPolygon  == NULL)
    3391               0 :                     continue;
    3392                 : 
    3393               0 :                 numRingsTotal += poPolygon->getNumInteriorRings()+1;
    3394                 : 
    3395               0 :                 if (ppasSecHdrs)
    3396                 :                 {
    3397               0 :                     if (AppendSecHdrs(poPolygon, *ppasSecHdrs, 
    3398                 :                                       poMapFile, iLastSect) != 0)
    3399               0 :                         return 0; // An error happened, return count=0
    3400                 :                 }
    3401                 : 
    3402                 :             }/*for*/
    3403                 :         }
    3404                 :         else
    3405                 :         {
    3406              32 :             poPolygon = (OGRPolygon*)poGeom;
    3407              32 :             numRingsTotal = poPolygon->getNumInteriorRings()+1;
    3408                 : 
    3409              32 :             if (ppasSecHdrs)
    3410                 :             {
    3411              11 :                 if (AppendSecHdrs(poPolygon, *ppasSecHdrs, 
    3412                 :                                   poMapFile, iLastSect) != 0)
    3413               0 :                     return 0;  // An error happened, return count=0
    3414                 :             }
    3415                 :         }
    3416                 :     }
    3417                 : 
    3418                 :     /*-----------------------------------------------------------------
    3419                 :      * If we're generating section header blocks, then init the 
    3420                 :      * coordinate offset values.
    3421                 :      *
    3422                 :      * In calculation of nDataOffset, we have to take into account that
    3423                 :      * V450 header section uses int32 instead of int16 for numVertices
    3424                 :      * and we add another 2 bytes to align with a 4 bytes boundary.
    3425                 :      *------------------------------------------------------------*/
    3426                 :     int nTotalHdrSizeUncompressed;
    3427              32 :     if (m_nMapInfoType == TAB_GEOM_V450_REGION ||
    3428                 :         m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
    3429                 :         m_nMapInfoType == TAB_GEOM_V800_REGION ||
    3430                 :         m_nMapInfoType == TAB_GEOM_V800_REGION_C)
    3431               0 :         nTotalHdrSizeUncompressed = 28 * numRingsTotal;
    3432                 :     else
    3433              32 :         nTotalHdrSizeUncompressed = 24 * numRingsTotal;
    3434                 : 
    3435              32 :     if (ppasSecHdrs)
    3436                 :     {
    3437              11 :         int numPointsTotal = 0;
    3438              11 :         CPLAssert(iLastSect == numRingsTotal);
    3439              22 :         for (int iRing=0; iRing<numRingsTotal; iRing++)
    3440                 :         {
    3441                 :             (*ppasSecHdrs)[iRing].nDataOffset = nTotalHdrSizeUncompressed +
    3442              11 :                                                    numPointsTotal*4*2;
    3443              11 :             (*ppasSecHdrs)[iRing].nVertexOffset = numPointsTotal;
    3444                 : 
    3445              11 :             numPointsTotal += (*ppasSecHdrs)[iRing].numVertices;
    3446                 :         }
    3447                 :     }
    3448                 : 
    3449              32 :     return numRingsTotal;
    3450                 : }
    3451                 : 
    3452                 : 
    3453                 : /**********************************************************************
    3454                 :  *                   TABRegion::AppendSecHdrs()
    3455                 :  *
    3456                 :  * (Private method)
    3457                 :  *
    3458                 :  * Add a TABMAPCoordSecHdr for each ring in the specified polygon.
    3459                 :  **********************************************************************/
    3460                 : int TABRegion::AppendSecHdrs(OGRPolygon *poPolygon,
    3461                 :                              TABMAPCoordSecHdr * &pasSecHdrs,
    3462                 :                              TABMAPFile *poMapFile,
    3463              11 :                              int &iLastRing)
    3464                 : {
    3465                 :     int iRing, numRingsInPolygon;
    3466                 :     /*-------------------------------------------------------------
    3467                 :      * Add a pasSecHdrs[] entry for each ring in this polygon.
    3468                 :      * Note that the structs won't be fully initialized.
    3469                 :      *------------------------------------------------------------*/
    3470              11 :     numRingsInPolygon = poPolygon->getNumInteriorRings()+1;
    3471                 : 
    3472                 :     pasSecHdrs = (TABMAPCoordSecHdr*)CPLRealloc(pasSecHdrs,
    3473                 :                                                 (iLastRing+numRingsInPolygon)*
    3474              11 :                                                 sizeof(TABMAPCoordSecHdr));
    3475                 : 
    3476              22 :     for(iRing=0; iRing < numRingsInPolygon; iRing++)
    3477                 :     {
    3478                 :         OGRLinearRing   *poRing;
    3479              11 :         OGREnvelope     sEnvelope;
    3480                 : 
    3481              11 :         if (iRing == 0)
    3482              11 :             poRing = poPolygon->getExteriorRing();
    3483                 :         else 
    3484               0 :             poRing = poPolygon->getInteriorRing(iRing-1);
    3485                 : 
    3486              11 :         if (poRing == NULL)
    3487                 :         {
    3488                 :             CPLError(CE_Failure, CPLE_AssertionFailed, 
    3489               0 :                      "Assertion Failed: Encountered NULL ring in OGRPolygon");
    3490               0 :             return -1;
    3491                 :         }
    3492                 : 
    3493              11 :         poRing->getEnvelope(&sEnvelope);
    3494                 :             
    3495              11 :         pasSecHdrs[iLastRing].numVertices = poRing->getNumPoints();
    3496                 : 
    3497              11 :         if (iRing == 0)
    3498              11 :             pasSecHdrs[iLastRing].numHoles = numRingsInPolygon-1;
    3499                 :         else 
    3500               0 :             pasSecHdrs[iLastRing].numHoles = 0;
    3501                 : 
    3502                 :         poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
    3503                 :                                 pasSecHdrs[iLastRing].nXMin,
    3504              11 :                                 pasSecHdrs[iLastRing].nYMin);
    3505                 :         poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
    3506                 :                                 pasSecHdrs[iLastRing].nXMax,
    3507              11 :                                 pasSecHdrs[iLastRing].nYMax);
    3508                 : 
    3509              11 :         iLastRing++;
    3510                 :     }/* for iRing*/
    3511                 : 
    3512              11 :     return 0;
    3513                 : }
    3514                 : 
    3515                 : /**********************************************************************
    3516                 :  *                   TABRegion::GetRingRef()
    3517                 :  *
    3518                 :  * Returns a reference to the specified ring number making it look like
    3519                 :  * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
    3520                 :  * of rings... hides the complexity of handling OGRMultiPolygons vs 
    3521                 :  * OGRPolygons, etc.
    3522                 :  *
    3523                 :  * Returns NULL if the geometry contained in the object is invalid or 
    3524                 :  * missing or if the specified ring index is invalid.
    3525                 :  **********************************************************************/
    3526              32 : OGRLinearRing *TABRegion::GetRingRef(int nRequestedRingIndex)
    3527                 : {
    3528                 :     OGRGeometry     *poGeom;
    3529              32 :     OGRLinearRing   *poRing = NULL;
    3530                 : 
    3531              32 :     poGeom = GetGeometryRef();
    3532                 : 
    3533              32 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3534                 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3535                 :     {
    3536                 :         /*-------------------------------------------------------------
    3537                 :          * Establish number of polygons based on geometry type
    3538                 :          *------------------------------------------------------------*/
    3539              32 :         OGRPolygon      *poPolygon=NULL;
    3540              32 :         OGRMultiPolygon *poMultiPolygon = NULL;
    3541              32 :         int             iCurRing = 0;
    3542              32 :         int             numOGRPolygons = 0;
    3543                 : 
    3544              32 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3545                 :         {
    3546               0 :             poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3547               0 :             numOGRPolygons = poMultiPolygon->getNumGeometries();
    3548                 :         }
    3549                 :         else
    3550                 :         {
    3551              32 :             poPolygon = (OGRPolygon*)poGeom;
    3552              32 :             numOGRPolygons = 1;
    3553                 :         }
    3554                 : 
    3555                 :         /*-------------------------------------------------------------
    3556                 :          * Loop through polygons until we find the requested ring.
    3557                 :          *------------------------------------------------------------*/
    3558              32 :         iCurRing = 0;
    3559              64 :         for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
    3560                 :         {
    3561              32 :             if (poMultiPolygon)
    3562               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
    3563                 :             else
    3564              32 :                 poPolygon = (OGRPolygon*)poGeom;
    3565                 : 
    3566              32 :             int numIntRings = poPolygon->getNumInteriorRings();
    3567                 : 
    3568              32 :             if (iCurRing == nRequestedRingIndex)
    3569                 :             {
    3570              32 :                 poRing = poPolygon->getExteriorRing();
    3571                 :             }
    3572               0 :             else if (nRequestedRingIndex > iCurRing &&
    3573                 :                      nRequestedRingIndex-(iCurRing+1) < numIntRings)
    3574                 :            {
    3575                 :                 poRing = poPolygon->getInteriorRing(nRequestedRingIndex-
    3576               0 :                                                                 (iCurRing+1) );
    3577                 :             }
    3578              32 :             iCurRing += numIntRings+1;
    3579                 :         }
    3580                 :     }
    3581                 : 
    3582              32 :     return poRing;
    3583                 : }
    3584                 : 
    3585                 : /**********************************************************************
    3586                 :  *                   TABRegion::RingIsHole()
    3587                 :  *
    3588                 :  * Return false if the requested ring index is the first of a polygon
    3589                 :  **********************************************************************/
    3590               0 : GBool TABRegion::IsInteriorRing(int nRequestedRingIndex)
    3591                 : {
    3592                 :     OGRGeometry     *poGeom;
    3593               0 :     OGRLinearRing   *poRing = NULL;
    3594                 : 
    3595               0 :     poGeom = GetGeometryRef();
    3596                 : 
    3597               0 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3598                 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3599                 :     {
    3600                 :         /*-------------------------------------------------------------
    3601                 :          * Establish number of polygons based on geometry type
    3602                 :          *------------------------------------------------------------*/
    3603               0 :         OGRPolygon      *poPolygon=NULL;
    3604               0 :         OGRMultiPolygon *poMultiPolygon = NULL;
    3605               0 :         int             iCurRing = 0;
    3606               0 :         int             numOGRPolygons = 0;
    3607                 : 
    3608               0 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3609                 :         {
    3610               0 :             poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3611               0 :             numOGRPolygons = poMultiPolygon->getNumGeometries();
    3612                 :         }
    3613                 :         else
    3614                 :         {
    3615               0 :             poPolygon = (OGRPolygon*)poGeom;
    3616               0 :             numOGRPolygons = 1;
    3617                 :         }
    3618                 : 
    3619                 :         /*-------------------------------------------------------------
    3620                 :          * Loop through polygons until we find the requested ring.
    3621                 :          *------------------------------------------------------------*/
    3622               0 :         iCurRing = 0;
    3623               0 :         for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
    3624                 :         {
    3625               0 :             if (poMultiPolygon)
    3626               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
    3627                 :             else
    3628               0 :                 poPolygon = (OGRPolygon*)poGeom;
    3629                 : 
    3630               0 :             int numIntRings = poPolygon->getNumInteriorRings();
    3631                 : 
    3632               0 :             if (iCurRing == nRequestedRingIndex)
    3633                 :             {
    3634               0 :                 return FALSE;
    3635                 :             }
    3636               0 :             else if (nRequestedRingIndex > iCurRing &&
    3637                 :                      nRequestedRingIndex-(iCurRing+1) < numIntRings)
    3638                 :            {
    3639               0 :                 return TRUE;
    3640                 :             }
    3641               0 :             iCurRing += numIntRings+1;
    3642                 :         }
    3643                 :     }
    3644                 : 
    3645               0 :     return FALSE;
    3646                 : }
    3647                 : 
    3648                 : /**********************************************************************
    3649                 :  *                   TABRegion::GetStyleString()
    3650                 :  *
    3651                 :  * Return style string for this feature.
    3652                 :  *
    3653                 :  * Style String is built only once during the first call to GetStyleString().
    3654                 :  **********************************************************************/
    3655              11 : const char *TABRegion::GetStyleString()
    3656                 : {
    3657              11 :     if (m_pszStyleString == NULL)
    3658                 :     {
    3659                 :         // Since GetPen/BrushStyleString() use CPLSPrintf(), we need 
    3660                 :         // to use temporary buffers
    3661               7 :         char *pszPen = CPLStrdup(GetPenStyleString());
    3662               7 :         char *pszBrush = CPLStrdup(GetBrushStyleString());
    3663                 : 
    3664               7 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
    3665                 : 
    3666               7 :         CPLFree(pszPen);
    3667               7 :         CPLFree(pszBrush);
    3668                 :     }
    3669                 : 
    3670              11 :     return m_pszStyleString;
    3671                 : }
    3672                 : 
    3673                 : 
    3674                 : 
    3675                 : /**********************************************************************
    3676                 :  *                   TABRegion::DumpMIF()
    3677                 :  *
    3678                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    3679                 :  **********************************************************************/
    3680               0 : void TABRegion::DumpMIF(FILE *fpOut /*=NULL*/)
    3681                 : {
    3682                 :     OGRGeometry   *poGeom;
    3683                 :     int i, numPoints;
    3684                 : 
    3685               0 :     if (fpOut == NULL)
    3686               0 :         fpOut = stdout;
    3687                 : 
    3688                 :     /*-----------------------------------------------------------------
    3689                 :      * Fetch and validate geometry
    3690                 :      *----------------------------------------------------------------*/
    3691               0 :     poGeom = GetGeometryRef();
    3692               0 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3693                 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3694                 :     {
    3695                 :         /*-------------------------------------------------------------
    3696                 :          * Generate output for region
    3697                 :          *
    3698                 :          * Note that we want to handle both OGRPolygons and OGRMultiPolygons
    3699                 :          * that's why we use the GetNumRings()/GetRingRef() interface.
    3700                 :          *------------------------------------------------------------*/
    3701               0 :         int iRing, numRingsTotal = GetNumRings();
    3702                 : 
    3703               0 :         fprintf(fpOut, "REGION %d\n", numRingsTotal);
    3704                 : 
    3705               0 :         for(iRing=0; iRing < numRingsTotal; iRing++)
    3706                 :         {
    3707                 :             OGRLinearRing       *poRing;
    3708                 : 
    3709               0 :             poRing = GetRingRef(iRing);
    3710                 : 
    3711               0 :             if (poRing == NULL)
    3712                 :             {
    3713                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    3714               0 :                          "TABRegion: Object Geometry contains NULL rings!");
    3715               0 :                 return;
    3716                 :             }
    3717                 : 
    3718               0 :             numPoints = poRing->getNumPoints();
    3719               0 :             fprintf(fpOut, " %d\n", numPoints);
    3720               0 :             for(i=0; i<numPoints; i++)
    3721               0 :                 fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
    3722                 :         }
    3723                 :     }
    3724                 :     else
    3725                 :     {
    3726                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3727               0 :                  "TABRegion: Missing or Invalid Geometry!");
    3728               0 :         return;
    3729                 :     }
    3730                 : 
    3731               0 :     if (m_bCenterIsSet)
    3732               0 :         fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
    3733                 : 
    3734                 :     // Finish with PEN/BRUSH/etc. clauses
    3735               0 :     DumpPenDef();
    3736               0 :     DumpBrushDef();
    3737                 : 
    3738               0 :     fflush(fpOut);
    3739                 : }
    3740                 : 
    3741                 : /**********************************************************************
    3742                 :  *                   TABRegion::GetCenter()
    3743                 :  *
    3744                 :  * Returns the center/label point of the region.  
    3745                 :  * Compute one using OGRPolygonLabelPoint() if it was not explicitly set 
    3746                 :  * before.
    3747                 :  *
    3748                 :  * Returns 0 on success, -1 on error.
    3749                 :  **********************************************************************/
    3750              11 : int TABRegion::GetCenter(double &dX, double &dY)
    3751                 : {
    3752              11 :     if (!m_bCenterIsSet)
    3753                 :     {
    3754                 :         /*-------------------------------------------------------------
    3755                 :          * Calculate label point.  If we have a multipolygon then we use 
    3756                 :          * the first OGRPolygon in the feature to calculate the point.
    3757                 :          *------------------------------------------------------------*/
    3758              11 :         OGRPoint        oLabelPoint;
    3759              11 :         OGRPolygon      *poPolygon=NULL;
    3760                 :         OGRGeometry     *poGeom;
    3761                 : 
    3762              11 :         poGeom = GetGeometryRef();
    3763              11 :         if (poGeom == NULL)
    3764               0 :             return -1;
    3765                 : 
    3766              11 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3767                 :         {
    3768               0 :             OGRMultiPolygon *poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3769               0 :             if (poMultiPolygon->getNumGeometries() > 0)
    3770               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(0);
    3771                 :         }
    3772              11 :         else if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    3773                 :         {
    3774              11 :             poPolygon = (OGRPolygon*)poGeom;
    3775                 :         }
    3776                 : 
    3777              11 :         if (poPolygon != NULL &&
    3778                 :             OGRPolygonLabelPoint(poPolygon, &oLabelPoint) == OGRERR_NONE)
    3779                 :         {
    3780              11 :             m_dCenterX = oLabelPoint.getX();
    3781              11 :             m_dCenterY = oLabelPoint.getY();
    3782                 :         }
    3783                 :         else
    3784                 :         {
    3785               0 :             OGREnvelope oEnv;
    3786               0 :             poGeom->getEnvelope(&oEnv);
    3787               0 :             m_dCenterX = (oEnv.MaxX + oEnv.MinX)/2.0;
    3788               0 :             m_dCenterY = (oEnv.MaxY + oEnv.MinY)/2.0;
    3789                 :         }
    3790                 : 
    3791              11 :         m_bCenterIsSet = TRUE;
    3792                 :     }
    3793                 : 
    3794              11 :     if (!m_bCenterIsSet)
    3795               0 :         return -1;
    3796                 : 
    3797              11 :     dX = m_dCenterX;
    3798              11 :     dY = m_dCenterY;
    3799              11 :     return 0;
    3800                 : }
    3801                 : 
    3802                 : /**********************************************************************
    3803                 :  *                   TABRegion::SetCenter()
    3804                 :  *
    3805                 :  * Set the X,Y coordinates to use as center/label point for the region.
    3806                 :  **********************************************************************/
    3807              51 : void TABRegion::SetCenter(double dX, double dY)
    3808                 : {
    3809              51 :     m_dCenterX = dX;
    3810              51 :     m_dCenterY = dY;
    3811              51 :     m_bCenterIsSet = TRUE;
    3812              51 : }
    3813                 : 
    3814                 : 
    3815                 : /*=====================================================================
    3816                 :  *                      class TABRectangle
    3817                 :  *====================================================================*/
    3818                 : 
    3819                 : /**********************************************************************
    3820                 :  *                   TABRectangle::TABRectangle()
    3821                 :  *
    3822                 :  * Constructor.
    3823                 :  **********************************************************************/
    3824               0 : TABRectangle::TABRectangle(OGRFeatureDefn *poDefnIn):
    3825               0 :               TABFeature(poDefnIn)
    3826                 : {
    3827               0 :     m_bRoundCorners = FALSE;
    3828               0 :     m_dRoundXRadius = m_dRoundYRadius = 0.0;
    3829               0 : }
    3830                 : 
    3831                 : /**********************************************************************
    3832                 :  *                   TABRectangle::~TABRectangle()
    3833                 :  *
    3834                 :  * Destructor.
    3835                 :  **********************************************************************/
    3836               0 : TABRectangle::~TABRectangle()
    3837                 : {
    3838               0 : }
    3839                 : 
    3840                 : /**********************************************************************
    3841                 :  *                     TABRectangle::CloneTABFeature()
    3842                 :  *
    3843                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    3844                 :  *
    3845                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    3846                 :  * then copies any members specific to its own type.
    3847                 :  **********************************************************************/
    3848               0 : TABFeature *TABRectangle::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    3849                 : {
    3850                 :     /*-----------------------------------------------------------------
    3851                 :      * Alloc new feature and copy the base stuff
    3852                 :      *----------------------------------------------------------------*/
    3853                 :     TABRectangle *poNew = new TABRectangle(poNewDefn ? poNewDefn : 
    3854               0 :                                                        GetDefnRef());
    3855                 : 
    3856               0 :     CopyTABFeatureBase(poNew);
    3857                 : 
    3858                 :     /*-----------------------------------------------------------------
    3859                 :      * And members specific to this class
    3860                 :      *----------------------------------------------------------------*/
    3861                 :     // ITABFeaturePen
    3862               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    3863                 : 
    3864                 :     // ITABFeatureBrush
    3865               0 :     *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
    3866                 : 
    3867               0 :     poNew->m_bRoundCorners = m_bRoundCorners;
    3868               0 :     poNew->m_dRoundXRadius = m_dRoundXRadius;
    3869               0 :     poNew->m_dRoundYRadius = m_dRoundYRadius;
    3870                 : 
    3871               0 :     return poNew;
    3872                 : }
    3873                 : 
    3874                 : /**********************************************************************
    3875                 :  *                   TABRectangle::ValidateMapInfoType()
    3876                 :  *
    3877                 :  * Check the feature's geometry part and return the corresponding
    3878                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    3879                 :  * be updated for further calls to GetMapInfoType();
    3880                 :  *
    3881                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    3882                 :  * is expected for this object class.
    3883                 :  **********************************************************************/
    3884               0 : int  TABRectangle::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    3885                 : {
    3886                 :     OGRGeometry *poGeom;
    3887                 : 
    3888                 :     /*-----------------------------------------------------------------
    3889                 :      * Fetch and validate geometry
    3890                 :      *----------------------------------------------------------------*/
    3891               0 :     poGeom = GetGeometryRef();
    3892               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    3893                 :     {
    3894               0 :         if (m_bRoundCorners && m_dRoundXRadius!=0.0 && m_dRoundYRadius!=0.0)
    3895               0 :             m_nMapInfoType = TAB_GEOM_ROUNDRECT;
    3896                 :         else
    3897               0 :             m_nMapInfoType = TAB_GEOM_RECT;
    3898                 :     }
    3899                 :     else
    3900                 :     {
    3901                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3902               0 :                  "TABRectangle: Missing or Invalid Geometry!");
    3903               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    3904                 :     }
    3905                 : 
    3906                 :     /*-----------------------------------------------------------------
    3907                 :      * Decide if coordinates should be compressed or not.
    3908                 :      *----------------------------------------------------------------*/
    3909                 :     // __TODO__ For now we always write uncompressed for this class...
    3910                 :     // ValidateCoordType(poMapFile);    
    3911               0 :     UpdateMBR(poMapFile);
    3912                 : 
    3913               0 :     return m_nMapInfoType;
    3914                 : }
    3915                 : 
    3916                 : /**********************************************************************
    3917                 :  *                   TABRectangle::UpdateMBR()
    3918                 :  *
    3919                 :  * Update the feature MBR members using the geometry
    3920                 :  *
    3921                 :  * Returns 0 on success, or -1 if there is no geometry in object
    3922                 :  **********************************************************************/
    3923               0 : int TABRectangle::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    3924                 : {
    3925                 :     OGRGeometry *poGeom;
    3926               0 :     OGREnvelope sEnvelope;
    3927                 : 
    3928                 :     /*-----------------------------------------------------------------
    3929                 :      * Fetch and validate geometry
    3930                 :      *----------------------------------------------------------------*/
    3931               0 :     poGeom = GetGeometryRef();
    3932               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    3933               0 :         poGeom->getEnvelope(&sEnvelope);
    3934                 :     else
    3935                 :     {
    3936                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3937               0 :                  "TABRectangle: Missing or Invalid Geometry!");
    3938               0 :         return -1;
    3939                 :     }
    3940                 : 
    3941                 :     /*-----------------------------------------------------------------
    3942                 :      * Note that we will simply use the rectangle's MBR and don't really 
    3943                 :      * read the polygon geometry... this should be OK unless the 
    3944                 :      * polygon geometry was not really a rectangle.
    3945                 :      *----------------------------------------------------------------*/
    3946               0 :     m_dXMin = sEnvelope.MinX;
    3947               0 :     m_dYMin = sEnvelope.MinY;
    3948               0 :     m_dXMax = sEnvelope.MaxX;
    3949               0 :     m_dYMax = sEnvelope.MaxY;
    3950                 : 
    3951               0 :     if (poMapFile)
    3952                 :     {
    3953               0 :         poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    3954               0 :         poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    3955                 :     }
    3956                 : 
    3957               0 :     return 0;
    3958                 : }
    3959                 : 
    3960                 : /**********************************************************************
    3961                 :  *                   TABRectangle::ReadGeometryFromMAPFile()
    3962                 :  *
    3963                 :  * Fill the geometry and representation (color, etc...) part of the
    3964                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    3965                 :  *
    3966                 :  * It is assumed that poMAPFile currently points to the beginning of
    3967                 :  * a map object.
    3968                 :  *
    3969                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    3970                 :  * been called.
    3971                 :  **********************************************************************/
    3972                 : int TABRectangle::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    3973                 :                                           TABMAPObjHdr *poObjHdr,
    3974                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    3975               0 :                                           TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    3976                 : {
    3977                 :     double              dXMin, dYMin, dXMax, dYMax;
    3978                 :     OGRPolygon          *poPolygon;
    3979                 :     OGRLinearRing       *poRing;
    3980                 : 
    3981                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    3982               0 :     if (bCoordBlockDataOnly)
    3983               0 :         return 0;
    3984                 : 
    3985                 :     /*-----------------------------------------------------------------
    3986                 :      * Fetch and validate geometry type
    3987                 :      *----------------------------------------------------------------*/
    3988               0 :     m_nMapInfoType = poObjHdr->m_nType;
    3989                 : 
    3990               0 :     if (m_nMapInfoType != TAB_GEOM_RECT &&
    3991                 :         m_nMapInfoType != TAB_GEOM_RECT_C &&
    3992                 :         m_nMapInfoType != TAB_GEOM_ROUNDRECT &&
    3993                 :         m_nMapInfoType != TAB_GEOM_ROUNDRECT_C)
    3994                 :     {
    3995                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3996                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    3997               0 :                  m_nMapInfoType, m_nMapInfoType);
    3998               0 :         return -1;
    3999                 :     }
    4000                 : 
    4001                 :     /*-----------------------------------------------------------------
    4002                 :      * Read object information
    4003                 :      *----------------------------------------------------------------*/
    4004               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4005                 : 
    4006                 :     // Read the corners radius
    4007                 : 
    4008               0 :     if (m_nMapInfoType == TAB_GEOM_ROUNDRECT ||
    4009                 :         m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
    4010                 :     {
    4011                 :         // Read the corner's diameters
    4012                 :         poMapFile->Int2CoordsysDist(poRectHdr->m_nCornerWidth, 
    4013                 :                                     poRectHdr->m_nCornerHeight,
    4014               0 :                                     m_dRoundXRadius, m_dRoundYRadius);
    4015                 : 
    4016                 :         // Divide by 2 since we store the corner's radius
    4017               0 :         m_dRoundXRadius /= 2.0;
    4018               0 :         m_dRoundYRadius /= 2.0;
    4019                 : 
    4020               0 :         m_bRoundCorners = TRUE;
    4021                 :     }
    4022                 :     else
    4023                 :     {
    4024               0 :         m_bRoundCorners = FALSE;
    4025               0 :         m_dRoundXRadius = m_dRoundYRadius = 0.0;
    4026                 :     }
    4027                 : 
    4028                 :     // A rectangle is defined by its MBR
    4029                 : 
    4030                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY, 
    4031               0 :                             dXMin, dYMin);
    4032                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY, 
    4033               0 :                             dXMax, dYMax);
    4034                 : 
    4035               0 :     m_nPenDefIndex = poRectHdr->m_nPenId;       // Pen index
    4036               0 :     poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    4037                 : 
    4038               0 :     m_nBrushDefIndex = poRectHdr->m_nBrushId;   // Brush index
    4039               0 :     poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
    4040                 : 
    4041                 :     /*-----------------------------------------------------------------
    4042                 :      * Call SetMBR() and GetMBR() now to make sure that min values are
    4043                 :      * really smaller than max values.
    4044                 :      *----------------------------------------------------------------*/
    4045               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    4046               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    4047                 : 
    4048                 :     /* Copy int MBR to feature class members */
    4049                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    4050               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    4051                 : 
    4052                 :     /*-----------------------------------------------------------------
    4053                 :      * Create and fill geometry object
    4054                 :      *----------------------------------------------------------------*/
    4055               0 :     poPolygon = new OGRPolygon;
    4056               0 :     poRing = new OGRLinearRing();
    4057               0 :     if (m_bRoundCorners && m_dRoundXRadius != 0.0 && m_dRoundYRadius != 0.0)
    4058                 :     {
    4059                 :         /*-------------------------------------------------------------
    4060                 :          * For rounded rectangles, we generate arcs with 45 line
    4061                 :          * segments for each corner.  We start with lower-left corner 
    4062                 :          * and proceed counterclockwise
    4063                 :          * We also have to make sure that rounding radius is not too
    4064                 :          * large for the MBR in the generated polygon... however, we 
    4065                 :          * always return the true X/Y radius (not adjusted) since this
    4066                 :          * is the way MapInfo seems to do it when a radius bigger than
    4067                 :          * the MBR is passed from TBA to MIF.
    4068                 :          *------------------------------------------------------------*/
    4069               0 :         double dXRadius = MIN(m_dRoundXRadius, (dXMax-dXMin)/2.0);
    4070               0 :         double dYRadius = MIN(m_dRoundYRadius, (dYMax-dYMin)/2.0);
    4071                 :         TABGenerateArc(poRing, 45, 
    4072                 :                        dXMin + dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
    4073               0 :                        PI, 3.0*PI/2.0);
    4074                 :         TABGenerateArc(poRing, 45, 
    4075                 :                        dXMax - dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
    4076               0 :                        3.0*PI/2.0, 2.0*PI);
    4077                 :         TABGenerateArc(poRing, 45, 
    4078                 :                        dXMax - dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
    4079               0 :                        0.0, PI/2.0);
    4080                 :         TABGenerateArc(poRing, 45, 
    4081                 :                        dXMin + dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
    4082               0 :                        PI/2.0, PI);
    4083                 :                        
    4084               0 :         TABCloseRing(poRing);
    4085                 :     }
    4086                 :     else
    4087                 :     {
    4088               0 :         poRing->addPoint(dXMin, dYMin);
    4089               0 :         poRing->addPoint(dXMax, dYMin);
    4090               0 :         poRing->addPoint(dXMax, dYMax);
    4091               0 :         poRing->addPoint(dXMin, dYMax);
    4092               0 :         poRing->addPoint(dXMin, dYMin);
    4093                 :     }
    4094                 : 
    4095               0 :     poPolygon->addRingDirectly(poRing);
    4096               0 :     SetGeometryDirectly(poPolygon);
    4097                 : 
    4098               0 :     return 0;
    4099                 : }
    4100                 : 
    4101                 : /**********************************************************************
    4102                 :  *                   TABRectangle::WriteGeometryToMAPFile()
    4103                 :  *
    4104                 :  * Write the geometry and representation (color, etc...) part of the
    4105                 :  * feature to the .MAP object pointed to by poMAPFile.
    4106                 :  *
    4107                 :  * It is assumed that poMAPFile currently points to a valid map object.
    4108                 :  *
    4109                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4110                 :  * been called.
    4111                 :  **********************************************************************/
    4112                 : int TABRectangle::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    4113                 :                                          TABMAPObjHdr *poObjHdr,
    4114                 :                                          GBool bCoordBlockDataOnly /*=FALSE*/, 
    4115               0 :                                          TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4116                 : {
    4117                 : 
    4118                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4119               0 :     if (bCoordBlockDataOnly)
    4120               0 :         return 0;
    4121                 : 
    4122                 :     /*-----------------------------------------------------------------
    4123                 :      * We assume that ValidateMapInfoType() was called already and that
    4124                 :      * the type in poObjHdr->m_nType is valid.
    4125                 :      *----------------------------------------------------------------*/
    4126               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    4127                 : 
    4128                 :     /*-----------------------------------------------------------------
    4129                 :      * Fetch and validate geometry and update MBR
    4130                 :      * Note that we will simply use the geometry's MBR and don't really 
    4131                 :      * read the polygon geometry... this should be OK unless the 
    4132                 :      * polygon geometry was not really a rectangle.
    4133                 :      *----------------------------------------------------------------*/
    4134               0 :     if (UpdateMBR(poMapFile) != 0)
    4135               0 :         return -1;  /* Error already reported */
    4136                 : 
    4137                 :     /*-----------------------------------------------------------------
    4138                 :      * Copy object information
    4139                 :      *----------------------------------------------------------------*/
    4140               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4141                 : 
    4142               0 :     if (m_nMapInfoType == TAB_GEOM_ROUNDRECT || 
    4143                 :         m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
    4144                 :     {
    4145                 :         poMapFile->Coordsys2IntDist(m_dRoundXRadius*2.0, m_dRoundYRadius*2.0,
    4146                 :                                     poRectHdr->m_nCornerWidth,
    4147               0 :                                     poRectHdr->m_nCornerHeight);
    4148                 :     }
    4149                 :     else
    4150                 :     {
    4151               0 :         poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
    4152                 :     }
    4153                 : 
    4154                 :     // A rectangle is defined by its MBR (values were set in UpdateMBR())
    4155               0 :     poRectHdr->m_nMinX = m_nXMin;
    4156               0 :     poRectHdr->m_nMinY = m_nYMin;
    4157               0 :     poRectHdr->m_nMaxX = m_nXMax;
    4158               0 :     poRectHdr->m_nMaxY = m_nYMax;
    4159                 : 
    4160               0 :     m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    4161               0 :     poRectHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    4162                 : 
    4163               0 :     m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
    4164               0 :     poRectHdr->m_nBrushId = m_nBrushDefIndex;      // Brush index
    4165                 : 
    4166               0 :     if (CPLGetLastErrorNo() != 0)
    4167               0 :         return -1;
    4168                 : 
    4169               0 :     return 0;
    4170                 : }
    4171                 : 
    4172                 : /**********************************************************************
    4173                 :  *                   TABRectangle::GetStyleString()
    4174                 :  *
    4175                 :  * Return style string for this feature.
    4176                 :  *
    4177                 :  * Style String is built only once during the first call to GetStyleString().
    4178                 :  **********************************************************************/
    4179               0 : const char *TABRectangle::GetStyleString()
    4180                 : {
    4181               0 :     if (m_pszStyleString == NULL)
    4182                 :     {
    4183                 :         // Since GetPen/BrushStyleString() use CPLSPrintf(), we need 
    4184                 :         // to use temporary buffers
    4185               0 :         char *pszPen = CPLStrdup(GetPenStyleString());
    4186               0 :         char *pszBrush = CPLStrdup(GetBrushStyleString());
    4187                 : 
    4188               0 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
    4189                 : 
    4190               0 :         CPLFree(pszPen);
    4191               0 :         CPLFree(pszBrush);
    4192                 :     }
    4193                 : 
    4194               0 :     return m_pszStyleString;
    4195                 : }
    4196                 : 
    4197                 : /**********************************************************************
    4198                 :  *                   TABRectangle::DumpMIF()
    4199                 :  *
    4200                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    4201                 :  **********************************************************************/
    4202               0 : void TABRectangle::DumpMIF(FILE *fpOut /*=NULL*/)
    4203                 : {
    4204                 :     OGRGeometry   *poGeom;
    4205               0 :     OGRPolygon    *poPolygon = NULL;
    4206                 :     int i, numPoints;
    4207                 : 
    4208               0 :     if (fpOut == NULL)
    4209               0 :         fpOut = stdout;
    4210                 : 
    4211                 :     /*-----------------------------------------------------------------
    4212                 :      * Output RECT or ROUNDRECT parameters
    4213                 :      *----------------------------------------------------------------*/
    4214                 :     double dXMin, dYMin, dXMax, dYMax;
    4215               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    4216               0 :     if (m_bRoundCorners)
    4217                 :         fprintf(fpOut, "(ROUNDRECT %.15g %.15g %.15g %.15g    %.15g %.15g)\n", 
    4218                 :                 dXMin, dYMin, dXMax, dYMax, 
    4219               0 :                 m_dRoundXRadius, m_dRoundYRadius);
    4220                 :     else
    4221               0 :         fprintf(fpOut, "(RECT %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
    4222                 : 
    4223                 :     /*-----------------------------------------------------------------
    4224                 :      * Fetch and validate geometry
    4225                 :      *----------------------------------------------------------------*/
    4226               0 :     poGeom = GetGeometryRef();
    4227               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    4228                 :     {
    4229                 :         /*-------------------------------------------------------------
    4230                 :          * Generate rectangle output as a region
    4231                 :          * We could also output as a RECT or ROUNDRECT in a real MIF generator
    4232                 :          *------------------------------------------------------------*/
    4233                 :         int iRing, numIntRings;
    4234               0 :         poPolygon = (OGRPolygon*)poGeom;
    4235               0 :         numIntRings = poPolygon->getNumInteriorRings();
    4236               0 :         fprintf(fpOut, "REGION %d\n", numIntRings+1);
    4237                 :         // In this loop, iRing=-1 for the outer ring.
    4238               0 :         for(iRing=-1; iRing < numIntRings; iRing++)
    4239                 :         {
    4240                 :             OGRLinearRing       *poRing;
    4241                 : 
    4242               0 :             if (iRing == -1)
    4243               0 :                 poRing = poPolygon->getExteriorRing();
    4244                 :             else
    4245               0 :                 poRing = poPolygon->getInteriorRing(iRing);
    4246                 : 
    4247               0 :             if (poRing == NULL)
    4248                 :             {
    4249                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    4250               0 :                          "TABRectangle: Object Geometry contains NULL rings!");
    4251               0 :                 return;
    4252                 :             }
    4253                 : 
    4254               0 :             numPoints = poRing->getNumPoints();
    4255               0 :             fprintf(fpOut, " %d\n", numPoints);
    4256               0 :             for(i=0; i<numPoints; i++)
    4257               0 :                 fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
    4258                 :         }
    4259                 :     }
    4260                 :     else
    4261                 :     {
    4262                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4263               0 :                  "TABRectangle: Missing or Invalid Geometry!");
    4264               0 :         return;
    4265                 :     }
    4266                 : 
    4267                 :     // Finish with PEN/BRUSH/etc. clauses
    4268               0 :     DumpPenDef();
    4269               0 :     DumpBrushDef();
    4270                 : 
    4271               0 :     fflush(fpOut);
    4272                 : }
    4273                 : 
    4274                 : 
    4275                 : /*=====================================================================
    4276                 :  *                      class TABEllipse
    4277                 :  *====================================================================*/
    4278                 : 
    4279                 : /**********************************************************************
    4280                 :  *                   TABEllipse::TABEllipse()
    4281                 :  *
    4282                 :  * Constructor.
    4283                 :  **********************************************************************/
    4284               0 : TABEllipse::TABEllipse(OGRFeatureDefn *poDefnIn):
    4285               0 :               TABFeature(poDefnIn)
    4286                 : {
    4287               0 : }
    4288                 : 
    4289                 : /**********************************************************************
    4290                 :  *                   TABEllipse::~TABEllipse()
    4291                 :  *
    4292                 :  * Destructor.
    4293                 :  **********************************************************************/
    4294               0 : TABEllipse::~TABEllipse()
    4295                 : {
    4296               0 : }
    4297                 : 
    4298                 : /**********************************************************************
    4299                 :  *                     TABEllipse::CloneTABFeature()
    4300                 :  *
    4301                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    4302                 :  *
    4303                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    4304                 :  * then copies any members specific to its own type.
    4305                 :  **********************************************************************/
    4306               0 : TABFeature *TABEllipse::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    4307                 : {
    4308                 :     /*-----------------------------------------------------------------
    4309                 :      * Alloc new feature and copy the base stuff
    4310                 :      *----------------------------------------------------------------*/
    4311                 :     TABEllipse *poNew = new TABEllipse(poNewDefn ? poNewDefn : 
    4312               0 :                                                    GetDefnRef());
    4313                 : 
    4314               0 :     CopyTABFeatureBase(poNew);
    4315                 : 
    4316                 :     /*-----------------------------------------------------------------
    4317                 :      * And members specific to this class
    4318                 :      *----------------------------------------------------------------*/
    4319                 :     // ITABFeaturePen
    4320               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    4321                 : 
    4322                 :     // ITABFeatureBrush
    4323               0 :     *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
    4324                 : 
    4325               0 :     poNew->m_dCenterX = m_dCenterX;
    4326               0 :     poNew->m_dCenterY = m_dCenterY;
    4327               0 :     poNew->m_dXRadius = m_dXRadius;
    4328               0 :     poNew->m_dYRadius = m_dYRadius;
    4329                 : 
    4330               0 :     return poNew;
    4331                 : }
    4332                 : 
    4333                 : /**********************************************************************
    4334                 :  *                   TABEllipse::ValidateMapInfoType()
    4335                 :  *
    4336                 :  * Check the feature's geometry part and return the corresponding
    4337                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    4338                 :  * be updated for further calls to GetMapInfoType();
    4339                 :  *
    4340                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    4341                 :  * is expected for this object class.
    4342                 :  **********************************************************************/
    4343               0 : int  TABEllipse::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    4344                 : {
    4345                 :     OGRGeometry *poGeom;
    4346                 : 
    4347                 :     /*-----------------------------------------------------------------
    4348                 :      * Fetch and validate geometry
    4349                 :      *----------------------------------------------------------------*/
    4350               0 :     poGeom = GetGeometryRef();
    4351               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
    4352                 :          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
    4353                 :     {
    4354               0 :         m_nMapInfoType = TAB_GEOM_ELLIPSE;
    4355                 :     }
    4356                 :     else
    4357                 :     {
    4358                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4359               0 :                  "TABEllipse: Missing or Invalid Geometry!");
    4360               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    4361                 :     }
    4362                 : 
    4363                 :     /*-----------------------------------------------------------------
    4364                 :      * Decide if coordinates should be compressed or not.
    4365                 :      *----------------------------------------------------------------*/
    4366                 :     // __TODO__ For now we always write uncompressed for this class...
    4367                 :     // ValidateCoordType(poMapFile);
    4368               0 :     UpdateMBR(poMapFile);
    4369                 : 
    4370               0 :     return m_nMapInfoType;
    4371                 : }
    4372                 : 
    4373                 : /**********************************************************************
    4374                 :  *                   TABEllipse::UpdateMBR()
    4375                 :  *
    4376                 :  * Update the feature MBR members using the geometry
    4377                 :  *
    4378                 :  * Returns 0 on success, or -1 if there is no geometry in object
    4379                 :  **********************************************************************/
    4380               0 : int TABEllipse::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    4381                 : {
    4382                 :     OGRGeometry *poGeom;
    4383               0 :     OGREnvelope sEnvelope;
    4384                 : 
    4385                 :     /*-----------------------------------------------------------------
    4386                 :      * Fetch and validate geometry... Polygon and point are accepted.
    4387                 :      * Note that we will simply use the ellipse's MBR and don't really 
    4388                 :      * read the polygon geometry... this should be OK unless the 
    4389                 :      * polygon geometry was not really an ellipse.
    4390                 :      *----------------------------------------------------------------*/
    4391               0 :     poGeom = GetGeometryRef();
    4392               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
    4393                 :          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint )  )
    4394               0 :         poGeom->getEnvelope(&sEnvelope);
    4395                 :     else
    4396                 :     {
    4397                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4398               0 :                  "TABEllipse: Missing or Invalid Geometry!");
    4399               0 :         return -1;
    4400                 :     }
    4401                 : 
    4402                 :     /*-----------------------------------------------------------------
    4403                 :      * We use the center of the MBR as the ellipse center, and the 
    4404                 :      * X/Y radius to define the MBR size.  If X/Y radius are null then
    4405                 :      * we'll try to use the MBR to recompute them.
    4406                 :      *----------------------------------------------------------------*/
    4407                 :     double      dXCenter, dYCenter;
    4408               0 :     dXCenter = (sEnvelope.MaxX + sEnvelope.MinX)/2.0;
    4409               0 :     dYCenter = (sEnvelope.MaxY + sEnvelope.MinY)/2.0;
    4410               0 :     if (m_dXRadius == 0.0 && m_dYRadius == 0.0)
    4411                 :     {
    4412               0 :         m_dXRadius = ABS(sEnvelope.MaxX - sEnvelope.MinX) / 2.0;
    4413               0 :         m_dYRadius = ABS(sEnvelope.MaxY - sEnvelope.MinY) / 2.0;
    4414                 :     }
    4415                 : 
    4416               0 :     m_dXMin = dXCenter - m_dXRadius;
    4417               0 :     m_dYMin = dYCenter - m_dYRadius;
    4418               0 :     m_dXMax = dXCenter + m_dXRadius;
    4419               0 :     m_dYMax = dYCenter + m_dYRadius;
    4420                 : 
    4421               0 :     if (poMapFile)
    4422                 :     {
    4423               0 :         poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    4424               0 :         poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    4425                 :     }
    4426                 : 
    4427               0 :     return 0;
    4428                 : }
    4429                 : 
    4430                 : /**********************************************************************
    4431                 :  *                   TABEllipse::ReadGeometryFromMAPFile()
    4432                 :  *
    4433                 :  * Fill the geometry and representation (color, etc...) part of the
    4434                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    4435                 :  *
    4436                 :  * It is assumed that poMAPFile currently points to the beginning of
    4437                 :  * a map object.
    4438                 :  *
    4439                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4440                 :  * been called.
    4441                 :  **********************************************************************/
    4442                 : int TABEllipse::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    4443                 :                                         TABMAPObjHdr *poObjHdr,
    4444                 :                                         GBool bCoordBlockDataOnly /*=FALSE*/,
    4445               0 :                                         TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4446                 : {
    4447                 :     double              dXMin, dYMin, dXMax, dYMax;
    4448                 :     OGRPolygon          *poPolygon;
    4449                 :     OGRLinearRing       *poRing;
    4450                 : 
    4451                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4452               0 :     if (bCoordBlockDataOnly)
    4453               0 :         return 0;
    4454                 : 
    4455                 :     /*-----------------------------------------------------------------
    4456                 :      * Fetch and validate geometry type
    4457                 :      *----------------------------------------------------------------*/
    4458               0 :     m_nMapInfoType = poObjHdr->m_nType;
    4459                 : 
    4460               0 :     if (m_nMapInfoType != TAB_GEOM_ELLIPSE &&
    4461                 :         m_nMapInfoType != TAB_GEOM_ELLIPSE_C )
    4462                 :     {
    4463                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4464                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    4465               0 :                  m_nMapInfoType, m_nMapInfoType);
    4466               0 :         return -1;
    4467                 :     }
    4468                 : 
    4469                 :     /*-----------------------------------------------------------------
    4470                 :      * Read object information
    4471                 :      *----------------------------------------------------------------*/
    4472               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4473                 : 
    4474                 :     // An ellipse is defined by its MBR
    4475                 : 
    4476                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY, 
    4477               0 :                             dXMin, dYMin);
    4478                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY, 
    4479               0 :                             dXMax, dYMax);
    4480                 : 
    4481               0 :     m_nPenDefIndex = poRectHdr->m_nPenId;       // Pen index
    4482               0 :     poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    4483                 : 
    4484               0 :     m_nBrushDefIndex = poRectHdr->m_nBrushId;   // Brush index
    4485               0 :     poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
    4486                 : 
    4487                 :     /*-----------------------------------------------------------------
    4488                 :      * Save info about the ellipse def. inside class members
    4489                 :      *----------------------------------------------------------------*/
    4490               0 :     m_dCenterX = (dXMin + dXMax) / 2.0;
    4491               0 :     m_dCenterY = (dYMin + dYMax) / 2.0;
    4492               0 :     m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
    4493               0 :     m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
    4494                 : 
    4495               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    4496                 : 
    4497                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    4498               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    4499                 : 
    4500                 :     /*-----------------------------------------------------------------
    4501                 :      * Create and fill geometry object
    4502                 :      *----------------------------------------------------------------*/
    4503               0 :     poPolygon = new OGRPolygon;
    4504               0 :     poRing = new OGRLinearRing();
    4505                 : 
    4506                 : 
    4507                 :     /*-----------------------------------------------------------------
    4508                 :      * For the OGR geometry, we generate an ellipse with 2 degrees line
    4509                 :      * segments.
    4510                 :      *----------------------------------------------------------------*/
    4511                 :     TABGenerateArc(poRing, 180, 
    4512                 :                    m_dCenterX, m_dCenterY,
    4513                 :                    m_dXRadius, m_dYRadius,
    4514               0 :                    0.0, 2.0*PI);
    4515               0 :     TABCloseRing(poRing);
    4516                 : 
    4517               0 :     poPolygon->addRingDirectly(poRing);
    4518               0 :     SetGeometryDirectly(poPolygon);
    4519                 : 
    4520               0 :     return 0;
    4521                 : }
    4522                 : 
    4523                 : /**********************************************************************
    4524                 :  *                   TABEllipse::WriteGeometryToMAPFile()
    4525                 :  *
    4526                 :  * Write the geometry and representation (color, etc...) part of the
    4527                 :  * feature to the .MAP object pointed to by poMAPFile.
    4528                 :  *
    4529                 :  * It is assumed that poMAPFile currently points to a valid map object.
    4530                 :  *
    4531                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4532                 :  * been called.
    4533                 :  **********************************************************************/
    4534                 : int TABEllipse::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    4535                 :                                        TABMAPObjHdr *poObjHdr,
    4536                 :                                        GBool bCoordBlockDataOnly /*=FALSE*/, 
    4537               0 :                                        TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4538                 : {
    4539                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4540               0 :     if (bCoordBlockDataOnly)
    4541               0 :         return 0;
    4542                 : 
    4543                 :     /*-----------------------------------------------------------------
    4544                 :      * We assume that ValidateMapInfoType() was called already and that
    4545                 :      * the type in poObjHdr->m_nType is valid.
    4546                 :      *----------------------------------------------------------------*/
    4547               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    4548                 : 
    4549                 :     /*-----------------------------------------------------------------
    4550                 :      * Fetch and validate geometry... Polygon and point are accepted.
    4551                 :      * Note that we will simply use the ellipse's MBR and don't really 
    4552                 :      * read the polygon geometry... this should be OK unless the 
    4553                 :      * polygon geometry was not really an ellipse.
    4554                 :      *
    4555                 :      * We use the center of the MBR as the ellipse center, and the 
    4556                 :      * X/Y radius to define the MBR size.  If X/Y radius are null then
    4557                 :      * we'll try to use the MBR to recompute them.
    4558                 :      *----------------------------------------------------------------*/
    4559               0 :     if (UpdateMBR(poMapFile) != 0)
    4560               0 :         return -1;  /* Error already reported */
    4561                 : 
    4562                 :     /*-----------------------------------------------------------------
    4563                 :      * Copy object information
    4564                 :      *----------------------------------------------------------------*/
    4565               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4566                 : 
    4567                 :     // Reset RoundRect Corner members... just in case (unused for ellipse)
    4568               0 :     poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
    4569                 : 
    4570                 :     // An ellipse is defined by its MBR (values were set in UpdateMBR())
    4571               0 :     poRectHdr->m_nMinX = m_nXMin;
    4572               0 :     poRectHdr->m_nMinY = m_nYMin;
    4573               0 :     poRectHdr->m_nMaxX = m_nXMax;
    4574               0 :     poRectHdr->m_nMaxY = m_nYMax;
    4575                 : 
    4576               0 :     m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    4577               0 :     poRectHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    4578                 : 
    4579               0 :     m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
    4580               0 :     poRectHdr->m_nBrushId = m_nBrushDefIndex;      // Brush index
    4581                 : 
    4582               0 :     if (CPLGetLastErrorNo() != 0)
    4583               0 :         return -1;
    4584                 : 
    4585               0 :     return 0;
    4586                 : }
    4587                 : 
    4588                 : /**********************************************************************
    4589                 :  *                   TABEllipse::GetStyleString()
    4590                 :  *
    4591                 :  * Return style string for this feature.
    4592                 :  *
    4593                 :  * Style String is built only once during the first call to GetStyleString().
    4594                 :  **********************************************************************/
    4595               0 : const char *TABEllipse::GetStyleString()
    4596                 : {
    4597               0 :     if (m_pszStyleString == NULL)
    4598                 :     {
    4599                 :         // Since GetPen/BrushStyleString() use CPLSPrintf(), we need 
    4600                 :         // to use temporary buffers
    4601               0 :         char *pszPen = CPLStrdup(GetPenStyleString());
    4602               0 :         char *pszBrush = CPLStrdup(GetBrushStyleString());
    4603                 : 
    4604               0 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
    4605                 : 
    4606               0 :         CPLFree(pszPen);
    4607               0 :         CPLFree(pszBrush);
    4608                 :     }
    4609                 : 
    4610               0 :     return m_pszStyleString;
    4611                 : }
    4612                 : 
    4613                 : 
    4614                 : /**********************************************************************
    4615                 :  *                   TABEllipse::DumpMIF()
    4616                 :  *
    4617                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    4618                 :  **********************************************************************/
    4619               0 : void TABEllipse::DumpMIF(FILE *fpOut /*=NULL*/)
    4620                 : {
    4621                 :     OGRGeometry   *poGeom;
    4622               0 :     OGRPolygon    *poPolygon = NULL;
    4623                 :     int i, numPoints;
    4624                 : 
    4625               0 :     if (fpOut == NULL)
    4626               0 :         fpOut = stdout;
    4627                 : 
    4628                 :     /*-----------------------------------------------------------------
    4629                 :      * Output ELLIPSE parameters
    4630                 :      *----------------------------------------------------------------*/
    4631                 :     double dXMin, dYMin, dXMax, dYMax;
    4632               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    4633               0 :     fprintf(fpOut, "(ELLIPSE %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
    4634                 : 
    4635                 :     /*-----------------------------------------------------------------
    4636                 :      * Fetch and validate geometry
    4637                 :      *----------------------------------------------------------------*/
    4638               0 :     poGeom = GetGeometryRef();
    4639               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    4640                 :     {
    4641                 :         /*-------------------------------------------------------------
    4642                 :          * Generate ellipse output as a region
    4643                 :          * We could also output as an ELLIPSE in a real MIF generator
    4644                 :          *------------------------------------------------------------*/
    4645                 :         int iRing, numIntRings;
    4646               0 :         poPolygon = (OGRPolygon*)poGeom;
    4647               0 :         numIntRings = poPolygon->getNumInteriorRings();
    4648               0 :         fprintf(fpOut, "REGION %d\n", numIntRings+1);
    4649                 :         // In this loop, iRing=-1 for the outer ring.
    4650               0 :         for(iRing=-1; iRing < numIntRings; iRing++)
    4651                 :         {
    4652                 :             OGRLinearRing       *poRing;
    4653                 : 
    4654               0 :             if (iRing == -1)
    4655               0 :                 poRing = poPolygon->getExteriorRing();
    4656                 :             else
    4657               0 :                 poRing = poPolygon->getInteriorRing(iRing);
    4658                 : 
    4659               0 :             if (poRing == NULL)
    4660                 :             {
    4661                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    4662               0 :                          "TABEllipse: Object Geometry contains NULL rings!");
    4663               0 :                 return;
    4664                 :             }
    4665                 : 
    4666               0 :             numPoints = poRing->getNumPoints();
    4667               0 :             fprintf(fpOut, " %d\n", numPoints);
    4668               0 :             for(i=0; i<numPoints; i++)
    4669               0 :                 fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
    4670                 :         }
    4671                 :     }
    4672                 :     else
    4673                 :     {
    4674                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4675               0 :                  "TABEllipse: Missing or Invalid Geometry!");
    4676               0 :         return;
    4677                 :     }
    4678                 : 
    4679                 :     // Finish with PEN/BRUSH/etc. clauses
    4680               0 :     DumpPenDef();
    4681               0 :     DumpBrushDef();
    4682                 : 
    4683               0 :     fflush(fpOut);
    4684                 : }
    4685                 : 
    4686                 : 
    4687                 : /*=====================================================================
    4688                 :  *                      class TABArc
    4689                 :  *====================================================================*/
    4690                 : 
    4691                 : /**********************************************************************
    4692                 :  *                   TABArc::TABArc()
    4693                 :  *
    4694                 :  * Constructor.
    4695                 :  **********************************************************************/
    4696               0 : TABArc::TABArc(OGRFeatureDefn *poDefnIn):
    4697               0 :               TABFeature(poDefnIn)
    4698                 : {
    4699               0 :     m_dStartAngle = m_dEndAngle = 0.0;
    4700               0 :     m_dCenterX = m_dCenterY = m_dXRadius = m_dYRadius = 0.0;
    4701                 : 
    4702               0 : }
    4703                 : 
    4704                 : /**********************************************************************
    4705                 :  *                   TABArc::~TABArc()
    4706                 :  *
    4707                 :  * Destructor.
    4708                 :  **********************************************************************/
    4709               0 : TABArc::~TABArc()
    4710                 : {
    4711               0 : }
    4712                 : 
    4713                 : /**********************************************************************
    4714                 :  *                     TABArc::CloneTABFeature()
    4715                 :  *
    4716                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    4717                 :  *
    4718                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    4719                 :  * then copies any members specific to its own type.
    4720                 :  **********************************************************************/
    4721               0 : TABFeature *TABArc::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    4722                 : {
    4723                 :     /*-----------------------------------------------------------------
    4724                 :      * Alloc new feature and copy the base stuff
    4725                 :      *----------------------------------------------------------------*/
    4726               0 :     TABArc *poNew = new TABArc(poNewDefn ? poNewDefn : GetDefnRef());
    4727                 : 
    4728               0 :     CopyTABFeatureBase(poNew);
    4729                 : 
    4730                 :     /*-----------------------------------------------------------------
    4731                 :      * And members specific to this class
    4732                 :      *----------------------------------------------------------------*/
    4733                 :     // ITABFeaturePen
    4734               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    4735                 : 
    4736               0 :     poNew->SetStartAngle( GetStartAngle() );
    4737               0 :     poNew->SetEndAngle( GetEndAngle() );
    4738                 : 
    4739               0 :     poNew->m_dCenterX = m_dCenterX;
    4740               0 :     poNew->m_dCenterY = m_dCenterY;
    4741               0 :     poNew->m_dXRadius = m_dXRadius;
    4742               0 :     poNew->m_dYRadius = m_dYRadius;
    4743                 : 
    4744               0 :     return poNew;
    4745                 : }
    4746                 : 
    4747                 : /**********************************************************************
    4748                 :  *                   TABArc::ValidateMapInfoType()
    4749                 :  *
    4750                 :  * Check the feature's geometry part and return the corresponding
    4751                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    4752                 :  * be updated for further calls to GetMapInfoType();
    4753                 :  *
    4754                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    4755                 :  * is expected for this object class.
    4756                 :  **********************************************************************/
    4757               0 : int  TABArc::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    4758                 : {
    4759                 :     OGRGeometry *poGeom;
    4760                 : 
    4761                 :     /*-----------------------------------------------------------------
    4762                 :      * Fetch and validate geometry
    4763                 :      *----------------------------------------------------------------*/
    4764               0 :     poGeom = GetGeometryRef();
    4765               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) ||
    4766                 :          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
    4767                 :     {
    4768               0 :         m_nMapInfoType = TAB_GEOM_ARC;
    4769                 :     }
    4770                 :     else
    4771                 :     {
    4772                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4773               0 :                  "TABArc: Missing or Invalid Geometry!");
    4774               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    4775                 :     }
    4776                 : 
    4777                 :     /*-----------------------------------------------------------------
    4778                 :      * Decide if coordinates should be compressed or not.
    4779                 :      *----------------------------------------------------------------*/
    4780                 :     // __TODO__ For now we always write uncompressed for this class...
    4781                 :     // ValidateCoordType(poMapFile);
    4782               0 :     UpdateMBR(poMapFile);
    4783                 : 
    4784               0 :     return m_nMapInfoType;
    4785                 : }
    4786                 : 
    4787                 : /**********************************************************************
    4788                 :  *                   TABArc::UpdateMBR()
    4789                 :  *
    4790                 :  * Update the feature MBR members using the geometry
    4791                 :  *
    4792                 :  * Returns 0 on success, or -1 if there is no geometry in object
    4793                 :  **********************************************************************/
    4794               0 : int TABArc::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    4795                 : {
    4796                 :     OGRGeometry *poGeom;
    4797               0 :     OGREnvelope sEnvelope;
    4798                 : 
    4799               0 :     poGeom = GetGeometryRef();
    4800               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) )
    4801                 :     {
    4802                 :         /*-------------------------------------------------------------
    4803                 :          * POLYGON geometry:
    4804                 :          * Note that we will simply use the ellipse's MBR and don't really 
    4805                 :          * read the polygon geometry... this should be OK unless the 
    4806                 :          * polygon geometry was not really an ellipse.
    4807                 :          * In the case of a polygon geometry. the m_dCenterX/Y values MUST
    4808                 :          * have been set by the caller.
    4809                 :          *------------------------------------------------------------*/
    4810               0 :         poGeom->getEnvelope(&sEnvelope);
    4811                 :     }
    4812               0 :     else if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) ) 
    4813                 :     {
    4814                 :         /*-------------------------------------------------------------
    4815                 :          * In the case of a POINT GEOMETRY, we will make sure the the 
    4816                 :          * feature's m_dCenterX/Y are in sync with the point's X,Y coords.
    4817                 :          *
    4818                 :          * In this case we have to reconstruct the arc inside a temporary
    4819                 :          * geometry object in order to find its real MBR.
    4820                 :          *------------------------------------------------------------*/
    4821               0 :         OGRPoint *poPoint = (OGRPoint *)poGeom;
    4822               0 :         m_dCenterX = poPoint->getX();
    4823               0 :         m_dCenterY = poPoint->getY();
    4824                 : 
    4825               0 :         OGRLineString oTmpLine;
    4826               0 :         int numPts=0;
    4827               0 :         if (m_dEndAngle < m_dStartAngle)
    4828               0 :             numPts = (int) ABS( ((m_dEndAngle+360)-m_dStartAngle)/2 ) + 1;
    4829                 :         else
    4830               0 :             numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2 ) + 1;
    4831               0 :         numPts = MAX(2, numPts);
    4832                 : 
    4833                 :         TABGenerateArc(&oTmpLine, numPts,
    4834                 :                        m_dCenterX, m_dCenterY,
    4835                 :                        m_dXRadius, m_dYRadius,
    4836               0 :                        m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
    4837                 : 
    4838               0 :         oTmpLine.getEnvelope(&sEnvelope);
    4839                 :     }
    4840                 :     else
    4841                 :     {
    4842                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4843               0 :                  "TABArc: Missing or Invalid Geometry!");
    4844               0 :         return -1;
    4845                 :     }
    4846                 : 
    4847                 :     // Update the Arc's MBR
    4848               0 :     m_dXMin = sEnvelope.MinX;
    4849               0 :     m_dYMin = sEnvelope.MinY;
    4850               0 :     m_dXMax = sEnvelope.MaxX;
    4851               0 :     m_dYMax = sEnvelope.MaxY;
    4852                 : 
    4853               0 :     if (poMapFile)
    4854                 :     {
    4855               0 :         poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    4856               0 :         poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    4857                 :     }
    4858                 : 
    4859               0 :     return 0;
    4860                 : }
    4861                 : 
    4862                 : /**********************************************************************
    4863                 :  *                   TABArc::ReadGeometryFromMAPFile()
    4864                 :  *
    4865                 :  * Fill the geometry and representation (color, etc...) part of the
    4866                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    4867                 :  *
    4868                 :  * It is assumed that poMAPFile currently points to the beginning of
    4869                 :  * a map object.
    4870                 :  *
    4871                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4872                 :  * been called.
    4873                 :  **********************************************************************/
    4874                 : int TABArc::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    4875                 :                                     TABMAPObjHdr *poObjHdr,
    4876                 :                                     GBool bCoordBlockDataOnly /*=FALSE*/, 
    4877               0 :                                     TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4878                 : {
    4879                 :     double              dXMin, dYMin, dXMax, dYMax;
    4880                 :     OGRLineString       *poLine;
    4881                 :     int                 numPts;
    4882                 : 
    4883                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4884               0 :     if (bCoordBlockDataOnly)
    4885               0 :         return 0;
    4886                 : 
    4887                 :     /*-----------------------------------------------------------------
    4888                 :      * Fetch and validate geometry type
    4889                 :      *----------------------------------------------------------------*/
    4890               0 :     m_nMapInfoType = poObjHdr->m_nType;
    4891                 : 
    4892               0 :     if (m_nMapInfoType != TAB_GEOM_ARC &&
    4893                 :         m_nMapInfoType != TAB_GEOM_ARC_C )
    4894                 :     {
    4895                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4896                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    4897               0 :                  m_nMapInfoType, m_nMapInfoType);
    4898               0 :         return -1;
    4899                 :     }
    4900                 : 
    4901                 : 
    4902                 :     /*-----------------------------------------------------------------
    4903                 :      * Read object information
    4904                 :      *----------------------------------------------------------------*/
    4905               0 :     TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
    4906                 : 
    4907                 :     /*-------------------------------------------------------------
    4908                 :      * Start/End angles
    4909                 :      * Since the angles are specified for integer coordinates, and
    4910                 :      * that these coordinates can have the X axis reversed, we have to
    4911                 :      * adjust the angle values for the change in the X axis
    4912                 :      * direction.
    4913                 :      *
    4914                 :      * This should be necessary only when X axis is flipped.
    4915                 :      * __TODO__ Why is order of start/end values reversed as well???
    4916                 :      *------------------------------------------------------------*/
    4917                 : 
    4918                 :     /*-------------------------------------------------------------
    4919                 :      * OK, Arc angles again!!!!!!!!!!!!
    4920                 :      * After some tests in 1999-11, it appeared that the angle values
    4921                 :      * ALWAYS had to be flipped (read order= end angle followed by 
    4922                 :      * start angle), no matter which quadrant the file is in.
    4923                 :      * This does not make any sense, so I suspect that there is something
    4924                 :      * that we are missing here!
    4925                 :      *
    4926                 :      * 2000-01-14.... Again!!!  Based on some sample data files:
    4927                 :      *  File         Ver Quadr  ReflXAxis  Read_Order   Adjust_Angle
    4928                 :      * test_symb.tab 300    2        1      end,start    X=yes Y=no
    4929                 :      * alltypes.tab: 300    1        0      start,end    X=no  Y=no
    4930                 :      * arcs.tab:     300    2        0      end,start    X=yes Y=no
    4931                 :      *
    4932                 :      * Until we prove it wrong, the rule would be:
    4933                 :      *  -> Quadrant 1 and 3, angles order = start, end
    4934                 :      *  -> Quadrant 2 and 4, angles order = end, start
    4935                 :      * + Always adjust angles for x and y axis based on quadrant.
    4936                 :      *
    4937                 :      * This was confirmed using some more files in which the quadrant was 
    4938                 :      * manually changed, but whether these are valid results is 
    4939                 :      * discutable.
    4940                 :      *
    4941                 :      * The ReflectXAxis flag seems to have no effect here...
    4942                 :      *------------------------------------------------------------*/
    4943                 : 
    4944                 :     /*-------------------------------------------------------------
    4945                 :      * In version 100 .tab files (version 400 .map), it is possible
    4946                 :      * to have a quadrant value of 0 and it should be treated the 
    4947                 :      * same way as quadrant 3
    4948                 :      *------------------------------------------------------------*/
    4949               0 :     if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==1 ||
    4950                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
    4951                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0  )
    4952                 :     {
    4953                 :         // Quadrants 1 and 3 ... read order = start, end
    4954               0 :         m_dStartAngle = poArcHdr->m_nStartAngle/10.0;
    4955               0 :         m_dEndAngle = poArcHdr->m_nEndAngle/10.0;
    4956                 :     }
    4957                 :     else
    4958                 :     {
    4959                 :         // Quadrants 2 and 4 ... read order = end, start
    4960               0 :         m_dStartAngle = poArcHdr->m_nEndAngle/10.0;
    4961               0 :         m_dEndAngle = poArcHdr->m_nStartAngle/10.0;
    4962                 :     }
    4963                 : 
    4964               0 :     if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==2 ||
    4965                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
    4966                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
    4967                 :     {
    4968                 :         // X axis direction is flipped... adjust angle
    4969                 :         m_dStartAngle = (m_dStartAngle<=180.0) ? (180.0-m_dStartAngle):
    4970               0 :             (540.0-m_dStartAngle);
    4971                 :         m_dEndAngle   = (m_dEndAngle<=180.0) ? (180.0-m_dEndAngle):
    4972               0 :             (540.0-m_dEndAngle);
    4973                 :     }
    4974                 : 
    4975               0 :     if (poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
    4976                 :         poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==4 ||
    4977                 :         poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
    4978                 :     {
    4979                 :         // Y axis direction is flipped... this reverses angle direction
    4980                 :         // Unfortunately we never found any file that contains this case,
    4981                 :         // but this should be the behavior to expect!!!
    4982                 :         //
    4983                 :         // 2000-01-14: some files in which quadrant was set to 3 and 4
    4984                 :         // manually seemed to confirm that this is the right thing to do.
    4985               0 :         m_dStartAngle = 360.0 - m_dStartAngle;
    4986               0 :         m_dEndAngle = 360.0 - m_dEndAngle;
    4987                 :     }
    4988                 : 
    4989                 :     // An arc is defined by its defining ellipse's MBR:
    4990                 : 
    4991                 :     poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMinX, 
    4992               0 :                             poArcHdr->m_nArcEllipseMinY , dXMin, dYMin);
    4993                 :     poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMaxX, 
    4994               0 :                             poArcHdr->m_nArcEllipseMaxY , dXMax, dYMax);
    4995                 : 
    4996               0 :     m_dCenterX = (dXMin + dXMax) / 2.0;
    4997               0 :     m_dCenterY = (dYMin + dYMax) / 2.0;
    4998               0 :     m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
    4999               0 :     m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
    5000                 : 
    5001                 :     // Read the Arc's MBR and use that as this feature's MBR
    5002                 :     poMapFile->Int2Coordsys(poArcHdr->m_nMinX, poArcHdr->m_nMinY, 
    5003               0 :                             dXMin, dYMin);
    5004                 :     poMapFile->Int2Coordsys(poArcHdr->m_nMaxX, poArcHdr->m_nMaxY, 
    5005               0 :                             dXMax, dYMax);
    5006               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    5007                 : 
    5008               0 :     m_nPenDefIndex = poArcHdr->m_nPenId;        // Pen index
    5009               0 :     poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    5010                 : 
    5011                 : 
    5012                 :     /*-----------------------------------------------------------------
    5013                 :      * Create and fill geometry object
    5014                 :      * For the OGR geometry, we generate an arc with 2 degrees line
    5015                 :      * segments.
    5016                 :      *----------------------------------------------------------------*/
    5017               0 :     poLine = new OGRLineString;
    5018                 : 
    5019               0 :     if (m_dEndAngle < m_dStartAngle)
    5020               0 :         numPts = (int) ABS( ((m_dEndAngle+360.0)-m_dStartAngle)/2.0 ) + 1;
    5021                 :     else
    5022               0 :         numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2.0 ) + 1;
    5023               0 :     numPts = MAX(2, numPts);
    5024                 : 
    5025                 :     TABGenerateArc(poLine, numPts,
    5026                 :                    m_dCenterX, m_dCenterY,
    5027                 :                    m_dXRadius, m_dYRadius,
    5028               0 :                    m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
    5029                 : 
    5030               0 :     SetGeometryDirectly(poLine);
    5031                 : 
    5032               0 :     return 0;
    5033                 : }
    5034                 : 
    5035                 : /**********************************************************************
    5036                 :  *                   TABArc::WriteGeometryToMAPFile()
    5037                 :  *
    5038                 :  * Write the geometry and representation (color, etc...) part of the
    5039                 :  * feature to the .MAP object pointed to by poMAPFile.
    5040                 :  *
    5041                 :  * It is assumed that poMAPFile currently points to a valid map object.
    5042                 :  *
    5043                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    5044                 :  * been called.
    5045                 :  **********************************************************************/
    5046                 : int TABArc::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    5047                 :                                    TABMAPObjHdr *poObjHdr,
    5048                 :                                    GBool bCoordBlockDataOnly /*=FALSE*/, 
    5049               0 :                                    TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    5050                 : {
    5051                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    5052               0 :     if (bCoordBlockDataOnly)
    5053               0 :         return 0;
    5054                 : 
    5055                 :     /*-----------------------------------------------------------------
    5056                 :      * We assume that ValidateMapInfoType() was called already and that
    5057                 :      * the type in poObjHdr->m_nType is valid.
    5058                 :      *----------------------------------------------------------------*/
    5059               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    5060                 : 
    5061                 :     /*-----------------------------------------------------------------
    5062                 :      * Fetch and validate geometry
    5063                 :      * In the case of ARCs, this is all done inside UpdateMBR()
    5064                 :      *----------------------------------------------------------------*/
    5065               0 :     if (UpdateMBR(poMapFile) != 0)
    5066               0 :         return -1;  /* Error already reported */
    5067                 : 
    5068                 :     /*-----------------------------------------------------------------
    5069                 :      * Copy object information
    5070                 :      *----------------------------------------------------------------*/
    5071               0 :     TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
    5072                 : 
    5073                 :     /*-------------------------------------------------------------
    5074                 :      * Start/End angles
    5075                 :      * Since we ALWAYS produce files in quadrant 1 then we can
    5076                 :      * ignore the special angle conversion required by flipped axis.
    5077                 :      *
    5078                 :      * See the notes about Arc angles in TABArc::ReadGeometryFromMAPFile()
    5079                 :      *------------------------------------------------------------*/
    5080               0 :     CPLAssert(poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant == 1);
    5081                 : 
    5082               0 :     poArcHdr->m_nStartAngle = ROUND_INT(m_dStartAngle*10.0);
    5083               0 :     poArcHdr->m_nEndAngle = ROUND_INT(m_dEndAngle*10.0);
    5084                 :     
    5085                 :     // An arc is defined by its defining ellipse's MBR:
    5086                 :     poMapFile->Coordsys2Int(m_dCenterX-m_dXRadius, m_dCenterY-m_dYRadius,
    5087                 :                             poArcHdr->m_nArcEllipseMinX, 
    5088               0 :                             poArcHdr->m_nArcEllipseMinY);
    5089                 :     poMapFile->Coordsys2Int(m_dCenterX+m_dXRadius, m_dCenterY+m_dYRadius,
    5090                 :                             poArcHdr->m_nArcEllipseMaxX, 
    5091               0 :                             poArcHdr->m_nArcEllipseMaxY);
    5092                 : 
    5093                 :     // Pass the Arc's actual MBR (values were set in UpdateMBR())
    5094               0 :     poArcHdr->m_nMinX = m_nXMin;
    5095               0 :     poArcHdr->m_nMinY = m_nYMin;
    5096               0 :     poArcHdr->m_nMaxX = m_nXMax;
    5097               0 :     poArcHdr->m_nMaxY = m_nYMax;
    5098                 : 
    5099               0 :     m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    5100               0 :     poArcHdr->m_nPenId = m_nPenDefIndex;      // Pen index
    5101                 : 
    5102               0 :     if (CPLGetLastErrorNo() != 0)
    5103               0 :         return -1;
    5104                 : 
    5105               0 :     return 0;
    5106                 : }
    5107                 : 
    5108                 : /**********************************************************************
    5109                 :  *                   TABArc::SetStart/EndAngle()
    5110                 :  *
    5111                 :  * Set the start/end angle values in degrees, making sure the values are
    5112                 :  * always in the range [0..360]
    5113                 :  **********************************************************************/
    5114               0 : void TABArc::SetStartAngle(double dAngle)
    5115                 : {
    5116               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    5117               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    5118                 : 
    5119               0 :     m_dStartAngle = dAngle;
    5120               0 : }
    5121                 : 
    5122               0 : void TABArc::SetEndAngle(double dAngle)
    5123                 : {
    5124               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    5125               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    5126                 : 
    5127               0 :     m_dEndAngle = dAngle;
    5128               0 : }
    5129                 : 
    5130                 : 
    5131                 : /**********************************************************************
    5132                 :  *                   TABArc::GetStyleString()
    5133                 :  *
    5134                 :  * Return style string for this feature.
    5135                 :  *
    5136                 :  * Style String is built only once during the first call to GetStyleString().
    5137                 :  **********************************************************************/
    5138               0 : const char *TABArc::GetStyleString()
    5139                 : {
    5140               0 :     if (m_pszStyleString == NULL)
    5141                 :     {
    5142               0 :         m_pszStyleString = CPLStrdup(GetPenStyleString());
    5143                 :     }
    5144                 : 
    5145               0 :     return m_pszStyleString;
    5146                 : }
    5147                 : 
    5148                 : /**********************************************************************
    5149                 :  *                   TABArc::DumpMIF()
    5150                 :  *
    5151                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    5152                 :  **********************************************************************/
    5153               0 : void TABArc::DumpMIF(FILE *fpOut /*=NULL*/)
    5154                 : {
    5155                 :     OGRGeometry   *poGeom;
    5156               0 :     OGRLineString *poLine = NULL;
    5157                 :     int i, numPoints;
    5158                 : 
    5159               0 :     if (fpOut == NULL)
    5160               0 :         fpOut = stdout;
    5161                 : 
    5162                 :     /*-----------------------------------------------------------------
    5163                 :      * Output ARC parameters
    5164                 :      *----------------------------------------------------------------*/
    5165                 :     fprintf(fpOut, "(ARC %.15g %.15g %.15g %.15g   %d %d)\n",
    5166                 :             m_dCenterX - m_dXRadius, m_dCenterY - m_dYRadius,
    5167                 :             m_dCenterX + m_dXRadius, m_dCenterY + m_dYRadius,
    5168               0 :             (int)m_dStartAngle, (int)m_dEndAngle);
    5169                 : 
    5170                 :     /*-----------------------------------------------------------------
    5171                 :      * Fetch and validate geometry
    5172                 :      *----------------------------------------------------------------*/
    5173               0 :     poGeom = GetGeometryRef();
    5174               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    5175                 :     {
    5176                 :         /*-------------------------------------------------------------
    5177                 :          * Generate arc output as a simple polyline
    5178                 :          * We could also output as an ELLIPSE in a real MIF generator
    5179                 :          *------------------------------------------------------------*/
    5180               0 :         poLine = (OGRLineString*)poGeom;
    5181               0 :         numPoints = poLine->getNumPoints();
    5182               0 :         fprintf(fpOut, "PLINE %d\n", numPoints);
    5183               0 :         for(i=0; i<numPoints; i++)
    5184               0 :             fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
    5185                 :     }
    5186                 :     else
    5187                 :     {
    5188                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5189               0 :                  "TABArc: Missing or Invalid Geometry!");
    5190               0 :         return;
    5191                 :     }
    5192                 : 
    5193                 :     // Finish with PEN/BRUSH/etc. clauses
    5194               0 :     DumpPenDef();
    5195                 : 
    5196               0 :     fflush(fpOut);
    5197                 : }
    5198                 : 
    5199                 : 
    5200                 : 
    5201                 : /*=====================================================================
    5202                 :  *                      class TABText
    5203                 :  *====================================================================*/
    5204                 : 
    5205                 : /**********************************************************************
    5206                 :  *                   TABText::TABText()
    5207                 :  *
    5208                 :  * Constructor.
    5209                 :  **********************************************************************/
    5210               0 : TABText::TABText(OGRFeatureDefn *poDefnIn):
    5211               0 :               TABFeature(poDefnIn)
    5212                 : {
    5213               0 :     m_pszString = NULL;
    5214                 : 
    5215               0 :     m_dAngle = m_dHeight = 0.0;
    5216               0 :     m_dfLineEndX = m_dfLineEndY = 0.0;
    5217               0 :     m_bLineEndSet = FALSE;
    5218                 : 
    5219               0 :     m_rgbForeground = 0x000000;
    5220               0 :     m_rgbBackground = 0xffffff;
    5221               0 :     m_rgbOutline    = 0xffffff;
    5222               0 :     m_rgbShadow     = 0x808080;
    5223                 : 
    5224               0 :     m_nTextAlignment = 0;
    5225               0 :     m_nFontStyle = 0;
    5226               0 :     m_dWidth = 0;
    5227               0 : }
    5228                 : 
    5229                 : /**********************************************************************
    5230                 :  *                   TABText::~TABText()
    5231                 :  *
    5232                 :  * Destructor.
    5233                 :  **********************************************************************/
    5234               0 : TABText::~TABText()
    5235                 : {
    5236               0 :     CPLFree(m_pszString);
    5237               0 : }
    5238                 : 
    5239                 : /**********************************************************************
    5240                 :  *                     TABText::CloneTABFeature()
    5241                 :  *
    5242                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    5243                 :  *
    5244                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    5245                 :  * then copies any members specific to its own type.
    5246                 :  **********************************************************************/
    5247               0 : TABFeature *TABText::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    5248                 : {
    5249                 :     /*-----------------------------------------------------------------
    5250                 :      * Alloc new feature and copy the base stuff
    5251                 :      *----------------------------------------------------------------*/
    5252               0 :     TABText *poNew = new TABText(poNewDefn ? poNewDefn : GetDefnRef());
    5253                 : 
    5254               0 :     CopyTABFeatureBase(poNew);
    5255                 : 
    5256                 :     /*-----------------------------------------------------------------
    5257                 :      * And members specific to this class
    5258                 :      *----------------------------------------------------------------*/
    5259                 :     // ITABFeaturePen
    5260               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    5261                 : 
    5262                 :     // ITABFeatureFont
    5263               0 :     *(poNew->GetFontDefRef()) = *GetFontDefRef();
    5264                 : 
    5265                 : 
    5266               0 :     poNew->SetTextString( GetTextString() );
    5267               0 :     poNew->SetTextAngle( GetTextAngle() );
    5268               0 :     poNew->SetTextBoxHeight( GetTextBoxHeight() );
    5269               0 :     poNew->SetTextBoxWidth( GetTextBoxWidth() );
    5270               0 :     poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
    5271               0 :     poNew->SetFontBGColor( GetFontBGColor() );
    5272               0 :     poNew->SetFontFGColor( GetFontFGColor() );
    5273               0 :     poNew->SetFontOColor( GetFontOColor() );
    5274               0 :     poNew->SetFontSColor( GetFontSColor() );
    5275                 : 
    5276               0 :     poNew->SetTextJustification( GetTextJustification() );
    5277               0 :     poNew->SetTextSpacing( GetTextSpacing() );
    5278                 :     // Note: Text arrow/line coordinates are not transported... but 
    5279                 :     //       we ignore them most of the time anyways.
    5280               0 :     poNew->SetTextLineType( TABTLNoLine );
    5281                 : 
    5282               0 :     return poNew;
    5283                 : }
    5284                 : 
    5285                 : /**********************************************************************
    5286                 :  *                   TABText::ValidateMapInfoType()
    5287                 :  *
    5288                 :  * Check the feature's geometry part and return the corresponding
    5289                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    5290                 :  * be updated for further calls to GetMapInfoType();
    5291                 :  *
    5292                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    5293                 :  * is expected for this object class.
    5294                 :  **********************************************************************/
    5295               0 : int  TABText::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    5296                 : {
    5297                 :     OGRGeometry *poGeom;
    5298                 : 
    5299                 :     /*-----------------------------------------------------------------
    5300                 :      * Fetch and validate geometry
    5301                 :      *----------------------------------------------------------------*/
    5302               0 :     poGeom = GetGeometryRef();
    5303               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    5304                 :     {
    5305               0 :         m_nMapInfoType = TAB_GEOM_TEXT;
    5306                 :     }
    5307                 :     else
    5308                 :     {
    5309                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5310               0 :                  "TABText: Missing or Invalid Geometry!");
    5311               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    5312                 :     }
    5313                 : 
    5314                 :     /*-----------------------------------------------------------------
    5315                 :      * Decide if coordinates should be compressed or not.
    5316                 :      *----------------------------------------------------------------*/
    5317                 :     // __TODO__ For now we always write uncompressed for this class...
    5318                 :     // ValidateCoordType(poMapFile);
    5319               0 :     UpdateMBR(poMapFile);
    5320                 : 
    5321               0 :     return m_nMapInfoType;
    5322                 : }
    5323                 : 
    5324                 : /**********************************************************************
    5325                 :  *                   TABText::ReadGeometryFromMAPFile()
    5326                 :  *
    5327                 :  * Fill the geometry and representation (color, etc...) part of the
    5328                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    5329                 :  *
    5330                 :  * It is assumed that poMAPFile currently points to the beginning of
    5331                 :  * a map object.
    5332                 :  *
    5333                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    5334                 :  * been called.
    5335                 :  **********************************************************************/
    5336                 : int TABText::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    5337                 :                                      TABMAPObjHdr *poObjHdr,
    5338                 :                                      GBool bCoordBlockDataOnly /*=FALSE*/,
    5339               0 :                                      TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    5340                 : {
    5341                 :     double              dXMin, dYMin, dXMax, dYMax;
    5342                 :     OGRGeometry         *poGeometry;
    5343                 : 
    5344                 :     /*-----------------------------------------------------------------
    5345                 :      * Fetch and validate geometry type
    5346                 :      *----------------------------------------------------------------*/
    5347               0 :     m_nMapInfoType = poObjHdr->m_nType;
    5348                 : 
    5349               0 :     if (m_nMapInfoType != TAB_GEOM_TEXT &&
    5350                 :         m_nMapInfoType != TAB_GEOM_TEXT_C )
    5351                 :     {
    5352                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5353                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    5354               0 :                  m_nMapInfoType, m_nMapInfoType);
    5355               0 :         return -1;
    5356                 :     }
    5357                 : 
    5358                 :     /*=============================================================
    5359                 :      * TEXT
    5360                 :      *============================================================*/
    5361                 :     int     nStringLen;
    5362                 :     GInt32  nCoordBlockPtr;
    5363                 :     double  dJunk;
    5364                 : 
    5365                 :     /*-----------------------------------------------------------------
    5366                 :      * Read object information
    5367                 :      *----------------------------------------------------------------*/
    5368               0 :     TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
    5369                 : 
    5370               0 :     nCoordBlockPtr = poTextHdr->m_nCoordBlockPtr;   // String position
    5371               0 :     nStringLen      = poTextHdr->m_nCoordDataSize;   // String length
    5372               0 :     m_nTextAlignment = poTextHdr->m_nTextAlignment; // just./spacing/arrow
    5373                 : 
    5374                 :     /*-------------------------------------------------------------
    5375                 :      * Text Angle, in thenths of degree.
    5376                 :      * Contrary to arc start/end angles, no conversion based on 
    5377                 :      * origin quadrant is required here
    5378                 :      *------------------------------------------------------------*/
    5379               0 :     m_dAngle       = poTextHdr->m_nAngle/10.0;
    5380                 : 
    5381               0 :     m_nFontStyle   = poTextHdr->m_nFontStyle;          // Font style
    5382                 : 
    5383                 :     m_rgbForeground = (poTextHdr->m_nFGColorR*256*256 +
    5384                 :                        poTextHdr->m_nFGColorG*256 +
    5385               0 :                        poTextHdr->m_nFGColorB);
    5386                 :     m_rgbBackground = (poTextHdr->m_nBGColorR*256*256 +
    5387                 :                        poTextHdr->m_nBGColorG*256 +
    5388               0 :                        poTextHdr->m_nBGColorB);
    5389               0 :     m_rgbOutline =  m_rgbBackground;
    5390                 :     // In MapInfo, the shadow color is always gray (128,128,128)
    5391               0 :     m_rgbShadow     = 0x808080;
    5392                 : 
    5393                 :     // arrow endpoint
    5394                 :     poMapFile->Int2Coordsys(poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY, 
    5395               0 :                             m_dfLineEndX, m_dfLineEndY);
    5396               0 :     m_bLineEndSet = TRUE;
    5397                 : 
    5398                 :     // Text Height
    5399               0 :     poMapFile->Int2CoordsysDist(0, poTextHdr->m_nHeight, dJunk, m_dHeight);
    5400                 : 
    5401               0 :     if (!bCoordBlockDataOnly)
    5402                 :     {
    5403               0 :         m_nFontDefIndex = poTextHdr->m_nFontId;      // Font name index
    5404               0 :         poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
    5405                 :     }
    5406                 : 
    5407                 :     // MBR after rotation
    5408                 :     poMapFile->Int2Coordsys(poTextHdr->m_nMinX, poTextHdr->m_nMinY, 
    5409               0 :                             dXMin, dYMin);
    5410                 :     poMapFile->Int2Coordsys(poTextHdr->m_nMaxX, poTextHdr->m_nMaxY, 
    5411               0 :                             dXMax, dYMax);
    5412                 : 
    5413               0 :     if (!bCoordBlockDataOnly)
    5414                 :     {
    5415               0 :         m_nPenDefIndex = poTextHdr->m_nPenId;      // Pen index for line
    5416               0 :         poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    5417                 :     }
    5418                 : 
    5419                 :     /*-------------------------------------------------------------
    5420                 :      * Read text string from the coord. block
    5421                 :      * Note that the string may contain binary '\n' and '\\' chars
    5422                 :      * that we keep to an unescaped form internally. This is to
    5423                 :      * be like OGR drivers. See bug 1107 for details.
    5424                 :      *------------------------------------------------------------*/
    5425               0 :     char *pszTmpString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
    5426                 : 
    5427               0 :     if (nStringLen > 0)
    5428                 :     {
    5429                 :         TABMAPCoordBlock        *poCoordBlock;
    5430               0 :         CPLAssert(nCoordBlockPtr > 0);
    5431               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    5432               0 :             poCoordBlock = *ppoCoordBlock;
    5433                 :         else
    5434               0 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    5435               0 :         if (poCoordBlock == NULL ||
    5436                 :             poCoordBlock->ReadBytes(nStringLen,(GByte*)pszTmpString) != 0)
    5437                 :         {
    5438                 :             CPLError(CE_Failure, CPLE_FileIO,
    5439                 :                      "Failed reading text string at offset %d", 
    5440               0 :                      nCoordBlockPtr);
    5441               0 :             CPLFree(pszTmpString);                
    5442               0 :             return -1;
    5443                 :         }
    5444                 : 
    5445                 :         /* Return a ref to coord block so that caller can continue reading
    5446                 :          * after the end of this object (used by index splitting)
    5447                 :          */
    5448               0 :         if (ppoCoordBlock)
    5449               0 :             *ppoCoordBlock = poCoordBlock;
    5450                 :     }
    5451                 : 
    5452               0 :     pszTmpString[nStringLen] = '\0';
    5453                 : 
    5454               0 :     CPLFree(m_pszString);
    5455               0 :     m_pszString = pszTmpString; // This string was Escaped before 20050714
    5456                 : 
    5457                 : 
    5458                 :     /* Set/retrieve the MBR to make sure Mins are smaller than Maxs
    5459                 :      */
    5460               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    5461               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    5462                 : 
    5463                 :     /* Copy int MBR to feature class members */
    5464                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    5465               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    5466                 : 
    5467                 :     /*-----------------------------------------------------------------
    5468                 :      * Create an OGRPoint Geometry... 
    5469                 :      * The point X,Y values will be the coords of the lower-left corner before
    5470                 :      * rotation is applied.  (Note that the rotation in MapInfo is done around
    5471                 :      * the upper-left corner)
    5472                 :      * We need to calculate the true lower left corner of the text based
    5473                 :      * on the MBR after rotation, the text height and the rotation angle.
    5474                 :      *----------------------------------------------------------------*/
    5475                 :     double dCos, dSin, dX, dY;
    5476               0 :     dSin = sin(m_dAngle*PI/180.0);
    5477               0 :     dCos = cos(m_dAngle*PI/180.0);
    5478               0 :     if (dSin > 0.0  && dCos > 0.0)
    5479                 :     {
    5480               0 :         dX = dXMin + m_dHeight * dSin;
    5481               0 :         dY = dYMin;
    5482                 :     }
    5483               0 :     else if (dSin > 0.0  && dCos < 0.0)
    5484                 :     {
    5485               0 :         dX = dXMax;
    5486               0 :         dY = dYMin - m_dHeight * dCos;
    5487                 :     }
    5488               0 :     else if (dSin < 0.0  && dCos < 0.0)
    5489                 :     {
    5490               0 :         dX = dXMax + m_dHeight * dSin;
    5491               0 :         dY = dYMax;
    5492                 :     }
    5493                 :     else  // dSin < 0 && dCos > 0
    5494                 :     {   
    5495               0 :         dX = dXMin;
    5496               0 :         dY = dYMax - m_dHeight * dCos;
    5497                 :     }
    5498                 : 
    5499               0 :     poGeometry = new OGRPoint(dX, dY);
    5500                 : 
    5501               0 :     SetGeometryDirectly(poGeometry);
    5502                 : 
    5503                 :     /*-----------------------------------------------------------------
    5504                 :      * Compute Text Width: the width of the Text MBR before rotation 
    5505                 :      * in ground units... unfortunately this value is not stored in the
    5506                 :      * file, so we have to compute it with the MBR after rotation and 
    5507                 :      * the height of the MBR before rotation:
    5508                 :      * With  W = Width of MBR before rotation
    5509                 :      *       H = Height of MBR before rotation
    5510                 :      *       dX = Width of MBR after rotation
    5511                 :      *       dY = Height of MBR after rotation
    5512                 :      *       teta = rotation angle
    5513                 :      *
    5514                 :      *  For [-PI/4..teta..+PI/4] or [3*PI/4..teta..5*PI/4], we'll use:
    5515                 :      *   W = H * (dX - H * sin(teta)) / (H * cos(teta))
    5516                 :      *
    5517                 :      * and for other teta values, use:
    5518                 :      *   W = H * (dY - H * cos(teta)) / (H * sin(teta))
    5519                 :      *----------------------------------------------------------------*/
    5520               0 :     dSin = ABS(dSin);
    5521               0 :     dCos = ABS(dCos);
    5522               0 :     if (m_dHeight == 0.0)
    5523               0 :         m_dWidth = 0.0;
    5524               0 :     else if ( dCos > dSin )
    5525                 :         m_dWidth = m_dHeight * ((dXMax-dXMin) - m_dHeight*dSin) / 
    5526               0 :                                                         (m_dHeight*dCos);
    5527                 :     else
    5528                 :         m_dWidth = m_dHeight * ((dYMax-dYMin) - m_dHeight*dCos) /
    5529               0 :                                                         (m_dHeight*dSin);
    5530               0 :     m_dWidth = ABS(m_dWidth);
    5531                 : 
    5532               0 :     return 0;
    5533                 : }
    5534                 : 
    5535                 : /**********************************************************************
    5536                 :  *                   TABText::WriteGeometryToMAPFile()
    5537                 :  *
    5538                 :  * Write the geometry and representation (color, etc...) part of the
    5539                 :  * feature to the .MAP object pointed to by poMAPFile.
    5540                 :  *
    5541                 :  * It is assumed that poMAPFile currently points to a valid map object.
    5542                 :  *
    5543                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    5544                 :  * been called.
    5545                 :  **********************************************************************/
    5546                 : int TABText::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    5547                 :                                     TABMAPObjHdr *poObjHdr,
    5548                 :                                     GBool bCoordBlockDataOnly /*=FALSE*/,
    5549               0 :                                     TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    5550                 : {
    5551                 :     GInt32              nX, nY, nXMin, nYMin, nXMax, nYMax;
    5552                 :     OGRGeometry         *poGeom;
    5553                 :     OGRPoint            *poPoint;
    5554                 :     GInt32              nCoordBlockPtr;
    5555                 :     TABMAPCoordBlock    *poCoordBlock;
    5556                 :     int                 nStringLen;
    5557                 :   
    5558                 :     /*-----------------------------------------------------------------
    5559                 :      * We assume that ValidateMapInfoType() was called already and that
    5560                 :      * the type in poObjHdr->m_nType is valid.
    5561                 :      *----------------------------------------------------------------*/
    5562               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    5563                 : 
    5564                 :     /*-----------------------------------------------------------------
    5565                 :      * Fetch and validate geometry
    5566                 :      *----------------------------------------------------------------*/
    5567               0 :     poGeom = GetGeometryRef();
    5568               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    5569               0 :         poPoint = (OGRPoint*)poGeom;
    5570                 :     else
    5571                 :     {
    5572                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5573               0 :                  "TABText: Missing or Invalid Geometry!");
    5574               0 :         return -1;
    5575                 :     }
    5576                 : 
    5577               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    5578                 : 
    5579                 :     /*-----------------------------------------------------------------
    5580                 :      * Write string to a coord block first...
    5581                 :      * Note that the string may contain unescaped '\n' and '\\'
    5582                 :      * that we have to keep like that for the MAP file.
    5583                 :      * See MapTools bug 1107 for more details. 
    5584                 :      *----------------------------------------------------------------*/
    5585               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    5586               0 :         poCoordBlock = *ppoCoordBlock;
    5587                 :     else
    5588               0 :         poCoordBlock = poMapFile->GetCurCoordBlock();
    5589               0 :     poCoordBlock->StartNewFeature();
    5590               0 :     nCoordBlockPtr = poCoordBlock->GetCurAddress();
    5591                 : 
    5592                 :     // This string was escaped before 20050714
    5593               0 :     char *pszTmpString = m_pszString;
    5594                 : 
    5595               0 :     nStringLen = strlen(pszTmpString);
    5596                 : 
    5597               0 :     if (nStringLen > 0)
    5598                 :     {
    5599               0 :         poCoordBlock->WriteBytes(nStringLen, (GByte *)pszTmpString);
    5600                 :     }
    5601                 :     else
    5602                 :     {
    5603               0 :         nCoordBlockPtr = 0;
    5604                 :     }
    5605                 : 
    5606               0 :     pszTmpString = NULL;
    5607                 : 
    5608                 :     /*-----------------------------------------------------------------
    5609                 :      * Copy object information
    5610                 :      *----------------------------------------------------------------*/
    5611               0 :     TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
    5612                 : 
    5613               0 :     poTextHdr->m_nCoordBlockPtr = nCoordBlockPtr;     // String position
    5614               0 :     poTextHdr->m_nCoordDataSize = nStringLen;         // String length
    5615               0 :     poTextHdr->m_nTextAlignment = m_nTextAlignment;   // just./spacing/arrow
    5616                 : 
    5617                 :     /*-----------------------------------------------------------------
    5618                 :      * Text Angle, (written in thenths of degrees)
    5619                 :      * Contrary to arc start/end angles, no conversion based on 
    5620                 :      * origin quadrant is required here
    5621                 :      *----------------------------------------------------------------*/
    5622               0 :     poTextHdr->m_nAngle = ROUND_INT(m_dAngle*10.0);
    5623                 : 
    5624               0 :     poTextHdr->m_nFontStyle = m_nFontStyle;          // Font style/effect
    5625                 : 
    5626               0 :     poTextHdr->m_nFGColorR = COLOR_R(m_rgbForeground);
    5627               0 :     poTextHdr->m_nFGColorG = COLOR_G(m_rgbForeground);
    5628               0 :     poTextHdr->m_nFGColorB = COLOR_B(m_rgbForeground);
    5629                 : 
    5630               0 :     poTextHdr->m_nBGColorR = COLOR_R(m_rgbBackground);
    5631               0 :     poTextHdr->m_nBGColorG = COLOR_G(m_rgbBackground);
    5632               0 :     poTextHdr->m_nBGColorB = COLOR_B(m_rgbBackground);
    5633                 : 
    5634                 :     /*-----------------------------------------------------------------
    5635                 :      * The OGRPoint's X,Y values were the coords of the lower-left corner
    5636                 :      * before rotation was applied.  (Note that the rotation in MapInfo is
    5637                 :      * done around the upper-left corner)
    5638                 :      * The Feature's MBR is the MBR of the text after rotation... that's
    5639                 :      * what MapInfo uses to define the text location.
    5640                 :      *----------------------------------------------------------------*/
    5641                 :     double dXMin, dYMin, dXMax, dYMax;
    5642                 :     // Make sure Feature MBR is in sync with other params
    5643                 :  
    5644               0 :     UpdateMBR();
    5645               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    5646                 : 
    5647               0 :     poMapFile->Coordsys2Int(dXMin, dYMin, nXMin, nYMin);
    5648               0 :     poMapFile->Coordsys2Int(dXMax, dYMax, nXMax, nYMax);
    5649                 : 
    5650                 :     // Label line end point
    5651                 :     double dX, dY;
    5652               0 :     GetTextLineEndPoint(dX, dY); // Make sure a default line end point is set
    5653                 :     poMapFile->Coordsys2Int(m_dfLineEndX, m_dfLineEndY, 
    5654               0 :                            poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY);
    5655                 : 
    5656                 :     // Text Height
    5657               0 :     poMapFile->Coordsys2IntDist(0.0, m_dHeight, nX, nY);
    5658               0 :     poTextHdr->m_nHeight = nY;
    5659                 : 
    5660               0 :     if (!bCoordBlockDataOnly)
    5661                 :     {
    5662                 :         // Font name
    5663               0 :         m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
    5664               0 :         poTextHdr->m_nFontId = m_nFontDefIndex;      // Font name index
    5665                 :     }
    5666                 : 
    5667                 :     // MBR after rotation
    5668               0 :     poTextHdr->SetMBR(nXMin, nYMin, nXMax, nYMax);
    5669                 : 
    5670               0 :     if (!bCoordBlockDataOnly)
    5671                 :     {
    5672               0 :         m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    5673               0 :         poTextHdr->m_nPenId = m_nPenDefIndex;      // Pen index for line/arrow
    5674                 :     }
    5675                 : 
    5676               0 :     if (CPLGetLastErrorNo() != 0)
    5677               0 :         return -1;
    5678                 : 
    5679                 :     /* Return a ref to coord block so that caller can continue writing
    5680                 :      * after the end of this object (used by index splitting)
    5681                 :      */
    5682               0 :     if (ppoCoordBlock)
    5683               0 :         *ppoCoordBlock = poCoordBlock;
    5684                 : 
    5685               0 :     return 0;
    5686                 : }
    5687                 : 
    5688                 : 
    5689                 : /**********************************************************************
    5690                 :  *                   TABText::GetTextString()
    5691                 :  *
    5692                 :  * Return ref to text string value.
    5693                 :  *
    5694                 :  * Returned string is a reference to the internal string buffer and should
    5695                 :  * not be modified or freed by the caller.
    5696                 :  **********************************************************************/
    5697               0 : const char *TABText::GetTextString()
    5698                 : {
    5699               0 :     if (m_pszString == NULL)
    5700               0 :         return "";
    5701                 : 
    5702               0 :     return m_pszString;
    5703                 : }
    5704                 : 
    5705                 : /**********************************************************************
    5706                 :  *                   TABText::SetTextString()
    5707                 :  *
    5708                 :  * Set new text string value.
    5709                 :  *
    5710                 :  * Note: The text string may contain "\n" chars or "\\" chars
    5711                 :  * and we expect to receive them in a 2 chars escaped form as 
    5712                 :  * described in the MIF format specs.
    5713                 :  **********************************************************************/
    5714               0 : void TABText::SetTextString(const char *pszNewStr)
    5715                 : {
    5716               0 :     CPLFree(m_pszString);
    5717               0 :     m_pszString = CPLStrdup(pszNewStr);
    5718               0 : }
    5719                 : 
    5720                 : /**********************************************************************
    5721                 :  *                   TABText::GetTextAngle()
    5722                 :  *
    5723                 :  * Return text angle in degrees.
    5724                 :  **********************************************************************/
    5725               0 : double TABText::GetTextAngle()
    5726                 : {
    5727               0 :     return m_dAngle;
    5728                 : }
    5729                 : 
    5730               0 : void TABText::SetTextAngle(double dAngle)
    5731                 : {
    5732                 :     // Make sure angle is in the range [0..360]
    5733               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    5734               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    5735               0 :     m_dAngle = dAngle;
    5736               0 :     UpdateMBR();
    5737               0 : }
    5738                 : 
    5739                 : /**********************************************************************
    5740                 :  *                   TABText::GetTextBoxHeight()
    5741                 :  *
    5742                 :  * Return text height in Y axis coord. units of the text box before rotation.
    5743                 :  **********************************************************************/
    5744               0 : double TABText::GetTextBoxHeight()
    5745                 : {
    5746               0 :     return m_dHeight;
    5747                 : }
    5748                 : 
    5749               0 : void TABText::SetTextBoxHeight(double dHeight)
    5750                 : {
    5751               0 :     m_dHeight = dHeight;
    5752               0 :     UpdateMBR();
    5753               0 : }
    5754                 : 
    5755                 : /**********************************************************************
    5756                 :  *                   TABText::GetTextBoxWidth()
    5757                 :  *
    5758                 :  * Return text width in X axis coord. units. of the text box before rotation.
    5759                 :  *
    5760                 :  * If value has not been set, then we force a default value that assumes
    5761                 :  * that one char's box width is 60% of its height... and we ignore
    5762                 :  * the multiline case.  This should not matter when the user PROPERLY sets
    5763                 :  * the value.
    5764                 :  **********************************************************************/
    5765               0 : double TABText::GetTextBoxWidth()
    5766                 : {
    5767               0 :     if (m_dWidth == 0.0 && m_pszString)
    5768                 :     {
    5769               0 :         m_dWidth = 0.6 * m_dHeight * strlen(m_pszString);
    5770                 :     }
    5771               0 :     return m_dWidth;
    5772                 : }
    5773                 : 
    5774               0 : void TABText::SetTextBoxWidth(double dWidth)
    5775                 : {
    5776               0 :     m_dWidth = dWidth;
    5777               0 :     UpdateMBR();
    5778               0 : }
    5779                 : 
    5780                 : /**********************************************************************
    5781                 :  *                   TABText::GetTextLineEndPoint()
    5782                 :  *
    5783                 :  * Return X,Y coordinates of the text label line end point.
    5784                 :  * Default is the center of the text MBR.
    5785                 :  **********************************************************************/
    5786               0 : void TABText::GetTextLineEndPoint(double &dX, double &dY)
    5787                 : {
    5788               0 :     if (!m_bLineEndSet)
    5789                 :     {
    5790                 :         // Set default location at center of text MBR
    5791                 :         double dXMin, dYMin, dXMax, dYMax;
    5792               0 :         UpdateMBR();
    5793               0 :         GetMBR(dXMin, dYMin, dXMax, dYMax);
    5794               0 :         m_dfLineEndX = (dXMin + dXMax) /2.0;
    5795               0 :         m_dfLineEndY = (dYMin + dYMax) /2.0;
    5796               0 :         m_bLineEndSet = TRUE;
    5797                 :     }
    5798                 : 
    5799                 :     // Return values
    5800               0 :     dX = m_dfLineEndX;
    5801               0 :     dY = m_dfLineEndY;
    5802               0 : }
    5803                 : 
    5804               0 : void TABText::SetTextLineEndPoint(double dX, double dY)
    5805                 : {
    5806               0 :     m_dfLineEndX = dX;
    5807               0 :     m_dfLineEndY = dY;
    5808               0 :     m_bLineEndSet = TRUE;
    5809               0 : }
    5810                 : 
    5811                 : /**********************************************************************
    5812                 :  *                   TABText::UpdateMBR()
    5813                 :  *
    5814                 :  * Update the feature MBR using the text origin (OGRPoint geometry), the
    5815                 :  * rotation angle, and the Width/height before rotation.
    5816                 :  *
    5817                 :  * This function cannot perform properly unless all the above have been set.
    5818                 :  *
    5819                 :  * Returns 0 on success, or -1 if there is no geometry in object
    5820                 :  **********************************************************************/
    5821               0 : int TABText::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    5822                 : {
    5823                 :     OGRGeometry *poGeom;
    5824               0 :     OGRPoint *poPoint=NULL;
    5825                 : 
    5826               0 :     poGeom = GetGeometryRef();
    5827               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    5828                 :     {
    5829                 :         double dSin, dCos, dX0, dY0, dX1, dY1;
    5830                 :         double dX[4], dY[4];
    5831               0 :         poPoint = (OGRPoint *)poGeom;
    5832                 : 
    5833               0 :         dX0 = poPoint->getX();
    5834               0 :         dY0 = poPoint->getY();
    5835                 : 
    5836               0 :         dSin = sin(m_dAngle*PI/180.0);
    5837               0 :         dCos = cos(m_dAngle*PI/180.0);
    5838                 : 
    5839               0 :         GetTextBoxWidth();  // Force default width value if necessary.
    5840                 :         
    5841               0 :         dX[0] = dX0;
    5842               0 :         dY[0] = dY0;
    5843               0 :         dX[1] = dX0 + m_dWidth;
    5844               0 :         dY[1] = dY0;
    5845               0 :         dX[2] = dX0 + m_dWidth;
    5846               0 :         dY[2] = dY0 + m_dHeight;
    5847               0 :         dX[3] = dX0;
    5848               0 :         dY[3] = dY0 + m_dHeight;
    5849                 : 
    5850               0 :         SetMBR(dX0, dY0, dX0, dY0);
    5851               0 :         for(int i=0; i<4; i++)
    5852                 :         {
    5853                 :             // Rotate one of the box corners
    5854               0 :             dX1 = dX0 + (dX[i]-dX0)*dCos - (dY[i]-dY0)*dSin;
    5855               0 :             dY1 = dY0 + (dX[i]-dX0)*dSin + (dY[i]-dY0)*dCos;
    5856                 : 
    5857                 :             // And update feature MBR with rotated coordinate
    5858               0 :             if (dX1 < m_dXMin) m_dXMin = dX1;
    5859               0 :             if (dX1 > m_dXMax) m_dXMax = dX1;
    5860               0 :             if (dY1 < m_dYMin) m_dYMin = dY1;
    5861               0 :             if (dY1 > m_dYMax) m_dYMax = dY1;
    5862                 :         }
    5863                 : 
    5864               0 :         if (poMapFile)
    5865                 :         {
    5866               0 :             poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    5867               0 :             poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    5868                 :         }
    5869                 : 
    5870               0 :         return 0;
    5871                 :     }
    5872                 : 
    5873               0 :     return -1;
    5874                 : }
    5875                 : 
    5876                 : /**********************************************************************
    5877                 :  *                   TABText::GetFontBGColor()
    5878                 :  *
    5879                 :  * Return background color.
    5880                 :  **********************************************************************/
    5881               0 : GInt32 TABText::GetFontBGColor()
    5882                 : {
    5883               0 :     return m_rgbBackground;
    5884                 : }
    5885                 : 
    5886               0 : void TABText::SetFontBGColor(GInt32 rgbColor)
    5887                 : {
    5888               0 :     m_rgbBackground = rgbColor;
    5889               0 : }
    5890                 : 
    5891                 : /**********************************************************************
    5892                 :  *                   TABText::GetFontOColor()
    5893                 :  *
    5894                 :  * Return outline color.
    5895                 :  **********************************************************************/
    5896               0 : GInt32 TABText::GetFontOColor()
    5897                 : {
    5898               0 :     return m_rgbOutline;
    5899                 : }
    5900                 : 
    5901               0 : void TABText::SetFontOColor(GInt32 rgbColor)
    5902                 : {
    5903               0 :     m_rgbOutline = rgbColor;
    5904               0 : }
    5905                 : 
    5906                 : /**********************************************************************
    5907                 :  *                   TABText::GetFontSColor()
    5908                 :  *
    5909                 :  * Return shadow color.
    5910                 :  **********************************************************************/
    5911               0 : GInt32 TABText::GetFontSColor()
    5912                 : {
    5913               0 :     return m_rgbShadow;
    5914                 : }
    5915                 : 
    5916               0 : void TABText::SetFontSColor(GInt32 rgbColor)
    5917                 : {
    5918               0 :     m_rgbShadow = rgbColor;
    5919               0 : }
    5920                 : 
    5921                 : /**********************************************************************
    5922                 :  *                   TABText::GetFontFGColor()
    5923                 :  *
    5924                 :  * Return foreground color.
    5925                 :  **********************************************************************/
    5926               0 : GInt32 TABText::GetFontFGColor()
    5927                 : {
    5928               0 :     return m_rgbForeground;
    5929                 : }
    5930                 : 
    5931               0 : void TABText::SetFontFGColor(GInt32 rgbColor)
    5932                 : {
    5933               0 :     m_rgbForeground = rgbColor;
    5934               0 : }
    5935                 : 
    5936                 : /**********************************************************************
    5937                 :  *                   TABText::GetTextJustification()
    5938                 :  *
    5939                 :  * Return text justification.  Default is TABTJLeft
    5940                 :  **********************************************************************/
    5941               0 : TABTextJust TABText::GetTextJustification()
    5942                 : {
    5943               0 :     TABTextJust eJust = TABTJLeft;
    5944                 : 
    5945               0 :     if (m_nTextAlignment & 0x0200)
    5946               0 :         eJust = TABTJCenter;
    5947               0 :     else if (m_nTextAlignment & 0x0400)
    5948               0 :         eJust = TABTJRight;
    5949                 : 
    5950               0 :     return eJust;
    5951                 : }
    5952                 : 
    5953               0 : void TABText::SetTextJustification(TABTextJust eJustification)
    5954                 : {
    5955                 :     // Flush current value... default is TABTJLeft
    5956               0 :     m_nTextAlignment &= ~ 0x0600;
    5957                 :     // ... and set new one.
    5958               0 :     if (eJustification == TABTJCenter)
    5959               0 :         m_nTextAlignment |= 0x0200;
    5960               0 :     else if (eJustification == TABTJRight)
    5961               0 :         m_nTextAlignment |= 0x0400;
    5962               0 : }
    5963                 : 
    5964                 : /**********************************************************************
    5965                 :  *                   TABText::GetTextSpacing()
    5966                 :  *
    5967                 :  * Return text vertical spacing factor.  Default is TABTSSingle
    5968                 :  **********************************************************************/
    5969               0 : TABTextSpacing TABText::GetTextSpacing()
    5970                 : {
    5971               0 :     TABTextSpacing eSpacing = TABTSSingle;
    5972                 : 
    5973               0 :     if (m_nTextAlignment & 0x0800)
    5974               0 :         eSpacing = TABTS1_5;
    5975               0 :     else if (m_nTextAlignment & 0x1000)
    5976               0 :         eSpacing = TABTSDouble;
    5977                 : 
    5978               0 :     return eSpacing;
    5979                 : }
    5980                 : 
    5981               0 : void TABText::SetTextSpacing(TABTextSpacing eSpacing)
    5982                 : {
    5983                 :     // Flush current value... default is TABTSSingle
    5984               0 :     m_nTextAlignment &= ~ 0x1800;
    5985                 :     // ... and set new one.
    5986               0 :     if (eSpacing == TABTS1_5)
    5987               0 :         m_nTextAlignment |= 0x0800;
    5988               0 :     else if (eSpacing == TABTSDouble)
    5989               0 :         m_nTextAlignment |= 0x1000;
    5990               0 : }
    5991                 : 
    5992                 : /**********************************************************************
    5993                 :  *                   TABText::GetTextLineType()
    5994                 :  *
    5995                 :  * Return text line (arrow) type.  Default is TABTLNoLine
    5996                 :  **********************************************************************/
    5997               0 : TABTextLineType TABText::GetTextLineType()
    5998                 : {
    5999               0 :     TABTextLineType eLine = TABTLNoLine;
    6000                 : 
    6001               0 :     if (m_nTextAlignment & 0x2000)
    6002               0 :         eLine = TABTLSimple;
    6003               0 :     else if (m_nTextAlignment & 0x4000)
    6004               0 :         eLine = TABTLArrow;
    6005                 : 
    6006               0 :     return eLine;
    6007                 : }
    6008                 : 
    6009               0 : void TABText::SetTextLineType(TABTextLineType eLineType)
    6010                 : {
    6011                 :     // Flush current value... default is TABTLNoLine
    6012               0 :     m_nTextAlignment &= ~ 0x6000;
    6013                 :     // ... and set new one.
    6014               0 :     if (eLineType == TABTLSimple)
    6015               0 :         m_nTextAlignment |= 0x2000;
    6016               0 :     else if (eLineType == TABTLArrow)
    6017               0 :         m_nTextAlignment |= 0x4000;
    6018               0 : }
    6019                 : 
    6020                 : /**********************************************************************
    6021                 :  *                   TABText::QueryFontStyle()
    6022                 :  *
    6023                 :  * Return TRUE if the specified font style attribute is turned ON,
    6024                 :  * or FALSE otherwise.  See enum TABFontStyle for the list of styles
    6025                 :  * that can be queried on.
    6026                 :  **********************************************************************/
    6027               0 : GBool TABText::QueryFontStyle(TABFontStyle eStyleToQuery)
    6028                 : {
    6029               0 :     return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
    6030                 : }
    6031                 : 
    6032               0 : void TABText::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
    6033                 : {
    6034               0 :     if (bStyleOn)
    6035               0 :         m_nFontStyle |=  (int)eStyleToToggle;
    6036                 :     else
    6037               0 :         m_nFontStyle &=  ~ (int)eStyleToToggle;
    6038               0 : }
    6039                 : 
    6040                 : 
    6041                 : /**********************************************************************
    6042                 :  *                   TABText::GetFontStyleMIFValue()
    6043                 :  *
    6044                 :  * Return the Font Style value for this object using the style values
    6045                 :  * that are used in a MIF FONT() clause.  See MIF specs (appendix A).
    6046                 :  *
    6047                 :  * The reason why we have to differentiate between the TAB and the MIF font
    6048                 :  * style values is that in TAB, TABFSBox is included in the style value
    6049                 :  * as code 0x100, but in MIF it is not included, instead it is implied by
    6050                 :  * the presence of the BG color in the FONT() clause (the BG color is 
    6051                 :  * present only when TABFSBox or TABFSHalo is set).
    6052                 :  * This also has the effect of shifting all the other style values > 0x100
    6053                 :  * by 1 byte.
    6054                 :  **********************************************************************/
    6055               0 : int TABText::GetFontStyleMIFValue()
    6056                 : {
    6057                 :     // The conversion is simply to remove bit 0x100 from the value and shift
    6058                 :     // down all values past this bit.
    6059               0 :     return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
    6060                 : }
    6061                 : 
    6062               0 : void TABText:: SetFontStyleMIFValue(int nStyle, GBool bBGColorSet)
    6063                 : {
    6064               0 :     m_nFontStyle = (nStyle & 0xff) + (nStyle & 0x7f00)*2;
    6065                 :     // When BG color is set, then either BOX or HALO should be set.
    6066               0 :     if (bBGColorSet && !QueryFontStyle(TABFSHalo))
    6067               0 :         ToggleFontStyle(TABFSBox, TRUE);
    6068               0 : }
    6069                 : 
    6070               0 : int TABText::IsFontBGColorUsed()
    6071                 : {
    6072                 :     // Font BG color is used only when BOX is set.
    6073               0 :     return (QueryFontStyle(TABFSBox));
    6074                 : }
    6075                 : 
    6076               0 : int TABText::IsFontOColorUsed()
    6077                 : {
    6078                 :     // Font outline color is used only when HALO is set.
    6079               0 :     return (QueryFontStyle(TABFSHalo));
    6080                 : }
    6081                 : 
    6082               0 : int TABText::IsFontSColorUsed()
    6083                 : {
    6084                 :     // Font shadow color is used only when Shadow is set.
    6085               0 :     return (QueryFontStyle(TABFSShadow));
    6086                 : }
    6087                 : 
    6088               0 : int TABText::IsFontBold()
    6089                 : {
    6090                 :     // Font bold is used only when Bold is set.
    6091               0 :     return (QueryFontStyle(TABFSBold));
    6092                 : }
    6093                 : 
    6094               0 : int TABText::IsFontItalic()
    6095                 : {
    6096                 :     // Font italic is used only when Italic is set.
    6097               0 :     return (QueryFontStyle(TABFSItalic));
    6098                 : }
    6099                 : 
    6100               0 : int TABText::IsFontUnderline()
    6101                 : {
    6102                 :     // Font underline is used only when Underline is set.
    6103               0 :     return (QueryFontStyle(TABFSUnderline));
    6104                 : }
    6105                 : 
    6106                 : /**********************************************************************
    6107                 :  *                   TABText::GetLabelStyleString()
    6108                 :  *
    6109                 :  * This is not the correct location, it should be in ITABFeatureFont,
    6110                 :  * but it's really more easy to put it here.  This fct return a complete
    6111                 :  * string for the representation with the string to display
    6112                 :  **********************************************************************/
    6113               0 : const char *TABText::GetLabelStyleString()
    6114                 : {
    6115               0 :     const char *pszStyle = NULL;
    6116               0 :     int nStringLen = strlen(GetTextString());
    6117                 :     // ALL Caps, Extpanded need to modify the string value
    6118               0 :     char *pszTextString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
    6119                 :     char szPattern[20];
    6120               0 :     int nJustification = 1;
    6121                 :     
    6122               0 :     strcpy(pszTextString, GetTextString());
    6123               0 :     szPattern[0] = '\0';
    6124                 :     
    6125                 : 
    6126               0 :     switch(GetTextJustification())
    6127                 :     {
    6128                 :       case TABTJCenter:
    6129               0 :         nJustification = 2;
    6130               0 :         break;
    6131                 :       case TABTJRight:
    6132               0 :         nJustification = 1;
    6133               0 :         break;
    6134                 :       case TABTJLeft:
    6135                 :       default:
    6136               0 :         nJustification =1;
    6137                 :         break;
    6138                 :     }
    6139                 :     
    6140                 :     // Compute real font size, taking number of lines ("\\n", "\n") and line
    6141                 :     // spacing into account.
    6142               0 :     int numLines = 1;
    6143               0 :     for (int i=0; pszTextString[i];
    6144                 :          numLines += ((pszTextString[i]=='\n' ||
    6145                 :                        (pszTextString[i]=='\\' && pszTextString[i+1]=='n')) &&
    6146                 :                       pszTextString[i+1] != '\0' ),++i);
    6147                 :     
    6148               0 :     double dHeight = GetTextBoxHeight()/numLines;
    6149                 : 
    6150                 :     // In all cases, take out 20% of font height to account for line spacing
    6151               0 :     if (numLines > 1)
    6152                 :     {
    6153               0 :         switch(GetTextSpacing())
    6154                 :         {
    6155                 :           case TABTS1_5:
    6156               0 :             dHeight *= (0.80 * 0.69);
    6157               0 :             break;
    6158                 :           case TABTSDouble:
    6159               0 :             dHeight *= (0.66 * 0.69);
    6160               0 :             break;
    6161                 :           default:
    6162               0 :             dHeight *= 0.69;
    6163                 :         }
    6164                 :     }
    6165                 :     else
    6166                 :     {
    6167               0 :         dHeight *= 0.69;
    6168                 :     }
    6169                 : 
    6170               0 :     if (QueryFontStyle(TABFSAllCaps))
    6171               0 :         for (int i=0; pszTextString[i];++i)
    6172               0 :             if (isalpha(pszTextString[i])) 
    6173               0 :                 pszTextString[i] = (char)toupper(pszTextString[i]);
    6174                 :     
    6175               0 :     if  (QueryFontStyle(TABFSExpanded))
    6176                 :     {
    6177               0 :         char *pszTmpTextString = (char*)CPLMalloc(((nStringLen*2)+1)*sizeof(char));
    6178               0 :         int j = 0;
    6179                 : 
    6180               0 :         for (int i =0; i < nStringLen; ++i)
    6181                 :         { 
    6182               0 :             pszTmpTextString[j] = pszTextString[i];
    6183               0 :             pszTmpTextString[j+1] = ' ';
    6184               0 :             j += 2;
    6185                 :         }
    6186                 : 
    6187               0 :         pszTmpTextString[j-1] = '\0';
    6188               0 :         CPLFree(pszTextString);
    6189               0 :         pszTextString = (char*)CPLMalloc((strlen(pszTmpTextString)+1)*sizeof(char));
    6190               0 :         strcpy(pszTextString, pszTmpTextString);
    6191               0 :         CPLFree(pszTmpTextString);
    6192                 :     }
    6193                 :     
    6194                 :     const char *pszBGColor = IsFontBGColorUsed() ? CPLSPrintf(",b:#%6.6x",
    6195               0 :                                                               GetFontBGColor()) :"";
    6196                 :     const char *pszOColor =  IsFontOColorUsed() ? CPLSPrintf(",o:#%6.6x",
    6197               0 :                                                              GetFontOColor()) :"";
    6198                 :     const char *pszSColor = IsFontSColorUsed() ? CPLSPrintf(",h:#%6.6x",
    6199               0 :                                                               GetFontSColor()) :"";
    6200               0 :     const char *pszBold = IsFontBold() ? ",bo:1" :"";
    6201               0 :     const char *pszItalic = IsFontItalic() ? ",it:1" :"";
    6202               0 :     const char *pszUnderline = IsFontUnderline() ? ",un:1" : "";
    6203                 :     
    6204                 :     pszStyle=CPLSPrintf("LABEL(t:\"%s\",a:%f,s:%fg,c:#%6.6x%s%s%s%s%s%s,p:%d,f:\"%s\")",
    6205                 :                         pszTextString,GetTextAngle(), dHeight,
    6206                 :                         GetFontFGColor(),pszBGColor,pszOColor,pszSColor,
    6207               0 :                         pszBold,pszItalic,pszUnderline,nJustification,GetFontNameRef());
    6208                 :      
    6209               0 :     CPLFree(pszTextString);
    6210               0 :     return pszStyle;
    6211                 :     
    6212                 : }  
    6213                 : 
    6214                 : /**********************************************************************
    6215                 :  *                   TABText::GetStyleString()
    6216                 :  *
    6217                 :  * Return style string for this feature.
    6218                 :  *
    6219                 :  * Style String is built only once during the first call to GetStyleString().
    6220                 :  **********************************************************************/
    6221               0 : const char *TABText::GetStyleString()
    6222                 : {
    6223               0 :     if (m_pszStyleString == NULL)
    6224                 :     {
    6225               0 :         m_pszStyleString = CPLStrdup(GetLabelStyleString());
    6226                 :     }
    6227                 : 
    6228               0 :     return m_pszStyleString;
    6229                 : }
    6230                 : 
    6231                 : 
    6232                 : 
    6233                 : /**********************************************************************
    6234                 :  *                   TABText::DumpMIF()
    6235                 :  *
    6236                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    6237                 :  **********************************************************************/
    6238               0 : void TABText::DumpMIF(FILE *fpOut /*=NULL*/)
    6239                 : {
    6240                 :     OGRGeometry   *poGeom;
    6241               0 :     OGRPoint      *poPoint = NULL;
    6242                 : 
    6243               0 :     if (fpOut == NULL)
    6244               0 :         fpOut = stdout;
    6245                 : 
    6246                 :     /*-----------------------------------------------------------------
    6247                 :      * Fetch and validate geometry
    6248                 :      *----------------------------------------------------------------*/
    6249               0 :     poGeom = GetGeometryRef();
    6250               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    6251                 :     {
    6252                 :         /*-------------------------------------------------------------
    6253                 :          * Generate output for text object
    6254                 :          *------------------------------------------------------------*/
    6255               0 :         poPoint = (OGRPoint*)poGeom;
    6256                 : 
    6257                 :         fprintf(fpOut, "TEXT \"%s\" %.15g %.15g\n", m_pszString?m_pszString:"",
    6258               0 :                 poPoint->getX(), poPoint->getY());
    6259                 : 
    6260               0 :         fprintf(fpOut, "  m_pszString = '%s'\n", m_pszString);
    6261               0 :         fprintf(fpOut, "  m_dAngle    = %.15g\n",   m_dAngle);
    6262               0 :         fprintf(fpOut, "  m_dHeight   = %.15g\n",   m_dHeight);
    6263                 :         fprintf(fpOut, "  m_rgbForeground  = 0x%6.6x (%d)\n", 
    6264               0 :                                              m_rgbForeground, m_rgbForeground);
    6265                 :         fprintf(fpOut, "  m_rgbBackground  = 0x%6.6x (%d)\n", 
    6266               0 :                                              m_rgbBackground, m_rgbBackground);
    6267               0 :         fprintf(fpOut, "  m_nTextAlignment = 0x%4.4x\n",  m_nTextAlignment);
    6268               0 :         fprintf(fpOut, "  m_nFontStyle     = 0x%4.4x\n",  m_nFontStyle);
    6269                 :     }
    6270                 :     else
    6271                 :     {
    6272                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6273               0 :                  "TABText: Missing or Invalid Geometry!");
    6274               0 :         return;
    6275                 :     }
    6276                 : 
    6277                 :     // Finish with PEN/BRUSH/etc. clauses
    6278               0 :     DumpPenDef();
    6279               0 :     DumpFontDef();
    6280                 : 
    6281               0 :     fflush(fpOut);
    6282                 : }
    6283                 : 
    6284                 : /*=====================================================================
    6285                 :  *                      class TABMultiPoint
    6286                 :  *====================================================================*/
    6287                 : 
    6288                 : /**********************************************************************
    6289                 :  *                   TABMultiPoint::TABMultiPoint()
    6290                 :  *
    6291                 :  * Constructor.
    6292                 :  **********************************************************************/
    6293               0 : TABMultiPoint::TABMultiPoint(OGRFeatureDefn *poDefnIn):
    6294               0 :               TABFeature(poDefnIn)
    6295                 : {
    6296               0 :     m_bCenterIsSet = FALSE;
    6297               0 : }
    6298                 : 
    6299                 : /**********************************************************************
    6300                 :  *                   TABMultiPoint::~TABMultiPoint()
    6301                 :  *
    6302                 :  * Destructor.
    6303                 :  **********************************************************************/
    6304               0 : TABMultiPoint::~TABMultiPoint()
    6305                 : {
    6306               0 : }
    6307                 : 
    6308                 : /**********************************************************************
    6309                 :  *                     TABMultiPoint::CloneTABFeature()
    6310                 :  *
    6311                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    6312                 :  *
    6313                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    6314                 :  * then copies any members specific to its own type.
    6315                 :  **********************************************************************/
    6316               0 : TABFeature *TABMultiPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
    6317                 : {
    6318                 :     /*-----------------------------------------------------------------
    6319                 :      * Alloc new feature and copy the base stuff
    6320                 :      *----------------------------------------------------------------*/
    6321               0 :     TABMultiPoint *poNew = new TABMultiPoint(poNewDefn?poNewDefn:GetDefnRef());
    6322                 : 
    6323               0 :     CopyTABFeatureBase(poNew);
    6324                 : 
    6325                 :     /*-----------------------------------------------------------------
    6326                 :      * And members specific to this class
    6327                 :      *----------------------------------------------------------------*/
    6328                 :     // ITABFeatureSymbol
    6329               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
    6330                 : 
    6331               0 :     poNew->m_bCenterIsSet = m_bCenterIsSet;
    6332               0 :     poNew->m_dCenterX = m_dCenterX;
    6333               0 :     poNew->m_dCenterY = m_dCenterY;
    6334                 : 
    6335               0 :     return poNew;
    6336                 : }
    6337                 : 
    6338                 : 
    6339                 : /**********************************************************************
    6340                 :  *                   TABMultiPoint::ValidateMapInfoType()
    6341                 :  *
    6342                 :  * Check the feature's geometry part and return the corresponding
    6343                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    6344                 :  * be updated for further calls to GetMapInfoType();
    6345                 :  *
    6346                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    6347                 :  * is expected for this object class.
    6348                 :  **********************************************************************/
    6349               0 : int  TABMultiPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    6350                 : {
    6351                 :     OGRGeometry *poGeom;
    6352                 : 
    6353                 :     /*-----------------------------------------------------------------
    6354                 :      * Fetch and validate geometry 
    6355                 :      *----------------------------------------------------------------*/
    6356               0 :     poGeom = GetGeometryRef();
    6357               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6358                 :     {
    6359               0 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
    6360                 : 
    6361               0 :         if (poMPoint->getNumGeometries() > TAB_MULTIPOINT_650_MAX_VERTICES)
    6362               0 :             m_nMapInfoType = TAB_GEOM_V800_MULTIPOINT;
    6363                 :         else
    6364               0 :             m_nMapInfoType = TAB_GEOM_MULTIPOINT;
    6365                 :     }
    6366                 :     else
    6367                 :     {
    6368                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6369               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6370               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    6371                 :     }
    6372                 : 
    6373                 :     /*-----------------------------------------------------------------
    6374                 :      * Decide if coordinates should be compressed or not.
    6375                 :      *----------------------------------------------------------------*/
    6376               0 :     ValidateCoordType(poMapFile);
    6377                 : 
    6378               0 :     return m_nMapInfoType;
    6379                 : }
    6380                 : 
    6381                 : 
    6382                 : 
    6383                 : /**********************************************************************
    6384                 :  *                   TABMultiPoint::ReadGeometryFromMAPFile()
    6385                 :  *
    6386                 :  * Fill the geometry and representation (color, etc...) part of the
    6387                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    6388                 :  *
    6389                 :  * It is assumed that poMAPFile currently points to the beginning of
    6390                 :  * a map object.
    6391                 :  *
    6392                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    6393                 :  * been called.
    6394                 :  **********************************************************************/
    6395                 : int TABMultiPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    6396                 :                                            TABMAPObjHdr *poObjHdr,
    6397                 :                                            GBool bCoordBlockDataOnly /*=FALSE*/,
    6398               0 :                                            TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    6399                 : {
    6400                 :     GInt32              nX, nY;
    6401                 :     double              dX, dY, dXMin, dYMin, dXMax, dYMax;
    6402               0 :     OGRGeometry         *poGeometry=NULL;
    6403               0 :     GBool               bComprCoord = poObjHdr->IsCompressedType();
    6404               0 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    6405                 : 
    6406                 :     /*-----------------------------------------------------------------
    6407                 :      * Fetch and validate geometry type
    6408                 :      *----------------------------------------------------------------*/
    6409               0 :     m_nMapInfoType = poObjHdr->m_nType;
    6410                 : 
    6411                 :     /*-----------------------------------------------------------------
    6412                 :      * Read object information
    6413                 :      *----------------------------------------------------------------*/
    6414               0 :     if (m_nMapInfoType == TAB_GEOM_MULTIPOINT ||
    6415                 :         m_nMapInfoType == TAB_GEOM_MULTIPOINT_C ||
    6416                 :         m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT ||
    6417                 :         m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT_C )
    6418                 :     {
    6419                 :         /*-------------------------------------------------------------
    6420                 :          * Copy data from poObjHdr
    6421                 :          *------------------------------------------------------------*/
    6422               0 :         TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
    6423                 : 
    6424                 :         // MBR
    6425                 :         poMapFile->Int2Coordsys(poMPointHdr->m_nMinX, poMPointHdr->m_nMinY, 
    6426               0 :                                 dXMin, dYMin);
    6427                 :         poMapFile->Int2Coordsys(poMPointHdr->m_nMaxX, poMPointHdr->m_nMaxY, 
    6428               0 :                                 dXMax, dYMax);
    6429                 : 
    6430               0 :         if (!bCoordBlockDataOnly)
    6431                 :         {
    6432               0 :             m_nSymbolDefIndex = poMPointHdr->m_nSymbolId;   // Symbol index
    6433               0 :             poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
    6434                 :         }
    6435                 : 
    6436                 :         // Centroid/label point
    6437                 :         poMapFile->Int2Coordsys(poMPointHdr->m_nLabelX, poMPointHdr->m_nLabelY,
    6438               0 :                                 dX, dY);
    6439               0 :         SetCenter(dX, dY);
    6440                 : 
    6441                 :         // Compressed coordinate origin (useful only in compressed case!)
    6442               0 :         m_nComprOrgX = poMPointHdr->m_nComprOrgX;
    6443               0 :         m_nComprOrgY = poMPointHdr->m_nComprOrgY;
    6444                 : 
    6445                 :         /*-------------------------------------------------------------
    6446                 :          * Read Point Coordinates
    6447                 :          *------------------------------------------------------------*/
    6448                 :         OGRMultiPoint   *poMultiPoint;
    6449               0 :         poGeometry = poMultiPoint = new OGRMultiPoint();
    6450                 : 
    6451               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    6452               0 :             poCoordBlock = *ppoCoordBlock;
    6453                 :         else
    6454               0 :             poCoordBlock = poMapFile->GetCoordBlock(poMPointHdr->m_nCoordBlockPtr);
    6455                 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, 
    6456               0 :                                           m_nComprOrgY);
    6457                 : 
    6458               0 :         for(int iPoint=0; iPoint<poMPointHdr->m_nNumPoints; iPoint++)
    6459                 :         {
    6460               0 :             if (poCoordBlock->ReadIntCoord(bComprCoord, nX, nY) != 0)
    6461                 :             {
    6462                 :                 CPLError(CE_Failure, CPLE_FileIO,
    6463                 :                          "Failed reading coordinate data at offset %d", 
    6464               0 :                          poMPointHdr->m_nCoordBlockPtr);
    6465               0 :                 return -1;
    6466                 :             }
    6467                 : 
    6468               0 :             poMapFile->Int2Coordsys(nX, nY, dX, dY);
    6469               0 :             OGRPoint *poPoint = new OGRPoint(dX, dY);
    6470                 :     
    6471               0 :             if (poMultiPoint->addGeometryDirectly(poPoint) != OGRERR_NONE)
    6472                 :             {
    6473               0 :                 CPLAssert(FALSE); // Just in case lower-level lib is modified
    6474                 :             }
    6475                 :         }
    6476                 : 
    6477                 :     }
    6478                 :     else
    6479                 :     {
    6480                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6481                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    6482               0 :                  m_nMapInfoType, m_nMapInfoType);
    6483               0 :         return -1;
    6484                 :     }
    6485                 : 
    6486               0 :     SetGeometryDirectly(poGeometry);
    6487                 : 
    6488               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    6489                 : 
    6490                 :     /* Copy int MBR to feature class members */
    6491                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    6492               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    6493                 : 
    6494                 :     /* Return a ref to coord block so that caller can continue reading
    6495                 :      * after the end of this object (used by TABCollection and index splitting)
    6496                 :      */
    6497               0 :     if (ppoCoordBlock)
    6498               0 :         *ppoCoordBlock = poCoordBlock;
    6499                 : 
    6500               0 :     return 0;
    6501                 : }
    6502                 : 
    6503                 : /**********************************************************************
    6504                 :  *                   TABMultiPoint::WriteGeometryToMAPFile()
    6505                 :  *
    6506                 :  * Write the geometry and representation (color, etc...) part of the
    6507                 :  * feature to the .MAP object pointed to by poMAPFile.
    6508                 :  *
    6509                 :  * It is assumed that poMAPFile currently points to a valid map object.
    6510                 :  *
    6511                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    6512                 :  * been called.
    6513                 :  **********************************************************************/
    6514                 : int TABMultiPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    6515                 :                                           TABMAPObjHdr *poObjHdr,
    6516                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    6517               0 :                                           TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    6518                 : {
    6519                 :     GInt32              nX, nY;
    6520                 :     OGRGeometry         *poGeom;
    6521                 :     OGRMultiPoint       *poMPoint;
    6522                 : 
    6523                 :     /*-----------------------------------------------------------------
    6524                 :      * We assume that ValidateMapInfoType() was called already and that
    6525                 :      * the type in poObjHdr->m_nType is valid.
    6526                 :      *----------------------------------------------------------------*/
    6527               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    6528                 : 
    6529               0 :     TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
    6530                 : 
    6531                 :     /*-----------------------------------------------------------------
    6532                 :      * Fetch and validate geometry
    6533                 :      *----------------------------------------------------------------*/
    6534               0 :     poGeom = GetGeometryRef();
    6535               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6536               0 :         poMPoint = (OGRMultiPoint*)poGeom;
    6537                 :     else
    6538                 :     {
    6539                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6540               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6541               0 :         return -1;
    6542                 :     }
    6543                 : 
    6544               0 :     poMPointHdr->m_nNumPoints = poMPoint->getNumGeometries();
    6545                 : 
    6546                 :     /*-----------------------------------------------------------------
    6547                 :      * Write data to coordinate block
    6548                 :      *----------------------------------------------------------------*/
    6549                 :     int iPoint, nStatus;
    6550                 :     TABMAPCoordBlock *poCoordBlock;
    6551               0 :     GBool   bCompressed = poObjHdr->IsCompressedType();
    6552                 : 
    6553               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    6554               0 :         poCoordBlock = *ppoCoordBlock;
    6555                 :     else
    6556               0 :         poCoordBlock = poMapFile->GetCurCoordBlock();
    6557               0 :     poCoordBlock->StartNewFeature();
    6558               0 :     poMPointHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    6559               0 :     poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    6560                 : 
    6561                 : 
    6562               0 :     for(iPoint=0, nStatus=0; 
    6563                 :         nStatus == 0 && iPoint < poMPointHdr->m_nNumPoints; iPoint++)
    6564                 :     {
    6565               0 :         poGeom = poMPoint->getGeometryRef(iPoint);
    6566                 : 
    6567               0 :         if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    6568                 :         {
    6569               0 :             OGRPoint *poPoint = (OGRPoint*)poGeom;
    6570                 : 
    6571               0 :             poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    6572               0 :             if (iPoint == 0)
    6573                 :             {
    6574                 :                 // Default to the first point, we may use explicit value below
    6575               0 :                 poMPointHdr->m_nLabelX = nX;
    6576               0 :                 poMPointHdr->m_nLabelY = nY;
    6577                 :             }
    6578                 : 
    6579               0 :             if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY, 
    6580                 :                                                        bCompressed)) != 0)
    6581                 :             {
    6582                 :                 // Failed ... error message has already been produced
    6583               0 :                 return nStatus;
    6584                 :             }   
    6585                 : 
    6586                 :         }
    6587                 :         else
    6588                 :         {
    6589                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    6590               0 :                      "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
    6591               0 :             return -1;
    6592                 :         }
    6593                 :     }
    6594                 : 
    6595                 :     /*-----------------------------------------------------------------
    6596                 :      * Copy object information
    6597                 :      *----------------------------------------------------------------*/
    6598                 : 
    6599                 :     // Compressed coordinate origin (useful only in compressed case!)
    6600               0 :     poMPointHdr->m_nComprOrgX = m_nComprOrgX;
    6601               0 :     poMPointHdr->m_nComprOrgY = m_nComprOrgY;
    6602                 : 
    6603               0 :     poMPointHdr->m_nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    6604               0 :     poMPointHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    6605                 : 
    6606                 :     // Center/label point (default value already set above)
    6607                 :     double dX, dY;
    6608               0 :     if (GetCenter(dX, dY) != -1)
    6609                 :     {
    6610                 :         poMapFile->Coordsys2Int(dX, dY, poMPointHdr->m_nLabelX, 
    6611               0 :                                 poMPointHdr->m_nLabelY);
    6612                 :     }
    6613                 : 
    6614               0 :     if (!bCoordBlockDataOnly)
    6615                 :     {
    6616               0 :         m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
    6617               0 :         poMPointHdr->m_nSymbolId = m_nSymbolDefIndex;      // Symbol index
    6618                 :     }
    6619                 : 
    6620               0 :     if (CPLGetLastErrorNo() != 0)
    6621               0 :         return -1;
    6622                 : 
    6623                 :     /* Return a ref to coord block so that caller can continue writing
    6624                 :      * after the end of this object (used by index splitting)
    6625                 :      */
    6626               0 :     if (ppoCoordBlock)
    6627               0 :         *ppoCoordBlock = poCoordBlock;
    6628                 : 
    6629               0 :     return 0;
    6630                 : }
    6631                 : 
    6632                 : 
    6633                 : /**********************************************************************
    6634                 :  *                   TABMultiPoint::GetXY()
    6635                 :  *
    6636                 :  * Return this point's X,Y coordinates.
    6637                 :  **********************************************************************/
    6638               0 : int TABMultiPoint::GetXY(int i, double &dX, double &dY)
    6639                 : {
    6640                 :     OGRGeometry *poGeom;
    6641                 : 
    6642                 :     /*-----------------------------------------------------------------
    6643                 :      * Fetch and validate geometry
    6644                 :      *----------------------------------------------------------------*/
    6645               0 :     poGeom = GetGeometryRef();
    6646               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6647                 :     {
    6648               0 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
    6649                 : 
    6650               0 :         if (i >= 0 && i < poMPoint->getNumGeometries() &&
    6651                 :             (poGeom = poMPoint->getGeometryRef(i)) != NULL &&
    6652                 :             wkbFlatten(poGeom->getGeometryType()) == wkbPoint )
    6653                 :         {
    6654               0 :             OGRPoint *poPoint = (OGRPoint*)poGeom;
    6655                 : 
    6656               0 :             dX = poPoint->getX();
    6657               0 :             dY = poPoint->getY();
    6658                 :         }
    6659                 :     }
    6660                 :     else
    6661                 :     {
    6662                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6663               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6664               0 :         dX = dY = 0.0;
    6665               0 :         return -1;
    6666                 :     }
    6667                 : 
    6668               0 :     return 0;
    6669                 : }
    6670                 : 
    6671                 : /**********************************************************************
    6672                 :  *                   TABMultiPoint::GetNumPoints()
    6673                 :  *
    6674                 :  * Return the number of points in this multipoint object
    6675                 :  **********************************************************************/
    6676               0 : int TABMultiPoint::GetNumPoints()
    6677                 : {
    6678                 :     OGRGeometry *poGeom;
    6679                 : 
    6680                 :     /*-----------------------------------------------------------------
    6681                 :      * Fetch and validate geometry
    6682                 :      *----------------------------------------------------------------*/
    6683               0 :     poGeom = GetGeometryRef();
    6684               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6685                 :     {
    6686               0 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
    6687                 : 
    6688               0 :         return poMPoint->getNumGeometries();
    6689                 :     }
    6690                 :     else
    6691                 :     {
    6692                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6693               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6694               0 :         return 0;
    6695                 :     }
    6696                 : 
    6697                 :     return 0;
    6698                 : }
    6699                 : 
    6700                 : 
    6701                 : /**********************************************************************
    6702                 :  *                   TABMultiPoint::GetStyleString()
    6703                 :  *
    6704                 :  * Return style string for this feature.
    6705                 :  *
    6706                 :  * Style String is built only once during the first call to GetStyleString().
    6707                 :  **********************************************************************/
    6708               0 : const char *TABMultiPoint::GetStyleString()
    6709                 : {
    6710               0 :     if (m_pszStyleString == NULL)
    6711                 :     {
    6712               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    6713                 :     }
    6714                 : 
    6715               0 :     return m_pszStyleString;
    6716                 : }
    6717                 : 
    6718                 : /**********************************************************************
    6719                 :  *                   TABMultiPoint::GetCenter()
    6720                 :  *
    6721                 :  * Returns the center point (or label point?) of the object.  Compute one 
    6722                 :  * if it was not explicitly set:
    6723                 :  *
    6724                 :  * The default seems to be to use the first point in the collection as
    6725                 :  * the center.. so we'll use that.
    6726                 :  *
    6727                 :  * Returns 0 on success, -1 on error.
    6728                 :  **********************************************************************/
    6729               0 : int TABMultiPoint::GetCenter(double &dX, double &dY)
    6730                 : {
    6731               0 :     if (!m_bCenterIsSet && GetNumPoints() > 0)
    6732                 :     {
    6733                 :         // The default seems to be to use the first point in the collection
    6734                 :         // as the center... so we'll use that.
    6735               0 :         if (GetXY(0, m_dCenterX, m_dCenterY) == 0)
    6736               0 :             m_bCenterIsSet = TRUE;
    6737                 :     }
    6738                 : 
    6739               0 :     if (!m_bCenterIsSet)
    6740               0 :         return -1;
    6741                 : 
    6742               0 :     dX = m_dCenterX;
    6743               0 :     dY = m_dCenterY;
    6744               0 :     return 0;
    6745                 : }
    6746                 : 
    6747                 : /**********************************************************************
    6748                 :  *                   TABMultiPoint::SetCenter()
    6749                 :  *
    6750                 :  * Set the X,Y coordinates to use as center point (or label point?)
    6751                 :  **********************************************************************/
    6752               0 : void TABMultiPoint::SetCenter(double dX, double dY)
    6753                 : {
    6754               0 :     m_dCenterX = dX;
    6755               0 :     m_dCenterY = dY;
    6756               0 :     m_bCenterIsSet = TRUE;
    6757               0 : }
    6758                 : 
    6759                 : 
    6760                 : /**********************************************************************
    6761                 :  *                   TABMultiPoint::DumpMIF()
    6762                 :  *
    6763                 :  * Dump feature geometry in a format similar to .MIF POINTs.
    6764                 :  **********************************************************************/
    6765               0 : void TABMultiPoint::DumpMIF(FILE *fpOut /*=NULL*/)
    6766                 : {
    6767                 :     OGRGeometry *poGeom;
    6768                 :     OGRMultiPoint *poMPoint;
    6769                 : 
    6770               0 :     if (fpOut == NULL)
    6771               0 :         fpOut = stdout;
    6772                 : 
    6773                 :     /*-----------------------------------------------------------------
    6774                 :      * Fetch and validate geometry
    6775                 :      *----------------------------------------------------------------*/
    6776               0 :     poGeom = GetGeometryRef();
    6777               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6778               0 :         poMPoint = (OGRMultiPoint*)poGeom;
    6779                 :     else
    6780                 :     {
    6781                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6782               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6783               0 :         return;
    6784                 :     }
    6785                 : 
    6786                 :     /*-----------------------------------------------------------------
    6787                 :      * Generate output
    6788                 :      *----------------------------------------------------------------*/
    6789               0 :     fprintf(fpOut, "MULTIPOINT %d\n", poMPoint->getNumGeometries());
    6790                 : 
    6791               0 :     for (int iPoint=0; iPoint < poMPoint->getNumGeometries(); iPoint++)
    6792                 :     {
    6793               0 :         poGeom = poMPoint->getGeometryRef(iPoint);
    6794                 : 
    6795               0 :         if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    6796                 :         {
    6797               0 :             OGRPoint *poPoint = (OGRPoint*)poGeom;
    6798               0 :             fprintf(fpOut, "  %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
    6799                 :         }
    6800                 :         else
    6801                 :         {
    6802                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    6803               0 :                      "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
    6804               0 :             return;
    6805                 :         }
    6806                 :     }
    6807                 : 
    6808               0 :     DumpSymbolDef(fpOut);
    6809                 : 
    6810               0 :     if (m_bCenterIsSet)
    6811               0 :         fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
    6812                 : 
    6813               0 :     fflush(fpOut);
    6814                 : }
    6815                 : 
    6816                 : /*=====================================================================
    6817                 :  *                      class TABCollection
    6818                 :  *====================================================================*/
    6819                 : 
    6820                 : /**********************************************************************
    6821                 :  *                   TABCollection::TABCollection()
    6822                 :  *
    6823                 :  * Constructor.
    6824                 :  **********************************************************************/
    6825               0 : TABCollection::TABCollection(OGRFeatureDefn *poDefnIn):
    6826               0 :               TABFeature(poDefnIn)
    6827                 : {
    6828               0 :     m_poRegion = NULL;
    6829               0 :     m_poPline = NULL;
    6830               0 :     m_poMpoint = NULL;
    6831               0 : }
    6832                 : 
    6833                 : /**********************************************************************
    6834                 :  *                   TABCollection::~TABCollection()
    6835                 :  *
    6836                 :  * Destructor.
    6837                 :  **********************************************************************/
    6838               0 : TABCollection::~TABCollection()
    6839                 : {
    6840               0 :     EmptyCollection();
    6841               0 : }
    6842                 : 
    6843                 : /**********************************************************************
    6844                 :  *                   TABCollection::EmptyCollection()
    6845                 :  *
    6846                 :  * Delete/free all collection components.
    6847                 :  **********************************************************************/
    6848               0 : void TABCollection::EmptyCollection()
    6849                 : {
    6850                 : 
    6851               0 :     if (m_poRegion)
    6852                 :     {
    6853               0 :         delete m_poRegion;
    6854               0 :         m_poRegion = NULL;
    6855                 :     }
    6856                 : 
    6857               0 :     if (m_poPline)
    6858                 :     {
    6859               0 :         delete m_poPline;
    6860               0 :         m_poPline = NULL;
    6861                 :     }
    6862                 : 
    6863               0 :     if (m_poMpoint)
    6864                 :     {
    6865               0 :         delete m_poMpoint;
    6866               0 :         m_poMpoint = NULL;
    6867                 :     }
    6868                 : 
    6869                 :     // Empty OGR Geometry Collection as well
    6870               0 :     SyncOGRGeometryCollection(TRUE, TRUE, TRUE);
    6871                 : 
    6872               0 : }
    6873                 : 
    6874                 : /**********************************************************************
    6875                 :  *                     TABCollection::CloneTABFeature()
    6876                 :  *
    6877                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    6878                 :  *
    6879                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    6880                 :  * then copies any members specific to its own type.
    6881                 :  **********************************************************************/
    6882               0 : TABFeature *TABCollection::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
    6883                 : {
    6884                 :     /*-----------------------------------------------------------------
    6885                 :      * Alloc new feature and copy the base stuff
    6886                 :      *----------------------------------------------------------------*/
    6887               0 :     TABCollection *poNew = new TABCollection(poNewDefn?poNewDefn:GetDefnRef());
    6888                 : 
    6889               0 :     CopyTABFeatureBase(poNew);
    6890                 : 
    6891                 :     /*-----------------------------------------------------------------
    6892                 :      * And members specific to this class
    6893                 :      *----------------------------------------------------------------*/
    6894                 : 
    6895               0 :     if (m_poRegion)
    6896               0 :         poNew->SetRegionDirectly((TABRegion*)m_poRegion->CloneTABFeature());
    6897                 : 
    6898               0 :     if (m_poPline)
    6899               0 :         poNew->SetPolylineDirectly((TABPolyline*)m_poPline->CloneTABFeature());
    6900                 : 
    6901               0 :     if (m_poMpoint)
    6902               0 :         poNew->SetMultiPointDirectly((TABMultiPoint*)m_poMpoint->CloneTABFeature());
    6903                 : 
    6904               0 :     return poNew;
    6905                 : }
    6906                 : 
    6907                 : 
    6908                 : /**********************************************************************
    6909                 :  *                   TABCollection::ValidateMapInfoType()
    6910                 :  *
    6911                 :  * Check the feature's geometry part and return the corresponding
    6912                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    6913                 :  * be updated for further calls to GetMapInfoType();
    6914                 :  *
    6915                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    6916                 :  * is expected for this object class.
    6917                 :  **********************************************************************/
    6918               0 : int  TABCollection::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    6919                 : {
    6920                 :     OGRGeometry *poGeom;
    6921               0 :     int nRegionType=TAB_GEOM_NONE, nPLineType=TAB_GEOM_NONE, 
    6922               0 :         nMPointType=TAB_GEOM_NONE, nVersion = 650;
    6923                 : 
    6924                 :     /*-----------------------------------------------------------------
    6925                 :      * Fetch and validate geometry 
    6926                 :      *----------------------------------------------------------------*/
    6927               0 :     poGeom = GetGeometryRef();
    6928               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
    6929                 :     {
    6930               0 :         m_nMapInfoType = TAB_GEOM_COLLECTION;
    6931                 :     }
    6932                 :     else
    6933                 :     {
    6934                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6935               0 :                  "TABCollection: Missing or Invalid Geometry!");
    6936               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    6937                 :     }
    6938                 : 
    6939                 :     /*-----------------------------------------------------------------
    6940                 :      * Decide if coordinates should be compressed or not.
    6941                 :      *----------------------------------------------------------------*/
    6942               0 :     GBool bComprCoord = ValidateCoordType(poMapFile);
    6943                 : 
    6944                 :     /*-----------------------------------------------------------------
    6945                 :      * Since all members of the collection share the same compressed coord
    6946                 :      * origin, we should force the compressed origin in all components
    6947                 :      * to be the same. 
    6948                 :      * This also implies that ValidateMapInfoType() should *NOT* be called
    6949                 :      * again until the collection components are written by WriteGeom...()
    6950                 :      *----------------------------------------------------------------*/
    6951                 : 
    6952                 :     // First pass to figure collection type...
    6953               0 :     if (m_poRegion)
    6954                 :     {
    6955               0 :         m_poRegion->ValidateCoordType(poMapFile);
    6956               0 :         nRegionType = m_poRegion->ValidateMapInfoType(poMapFile);
    6957               0 :         if (TAB_GEOM_GET_VERSION(nRegionType) > nVersion)
    6958               0 :             nVersion = TAB_GEOM_GET_VERSION(nRegionType);
    6959                 :     }
    6960                 : 
    6961               0 :     if (m_poPline)
    6962                 :     {
    6963               0 :         m_poPline->ValidateCoordType(poMapFile);
    6964               0 :         nPLineType = m_poPline->ValidateMapInfoType(poMapFile);
    6965               0 :         if (TAB_GEOM_GET_VERSION(nPLineType) > nVersion)
    6966               0 :             nVersion = TAB_GEOM_GET_VERSION(nPLineType);
    6967                 :     }
    6968                 : 
    6969               0 :     if (m_poMpoint)
    6970                 :     {
    6971               0 :         m_poMpoint->ValidateCoordType(poMapFile);
    6972               0 :         nMPointType = m_poMpoint->ValidateMapInfoType(poMapFile);
    6973               0 :         if (TAB_GEOM_GET_VERSION(nMPointType) > nVersion)
    6974               0 :             nVersion = TAB_GEOM_GET_VERSION(nMPointType);
    6975                 :     }
    6976                 : 
    6977                 :     // Need to upgrade native type of collection?
    6978               0 :     if (nVersion == 800)
    6979                 :     {
    6980               0 :         m_nMapInfoType = TAB_GEOM_V800_COLLECTION;
    6981                 :     }
    6982                 : 
    6983                 :     // Make another pass updating native type and coordinates type and origin
    6984                 :     // of each component
    6985               0 :     if (m_poRegion && nRegionType != TAB_GEOM_NONE)
    6986                 :     {
    6987               0 :         GInt32 nXMin=0, nYMin=0, nXMax=0, nYMax=0;
    6988               0 :         m_poRegion->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
    6989                 :         m_poRegion->ForceCoordTypeAndOrigin((nVersion == 800 ? 
    6990                 :                                              TAB_GEOM_V800_REGION:
    6991                 :                                              TAB_GEOM_V450_REGION),
    6992                 :                                             bComprCoord,
    6993                 :                                             m_nComprOrgX, m_nComprOrgY,
    6994               0 :                                             nXMin, nYMin, nXMax, nYMax);
    6995                 :     }
    6996                 : 
    6997                 : 
    6998               0 :     if (m_poPline && nPLineType != TAB_GEOM_NONE)
    6999                 :     {
    7000                 :         GInt32 nXMin, nYMin, nXMax, nYMax;
    7001               0 :         m_poPline->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
    7002                 :         m_poPline->ForceCoordTypeAndOrigin((nVersion == 800 ? 
    7003                 :                                             TAB_GEOM_V800_MULTIPLINE:
    7004                 :                                             TAB_GEOM_V450_MULTIPLINE),
    7005                 :                                            bComprCoord,
    7006                 :                                            m_nComprOrgX, m_nComprOrgY,
    7007               0 :                                            nXMin, nYMin, nXMax, nYMax);
    7008                 :     }
    7009                 : 
    7010               0 :     if (m_poMpoint && nMPointType != TAB_GEOM_NONE)
    7011                 :     {
    7012                 :         GInt32 nXMin, nYMin, nXMax, nYMax;
    7013               0 :         m_poMpoint->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
    7014                 :         m_poMpoint->ForceCoordTypeAndOrigin((nVersion == 800 ? 
    7015                 :                                              TAB_GEOM_V800_MULTIPOINT:
    7016                 :                                              TAB_GEOM_MULTIPOINT),
    7017                 :                                             bComprCoord,
    7018                 :                                             m_nComprOrgX, m_nComprOrgY,
    7019               0 :                                             nXMin, nYMin, nXMax, nYMax);
    7020                 :     }
    7021                 : 
    7022                 : 
    7023               0 :     return m_nMapInfoType;
    7024                 : }
    7025                 : 
    7026                 : 
    7027                 : /**********************************************************************
    7028                 :  *                   TABCollection::ReadLabelAndMBR()
    7029                 :  *
    7030                 :  * Reads the label and MBR elements of the header of a collection component
    7031                 :  *
    7032                 :  * Returns 0 on success, -1 on failure.
    7033                 :  **********************************************************************/
    7034                 : int  TABCollection::ReadLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
    7035                 :                                     GBool bComprCoord,
    7036                 :                                     GInt32 nComprOrgX, GInt32 nComprOrgY,
    7037                 :                                     GInt32 &pnMinX, GInt32 &pnMinY,
    7038                 :                                     GInt32 &pnMaxX, GInt32 &pnMaxY,
    7039               0 :                                     GInt32 &pnLabelX, GInt32 &pnLabelY )
    7040                 : {
    7041                 :     //
    7042                 :     // The sections in the collection's coord blocks start with center/label
    7043                 :     // point + MBR that are normally found in the object data blocks 
    7044                 :     // of regular region/pline/mulitpoint objects.
    7045                 :     //
    7046                 : 
    7047               0 :     if (bComprCoord)
    7048                 :     {
    7049                 :         // Region center/label point, relative to compr. coord. origin
    7050                 :         // No it's not relative to the Object block center
    7051               0 :         pnLabelX = poCoordBlock->ReadInt16();
    7052               0 :         pnLabelY = poCoordBlock->ReadInt16();
    7053                 : 
    7054               0 :         pnLabelX += nComprOrgX;
    7055               0 :         pnLabelY += nComprOrgY;
    7056                 : 
    7057               0 :         pnMinX = nComprOrgX + poCoordBlock->ReadInt16(); // Read MBR
    7058               0 :         pnMinY = nComprOrgY + poCoordBlock->ReadInt16();
    7059               0 :         pnMaxX = nComprOrgX + poCoordBlock->ReadInt16();
    7060               0 :         pnMaxY = nComprOrgY + poCoordBlock->ReadInt16();
    7061                 :     }
    7062                 :     else
    7063                 :     {
    7064                 :         // Region center/label point, relative to compr. coord. origin
    7065                 :         // No it's not relative to the Object block center
    7066               0 :         pnLabelX = poCoordBlock->ReadInt32();
    7067               0 :         pnLabelY = poCoordBlock->ReadInt32();
    7068                 : 
    7069               0 :         pnMinX = poCoordBlock->ReadInt32();    // Read MBR
    7070               0 :         pnMinY = poCoordBlock->ReadInt32();
    7071               0 :         pnMaxX = poCoordBlock->ReadInt32();
    7072               0 :         pnMaxY = poCoordBlock->ReadInt32();
    7073                 :     }
    7074                 : 
    7075               0 :     return 0;
    7076                 : }
    7077                 : 
    7078                 : /**********************************************************************
    7079                 :  *                   TABCollection::WriteLabelAndMBR()
    7080                 :  *
    7081                 :  * Writes the label and MBR elements of the header of a collection component
    7082                 :  *
    7083                 :  * Returns 0 on success, -1 on failure.
    7084                 :  **********************************************************************/
    7085                 : int  TABCollection::WriteLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
    7086                 :                                      GBool bComprCoord,
    7087                 :                                      GInt32 nMinX, GInt32 nMinY,
    7088                 :                                      GInt32 nMaxX, GInt32 nMaxY,
    7089               0 :                                      GInt32 nLabelX, GInt32 nLabelY )
    7090                 : {
    7091                 :     int nStatus;
    7092                 : 
    7093                 :     //
    7094                 :     // The sections in the collection's coord blocks start with center/label
    7095                 :     // point + MBR that are normally found in the object data blocks 
    7096                 :     // of regular region/pline/mulitpoint objects.
    7097                 :     //
    7098                 : 
    7099               0 :     if ((nStatus = poCoordBlock->WriteIntCoord(nLabelX, nLabelY, 
    7100                 :                                                bComprCoord)) != 0 ||
    7101                 :         (nStatus = poCoordBlock->WriteIntCoord(nMinX, nMinY, 
    7102                 :                                                bComprCoord)) != 0 ||
    7103                 :         (nStatus = poCoordBlock->WriteIntCoord(nMaxX, nMaxY, 
    7104                 :                                                bComprCoord)) != 0   )
    7105                 :     {
    7106                 :         // Failed ... error message has already been produced
    7107               0 :         return nStatus;
    7108                 :     }   
    7109                 : 
    7110               0 :     return 0;
    7111                 : }
    7112                 : 
    7113                 : 
    7114                 : /**********************************************************************
    7115                 :  *                   TABCollection::ReadGeometryFromMAPFile()
    7116                 :  *
    7117                 :  * Fill the geometry and representation (color, etc...) part of the
    7118                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    7119                 :  *
    7120                 :  * It is assumed that poMAPFile currently points to the beginning of
    7121                 :  * a map object.
    7122                 :  *
    7123                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    7124                 :  * been called.
    7125                 :  **********************************************************************/
    7126                 : int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    7127                 :                                            TABMAPObjHdr *poObjHdr,
    7128                 :                                            GBool bCoordBlockDataOnly /*=FALSE*/,
    7129               0 :                                            TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    7130                 : {
    7131                 :     double              dXMin, dYMin, dXMax, dYMax;
    7132               0 :     GBool               bComprCoord = poObjHdr->IsCompressedType();
    7133               0 :     TABMAPCoordBlock*   poCoordBlock = NULL;
    7134                 :     int                 nCurCoordBlockPtr;
    7135                 : 
    7136                 :     /*-----------------------------------------------------------------
    7137                 :      * Fetch and validate geometry type
    7138                 :      *----------------------------------------------------------------*/
    7139               0 :     m_nMapInfoType = poObjHdr->m_nType;
    7140                 : 
    7141               0 :     if (m_nMapInfoType != TAB_GEOM_COLLECTION &&
    7142                 :         m_nMapInfoType != TAB_GEOM_COLLECTION_C &&
    7143                 :         m_nMapInfoType != TAB_GEOM_V800_COLLECTION &&
    7144                 :         m_nMapInfoType != TAB_GEOM_V800_COLLECTION_C )
    7145                 :     {
    7146                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    7147                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    7148               0 :                  m_nMapInfoType, m_nMapInfoType);
    7149               0 :         return -1;
    7150                 :     }
    7151                 : 
    7152               0 :     int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    7153                 : 
    7154                 :     // Make sure collection is empty
    7155               0 :     EmptyCollection();
    7156                 : 
    7157                 :     /*-------------------------------------------------------------
    7158                 :      * Copy data from poObjHdr
    7159                 :      *------------------------------------------------------------*/
    7160               0 :     TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
    7161                 : 
    7162                 :     // MBR
    7163                 :     poMapFile->Int2Coordsys(poCollHdr->m_nMinX, poCollHdr->m_nMinY, 
    7164               0 :                             dXMin, dYMin);
    7165                 :     poMapFile->Int2Coordsys(poCollHdr->m_nMaxX, poCollHdr->m_nMaxY, 
    7166               0 :                             dXMax, dYMax);
    7167                 : 
    7168               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    7169                 : 
    7170                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    7171               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    7172                 : 
    7173               0 :     nCurCoordBlockPtr = poCollHdr->m_nCoordBlockPtr;
    7174               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    7175               0 :         poCoordBlock = *ppoCoordBlock;
    7176                 :     else
    7177               0 :         poCoordBlock = poMapFile->GetCoordBlock(nCurCoordBlockPtr);
    7178                 : 
    7179                 :     // Compressed coordinate origin (useful only in compressed case!)
    7180               0 :     m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7181               0 :     m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7182                 : 
    7183                 :     /*-----------------------------------------------------------------
    7184                 :      * Region Component
    7185                 :      *----------------------------------------------------------------*/
    7186               0 :     if(poCollHdr->m_nNumRegSections > 0)
    7187                 :     {
    7188                 :         //
    7189                 :         // Build fake coord section header to pass to TABRegion::ReadGeom...()
    7190                 :         //
    7191               0 :         TABMAPObjPLine      oRegionHdr;
    7192                 : 
    7193               0 :         oRegionHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7194               0 :         oRegionHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7195                 : 
    7196                 :         //
    7197                 :         // The region section in the coord block starts with center/label
    7198                 :         // point + MBR that are normally found in the object data blocks 
    7199                 :         // of regular region objects.
    7200                 :         //
    7201                 : 
    7202                 :         // In V800 the mini-header starts with a copy of num_parts
    7203               0 :         if (nVersion >= 800)
    7204                 :         {
    7205                 :             int numParts;
    7206               0 :             numParts = poCoordBlock->ReadInt32();
    7207               0 :             CPLAssert(numParts == poCollHdr->m_nNumRegSections);
    7208                 :         }
    7209                 : 
    7210                 :         ReadLabelAndMBR(poCoordBlock, bComprCoord,
    7211                 :                         oRegionHdr.m_nComprOrgX, oRegionHdr.m_nComprOrgY,
    7212                 :                         oRegionHdr.m_nMinX, oRegionHdr.m_nMinY,
    7213                 :                         oRegionHdr.m_nMaxX, oRegionHdr.m_nMaxY,
    7214               0 :                         oRegionHdr.m_nLabelX, oRegionHdr.m_nLabelY);
    7215                 : 
    7216                 :         // Set CoordBlockPtr so that TABRegion continues reading here
    7217               0 :         oRegionHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7218                 : 
    7219               0 :         if (bComprCoord)
    7220               0 :             oRegionHdr.m_nType = TAB_GEOM_V450_REGION_C;
    7221                 :         else
    7222               0 :             oRegionHdr.m_nType = TAB_GEOM_V450_REGION;
    7223               0 :         if (nVersion == 800)
    7224               0 :             oRegionHdr.m_nType += (TAB_GEOM_V800_REGION - TAB_GEOM_V450_REGION);
    7225                 : 
    7226               0 :         oRegionHdr.m_numLineSections = poCollHdr->m_nNumRegSections;
    7227               0 :         oRegionHdr.m_nPenId = poCollHdr->m_nRegionPenId;
    7228               0 :         oRegionHdr.m_nBrushId = poCollHdr->m_nRegionBrushId;
    7229               0 :         oRegionHdr.m_bSmooth = 0;       // TODO
    7230                 : 
    7231                 :         //
    7232                 :         // Use a TABRegion to read/store the Region coord data
    7233                 :         //
    7234               0 :         m_poRegion = new TABRegion(GetDefnRef());
    7235               0 :         if (m_poRegion->ReadGeometryFromMAPFile(poMapFile, &oRegionHdr, 
    7236                 :                                                 bCoordBlockDataOnly, 
    7237                 :                                                 &poCoordBlock) != 0)
    7238               0 :             return -1;
    7239                 : 
    7240                 :         // Set new coord block ptr for next object
    7241               0 :         if (poCoordBlock)
    7242               0 :             nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
    7243                 :     }
    7244                 : 
    7245                 : 
    7246                 :     /*-----------------------------------------------------------------
    7247                 :      * PLine Component
    7248                 :      *----------------------------------------------------------------*/
    7249               0 :     if(poCollHdr->m_nNumPLineSections > 0)
    7250                 :     {
    7251                 :         //
    7252                 :         // Build fake coord section header to pass to TABPolyline::ReadGeom..()
    7253                 :         //
    7254               0 :         TABMAPObjPLine      oPLineHdr;
    7255                 : 
    7256               0 :         oPLineHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7257               0 :         oPLineHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7258                 : 
    7259                 :         //
    7260                 :         // The pline section in the coord block starts with center/label
    7261                 :         // point + MBR that are normally found in the object data blocks 
    7262                 :         // of regular pline objects.
    7263                 :         //
    7264                 : 
    7265                 :         // In V800 the mini-header starts with a copy of num_parts
    7266               0 :         if (nVersion >= 800)
    7267                 :         {
    7268                 :             int numParts;
    7269               0 :             numParts = poCoordBlock->ReadInt32();
    7270               0 :             CPLAssert(numParts == poCollHdr->m_nNumPLineSections);
    7271                 :         }
    7272                 : 
    7273                 :         ReadLabelAndMBR(poCoordBlock, bComprCoord,
    7274                 :                         oPLineHdr.m_nComprOrgX, oPLineHdr.m_nComprOrgY,
    7275                 :                         oPLineHdr.m_nMinX, oPLineHdr.m_nMinY,
    7276                 :                         oPLineHdr.m_nMaxX, oPLineHdr.m_nMaxY,
    7277               0 :                         oPLineHdr.m_nLabelX, oPLineHdr.m_nLabelY);
    7278                 : 
    7279                 :         // Set CoordBlockPtr so that TABRegion continues reading here
    7280               0 :         oPLineHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7281                 : 
    7282               0 :         if (bComprCoord)
    7283               0 :             oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE_C;
    7284                 :         else
    7285               0 :             oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE;
    7286               0 :         if (nVersion == 800)
    7287                 :             oPLineHdr.m_nType += (TAB_GEOM_V800_MULTIPLINE - 
    7288               0 :                                   TAB_GEOM_V450_MULTIPLINE);
    7289                 : 
    7290               0 :         oPLineHdr.m_numLineSections = poCollHdr->m_nNumPLineSections;
    7291               0 :         oPLineHdr.m_nPenId = poCollHdr->m_nPolylinePenId;
    7292               0 :         oPLineHdr.m_bSmooth = 0;        // TODO
    7293                 : 
    7294                 :         //
    7295                 :         // Use a TABPolyline to read/store the Polyline coord data
    7296                 :         //
    7297               0 :         m_poPline = new TABPolyline(GetDefnRef());
    7298               0 :         if (m_poPline->ReadGeometryFromMAPFile(poMapFile, &oPLineHdr, 
    7299                 :                                                bCoordBlockDataOnly,
    7300                 :                                                &poCoordBlock) != 0)
    7301               0 :             return -1;
    7302                 : 
    7303                 :         // Set new coord block ptr for next object
    7304               0 :         if (poCoordBlock)
    7305               0 :             nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
    7306                 :     }
    7307                 : 
    7308                 :     /*-----------------------------------------------------------------
    7309                 :      * MultiPoint Component
    7310                 :      *----------------------------------------------------------------*/
    7311               0 :     if(poCollHdr->m_nNumMultiPoints > 0)
    7312                 :     {
    7313                 :         //
    7314                 :         // Build fake coord section header to pass to TABMultiPoint::ReadGeom()
    7315                 :         //
    7316               0 :         TABMAPObjMultiPoint oMPointHdr;
    7317                 : 
    7318               0 :         oMPointHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7319               0 :         oMPointHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7320                 : 
    7321                 :         //
    7322                 :         // The pline section in the coord block starts with center/label
    7323                 :         // point + MBR that are normally found in the object data blocks 
    7324                 :         // of regular pline objects.
    7325                 :         //
    7326                 :         ReadLabelAndMBR(poCoordBlock, bComprCoord,
    7327                 :                         oMPointHdr.m_nComprOrgX, oMPointHdr.m_nComprOrgY,
    7328                 :                         oMPointHdr.m_nMinX, oMPointHdr.m_nMinY,
    7329                 :                         oMPointHdr.m_nMaxX, oMPointHdr.m_nMaxY,
    7330               0 :                         oMPointHdr.m_nLabelX, oMPointHdr.m_nLabelY);
    7331                 : 
    7332                 :         // Set CoordBlockPtr so that TABRegion continues reading here
    7333               0 :         oMPointHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7334                 : 
    7335               0 :         if (bComprCoord)
    7336               0 :             oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT_C;
    7337                 :         else
    7338               0 :             oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT;
    7339               0 :         if (nVersion == 800)
    7340                 :             oMPointHdr.m_nType += (TAB_GEOM_V800_MULTIPOINT - 
    7341               0 :                                    TAB_GEOM_MULTIPOINT);
    7342                 : 
    7343               0 :         oMPointHdr.m_nNumPoints = poCollHdr->m_nNumMultiPoints;
    7344               0 :         oMPointHdr.m_nSymbolId = poCollHdr->m_nMultiPointSymbolId;
    7345                 : 
    7346                 :         //
    7347                 :         // Use a TABMultiPoint to read/store the coord data
    7348                 :         //
    7349               0 :         m_poMpoint = new TABMultiPoint(GetDefnRef());
    7350               0 :         if (m_poMpoint->ReadGeometryFromMAPFile(poMapFile, &oMPointHdr, 
    7351                 :                                                 bCoordBlockDataOnly,
    7352                 :                                                 &poCoordBlock) != 0)
    7353               0 :             return -1;
    7354                 : 
    7355                 :         // Set new coord block ptr for next object (not really useful here)
    7356               0 :         if (poCoordBlock)
    7357               0 :             nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
    7358                 :     }
    7359                 :     
    7360                 :     /*-----------------------------------------------------------------
    7361                 :      * Set the main OGRFeature Geometry 
    7362                 :      * (this is actually duplicating geometries from each member)
    7363                 :      *----------------------------------------------------------------*/
    7364               0 :     if (SyncOGRGeometryCollection(TRUE, TRUE, TRUE) != 0)
    7365               0 :         return -1;
    7366                 : 
    7367                 :     /* Return a ref to coord block so that caller can continue reading
    7368                 :      * after the end of this object (used by index splitting)
    7369                 :      */
    7370               0 :     if (ppoCoordBlock)
    7371               0 :         *ppoCoordBlock = poCoordBlock;
    7372                 : 
    7373               0 :     return 0;
    7374                 : }
    7375                 : 
    7376                 : /**********************************************************************
    7377                 :  *                   TABCollection::WriteGeometryToMAPFile()
    7378                 :  *
    7379                 :  * Write the geometry and representation (color, etc...) part of the
    7380                 :  * feature to the .MAP object pointed to by poMAPFile.
    7381                 :  *
    7382                 :  * It is assumed that poMAPFile currently points to a valid map object.
    7383                 :  *
    7384                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    7385                 :  * been called.
    7386                 :  **********************************************************************/
    7387                 : int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    7388                 :                                           TABMAPObjHdr *poObjHdr,
    7389                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    7390               0 :                                           TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    7391                 : {
    7392                 :     /*-----------------------------------------------------------------
    7393                 :      * Note that the current implementation does not allow setting the
    7394                 :      * Geometry via OGRFeature::SetGeometry(). The geometries must be set
    7395                 :      * via the SetRegion/Pline/MpointDirectly() methods which will take 
    7396                 :      * care of keeping the OGRFeature's geometry in sync.
    7397                 :      * 
    7398                 :      * TODO: If we ever want to support sync'ing changes from the OGRFeature's
    7399                 :      * geometry to the m_poRegion/Pline/Mpoint then a call should be added
    7400                 :      * here, or perhaps in ValidateMapInfoType(), or even better in 
    7401                 :      * custom TABCollection::SetGeometry*()... but then this last option
    7402                 :      * won't work unless OGRFeature::SetGeometry*() are made virtual in OGR.
    7403                 :      *----------------------------------------------------------------*/
    7404                 : 
    7405                 : 
    7406                 :     /*-----------------------------------------------------------------
    7407                 :      * We assume that ValidateMapInfoType() was called already and that
    7408                 :      * the type in poObjHdr->m_nType is valid.
    7409                 :      *----------------------------------------------------------------*/
    7410               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    7411                 : 
    7412               0 :     TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
    7413                 : 
    7414                 :     /*-----------------------------------------------------------------
    7415                 :      * Write data to coordinate block for each component...
    7416                 :      *
    7417                 :      * Note that at this point, the caller (TABFile) has called 
    7418                 :      * TABCollection::ValidateMapInfoType() which in turn has called
    7419                 :      * each component's respective ValidateMapInfoType() and
    7420                 :      * ForceCoordTypeAndCoordOrigin() so the objects are ready to have
    7421                 :      * their respective WriteGeometryToMapFile() called.
    7422                 :      *----------------------------------------------------------------*/
    7423                 :     TABMAPCoordBlock *poCoordBlock;
    7424               0 :     GBool   bCompressed = poObjHdr->IsCompressedType();
    7425                 :     // TODO: ??? Do we need to track overall collection coord data size???
    7426               0 :     int     nTotalFeatureDataSize = 0;
    7427                 : 
    7428               0 :     int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    7429                 : 
    7430               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    7431               0 :         poCoordBlock = *ppoCoordBlock;
    7432                 :     else
    7433               0 :         poCoordBlock = poMapFile->GetCurCoordBlock();
    7434               0 :     poCoordBlock->StartNewFeature();
    7435               0 :     poCollHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7436               0 :     poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    7437                 : 
    7438                 :     /*-----------------------------------------------------------------
    7439                 :      * Region component
    7440                 :      *----------------------------------------------------------------*/
    7441               0 :     if (m_poRegion && m_poRegion->GetMapInfoType() != TAB_GEOM_NONE)
    7442                 :     {
    7443               0 :         CPLAssert(m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION ||
    7444                 :                   m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION_C ||
    7445                 :                   m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION ||
    7446                 :                   m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION_C );
    7447                 : 
    7448                 :         TABMAPObjPLine *poRegionHdr = (TABMAPObjPLine *)
    7449               0 :             TABMAPObjHdr::NewObj(m_poRegion->GetMapInfoType(), -1);
    7450                 : 
    7451                 :         // Update count of objects by type in header
    7452               0 :         if (!bCoordBlockDataOnly)
    7453               0 :             poMapFile->UpdateMapHeaderInfo(m_poRegion->GetMapInfoType());
    7454                 : 
    7455                 :         // Write a placeholder for centroid/label point and MBR mini-header
    7456                 :         // and we'll come back later to write the real values.
    7457                 :         //
    7458                 :         // Note that the call to WriteGeometryToMAPFile() below will call 
    7459                 :         // StartNewFeature() as well, so we need to track the current 
    7460                 :         // value before calling it
    7461                 : 
    7462               0 :         poCoordBlock->StartNewFeature();
    7463               0 :         int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
    7464                 : 
    7465                 :         // In V800 the mini-header starts with a copy of num_parts
    7466               0 :         if (nVersion >= 800)
    7467                 :         {
    7468               0 :             poCoordBlock->WriteInt32(0);
    7469                 :         }
    7470                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7471               0 :                          0, 0, 0, 0, 0, 0);
    7472               0 :         nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
    7473                 : 
    7474               0 :         if (m_poRegion->WriteGeometryToMAPFile(poMapFile, poRegionHdr,
    7475                 :                                                bCoordBlockDataOnly,
    7476                 :                                                &poCoordBlock) != 0)
    7477                 :         {
    7478                 :             CPLError(CE_Failure, CPLE_FileIO,
    7479               0 :                      "Failed writing Region part in collection.");
    7480               0 :             delete poRegionHdr;
    7481               0 :             return -1;
    7482                 :         }
    7483                 : 
    7484               0 :         nTotalFeatureDataSize += poRegionHdr->m_nCoordDataSize;
    7485                 : 
    7486                 :         // Come back to write the real values in the mini-header
    7487               0 :         int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
    7488               0 :         poCoordBlock->StartNewFeature();
    7489                 : 
    7490               0 :         if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
    7491                 :         {
    7492               0 :             delete poRegionHdr;
    7493               0 :             return -1;
    7494                 :         }
    7495                 : 
    7496                 :         // In V800 the mini-header starts with a copy of num_parts
    7497               0 :         if (nVersion >= 800)
    7498                 :         {
    7499               0 :             poCoordBlock->WriteInt32(poRegionHdr->m_numLineSections);
    7500                 :         }
    7501                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7502                 :                          poRegionHdr->m_nMinX, poRegionHdr->m_nMinY, 
    7503                 :                          poRegionHdr->m_nMaxX, poRegionHdr->m_nMaxY,
    7504               0 :                          poRegionHdr->m_nLabelX, poRegionHdr->m_nLabelY);
    7505                 : 
    7506                 :         // And finally move the pointer back to the end of this component
    7507               0 :         if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
    7508                 :         {
    7509               0 :             delete poRegionHdr;
    7510               0 :             return -1;
    7511                 :         }
    7512                 : 
    7513                 :         // Copy other header members to the main collection header
    7514                 :         // TODO: Does m_nRegionDataSize need to include the centroid+mbr
    7515                 :         //       mini-header???
    7516               0 :         poCollHdr->m_nRegionDataSize = poRegionHdr->m_nCoordDataSize;
    7517               0 :         poCollHdr->m_nNumRegSections = poRegionHdr->m_numLineSections;
    7518                 : 
    7519               0 :         if (!bCoordBlockDataOnly)
    7520                 :         {
    7521               0 :             poCollHdr->m_nRegionPenId    = poRegionHdr->m_nPenId;
    7522               0 :             poCollHdr->m_nRegionBrushId  = poRegionHdr->m_nBrushId;
    7523                 :             // TODO: Smooth flag         = poRegionHdr->m_bSmooth;
    7524                 :         }
    7525                 :         
    7526               0 :         delete poRegionHdr;
    7527                 :     }
    7528                 :     else
    7529                 :     {
    7530                 :         // No Region component. Set corresponding header fields to 0
    7531                 : 
    7532               0 :         poCollHdr->m_nRegionDataSize = 0;
    7533               0 :         poCollHdr->m_nNumRegSections = 0;
    7534               0 :         poCollHdr->m_nRegionPenId = 0;
    7535               0 :         poCollHdr->m_nRegionBrushId = 0;
    7536                 :     }
    7537                 : 
    7538                 :     /*-----------------------------------------------------------------
    7539                 :      * PLine component
    7540                 :      *----------------------------------------------------------------*/
    7541               0 :     if (m_poPline && m_poPline->GetMapInfoType() != TAB_GEOM_NONE)
    7542                 :     {
    7543               0 :         CPLAssert(m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE ||
    7544                 :                   m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE_C ||
    7545                 :                   m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE ||
    7546                 :                   m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE_C );
    7547                 : 
    7548                 :         TABMAPObjPLine *poPlineHdr = (TABMAPObjPLine *)
    7549               0 :             TABMAPObjHdr::NewObj(m_poPline->GetMapInfoType(), -1);
    7550                 : 
    7551                 :         // Update count of objects by type in header
    7552               0 :         if (!bCoordBlockDataOnly)
    7553               0 :             poMapFile->UpdateMapHeaderInfo(m_poPline->GetMapInfoType());
    7554                 : 
    7555                 :         // Write a placeholder for centroid/label point and MBR mini-header
    7556                 :         // and we'll come back later to write the real values.
    7557                 :         //
    7558                 :         // Note that the call to WriteGeometryToMAPFile() below will call 
    7559                 :         // StartNewFeature() as well, so we need to track the current 
    7560                 :         // value before calling it
    7561                 : 
    7562               0 :         poCoordBlock->StartNewFeature();
    7563               0 :         int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
    7564                 : 
    7565                 :         // In V800 the mini-header starts with a copy of num_parts
    7566               0 :         if (nVersion >= 800)
    7567                 :         {
    7568               0 :             poCoordBlock->WriteInt32(0);
    7569                 :         }
    7570                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7571               0 :                          0, 0, 0, 0, 0, 0);
    7572               0 :         nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
    7573                 : 
    7574               0 :         if (m_poPline->WriteGeometryToMAPFile(poMapFile, poPlineHdr,
    7575                 :                                               bCoordBlockDataOnly,
    7576                 :                                               &poCoordBlock) != 0)
    7577                 :         {
    7578                 :             CPLError(CE_Failure, CPLE_FileIO,
    7579               0 :                      "Failed writing Region part in collection.");
    7580               0 :             delete poPlineHdr;
    7581               0 :             return -1;
    7582                 :         }
    7583                 : 
    7584               0 :         nTotalFeatureDataSize += poPlineHdr->m_nCoordDataSize;
    7585                 : 
    7586                 :         // Come back to write the real values in the mini-header
    7587               0 :         int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
    7588               0 :         poCoordBlock->StartNewFeature();
    7589                 : 
    7590               0 :         if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
    7591                 :         {
    7592               0 :             delete poPlineHdr;
    7593               0 :             return -1;
    7594                 :         }
    7595                 : 
    7596                 :         // In V800 the mini-header starts with a copy of num_parts
    7597               0 :         if (nVersion >= 800)
    7598                 :         {
    7599               0 :             poCoordBlock->WriteInt32(poPlineHdr->m_numLineSections);
    7600                 :         }
    7601                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7602                 :                          poPlineHdr->m_nMinX, poPlineHdr->m_nMinY, 
    7603                 :                          poPlineHdr->m_nMaxX, poPlineHdr->m_nMaxY,
    7604               0 :                          poPlineHdr->m_nLabelX, poPlineHdr->m_nLabelY);
    7605                 : 
    7606                 :         // And finally move the pointer back to the end of this component
    7607               0 :         if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
    7608                 :         {
    7609               0 :             delete poPlineHdr;
    7610               0 :             return -1;
    7611                 :         }
    7612                 : 
    7613                 :         // Copy other header members to the main collection header
    7614                 :         // TODO: Does m_nRegionDataSize need to include the centroid+mbr
    7615                 :         //       mini-header???
    7616               0 :         poCollHdr->m_nPolylineDataSize = poPlineHdr->m_nCoordDataSize;
    7617               0 :         poCollHdr->m_nNumPLineSections = poPlineHdr->m_numLineSections;
    7618               0 :         if (!bCoordBlockDataOnly)
    7619                 :         {
    7620               0 :             poCollHdr->m_nPolylinePenId    = poPlineHdr->m_nPenId;
    7621                 :             // TODO: Smooth flag           = poPlineHdr->m_bSmooth;
    7622                 :         }
    7623                 : 
    7624               0 :         delete poPlineHdr;        
    7625                 :     }
    7626                 :     else
    7627                 :     {
    7628                 :         // No Polyline component. Set corresponding header fields to 0
    7629                 : 
    7630               0 :         poCollHdr->m_nPolylineDataSize = 0;
    7631               0 :         poCollHdr->m_nNumPLineSections = 0;
    7632               0 :         poCollHdr->m_nPolylinePenId = 0;
    7633                 :     }
    7634                 : 
    7635                 : 
    7636                 :     /*-----------------------------------------------------------------
    7637                 :      * MultiPoint component
    7638                 :      *----------------------------------------------------------------*/
    7639               0 :     if (m_poMpoint && m_poMpoint->GetMapInfoType() != TAB_GEOM_NONE)
    7640                 :     {
    7641               0 :         CPLAssert(m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT ||
    7642                 :                   m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT_C ||
    7643                 :                   m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT ||
    7644                 :                   m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT_C );
    7645                 : 
    7646                 :         TABMAPObjMultiPoint *poMpointHdr = (TABMAPObjMultiPoint *)
    7647               0 :             TABMAPObjHdr::NewObj(m_poMpoint->GetMapInfoType(), -1);
    7648                 : 
    7649                 :         // Update count of objects by type in header
    7650               0 :         if (!bCoordBlockDataOnly)
    7651               0 :             poMapFile->UpdateMapHeaderInfo(m_poMpoint->GetMapInfoType());
    7652                 : 
    7653                 :         // Write a placeholder for centroid/label point and MBR mini-header
    7654                 :         // and we'll come back later to write the real values.
    7655                 :         //
    7656                 :         // Note that the call to WriteGeometryToMAPFile() below will call 
    7657                 :         // StartNewFeature() as well, so we need to track the current 
    7658                 :         // value before calling it
    7659                 : 
    7660               0 :         poCoordBlock->StartNewFeature();
    7661               0 :         int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
    7662                 : 
    7663                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7664               0 :                          0, 0, 0, 0, 0, 0);
    7665               0 :         nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
    7666                 : 
    7667               0 :         if (m_poMpoint->WriteGeometryToMAPFile(poMapFile, poMpointHdr,
    7668                 :                                                bCoordBlockDataOnly,
    7669                 :                                                &poCoordBlock) != 0)
    7670                 :         {
    7671                 :             CPLError(CE_Failure, CPLE_FileIO,
    7672               0 :                      "Failed writing Region part in collection.");
    7673               0 :             delete poMpointHdr;
    7674               0 :             return -1;
    7675                 :         }
    7676                 : 
    7677               0 :         nTotalFeatureDataSize += poMpointHdr->m_nCoordDataSize;
    7678                 : 
    7679                 :         // Come back to write the real values in the mini-header
    7680               0 :         int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
    7681               0 :         poCoordBlock->StartNewFeature();
    7682                 : 
    7683               0 :         if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
    7684                 :         {
    7685               0 :             delete poMpointHdr;
    7686               0 :             return -1;
    7687                 :         }
    7688                 : 
    7689                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7690                 :                          poMpointHdr->m_nMinX, poMpointHdr->m_nMinY, 
    7691                 :                          poMpointHdr->m_nMaxX, poMpointHdr->m_nMaxY,
    7692               0 :                          poMpointHdr->m_nLabelX, poMpointHdr->m_nLabelY);
    7693                 : 
    7694                 :         // And finally move the pointer back to the end of this component
    7695               0 :         if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
    7696                 :         {
    7697               0 :             delete poMpointHdr;
    7698               0 :             return -1;
    7699                 :         }
    7700                 : 
    7701                 :         // Copy other header members to the main collection header
    7702                 :         // TODO: Does m_nRegionDataSize need to include the centroid+mbr
    7703                 :         //       mini-header???
    7704               0 :         poCollHdr->m_nMPointDataSize     = poMpointHdr->m_nCoordDataSize;
    7705               0 :         poCollHdr->m_nNumMultiPoints     = poMpointHdr->m_nNumPoints;
    7706               0 :         if (!bCoordBlockDataOnly)
    7707                 :         {
    7708               0 :             poCollHdr->m_nMultiPointSymbolId = poMpointHdr->m_nSymbolId;
    7709                 :         }
    7710                 : 
    7711               0 :         delete poMpointHdr;        
    7712                 :     }
    7713                 :     else
    7714                 :     {
    7715                 :         // No Multipoint component. Set corresponding header fields to 0
    7716                 : 
    7717               0 :         poCollHdr->m_nMPointDataSize = 0;
    7718               0 :         poCollHdr->m_nNumMultiPoints = 0;
    7719               0 :         poCollHdr->m_nMultiPointSymbolId = 0;
    7720                 :     }
    7721                 : 
    7722                 : 
    7723                 :     /*-----------------------------------------------------------------
    7724                 :      * Copy object information
    7725                 :      *----------------------------------------------------------------*/
    7726                 : 
    7727                 :     // Compressed coordinate origin (useful only in compressed case!)
    7728               0 :     poCollHdr->m_nComprOrgX = m_nComprOrgX;
    7729               0 :     poCollHdr->m_nComprOrgY = m_nComprOrgY;
    7730                 : 
    7731               0 :     poCollHdr->m_nCoordDataSize = nTotalFeatureDataSize;
    7732                 : 
    7733               0 :     poCollHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    7734                 : 
    7735                 : 
    7736               0 :     if (CPLGetLastErrorNo() != 0)
    7737               0 :         return -1;
    7738                 : 
    7739                 :     /* Return a ref to coord block so that caller can continue writing
    7740                 :      * after the end of this object (used by index splitting)
    7741                 :      */
    7742               0 :     if (ppoCoordBlock)
    7743               0 :         *ppoCoordBlock = poCoordBlock;
    7744                 : 
    7745               0 :     return 0;
    7746                 : }
    7747                 : 
    7748                 : 
    7749                 : /**********************************************************************
    7750                 :  *                   TABCollection::SyncOGRGeometryCollection()
    7751                 :  *
    7752                 :  * Copy the region/pline/multipoint's geometries to the OGRFeature's
    7753                 :  * geometry.
    7754                 :  **********************************************************************/
    7755                 : int    TABCollection::SyncOGRGeometryCollection(GBool bSyncRegion,
    7756                 :                                                 GBool bSyncPline,
    7757               0 :                                                 GBool bSyncMpoint)
    7758                 : {
    7759               0 :     OGRGeometry         *poThisGeom = GetGeometryRef();
    7760                 :     OGRGeometryCollection *poGeomColl;
    7761                 : 
    7762                 :     // poGeometry is defined in the OGRFeature class
    7763               0 :     if (poThisGeom == NULL)
    7764                 :     {
    7765               0 :         poThisGeom = poGeomColl = new OGRGeometryCollection();
    7766               0 :         SetGeometryDirectly(poGeomColl);
    7767                 :     }
    7768               0 :     else if (wkbFlatten(poThisGeom->getGeometryType())==wkbGeometryCollection)
    7769                 :     {
    7770               0 :          poGeomColl = (OGRGeometryCollection *)poThisGeom;
    7771                 :     }
    7772                 :     else
    7773                 :     {
    7774                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    7775               0 :                  "TABCollection: Invalid Geometry. Type must be OGRCollection.");
    7776               0 :         return -1;
    7777                 :     }
    7778                 : 
    7779                 :     /*-----------------------------------------------------------------
    7780                 :      * Start by removing geometries that need to be replaced
    7781                 :      * In theory there should be a single geometry of each type, but 
    7782                 :      * just in case, we'll loop over the whole collection and delete all
    7783                 :      * instances of each type if there are some.
    7784                 :      *----------------------------------------------------------------*/
    7785               0 :     int numGeometries = poGeomColl->getNumGeometries();
    7786               0 :     for (int i=0; i<numGeometries; i++)
    7787                 :     {
    7788               0 :         OGRGeometry *poGeom = poGeomColl->getGeometryRef(i);
    7789               0 :         if (!poGeom)
    7790               0 :             continue;
    7791                 : 
    7792               0 :         if ( (bSyncRegion && 
    7793                 :               (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    7794                 :                wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) ) ||
    7795                 :              (bSyncPline && 
    7796                 :               (wkbFlatten(poGeom->getGeometryType()) == wkbLineString ||
    7797                 :                wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)) ||
    7798                 :              (bSyncMpoint && 
    7799                 :               (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint) ) )
    7800                 :         {
    7801                 :             // Remove this geometry
    7802               0 :             poGeomColl->removeGeometry(i);
    7803                 : 
    7804                 :             // Unless this was the last geometry, we need to restart
    7805                 :             // scanning the collection since we modified it
    7806               0 :             if (i != numGeometries-1)
    7807                 :             {
    7808               0 :                 i=0;
    7809               0 :                 numGeometries = poGeomColl->getNumGeometries();
    7810                 :             }
    7811                 :         }
    7812                 :     }
    7813                 : 
    7814                 :     /*-----------------------------------------------------------------
    7815                 :      * Copy TAB Feature geometries to OGRGeometryCollection
    7816                 :      *----------------------------------------------------------------*/
    7817               0 :     if(bSyncRegion && m_poRegion && m_poRegion->GetGeometryRef() != NULL)
    7818               0 :         poGeomColl->addGeometry(m_poRegion->GetGeometryRef());
    7819                 :     
    7820               0 :     if(bSyncPline && m_poPline && m_poPline->GetGeometryRef() != NULL)
    7821               0 :         poGeomColl->addGeometry(m_poPline->GetGeometryRef());
    7822                 : 
    7823               0 :     if(bSyncMpoint && m_poMpoint && m_poMpoint->GetGeometryRef() != NULL)
    7824               0 :         poGeomColl->addGeometry(m_poMpoint->GetGeometryRef());
    7825                 : 
    7826               0 :     return 0;
    7827                 : }
    7828                 : 
    7829                 : 
    7830                 : /**********************************************************************
    7831                 :  *                   TABCollection::SetRegionDirectly()
    7832                 :  *
    7833                 :  * Set the region component of the collection, deleting the current
    7834                 :  * region component if there is one. The object is then owned by the
    7835                 :  * TABCollection object. Passing NULL just deletes it.
    7836                 :  *
    7837                 :  * Note that an intentional side-effect is that calling this method
    7838                 :  * with the same poRegion pointer that is already owned by this object
    7839                 :  * will force resync'ing the OGR Geometry member.
    7840                 :  **********************************************************************/
    7841               0 : int    TABCollection::SetRegionDirectly(TABRegion *poRegion)
    7842                 : {
    7843               0 :     if (m_poRegion && m_poRegion != poRegion)
    7844               0 :         delete m_poRegion;
    7845               0 :     m_poRegion = poRegion;
    7846                 : 
    7847                 :     // Update OGRGeometryCollection component as well
    7848               0 :     return SyncOGRGeometryCollection(TRUE, FALSE, FALSE);
    7849                 : }
    7850                 : 
    7851                 : /**********************************************************************
    7852                 :  *                   TABCollection::SetPolylineDirectly()
    7853                 :  *
    7854                 :  * Set the polyline component of the collection, deleting the current
    7855                 :  * polyline component if there is one. The object is then owned by the
    7856                 :  * TABCollection object. Passing NULL just deletes it.
    7857                 :  *
    7858                 :  * Note that an intentional side-effect is that calling this method
    7859                 :  * with the same poPline pointer that is already owned by this object
    7860                 :  * will force resync'ing the OGR Geometry member.
    7861                 :  **********************************************************************/
    7862               0 : int    TABCollection::SetPolylineDirectly(TABPolyline *poPline)
    7863                 : {
    7864               0 :     if (m_poPline && m_poPline != poPline)
    7865               0 :         delete m_poPline;
    7866               0 :     m_poPline = poPline;
    7867                 : 
    7868                 :     // Update OGRGeometryCollection component as well
    7869               0 :     return SyncOGRGeometryCollection(FALSE, TRUE, FALSE);
    7870                 : }
    7871                 : 
    7872                 : /**********************************************************************
    7873                 :  *                   TABCollection::SetMultiPointDirectly()
    7874                 :  *
    7875                 :  * Set the multipoint component of the collection, deleting the current
    7876                 :  * multipoint component if there is one. The object is then owned by the
    7877                 :  * TABCollection object. Passing NULL just deletes it.
    7878                 :  *
    7879                 :  * Note that an intentional side-effect is that calling this method
    7880                 :  * with the same poMpoint pointer that is already owned by this object
    7881                 :  * will force resync'ing the OGR Geometry member.
    7882                 :  **********************************************************************/
    7883               0 : int    TABCollection::SetMultiPointDirectly(TABMultiPoint *poMpoint)
    7884                 : {
    7885               0 :     if (m_poMpoint && m_poMpoint != poMpoint)
    7886               0 :         delete m_poMpoint;
    7887               0 :     m_poMpoint = poMpoint;
    7888                 : 
    7889                 :     // Update OGRGeometryCollection component as well
    7890               0 :     return SyncOGRGeometryCollection(FALSE, FALSE, TRUE);
    7891                 : }
    7892                 : 
    7893                 : 
    7894                 : /**********************************************************************
    7895                 :  *                   TABCollection::GetStyleString()
    7896                 :  *
    7897                 :  * Return style string for this feature.
    7898                 :  *
    7899                 :  * Style String is built only once during the first call to GetStyleString().
    7900                 :  **********************************************************************/
    7901               0 : const char *TABCollection::GetStyleString()
    7902                 : {
    7903               0 :     if (m_pszStyleString == NULL)
    7904                 :     {
    7905               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    7906                 :     }
    7907                 : 
    7908               0 :     return m_pszStyleString;
    7909                 : }
    7910                 : 
    7911                 : 
    7912                 : /**********************************************************************
    7913                 :  *                   TABCollection::DumpMIF()
    7914                 :  *
    7915                 :  * Dump feature geometry 
    7916                 :  **********************************************************************/
    7917               0 : void TABCollection::DumpMIF(FILE *fpOut /*=NULL*/)
    7918                 : {
    7919               0 :     if (fpOut == NULL)
    7920               0 :         fpOut = stdout;
    7921                 : 
    7922                 :     /*-----------------------------------------------------------------
    7923                 :      * Generate output
    7924                 :      *----------------------------------------------------------------*/
    7925               0 :     int numParts = 0;
    7926               0 :     if (m_poRegion)     numParts++;
    7927               0 :     if (m_poPline)      numParts++;
    7928               0 :     if (m_poMpoint)     numParts++;
    7929                 : 
    7930               0 :     fprintf(fpOut, "COLLECTION %d\n", numParts);
    7931                 : 
    7932               0 :     if (m_poRegion)
    7933               0 :         m_poRegion->DumpMIF(fpOut);
    7934                 : 
    7935               0 :     if (m_poPline)
    7936               0 :         m_poPline->DumpMIF(fpOut);
    7937                 : 
    7938               0 :     if (m_poMpoint)
    7939               0 :         m_poMpoint->DumpMIF(fpOut);
    7940                 : 
    7941                 : 
    7942               0 :     DumpSymbolDef(fpOut);
    7943                 : 
    7944               0 :     fflush(fpOut);
    7945               0 : }
    7946                 : 
    7947                 : /*=====================================================================
    7948                 :  *                      class TABDebugFeature
    7949                 :  *====================================================================*/
    7950                 : 
    7951                 : /**********************************************************************
    7952                 :  *                   TABDebugFeature::TABDebugFeature()
    7953                 :  *
    7954                 :  * Constructor.
    7955                 :  **********************************************************************/
    7956               0 : TABDebugFeature::TABDebugFeature(OGRFeatureDefn *poDefnIn):
    7957               0 :               TABFeature(poDefnIn)
    7958                 : {
    7959               0 : }
    7960                 : 
    7961                 : /**********************************************************************
    7962                 :  *                   TABDebugFeature::~TABDebugFeature()
    7963                 :  *
    7964                 :  * Destructor.
    7965                 :  **********************************************************************/
    7966               0 : TABDebugFeature::~TABDebugFeature()
    7967                 : {
    7968               0 : }
    7969                 : 
    7970                 : /**********************************************************************
    7971                 :  *                   TABDebugFeature::ReadGeometryFromMAPFile()
    7972                 :  *
    7973                 :  * Fill the geometry and representation (color, etc...) part of the
    7974                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    7975                 :  *
    7976                 :  * It is assumed that poMAPFile currently points to the beginning of
    7977                 :  * a map object.
    7978                 :  *
    7979                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    7980                 :  * been called.
    7981                 :  **********************************************************************/
    7982                 : int TABDebugFeature::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    7983                 :                                              TABMAPObjHdr *poObjHdr,
    7984                 :                                              GBool /*bCoordBlockDataOnly=FALSE*/, 
    7985               0 :                                              TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    7986                 : {
    7987                 :     TABMAPObjectBlock   *poObjBlock;
    7988                 :     TABMAPHeaderBlock   *poHeader;
    7989                 : 
    7990                 :     /*-----------------------------------------------------------------
    7991                 :      * Fetch geometry type
    7992                 :      *----------------------------------------------------------------*/
    7993               0 :     m_nMapInfoType = poObjHdr->m_nType;
    7994                 : 
    7995               0 :     poObjBlock = poMapFile->GetCurObjBlock();
    7996               0 :     poHeader = poMapFile->GetHeaderBlock();
    7997                 : 
    7998                 :     /*-----------------------------------------------------------------
    7999                 :      * If object type has coords in a type 3 block, then its position 
    8000                 :      * follows
    8001                 :      *----------------------------------------------------------------*/
    8002               0 :     if (poHeader->MapObjectUsesCoordBlock(m_nMapInfoType))
    8003                 :     {
    8004               0 :         m_nCoordDataPtr = poObjBlock->ReadInt32();
    8005               0 :         m_nCoordDataSize = poObjBlock->ReadInt32();
    8006                 :     }
    8007                 :     else
    8008                 :     {
    8009               0 :         m_nCoordDataPtr = -1;
    8010               0 :         m_nCoordDataSize = 0;
    8011                 :     }
    8012                 : 
    8013               0 :     m_nSize = poHeader->GetMapObjectSize(m_nMapInfoType);
    8014               0 :     if (m_nSize > 0)
    8015                 :     {
    8016               0 :         poObjBlock->GotoByteRel(-5);    // Go back to beginning of header
    8017               0 :         poObjBlock->ReadBytes(m_nSize, m_abyBuf);
    8018                 :     }
    8019                 : 
    8020               0 :     return 0;
    8021                 : }
    8022                 : 
    8023                 : /**********************************************************************
    8024                 :  *                   TABDebugFeature::WriteGeometryToMAPFile()
    8025                 :  *
    8026                 :  * Write the geometry and representation (color, etc...) part of the
    8027                 :  * feature to the .MAP object pointed to by poMAPFile.
    8028                 :  *
    8029                 :  * It is assumed that poMAPFile currently points to a valid map object.
    8030                 :  *
    8031                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    8032                 :  * been called.
    8033                 :  **********************************************************************/
    8034                 : int TABDebugFeature::WriteGeometryToMAPFile(TABMAPFile * /*poMapFile*/,
    8035                 :                                             TABMAPObjHdr * /*poObjHdr*/,
    8036                 :                                             GBool /*bCoordBlockDataOnly=FALSE*/, 
    8037               0 :                                             TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    8038                 : {
    8039                 :     // Nothing to do here!
    8040                 : 
    8041                 :     CPLError(CE_Failure, CPLE_NotSupported,
    8042               0 :              "TABDebugFeature::WriteGeometryToMAPFile() not implemented.\n");
    8043                 : 
    8044               0 :     return -1;
    8045                 : }
    8046                 : 
    8047                 : /**********************************************************************
    8048                 :  *                   TABDebugFeature::DumpMIF()
    8049                 :  *
    8050                 :  * Dump feature contents... available only in DEBUG mode.
    8051                 :  **********************************************************************/
    8052               0 : void TABDebugFeature::DumpMIF(FILE *fpOut /*=NULL*/)
    8053                 : {
    8054                 :     int i;
    8055                 : 
    8056               0 :     if (fpOut == NULL)
    8057               0 :         fpOut = stdout;
    8058                 : 
    8059                 :     fprintf(fpOut, "----- TABDebugFeature (type = 0x%2.2x) -----\n",
    8060               0 :             GetMapInfoType());
    8061               0 :     fprintf(fpOut, "  Object size: %d bytes\n", m_nSize);
    8062               0 :     fprintf(fpOut, "  m_nCoordDataPtr  = %d\n", m_nCoordDataPtr);
    8063               0 :     fprintf(fpOut, "  m_nCoordDataSize = %d\n", m_nCoordDataSize);
    8064               0 :     fprintf(fpOut, "  ");
    8065                 : 
    8066               0 :     for(i=0; i<m_nSize; i++)
    8067               0 :         fprintf(fpOut, " %2.2x", m_abyBuf[i]);
    8068                 : 
    8069               0 :     fprintf(fpOut, "  \n");
    8070                 : 
    8071                 : 
    8072               0 :     fflush(fpOut);
    8073               0 : }
    8074                 : 
    8075                 : 
    8076                 : /*=====================================================================
    8077                 :  *                      class ITABFeaturePen
    8078                 :  *====================================================================*/
    8079                 : 
    8080                 : /**********************************************************************
    8081                 :  *                   ITABFeaturePen::ITABFeaturePen()
    8082                 :  **********************************************************************/
    8083                 : 
    8084             102 : ITABFeaturePen::ITABFeaturePen()
    8085                 : {
    8086                 :     static const TABPenDef csDefaultPen = MITAB_PEN_DEFAULT;
    8087                 : 
    8088             102 :     m_nPenDefIndex=-1;
    8089                 : 
    8090                 :     /* MI default is PEN(1,2,0) */
    8091             102 :     m_sPenDef = csDefaultPen;
    8092             102 : }
    8093                 : 
    8094                 : 
    8095                 : /**********************************************************************
    8096                 :  *                   ITABFeaturePen::GetPenWidthPixel()
    8097                 :  *                   ITABFeaturePen::SetPenWidthPixel()
    8098                 :  *                   ITABFeaturePen::GetPenWidthPoint()
    8099                 :  *                   ITABFeaturePen::SetPenWidthPoint()
    8100                 :  *
    8101                 :  * Pen width can be expressed in pixels (value from 1 to 7 pixels) or 
    8102                 :  * in points (value from 0.1 to 203.7 points). The default pen width 
    8103                 :  * in MapInfo is 1 pixel.  Pen width in points exist only in file version 450.
    8104                 :  *
    8105                 :  * The following methods hide the way the pen width is stored in the files.
    8106                 :  *
    8107                 :  * In order to establish if a given pen def had its width specified in 
    8108                 :  * pixels or in points, one should first call GetPenWidthPoint(), and if
    8109                 :  * it returns 0 then the Pixel width should be used instead:
    8110                 :  *    if (GetPenWidthPoint() == 0)
    8111                 :  *       ... use pen width in points ...
    8112                 :  *    else
    8113                 :  *       ... use Pixel width from GetPenWidthPixel()
    8114                 :  *
    8115                 :  * Note that the reverse is not true: the default pixel width is always 1, 
    8116                 :  * even when the pen width was actually set in points.
    8117                 :  **********************************************************************/
    8118                 : 
    8119               7 : GByte ITABFeaturePen::GetPenWidthPixel()
    8120                 : {
    8121               7 :     return m_sPenDef.nPixelWidth;
    8122                 : }
    8123                 : 
    8124               0 : void  ITABFeaturePen::SetPenWidthPixel(GByte val) 
    8125                 : {
    8126               0 :     m_sPenDef.nPixelWidth = MIN(MAX(val, 1), 7);
    8127               0 :     m_sPenDef.nPointWidth = 0;
    8128               0 : }
    8129                 : 
    8130               0 : double ITABFeaturePen::GetPenWidthPoint()
    8131                 : {
    8132                 :     // We store point width internally as tenths of points
    8133               0 :     return m_sPenDef.nPointWidth/10.0;
    8134                 : }
    8135                 : 
    8136               0 : void  ITABFeaturePen::SetPenWidthPoint(double val) 
    8137                 : {
    8138               0 :     m_sPenDef.nPointWidth = MIN(MAX(((int)(val*10)), 1), 2037);
    8139               0 :     m_sPenDef.nPixelWidth = 1;
    8140               0 : }
    8141                 : 
    8142                 : /**********************************************************************
    8143                 :  *                   ITABFeaturePen::GetPenWidthMIF()
    8144                 :  *                   ITABFeaturePen::SetPenWidthMIF()
    8145                 :  *
    8146                 :  * The MIF representation for pen width is either a value from 1 to 7
    8147                 :  * for a pen width in pixels, or a value from 11 to 2047 for a pen
    8148                 :  * width in points = 10 + (point_width*10)
    8149                 :  **********************************************************************/
    8150              10 : int     ITABFeaturePen::GetPenWidthMIF()
    8151                 : {
    8152                 :     return ( m_sPenDef.nPointWidth > 0?
    8153              10 :              (m_sPenDef.nPointWidth+10): m_sPenDef.nPixelWidth );
    8154                 : }
    8155                 : 
    8156              28 : void  ITABFeaturePen::SetPenWidthMIF(int val) 
    8157                 : {
    8158              28 :     if (val > 10)
    8159                 :     {
    8160               0 :         m_sPenDef.nPointWidth = MIN((val-10), 2037);
    8161               0 :         m_sPenDef.nPixelWidth = 0;
    8162                 :     }
    8163                 :     else
    8164                 :     {
    8165              28 :         m_sPenDef.nPixelWidth = (GByte)MIN(MAX(val, 1), 7);
    8166              28 :         m_sPenDef.nPointWidth = 0;
    8167                 :     }
    8168              28 : }
    8169                 : 
    8170                 : /**********************************************************************
    8171                 :  *                   ITABFeaturePen::GetPenStyleString()
    8172                 :  *
    8173                 :  *  Return a PEN() string. All representations info for the pen are here.
    8174                 :  **********************************************************************/
    8175               7 : const char *ITABFeaturePen::GetPenStyleString()
    8176                 : {
    8177               7 :     const char *pszStyle = NULL;
    8178               7 :     int    nOGRStyle  = 0;
    8179                 :     char szPattern[20];
    8180                 :     
    8181               7 :     szPattern[0] = '\0';
    8182                 : 
    8183                 :     // For now, I only add the 25 first styles 
    8184               7 :     switch (GetPenPattern())
    8185                 :     {
    8186                 :       case 1:
    8187               0 :         nOGRStyle =1; 
    8188               0 :         break;
    8189                 :       case 2:
    8190               7 :         nOGRStyle = 0;
    8191               7 :         break;
    8192                 :       case 3:
    8193               0 :         nOGRStyle = 3; 
    8194               0 :         strcpy(szPattern,"1 1");
    8195               0 :         break;
    8196                 :       case 4:
    8197               0 :         nOGRStyle = 3;
    8198               0 :         strcpy(szPattern,"2 1");
    8199               0 :         break;
    8200                 :       case 5:
    8201               0 :         nOGRStyle = 3;
    8202               0 :         strcpy(szPattern,"3 1");
    8203               0 :         break;
    8204                 :       case 6:
    8205               0 :         nOGRStyle = 3;
    8206               0 :         strcpy(szPattern,"6 1");
    8207               0 :         break;
    8208                 :       case 7:
    8209               0 :         nOGRStyle = 4;
    8210               0 :         strcpy(szPattern,"12 2");
    8211               0 :         break;
    8212                 :       case 8:
    8213               0 :         nOGRStyle = 4;
    8214               0 :         strcpy(szPattern,"24 4");
    8215               0 :         break;
    8216                 :       case 9:
    8217               0 :         nOGRStyle = 3;
    8218               0 :         strcpy(szPattern,"4 3");
    8219               0 :         break;
    8220                 :       case 10:
    8221               0 :         nOGRStyle = 5;
    8222               0 :         strcpy(szPattern,"1 4");
    8223               0 :         break;
    8224                 :       case 11:
    8225               0 :         nOGRStyle = 3;
    8226               0 :         strcpy(szPattern,"4 6");
    8227               0 :         break;
    8228                 :       case 12:
    8229               0 :         nOGRStyle = 3;
    8230               0 :         strcpy(szPattern,"6 4");
    8231               0 :         break;
    8232                 :       case 13:
    8233               0 :         nOGRStyle = 4;
    8234               0 :         strcpy(szPattern,"12 12");
    8235               0 :         break;
    8236                 :       case 14:
    8237               0 :         nOGRStyle = 6;
    8238               0 :         strcpy(szPattern,"8 2 1 2");
    8239               0 :         break;
    8240                 :       case 15:
    8241               0 :         nOGRStyle = 6;
    8242               0 :         strcpy(szPattern,"12 1 1 1");
    8243               0 :         break;
    8244                 :       case 16:
    8245               0 :         nOGRStyle = 6;
    8246               0 :         strcpy(szPattern,"12 1 3 1");
    8247               0 :         break;
    8248                 :       case 17:
    8249               0 :         nOGRStyle = 6;
    8250               0 :         strcpy(szPattern,"24 6 4 6");
    8251               0 :         break;
    8252                 :       case 18:
    8253               0 :         nOGRStyle = 7;
    8254               0 :         strcpy(szPattern,"24 3 3 3 3 3");
    8255               0 :         break;
    8256                 :       case 19:
    8257               0 :         nOGRStyle = 7;
    8258               0 :         strcpy(szPattern,"24 3 3 3 3 3 3 3");
    8259               0 :         break;
    8260                 :       case 20:
    8261               0 :         nOGRStyle = 7;
    8262               0 :         strcpy(szPattern,"6 3 1 3 1 3");
    8263               0 :         break;
    8264                 :       case 21:
    8265               0 :         nOGRStyle = 7;
    8266               0 :         strcpy(szPattern,"12 2 1 2 1 2");
    8267               0 :         break;
    8268                 :       case 22:
    8269               0 :         nOGRStyle = 7;
    8270               0 :         strcpy(szPattern,"12 2 1 2 1 2 1 2");
    8271               0 :         break;
    8272                 :       case 23:
    8273               0 :         nOGRStyle = 6;
    8274               0 :         strcpy(szPattern,"4 1 1 1");
    8275               0 :         break;
    8276                 :       case 24:
    8277               0 :         nOGRStyle = 7;
    8278               0 :         strcpy(szPattern,"4 1 1 1 1");
    8279               0 :         break;
    8280                 :       case 25:
    8281               0 :         nOGRStyle = 6;
    8282               0 :         strcpy(szPattern,"4 1 1 1 2 1 1 1");
    8283               0 :         break;
    8284                 : 
    8285                 :         default:
    8286               0 :         nOGRStyle = 0;
    8287                 :         break;
    8288                 :     }
    8289                 : 
    8290               7 :     if (strlen(szPattern) != 0)
    8291                 :     {
    8292               0 :       if(m_sPenDef.nPointWidth > 0)
    8293                 :         pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\"mapinfo-pen-%d,"
    8294                 :                              "ogr-pen-%d\",p:\"%spx\")",
    8295                 :                              ((int)GetPenWidthPoint()),
    8296                 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
    8297               0 :                              szPattern);
    8298                 :       else
    8299                 :         pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\"mapinfo-pen-%d,"
    8300                 :                              "ogr-pen-%d\",p:\"%spx\")",
    8301                 :                              GetPenWidthPixel(),
    8302                 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
    8303               0 :                              szPattern);
    8304                 :     }
    8305                 :     else
    8306                 :     {
    8307               7 :       if(m_sPenDef.nPointWidth > 0)
    8308                 :         pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\""
    8309                 :                              "mapinfo-pen-%d,ogr-pen-%d\")",
    8310                 :                              ((int)GetPenWidthPoint()),
    8311               0 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
    8312                 :       else
    8313                 :         pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\""
    8314                 :                              "mapinfo-pen-%d,ogr-pen-%d\")",
    8315                 :                              GetPenWidthPixel(),
    8316               7 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
    8317                 :     }
    8318                 : 
    8319               7 :     return pszStyle;
    8320                 : }
    8321                 : 
    8322                 : /**********************************************************************
    8323                 :  *                   ITABFeaturePen::SetPenFromStyleString()
    8324                 :  *
    8325                 :  *  Init the Pen properties from a style string.
    8326                 :  **********************************************************************/
    8327               0 : void  ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
    8328                 : {
    8329                 :     int numParts, i;
    8330                 :     GBool bIsNull;
    8331                 : 
    8332                 :     const char *pszPenName, *pszPenPattern;
    8333                 : 
    8334                 :     double nPenWidth;
    8335                 : 
    8336                 :     GInt32 nPenColor;
    8337                 :     const char *pszPenColor;
    8338                 : 
    8339                 :     int   nPenId;
    8340                 :     char* pszPenId;
    8341                 : 
    8342                 :     // Use the Style Manager to retreive all the information we need.
    8343               0 :     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
    8344                 :     OGRStyleTool *poStylePart;
    8345                 : 
    8346                 :     // Init the StyleMgr with the StyleString.
    8347               0 :     poStyleMgr->InitStyleString(pszStyleString);
    8348                 : 
    8349                 :     // Retreive the Pen info.
    8350               0 :     numParts = poStyleMgr->GetPartCount();
    8351               0 :     for(i=0; i<numParts; i++)
    8352                 :     {
    8353               0 :         poStylePart = poStyleMgr->GetPart(i);
    8354                 : 
    8355               0 :         if(poStylePart->GetType() == OGRSTCPen)
    8356                 :         {
    8357               0 :             break;
    8358                 :         }
    8359                 :     }
    8360                 : 
    8361                 :     // If the no Pen found, do nothing.
    8362               0 :     if(i >= numParts)
    8363               0 :         return;
    8364                 : 
    8365               0 :     OGRStylePen *poPenStyle = (OGRStylePen*)poStylePart;
    8366                 : 
    8367                 :     // With Pen, we always want to output points or pixels (which are the same,
    8368                 :     // so just use points).
    8369                 :     //
    8370                 :     // It's very important to set the output unit of the feature.
    8371                 :     // The default value is meter. If we don't do it all numerical values 
    8372                 :     // will be assumed to be converted from the input unit to meter when we 
    8373                 :     // will get them via GetParam...() functions.
    8374                 :     // See OGRStyleTool::Parse() for more details.
    8375               0 :     poPenStyle->SetUnit(OGRSTUPoints, 1);
    8376                 : 
    8377                 :     // Get the Pen Id or pattern
    8378               0 :     pszPenName = poPenStyle->Id(bIsNull);
    8379               0 :     if (bIsNull) pszPenName = NULL;
    8380                 : 
    8381                 :     // Set the width
    8382               0 :     if(poPenStyle->Width(bIsNull))
    8383                 :     {
    8384               0 :         nPenWidth = poPenStyle->Width(bIsNull);
    8385                 :         // Width < 10 is a pixel
    8386               0 :         if(nPenWidth > 10)
    8387               0 :             SetPenWidthPoint(nPenWidth);
    8388                 :         else
    8389               0 :             SetPenWidthPixel((GByte)nPenWidth);
    8390                 :     }
    8391                 : 
    8392                 :     //Set the color
    8393               0 :     pszPenColor = poPenStyle->Color(bIsNull);
    8394               0 :     if(pszPenColor != NULL)
    8395                 :     {
    8396               0 :         if(pszPenColor[0] == '#')
    8397               0 :             pszPenColor++;
    8398                 :         // The Pen color is an Hexa string that need to be convert in a int
    8399               0 :         nPenColor = strtol(pszPenColor, NULL, 16);
    8400               0 :         SetPenColor(nPenColor);
    8401                 :     }
    8402                 : 
    8403                 :     // Set the Id of the Pen, use Pattern if necessary.
    8404               0 :     if(pszPenName && 
    8405                 :        (strstr(pszPenName, "mapinfo-pen-") || strstr(pszPenName, "ogr-pen-")) )
    8406                 :     {
    8407               0 :         if((pszPenId = (char *) strstr(pszPenName, "mapinfo-pen-")))
    8408                 :         {
    8409               0 :             nPenId = atoi(pszPenId+12);
    8410               0 :             SetPenPattern(nPenId);
    8411                 :         }
    8412               0 :         else if((pszPenId = (char *) strstr(pszPenName, "ogr-pen-")))
    8413                 :         {
    8414               0 :             nPenId = atoi(pszPenId+8);
    8415               0 :             if(nPenId == 0)
    8416               0 :                 nPenId = 2;
    8417               0 :             SetPenPattern(nPenId);
    8418                 :         }
    8419                 :     }
    8420                 :     else
    8421                 :     {
    8422                 :         // If no Pen Id, use the Pen Pattern to retreive the Id.
    8423               0 :         pszPenPattern = poPenStyle->Pattern(bIsNull);
    8424               0 :         if (bIsNull)
    8425               0 :             pszPenPattern = NULL;
    8426                 :         else
    8427                 :         {
    8428               0 :             if(strcmp(pszPenPattern, "1 1") == 0)
    8429               0 :                 SetPenPattern(3);
    8430               0 :             else if(strcmp(pszPenPattern, "2 1") == 0)
    8431               0 :                 SetPenPattern(4);
    8432               0 :             else if(strcmp(pszPenPattern, "3 1") == 0)
    8433               0 :                 SetPenPattern(5);
    8434               0 :             else if(strcmp(pszPenPattern, "6 1") == 0)
    8435               0 :                 SetPenPattern(6);
    8436               0 :             else if(strcmp(pszPenPattern, "12 2") == 0)
    8437               0 :                 SetPenPattern(7);
    8438               0 :             else if(strcmp(pszPenPattern, "24 4") == 0)
    8439               0 :                 SetPenPattern(8);
    8440               0 :             else if(strcmp(pszPenPattern, "4 3") == 0)
    8441               0 :                 SetPenPattern(9);
    8442               0 :             else if(strcmp(pszPenPattern, "1 4") == 0)
    8443               0 :                 SetPenPattern(10);
    8444               0 :             else if(strcmp(pszPenPattern, "4 6") == 0)
    8445               0 :                 SetPenPattern(11);
    8446               0 :             else if(strcmp(pszPenPattern, "6 4") == 0)
    8447               0 :                 SetPenPattern(12);
    8448               0 :             else if(strcmp(pszPenPattern, "12 12") == 0)
    8449               0 :                 SetPenPattern(13);
    8450               0 :             else if(strcmp(pszPenPattern, "8 2 1 2") == 0)
    8451               0 :                 SetPenPattern(14);
    8452               0 :             else if(strcmp(pszPenPattern, "12 1 1 1") == 0)
    8453               0 :                 SetPenPattern(15);
    8454               0 :             else if(strcmp(pszPenPattern, "12 1 3 1") == 0)
    8455               0 :                 SetPenPattern(16);
    8456               0 :             else if(strcmp(pszPenPattern, "24 6 4 6") == 0)
    8457               0 :                 SetPenPattern(17);
    8458               0 :             else if(strcmp(pszPenPattern, "24 3 3 3 3 3") == 0)
    8459               0 :                 SetPenPattern(18);
    8460               0 :             else if(strcmp(pszPenPattern, "24 3 3 3 3 3 3 3") == 0)
    8461               0 :                 SetPenPattern(19);
    8462               0 :             else if(strcmp(pszPenPattern, "6 3 1 3 1 3") == 0)
    8463               0 :                 SetPenPattern(20);
    8464               0 :             else if(strcmp(pszPenPattern, "12 2 1 2 1 2") == 0)
    8465               0 :                 SetPenPattern(21);
    8466               0 :             else if(strcmp(pszPenPattern, "12 2 1 2 1 2 1 2") == 0)
    8467               0 :                 SetPenPattern(22);
    8468               0 :             else if(strcmp(pszPenPattern, "4 1 1 1") == 0)
    8469               0 :                 SetPenPattern(23);
    8470               0 :             else if(strcmp(pszPenPattern, "4 1 1 1 1") == 0)
    8471               0 :                 SetPenPattern(24);
    8472               0 :             else if(strcmp(pszPenPattern, "4 1 1 1 2 1 1 1") == 0)
    8473               0 :                 SetPenPattern(25);
    8474                 :         }
    8475                 :     }
    8476                 : 
    8477               0 :     delete poStyleMgr;
    8478               0 :     delete poStylePart;
    8479                 : 
    8480               0 :     return;
    8481                 : }
    8482                 : 
    8483                 : /**********************************************************************
    8484                 :  *                   ITABFeaturePen::DumpPenDef()
    8485                 :  *
    8486                 :  * Dump pen definition information.
    8487                 :  **********************************************************************/
    8488               0 : void ITABFeaturePen::DumpPenDef(FILE *fpOut /*=NULL*/)
    8489                 : {
    8490               0 :     if (fpOut == NULL)
    8491               0 :         fpOut = stdout;
    8492                 : 
    8493               0 :     fprintf(fpOut, "  m_nPenDefIndex         = %d\n", m_nPenDefIndex);
    8494               0 :     fprintf(fpOut, "  m_sPenDef.nRefCount    = %d\n", m_sPenDef.nRefCount);
    8495               0 :     fprintf(fpOut, "  m_sPenDef.nPixelWidth  = %d\n", m_sPenDef.nPixelWidth);
    8496               0 :     fprintf(fpOut, "  m_sPenDef.nLinePattern = %d\n", m_sPenDef.nLinePattern);
    8497               0 :     fprintf(fpOut, "  m_sPenDef.nPointWidth  = %d\n", m_sPenDef.nPointWidth);
    8498                 :     fprintf(fpOut, "  m_sPenDef.rgbColor     = 0x%6.6x (%d)\n",
    8499               0 :                                      m_sPenDef.rgbColor, m_sPenDef.rgbColor);
    8500                 : 
    8501               0 :     fflush(fpOut);
    8502               0 : }
    8503                 : 
    8504                 : /*=====================================================================
    8505                 :  *                      class ITABFeatureBrush
    8506                 :  *====================================================================*/
    8507                 : 
    8508                 : /**********************************************************************
    8509                 :  *                   ITABFeatureBrush::ITABFeatureBrush()
    8510                 :  **********************************************************************/
    8511                 : 
    8512             100 : ITABFeatureBrush::ITABFeatureBrush()
    8513                 : {
    8514                 :     static const TABBrushDef csDefaultBrush = MITAB_BRUSH_DEFAULT;
    8515                 : 
    8516             100 :     m_nBrushDefIndex=-1;
    8517                 : 
    8518                 :     /* MI default is BRUSH(2,16777215,16777215) */
    8519             100 :     m_sBrushDef = csDefaultBrush;
    8520             100 : }
    8521                 : 
    8522                 : 
    8523                 : /**********************************************************************
    8524                 :  *                   ITABFeatureBrush::GetBrushStyleString()
    8525                 :  *
    8526                 :  *  Return a Brush() string. All representations info for the Brush are here.
    8527                 :  **********************************************************************/
    8528               7 : const char *ITABFeatureBrush::GetBrushStyleString()
    8529                 : {
    8530               7 :     const char *pszStyle = NULL;
    8531               7 :     int    nOGRStyle  = 0;
    8532                 :     char szPattern[20];
    8533                 :     
    8534               7 :     szPattern[0] = '\0';
    8535                 :     
    8536               7 :     if (m_sBrushDef.nFillPattern == 1)
    8537               7 :       nOGRStyle = 1;
    8538               0 :     else if (m_sBrushDef.nFillPattern == 3)
    8539               0 :       nOGRStyle = 2;
    8540               0 :     else if (m_sBrushDef.nFillPattern == 4)
    8541               0 :       nOGRStyle = 3;
    8542               0 :     else if (m_sBrushDef.nFillPattern == 5)
    8543               0 :       nOGRStyle = 5;
    8544               0 :     else if (m_sBrushDef.nFillPattern == 6)
    8545               0 :       nOGRStyle = 4;
    8546               0 :     else if (m_sBrushDef.nFillPattern == 7)
    8547               0 :       nOGRStyle = 6;
    8548               0 :     else if (m_sBrushDef.nFillPattern == 8)
    8549               0 :       nOGRStyle = 7;
    8550                 :           
    8551                 : 
    8552               7 :     if (GetBrushTransparent())
    8553                 :     {
    8554                 :         /* Omit BG Color for transparent brushes */
    8555                 :         pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
    8556                 :                              m_sBrushDef.rgbFGColor,
    8557               0 :                              m_sBrushDef.nFillPattern,nOGRStyle);
    8558                 :     }
    8559                 :     else
    8560                 :     {
    8561                 :         pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,bc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
    8562                 :                              m_sBrushDef.rgbFGColor,
    8563                 :                              m_sBrushDef.rgbBGColor,
    8564               7 :                              m_sBrushDef.nFillPattern,nOGRStyle);
    8565                 :     }
    8566                 : 
    8567               7 :      return pszStyle;
    8568                 :     
    8569                 : }  
    8570                 : 
    8571                 : 
    8572                 : /**********************************************************************
    8573                 :  *                   ITABFeatureBrush::SetBrushFromStyleString()
    8574                 :  *
    8575                 :  *  Set all Brush elements from a StyleString.
    8576                 :  *  Use StyleMgr to do so.
    8577                 :  **********************************************************************/
    8578               0 : void  ITABFeatureBrush::SetBrushFromStyleString(const char *pszStyleString)
    8579                 : {
    8580                 :     int numParts, i;
    8581                 :     GBool bIsNull;
    8582                 : 
    8583                 :     const char *pszBrushId;
    8584                 :     int nBrushId;
    8585                 : 
    8586                 :     const char *pszBrushColor;
    8587                 :     int nBrushColor;
    8588                 : 
    8589                 :     // Use the Style Manager to retreive all the information we need.
    8590               0 :     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
    8591                 :     OGRStyleTool *poStylePart;
    8592                 : 
    8593                 :     // Init the StyleMgr with the StyleString.
    8594               0 :     poStyleMgr->InitStyleString(pszStyleString);
    8595                 : 
    8596                 :     // Retreive the Brush info.
    8597               0 :     numParts = poStyleMgr->GetPartCount();
    8598               0 :     for(i=0; i<numParts; i++)
    8599                 :     {
    8600               0 :         poStylePart = poStyleMgr->GetPart(i);
    8601                 : 
    8602               0 :         if(poStylePart->GetType() == OGRSTCBrush)
    8603                 :         {
    8604               0 :             break;
    8605                 :         }
    8606                 :     }
    8607                 : 
    8608                 :     // If the no Brush found, do nothing.
    8609               0 :     if(i >= numParts)
    8610               0 :         return;
    8611                 : 
    8612               0 :     OGRStyleBrush *poBrushStyle = (OGRStyleBrush*)poStylePart;
    8613                 : 
    8614                 :     // Set the Brush Id (FillPattern)
    8615               0 :     pszBrushId = poBrushStyle->Id(bIsNull);
    8616               0 :     if(bIsNull) pszBrushId = NULL;
    8617                 : 
    8618               0 :     if(pszBrushId && 
    8619                 :        (strstr(pszBrushId, "mapinfo-brush-") || 
    8620                 :         strstr(pszBrushId, "ogr-brush-")) )
    8621                 :     {
    8622               0 :         if(strstr(pszBrushId, "mapinfo-brush-"))
    8623                 :         {
    8624               0 :             nBrushId = atoi(pszBrushId+14);
    8625               0 :             SetBrushPattern((GByte)nBrushId);
    8626                 :         }
    8627               0 :         else if(strstr(pszBrushId, "ogr-brush-"))
    8628                 :         {
    8629               0 :             nBrushId = atoi(pszBrushId+10);
    8630               0 :             if(nBrushId > 1)
    8631               0 :                 nBrushId++;
    8632               0 :             SetBrushPattern((GByte)nBrushId);
    8633                 :         }
    8634                 :     }
    8635                 : 
    8636                 :     // Set the BackColor, if not set, then it's transparent
    8637               0 :     pszBrushColor = poBrushStyle->BackColor(bIsNull);
    8638               0 :     if(bIsNull) pszBrushColor = NULL;
    8639                 : 
    8640               0 :     if(pszBrushColor)
    8641                 :     {
    8642               0 :         if(pszBrushColor[0] == '#')
    8643               0 :             pszBrushColor++;
    8644               0 :         nBrushColor = strtol(pszBrushColor, NULL, 16);
    8645               0 :         SetBrushBGColor((GInt32)nBrushColor);
    8646                 :     }
    8647                 :     else
    8648                 :     {
    8649               0 :         SetBrushTransparent(1);
    8650                 :     }
    8651                 : 
    8652                 :     // Set the ForeColor
    8653               0 :     pszBrushColor = poBrushStyle->ForeColor(bIsNull);
    8654               0 :     if(bIsNull) pszBrushColor = NULL;
    8655                 : 
    8656               0 :     if(pszBrushColor)
    8657                 :     {
    8658               0 :         if(pszBrushColor[0] == '#')
    8659               0 :             pszBrushColor++;
    8660               0 :         nBrushColor = strtol(pszBrushColor, NULL, 16);
    8661               0 :         SetBrushFGColor((GInt32)nBrushColor);
    8662                 :     }
    8663                 : 
    8664               0 :     delete poStyleMgr;
    8665               0 :     delete poStylePart;
    8666                 : 
    8667               0 :     return;
    8668                 : }  
    8669                 : 
    8670                 : /**********************************************************************
    8671                 :  *                   ITABFeatureBrush::DumpBrushDef()
    8672                 :  *
    8673                 :  * Dump Brush definition information.
    8674                 :  **********************************************************************/
    8675               0 : void ITABFeatureBrush::DumpBrushDef(FILE *fpOut /*=NULL*/)
    8676                 : {
    8677               0 :     if (fpOut == NULL)
    8678               0 :         fpOut = stdout;
    8679                 : 
    8680               0 :     fprintf(fpOut, "  m_nBrushDefIndex         = %d\n", m_nBrushDefIndex);
    8681               0 :     fprintf(fpOut, "  m_sBrushDef.nRefCount    = %d\n", m_sBrushDef.nRefCount);
    8682                 :     fprintf(fpOut, "  m_sBrushDef.nFillPattern = %d\n", 
    8683               0 :                                                 (int)m_sBrushDef.nFillPattern);
    8684                 :     fprintf(fpOut, "  m_sBrushDef.bTransparentFill = %d\n", 
    8685               0 :                                             (int)m_sBrushDef.bTransparentFill);
    8686                 :     fprintf(fpOut, "  m_sBrushDef.rgbFGColor   = 0x%6.6x (%d)\n",
    8687               0 :                                m_sBrushDef.rgbFGColor, m_sBrushDef.rgbFGColor);
    8688                 :     fprintf(fpOut, "  m_sBrushDef.rgbBGColor   = 0x%6.6x (%d)\n",
    8689               0 :                                m_sBrushDef.rgbBGColor, m_sBrushDef.rgbBGColor);
    8690                 : 
    8691               0 :     fflush(fpOut);
    8692               0 : }
    8693                 : 
    8694                 : /*=====================================================================
    8695                 :  *                      class ITABFeatureFont
    8696                 :  *====================================================================*/
    8697                 : 
    8698                 : /**********************************************************************
    8699                 :  *                   ITABFeatureFont::ITABFeatureFont()
    8700                 :  **********************************************************************/
    8701                 : 
    8702               0 : ITABFeatureFont::ITABFeatureFont()
    8703                 : {
    8704                 :     static const TABFontDef csDefaultFont = MITAB_FONT_DEFAULT;
    8705                 : 
    8706               0 :     m_nFontDefIndex=-1;
    8707                 : 
    8708                 :     /* MI default is Font("Arial",0,0,0) */
    8709               0 :     m_sFontDef = csDefaultFont;
    8710               0 : }
    8711                 : 
    8712                 : /**********************************************************************
    8713                 :  *                   ITABFeatureFont::SetFontName()
    8714                 :  **********************************************************************/
    8715               0 : void ITABFeatureFont::SetFontName(const char *pszName)
    8716                 : { 
    8717               0 :     strncpy( m_sFontDef.szFontName, pszName, 32);
    8718               0 :     m_sFontDef.szFontName[32] = '\0';  
    8719               0 : }
    8720                 : 
    8721                 : /**********************************************************************
    8722                 :  *                   ITABFeatureFont::DumpFontDef()
    8723                 :  *
    8724                 :  * Dump Font definition information.
    8725                 :  **********************************************************************/
    8726               0 : void ITABFeatureFont::DumpFontDef(FILE *fpOut /*=NULL*/)
    8727                 : {
    8728               0 :     if (fpOut == NULL)
    8729               0 :         fpOut = stdout;
    8730                 : 
    8731               0 :     fprintf(fpOut, "  m_nFontDefIndex       = %d\n", m_nFontDefIndex);
    8732               0 :     fprintf(fpOut, "  m_sFontDef.nRefCount  = %d\n", m_sFontDef.nRefCount);
    8733               0 :     fprintf(fpOut, "  m_sFontDef.szFontName = '%s'\n", m_sFontDef.szFontName);
    8734                 : 
    8735               0 :     fflush(fpOut);
    8736               0 : }
    8737                 : 
    8738                 : 
    8739                 : /*=====================================================================
    8740                 :  *                      class ITABFeatureSymbol
    8741                 :  *====================================================================*/
    8742                 : 
    8743                 : /**********************************************************************
    8744                 :  *                   ITABFeatureSymbol::ITABFeatureSymbol()
    8745                 :  **********************************************************************/
    8746                 : 
    8747               8 : ITABFeatureSymbol::ITABFeatureSymbol()
    8748                 : {
    8749                 :     static const TABSymbolDef csDefaultSymbol = MITAB_SYMBOL_DEFAULT;
    8750                 : 
    8751               8 :     m_nSymbolDefIndex=-1;
    8752                 : 
    8753                 :     /* MI default is Symbol(35,0,12) */
    8754               8 :     m_sSymbolDef = csDefaultSymbol;
    8755               8 : }
    8756                 : 
    8757                 : /**********************************************************************
    8758                 :  *                   ITABFeatureSymbol::GetSymbolStyleString()
    8759                 :  *
    8760                 :  *  Return a Symbol() string. All representations info for the Symbol are here.
    8761                 :  **********************************************************************/
    8762               0 : const char *ITABFeatureSymbol::GetSymbolStyleString(double dfAngle)
    8763                 : {
    8764               0 :     const char *pszStyle = NULL;
    8765               0 :     int    nOGRStyle  = 1;
    8766                 :     char szPattern[20];
    8767               0 :     int nAngle = 0;
    8768                 :     
    8769               0 :     szPattern[0] = '\0';
    8770                 :     
    8771               0 :     if (m_sSymbolDef.nSymbolNo == 31)
    8772               0 :       nOGRStyle = 0;
    8773               0 :     else if (m_sSymbolDef.nSymbolNo == 32)
    8774               0 :       nOGRStyle = 6;
    8775               0 :     else if (m_sSymbolDef.nSymbolNo == 33)
    8776                 :     {
    8777               0 :         nAngle = 45;
    8778               0 :         nOGRStyle = 6;
    8779                 :     }
    8780               0 :     else if (m_sSymbolDef.nSymbolNo == 34)
    8781               0 :       nOGRStyle = 4;
    8782               0 :     else if (m_sSymbolDef.nSymbolNo == 35)
    8783               0 :       nOGRStyle = 10;
    8784               0 :     else if (m_sSymbolDef.nSymbolNo == 36)
    8785               0 :       nOGRStyle = 8;
    8786               0 :     else if (m_sSymbolDef.nSymbolNo == 37)
    8787                 :     {
    8788               0 :         nAngle = 180;
    8789               0 :         nOGRStyle = 8;
    8790                 :     }
    8791               0 :     else if (m_sSymbolDef.nSymbolNo == 38)
    8792               0 :       nOGRStyle = 5;
    8793               0 :     else if (m_sSymbolDef.nSymbolNo == 39)
    8794                 :     {
    8795               0 :         nAngle = 45;
    8796               0 :         nOGRStyle = 5;
    8797                 :     }
    8798               0 :     else if (m_sSymbolDef.nSymbolNo == 40)
    8799               0 :       nOGRStyle = 3;
    8800               0 :     else if (m_sSymbolDef.nSymbolNo == 41)
    8801               0 :       nOGRStyle = 9;
    8802               0 :     else if (m_sSymbolDef.nSymbolNo == 42)
    8803               0 :       nOGRStyle = 7;
    8804               0 :     else if (m_sSymbolDef.nSymbolNo == 43)
    8805                 :     {
    8806               0 :         nAngle = 180;
    8807               0 :         nOGRStyle = 7;
    8808                 :     }
    8809               0 :     else if (m_sSymbolDef.nSymbolNo == 44)
    8810               0 :       nOGRStyle = 6;
    8811               0 :     else if (m_sSymbolDef.nSymbolNo == 45)
    8812               0 :       nOGRStyle = 8;
    8813               0 :     else if (m_sSymbolDef.nSymbolNo == 46)
    8814               0 :       nOGRStyle = 4;
    8815               0 :     else if (m_sSymbolDef.nSymbolNo == 49)
    8816               0 :       nOGRStyle = 1;
    8817               0 :     else if (m_sSymbolDef.nSymbolNo == 50)
    8818               0 :       nOGRStyle = 2;
    8819                 : 
    8820               0 :     nAngle += (int)dfAngle;
    8821                 :     
    8822                 :     pszStyle=CPLSPrintf("SYMBOL(a:%d,c:#%6.6x,s:%dpt,id:\"mapinfo-sym-%d,ogr-sym-%d\")",
    8823                 :                         nAngle,
    8824                 :                         m_sSymbolDef.rgbColor,
    8825                 :                         m_sSymbolDef.nPointSize,
    8826                 :                         m_sSymbolDef.nSymbolNo,
    8827               0 :                         nOGRStyle);
    8828                 :      
    8829               0 :     return pszStyle;
    8830                 :     
    8831                 : }  
    8832                 : 
    8833                 : /**********************************************************************
    8834                 :  *                   ITABFeatureSymbol::SetSymbolFromStyleString()
    8835                 :  *
    8836                 :  *  Set all Symbol var from a StyleString. Use StyleMgr to do so.
    8837                 :  **********************************************************************/
    8838               0 : void ITABFeatureSymbol::SetSymbolFromStyleString(const char *pszStyleString)
    8839                 : {
    8840                 :     int numParts, i;
    8841                 :     GBool bIsNull;
    8842                 : 
    8843                 :     const char *pszSymbolId;
    8844                 :     int nSymbolId;
    8845                 : 
    8846                 :     const char *pszSymbolColor;
    8847                 :     int nSymbolColor;
    8848                 : 
    8849                 :     double dSymbolSize;
    8850                 : 
    8851                 :     // Use the Style Manager to retreive all the information we need.
    8852               0 :     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
    8853                 :     OGRStyleTool *poStylePart;
    8854                 : 
    8855                 :     // Init the StyleMgr with the StyleString.
    8856               0 :     poStyleMgr->InitStyleString(pszStyleString);
    8857                 : 
    8858                 :     // Retreive the Symbol info.
    8859               0 :     numParts = poStyleMgr->GetPartCount();
    8860               0 :     for(i=0; i<numParts; i++)
    8861                 :     {
    8862               0 :         poStylePart = poStyleMgr->GetPart(i);
    8863                 : 
    8864               0 :         if(poStylePart->GetType() == OGRSTCSymbol)
    8865                 :         {
    8866               0 :             break;
    8867                 :         }
    8868                 :     }
    8869                 : 
    8870                 :     // If the no Symbol found, do nothing.
    8871               0 :     if(i >= numParts)
    8872               0 :         return;
    8873                 : 
    8874               0 :     OGRStyleSymbol *poSymbolStyle = (OGRStyleSymbol*)poStylePart;
    8875                 : 
    8876                 :     // With Symbol, we always want to output points
    8877                 :     //
    8878                 :     // It's very important to set the output unit of the feature.
    8879                 :     // The default value is meter. If we don't do it all numerical values 
    8880                 :     // will be assumed to be converted from the input unit to meter when we 
    8881                 :     // will get them via GetParam...() functions.
    8882                 :     // See OGRStyleTool::Parse() for more details.
    8883               0 :     poSymbolStyle->SetUnit(OGRSTUPoints, (72.0 * 39.37));
    8884                 : 
    8885                 :     // Set the Symbol Id (SymbolNo)
    8886               0 :     pszSymbolId = poSymbolStyle->Id(bIsNull);
    8887               0 :     if(bIsNull) pszSymbolId = NULL;
    8888                 : 
    8889               0 :     if(pszSymbolId &&  
    8890                 :        (strstr(pszSymbolId, "mapinfo-sym-") || 
    8891                 :         strstr(pszSymbolId, "ogr-sym-")) )
    8892                 :     {
    8893               0 :         if(strstr(pszSymbolId, "mapinfo-sym-"))
    8894                 :         {
    8895               0 :             nSymbolId = atoi(pszSymbolId+12);
    8896               0 :             SetSymbolNo((GByte)nSymbolId);
    8897                 :         }
    8898               0 :         else if(strstr(pszSymbolId, "ogr-sym-"))
    8899                 :         {
    8900               0 :             nSymbolId = atoi(pszSymbolId+8);
    8901                 : 
    8902                 :             // The OGR symbol is not the MapInfo one
    8903                 :             // Here's some mapping
    8904               0 :             switch (nSymbolId)
    8905                 :             {
    8906                 :               case 0:
    8907               0 :                 SetSymbolNo(31);
    8908               0 :                 break;
    8909                 :               case 1:
    8910               0 :                 SetSymbolNo(49);
    8911               0 :                 break;
    8912                 :               case 2:
    8913               0 :                 SetSymbolNo(50);
    8914               0 :                 break;
    8915                 :               case 3:
    8916               0 :                 SetSymbolNo(40);
    8917               0 :                 break;
    8918                 :               case 4:
    8919               0 :                 SetSymbolNo(34);
    8920               0 :                 break;
    8921                 :               case 5:
    8922               0 :                 SetSymbolNo(38);
    8923               0 :                 break;
    8924                 :               case 6:
    8925               0 :                 SetSymbolNo(32);
    8926               0 :                 break;
    8927                 :               case 7:
    8928               0 :                 SetSymbolNo(42);
    8929               0 :                 break;
    8930                 :               case 8:
    8931               0 :                 SetSymbolNo(36);
    8932               0 :                 break;
    8933                 :               case 9:
    8934               0 :                 SetSymbolNo(41);
    8935               0 :                 break;
    8936                 :               case 10:
    8937               0 :                 SetSymbolNo(35);
    8938                 :                 break;
    8939                 :             }
    8940                 :         }
    8941                 :     }
    8942                 : 
    8943                 :     // Set SymbolSize
    8944               0 :     dSymbolSize = poSymbolStyle->Size(bIsNull);
    8945               0 :     if(dSymbolSize)
    8946                 :     {
    8947               0 :         SetSymbolSize((GInt32)dSymbolSize);
    8948                 :     }
    8949                 : 
    8950                 :     // Set Symbol Color
    8951               0 :     pszSymbolColor = poSymbolStyle->Color(bIsNull);
    8952               0 :     if(pszSymbolColor)
    8953                 :     {
    8954               0 :         if(pszSymbolColor[0] == '#')
    8955               0 :             pszSymbolColor++;
    8956               0 :         nSymbolColor = strtol(pszSymbolColor, NULL, 16);
    8957               0 :         SetSymbolColor((GInt32)nSymbolColor);
    8958                 :     }
    8959                 : 
    8960               0 :     delete poStyleMgr;
    8961               0 :     delete poStylePart;
    8962                 :     
    8963               0 :     return;
    8964                 : }  
    8965                 : 
    8966                 : /**********************************************************************
    8967                 :  *                   ITABFeatureSymbol::DumpSymbolDef()
    8968                 :  *
    8969                 :  * Dump Symbol definition information.
    8970                 :  **********************************************************************/
    8971               0 : void ITABFeatureSymbol::DumpSymbolDef(FILE *fpOut /*=NULL*/)
    8972                 : {
    8973               0 :     if (fpOut == NULL)
    8974               0 :         fpOut = stdout;
    8975                 : 
    8976               0 :     fprintf(fpOut, "  m_nSymbolDefIndex       = %d\n", m_nSymbolDefIndex);
    8977               0 :     fprintf(fpOut, "  m_sSymbolDef.nRefCount  = %d\n", m_sSymbolDef.nRefCount);
    8978               0 :     fprintf(fpOut, "  m_sSymbolDef.nSymbolNo  = %d\n", m_sSymbolDef.nSymbolNo);
    8979               0 :     fprintf(fpOut, "  m_sSymbolDef.nPointSize = %d\n",m_sSymbolDef.nPointSize);
    8980                 :     fprintf(fpOut, "  m_sSymbolDef._unknown_  = %d\n", 
    8981               0 :                                             (int)m_sSymbolDef._nUnknownValue_);
    8982                 :     fprintf(fpOut, "  m_sSymbolDef.rgbColor   = 0x%6.6x (%d)\n",
    8983               0 :                                 m_sSymbolDef.rgbColor, m_sSymbolDef.rgbColor);
    8984                 : 
    8985               0 :     fflush(fpOut);
    8986               0 : }

Generated by: LTP GCOV extension version 1.5