LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/mitab - mitab_feature.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 3025 435 14.4 %
Date: 2012-12-26 Functions: 243 41 16.9 %

       1                 : /**********************************************************************
       2                 :  * $Id: mitab_feature.cpp,v 1.100 2010-10-12 19:55:32 aboudreault 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.100  2010-10-12 19:55:32  aboudreault
      34                 :  * Fixed style string ID parameter to use the proper delimiter as per OGR Feature Style Specification
      35                 :  *
      36                 :  * Revision 1.99  2010-10-08 19:36:44  aboudreault
      37                 :  * Fixed memory leak (GDAL bug #3045)
      38                 :  *
      39                 :  * Revision 1.98  2010-07-07 19:00:15  aboudreault
      40                 :  * Cleanup Win32 Compile Warnings (GDAL bug #2930)
      41                 :  *
      42                 :  * Revision 1.97  2010-07-06 13:56:26  aboudreault
      43                 :  * Fixed TABText::GetLabelStyleString() doesn't escape the double quote character (bug 2236)
      44                 :  *
      45                 :  * Revision 1.96  2009-07-30 13:13:43  dmorissette
      46                 :  * Fixed incorrect text justification returned by GetLabelStyleString()
      47                 :  * for TABTJRight (bug 2085)
      48                 :  *
      49                 :  * Revision 1.95  2008-11-27 20:50:22  aboudreault
      50                 :  * Improved support for OGR date/time types. New Read/Write methods (bug 1948)
      51                 :  * Added support of OGR date/time types for MIF features.
      52                 :  *
      53                 :  * Revision 1.94  2008/11/18 16:47:44  dmorissette
      54                 :  * Fixed compile warning when MITAB_USE_OFTDATETIME is set
      55                 :  *
      56                 :  * Revision 1.93  2008/11/17 22:06:21  aboudreault
      57                 :  * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
      58                 :  * OGR and fixed reading/writing support for these types.
      59                 :  *
      60                 :  * Revision 1.92  2008/07/29 13:06:17  aboudreault
      61                 :  * Added Font Point styles support (halo, border) (bug 1925)
      62                 :  *
      63                 :  * Revision 1.91  2008/07/21 19:23:03  aboudreault
      64                 :  * Fixed another small error with expanded text.
      65                 :  *
      66                 :  * Revision 1.90  2008/07/21 18:17:19  dmorissette
      67                 :  * Fixed a few compile warnings
      68                 :  *
      69                 :  * Revision 1.89  2008/07/21 17:59:28  aboudreault
      70                 :  * Fixed error in GetLabelStyleString() function: when text style expanded is
      71                 :  * set, no space is needed after the last char.
      72                 :  *
      73                 :  * Revision 1.88  2008/07/21 14:09:41  aboudreault
      74                 :  * Add font text styles support (bold, italic, etc.) (bug 1922)
      75                 :  *
      76                 :  * Revision 1.87  2008/07/17 14:09:30  aboudreault
      77                 :  * Add text outline color support (halo background in MapInfo)
      78                 :  *
      79                 :  * Revision 1.86  2008/07/14 17:51:21  aboudreault
      80                 :  * Fixed the text font size problem (bug 1918)
      81                 :  *
      82                 :  * Revision 1.85  2008/07/14 16:09:10  aboudreault
      83                 :  * Fixed multi-line text height problem (bug 1919)
      84                 :  *
      85                 :  * Revision 1.84  2008/07/14 14:39:52  aboudreault
      86                 :  * Fixed multi-line text rendering by adding support of the end of line char
      87                 :  * "\n" as well as the "\\n".
      88                 :  *
      89                 :  * Revision 1.83  2008/07/01 14:33:17  aboudreault
      90                 :  * * Fixed deprecated warnings generated by mitab.h by moving SetFontName to
      91                 :  *   mitab_feature.cpp.
      92                 :  *
      93                 :  * Revision 1.82  2008/02/22 20:20:44  dmorissette
      94                 :  * Fixed the internal compressed coordinate range detection test to prevent
      95                 :  * possible overflow of the compressed integer coordinate values leading
      96                 :  * to some coord. errors in very rare cases while writing to TAB (bug 1854)
      97                 :  *
      98                 :  * Revision 1.81  2008/02/20 21:35:30  dmorissette
      99                 :  * Added support for V800 COLLECTION of large objects (bug 1496)
     100                 :  *
     101                 :  * Revision 1.80  2008/02/05 22:22:48  dmorissette
     102                 :  * Added support for TAB_GEOM_V800_MULTIPOINT (bug 1496)
     103                 :  *
     104                 :  * Revision 1.79  2008/02/01 19:36:31  dmorissette
     105                 :  * Initial support for V800 REGION and MULTIPLINE (bug 1496)
     106                 :  *
     107                 :  * Revision 1.78  2008/01/29 20:46:32  dmorissette
     108                 :  * Added support for v9 Time and DateTime fields (byg 1754)
     109                 :  *
     110                 :  * Revision 1.77  2007/12/11 04:21:54  dmorissette
     111                 :  * Fixed leaks in ITABFeature???::Set???FromStyleString() (GDAL ticket 1696)
     112                 :  *
     113                 :  * Revision 1.76  2007/09/18 17:43:56  dmorissette
     114                 :  * Fixed another index splitting issue: compr coordinates origin was not
     115                 :  * stored in the TABFeature in ReadGeometry... (bug 1732)
     116                 :  *
     117                 :  * Revision 1.75  2007/09/14 19:29:24  dmorissette
     118                 :  * Completed handling of bCoordBlockDataOnly arg to Read/WriteGeometry()
     119                 :  * functions to avoid screwing up pen/brush ref counters (bug 1732)
     120                 :  *
     121                 :  * Revision 1.74  2007/09/14 18:30:19  dmorissette
     122                 :  * Fixed the splitting of object blocks with the optimized spatial
     123                 :  * index mode that was producing files with misaligned bytes that
     124                 :  * confused MapInfo (bug 1732)
     125                 :  *
     126                 :  * Revision 1.73  2007/09/12 20:22:31  dmorissette
     127                 :  * Added TABFeature::CreateFromMapInfoType()
     128                 :  *
     129                 :  * Revision 1.72  2007/06/12 14:17:16  dmorissette
     130                 :  * Added TABFile::TwoPointLineAsPolyline() to allow writing two point lines
     131                 :  * as polylines (bug 1735)
     132                 :  *
     133                 :  * Revision 1.71  2007/06/11 17:57:06  dmorissette
     134                 :  * Removed stray calls to poMapFile->GetCurObjBlock()
     135                 :  *
     136                 :  * Revision 1.70  2007/06/11 14:52:30  dmorissette
     137                 :  * Return a valid m_nCoordDatasize value for Collection objects to prevent
     138                 :  * trashing of collection data during object splitting (bug 1728)
     139                 :  *
     140                 :  * Revision 1.69  2007/02/28 20:41:40  dmorissette
     141                 :  * Added missing NULL pointer checks in SetPenFromStyleString(),
     142                 :  * SetBrushFromStyleString() and SetSymbolFromStyleString() (bug 1670)
     143                 :  *
     144                 :  * Revision 1.68  2007/02/22 18:35:53  dmorissette
     145                 :  * Fixed problem writing collections where MITAB was sometimes trying to
     146                 :  * read past EOF in write mode (bug 1657).
     147                 :  *
     148                 :  * Revision 1.67  2006/11/28 18:49:07  dmorissette
     149                 :  * Completed changes to split TABMAPObjectBlocks properly and produce an
     150                 :  * optimal spatial index (bug 1585)
     151                 :  *
     152                 :  * Revision 1.66  2006/10/17 14:34:31  dmorissette
     153                 :  * Fixed problem with null brush bg color (bug 1603)
     154                 :  *
     155                 :  * Revision 1.65  2006/07/25 13:22:58  dmorissette
     156                 :  * Fixed initialization of MBR of TABCollection members (bug 1520)
     157                 :  *
     158                 :  * Revision 1.64  2006/06/29 19:49:35  dmorissette
     159                 :  * Fixed problem writing PLINE MULTIPLE to TAB format introduced in
     160                 :  * MITAB 1.5.0 (bug 1466).
     161                 :  *
     162                 :  * Revision 1.63  2006/02/08 05:02:57  dmorissette
     163                 :  * Fixed crash when attempting to write TABPolyline object with an invalid
     164                 :  * geometry (GDAL bug 1059)
     165                 :  *
     166                 :  * ...
     167                 :  *
     168                 :  * Revision 1.1  1999/07/12 04:18:24  daniel
     169                 :  * Initial checkin
     170                 :  *
     171                 :  **********************************************************************/
     172                 : 
     173                 : #include "mitab.h"
     174                 : #include "mitab_utils.h"
     175                 : #include "mitab_geometry.h"
     176                 : 
     177                 : /*=====================================================================
     178                 :  *                      class TABFeature
     179                 :  *====================================================================*/
     180                 : 
     181                 : 
     182                 : /**********************************************************************
     183                 :  *                   TABFeature::TABFeature()
     184                 :  *
     185                 :  * Constructor.
     186                 :  **********************************************************************/
     187             132 : TABFeature::TABFeature(OGRFeatureDefn *poDefnIn):
     188             132 :                OGRFeature(poDefnIn)
     189                 : {
     190             132 :     m_nMapInfoType = TAB_GEOM_NONE;
     191             132 :     m_bDeletedFlag = FALSE;
     192                 : 
     193             132 :     SetMBR(0.0, 0.0, 0.0, 0.0);
     194             132 : }
     195                 : 
     196                 : /**********************************************************************
     197                 :  *                   TABFeature::~TABFeature()
     198                 :  *
     199                 :  * Destructor.
     200                 :  **********************************************************************/
     201             132 : TABFeature::~TABFeature()
     202                 : {
     203             132 : }
     204                 : 
     205                 : 
     206                 : /**********************************************************************
     207                 :  *                     TABFeature::CreateFromMapInfoType()
     208                 :  *
     209                 :  * Factory that creates a TABFeature of the right class for the specified
     210                 :  * MapInfo Type
     211                 :  *
     212                 :  **********************************************************************/
     213              53 : TABFeature *TABFeature::CreateFromMapInfoType(int nMapInfoType,
     214                 :                                               OGRFeatureDefn *poDefn)
     215                 : {
     216              53 :     TABFeature *poFeature = NULL;
     217                 : 
     218                 :     /*-----------------------------------------------------------------
     219                 :      * Create new feature object of the right type
     220                 :      *----------------------------------------------------------------*/
     221              53 :     switch(nMapInfoType)
     222                 :     {
     223                 :       case TAB_GEOM_NONE:
     224               1 :         poFeature = new TABFeature(poDefn);
     225               1 :         break;
     226                 :       case TAB_GEOM_SYMBOL_C:
     227                 :       case TAB_GEOM_SYMBOL:
     228               0 :         poFeature = new TABPoint(poDefn);
     229               0 :         break;
     230                 :       case TAB_GEOM_FONTSYMBOL_C:
     231                 :       case TAB_GEOM_FONTSYMBOL:
     232               0 :         poFeature = new TABFontPoint(poDefn);
     233               0 :         break;
     234                 :       case TAB_GEOM_CUSTOMSYMBOL_C:
     235                 :       case TAB_GEOM_CUSTOMSYMBOL:
     236               0 :         poFeature = new TABCustomPoint(poDefn);
     237               0 :         break;
     238                 :       case TAB_GEOM_LINE_C:
     239                 :       case TAB_GEOM_LINE:
     240                 :       case TAB_GEOM_PLINE_C:
     241                 :       case TAB_GEOM_PLINE:
     242                 :       case TAB_GEOM_MULTIPLINE_C:
     243                 :       case TAB_GEOM_MULTIPLINE:
     244                 :       case TAB_GEOM_V450_MULTIPLINE_C:
     245                 :       case TAB_GEOM_V450_MULTIPLINE:
     246                 :       case TAB_GEOM_V800_MULTIPLINE_C:
     247                 :       case TAB_GEOM_V800_MULTIPLINE:
     248               1 :        poFeature = new TABPolyline(poDefn);
     249               1 :         break;
     250                 :       case TAB_GEOM_ARC_C:
     251                 :       case TAB_GEOM_ARC:
     252               0 :         poFeature = new TABArc(poDefn);
     253               0 :         break;
     254                 : 
     255                 :       case TAB_GEOM_REGION_C:
     256                 :       case TAB_GEOM_REGION:
     257                 :       case TAB_GEOM_V450_REGION_C:
     258                 :       case TAB_GEOM_V450_REGION:
     259                 :       case TAB_GEOM_V800_REGION_C:
     260                 :       case TAB_GEOM_V800_REGION:
     261              51 :         poFeature = new TABRegion(poDefn);
     262              51 :         break;
     263                 :       case TAB_GEOM_RECT_C:
     264                 :       case TAB_GEOM_RECT:
     265                 :       case TAB_GEOM_ROUNDRECT_C:
     266                 :       case TAB_GEOM_ROUNDRECT:
     267               0 :         poFeature = new TABRectangle(poDefn);
     268               0 :         break;
     269                 :       case TAB_GEOM_ELLIPSE_C:
     270                 :       case TAB_GEOM_ELLIPSE:
     271               0 :         poFeature = new TABEllipse(poDefn);
     272               0 :         break;
     273                 :       case TAB_GEOM_TEXT_C:
     274                 :       case TAB_GEOM_TEXT:
     275               0 :         poFeature = new TABText(poDefn);
     276               0 :         break;
     277                 :       case TAB_GEOM_MULTIPOINT_C:
     278                 :       case TAB_GEOM_MULTIPOINT:
     279                 :       case TAB_GEOM_V800_MULTIPOINT_C:
     280                 :       case TAB_GEOM_V800_MULTIPOINT:
     281               0 :         poFeature = new TABMultiPoint(poDefn);
     282               0 :         break;
     283                 :       case TAB_GEOM_COLLECTION_C:
     284                 :       case TAB_GEOM_COLLECTION:
     285                 :       case TAB_GEOM_V800_COLLECTION_C:
     286                 :       case TAB_GEOM_V800_COLLECTION:
     287               0 :         poFeature = new TABCollection(poDefn);  
     288               0 :         break;
     289                 :       default:
     290                 :         /*-------------------------------------------------------------
     291                 :          * Unsupported feature type... we still return a valid feature
     292                 :          * with NONE geometry after producing a Warning.
     293                 :          * Callers can trap that case by checking CPLGetLastErrorNo() 
     294                 :          * against TAB_WarningFeatureTypeNotSupported
     295                 :          *------------------------------------------------------------*/
     296                 : //        poFeature = new TABDebugFeature(poDefn);
     297               0 :         poFeature = new TABFeature(poDefn);
     298                 : 
     299                 :         CPLError(CE_Warning, TAB_WarningFeatureTypeNotSupported,
     300                 :                  "Unsupported object type %d (0x%2.2x).  Feature will be "
     301                 :                  "returned with NONE geometry.",
     302               0 :                  nMapInfoType, nMapInfoType);
     303                 :     }
     304                 : 
     305              53 :     return poFeature;
     306                 : }
     307                 : 
     308                 : 
     309                 : /**********************************************************************
     310                 :  *                     TABFeature::CopyTABFeatureBase()
     311                 :  *
     312                 :  * Used by CloneTABFeature() to copy the basic (fields, geometry, etc.)
     313                 :  * TABFeature members.
     314                 :  *
     315                 :  * The newly created feature is owned by the caller, and will have it's own
     316                 :  * reference to the OGRFeatureDefn.
     317                 :  *
     318                 :  * It is possible to create the clone with a different OGRFeatureDefn,
     319                 :  * in this case, the fields won't be copied of course.
     320                 :  *
     321                 :  **********************************************************************/
     322               0 : void TABFeature::CopyTABFeatureBase(TABFeature *poDestFeature)
     323                 : {
     324                 :     /*-----------------------------------------------------------------
     325                 :      * Copy fields only if OGRFeatureDefn is the same
     326                 :      *----------------------------------------------------------------*/
     327               0 :     OGRFeatureDefn *poThisDefnRef = GetDefnRef();
     328                 : 
     329               0 :     if (poThisDefnRef == poDestFeature->GetDefnRef())
     330                 :     {
     331               0 :         for( int i = 0; i < poThisDefnRef->GetFieldCount(); i++ )
     332                 :         {
     333               0 :             poDestFeature->SetField( i, GetRawFieldRef( i ) );
     334                 :         }
     335                 :     }
     336                 : 
     337                 :     /*-----------------------------------------------------------------
     338                 :      * Copy the geometry
     339                 :      *----------------------------------------------------------------*/
     340               0 :     poDestFeature->SetGeometry( GetGeometryRef() );
     341                 : 
     342                 :     double dXMin, dYMin, dXMax, dYMax;
     343               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
     344               0 :     poDestFeature->SetMBR(dXMin, dYMin, dXMax, dYMax);
     345                 : 
     346                 :     GInt32 nXMin, nYMin, nXMax, nYMax;
     347               0 :     GetIntMBR(nXMin, nYMin, nXMax, nYMax);
     348               0 :     poDestFeature->SetIntMBR(nXMin, nYMin, nXMax, nYMax);
     349                 : 
     350                 :     // m_nMapInfoType is not carried but it is not required anyways.
     351                 :     // it will default to TAB_GEOM_NONE
     352               0 : }
     353                 : 
     354                 : 
     355                 : /**********************************************************************
     356                 :  *                     TABFeature::CloneTABFeature()
     357                 :  *
     358                 :  * Duplicate feature, including stuff specific to each TABFeature type.
     359                 :  *
     360                 :  * The newly created feature is owned by the caller, and will have it's own
     361                 :  * reference to the OGRFeatureDefn.
     362                 :  *
     363                 :  * It is possible to create the clone with a different OGRFeatureDefn,
     364                 :  * in this case, the fields won't be copied of course.
     365                 :  *
     366                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
     367                 :  * then copies any members specific to its own type.
     368                 :  **********************************************************************/
     369               0 : TABFeature *TABFeature::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
     370                 : {
     371                 :     /*-----------------------------------------------------------------
     372                 :      * Alloc new feature and copy the base stuff
     373                 :      *----------------------------------------------------------------*/
     374               0 :     TABFeature *poNew = new TABFeature(poNewDefn ? poNewDefn : GetDefnRef());
     375                 : 
     376               0 :     CopyTABFeatureBase(poNew);
     377                 : 
     378                 :     /*-----------------------------------------------------------------
     379                 :      * And members specific to this class
     380                 :      *----------------------------------------------------------------*/
     381                 :     // Nothing to do for this class
     382                 : 
     383               0 :     return poNew;
     384                 : }
     385                 : 
     386                 : /**********************************************************************
     387                 :  *                   TABFeature::SetMBR()
     388                 :  *
     389                 :  * Set the values for the MBR corners for this feature.
     390                 :  **********************************************************************/
     391             216 : void TABFeature::SetMBR(double dXMin, double dYMin, 
     392                 :                         double dXMax, double dYMax)
     393                 : {
     394             216 :     m_dXMin = MIN(dXMin, dXMax);
     395             216 :     m_dYMin = MIN(dYMin, dYMax);
     396             216 :     m_dXMax = MAX(dXMin, dXMax);
     397             216 :     m_dYMax = MAX(dYMin, dYMax);
     398             216 : }
     399                 : 
     400                 : /**********************************************************************
     401                 :  *                   TABFeature::GetMBR()
     402                 :  *
     403                 :  * Return the values for the MBR corners for this feature.
     404                 :  **********************************************************************/
     405               0 : void TABFeature::GetMBR(double &dXMin, double &dYMin, 
     406                 :                         double &dXMax, double &dYMax)
     407                 : {
     408               0 :     dXMin = m_dXMin;
     409               0 :     dYMin = m_dYMin;
     410               0 :     dXMax = m_dXMax;
     411               0 :     dYMax = m_dYMax;
     412               0 : }
     413                 : 
     414                 : /**********************************************************************
     415                 :  *                   TABFeature::SetIntMBR()
     416                 :  *
     417                 :  * Set the integer coordinates values of the MBR of this feature.
     418                 :  **********************************************************************/
     419              52 : void TABFeature::SetIntMBR(GInt32 nXMin, GInt32 nYMin, 
     420                 :                            GInt32 nXMax, GInt32 nYMax)
     421                 : {
     422              52 :     m_nXMin = nXMin;
     423              52 :     m_nYMin = nYMin;
     424              52 :     m_nXMax = nXMax;
     425              52 :     m_nYMax = nYMax;
     426              52 : }
     427                 : 
     428                 : /**********************************************************************
     429                 :  *                   TABFeature::GetIntMBR()
     430                 :  *
     431                 :  * Return the integer coordinates values of the MBR of this feature.
     432                 :  **********************************************************************/
     433              12 : void TABFeature::GetIntMBR(GInt32 &nXMin, GInt32 &nYMin, 
     434                 :                            GInt32 &nXMax, GInt32 &nYMax)
     435                 : {
     436              12 :     nXMin = m_nXMin;
     437              12 :     nYMin = m_nYMin;
     438              12 :     nXMax = m_nXMax;
     439              12 :     nYMax = m_nYMax;
     440              12 : }
     441                 : 
     442                 : /**********************************************************************
     443                 :  *                   TABFeature::ReadRecordFromDATFile()
     444                 :  *
     445                 :  * Fill the fields part of the feature from the contents of the 
     446                 :  * table record pointed to by poDATFile.
     447                 :  *
     448                 :  * It is assumed that poDATFile currently points to the beginning of
     449                 :  * the table record and that this feature's OGRFeatureDefn has been 
     450                 :  * properly initialized for this table.
     451                 :  **********************************************************************/
     452              53 : int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
     453                 : {
     454                 :     int         iField, numFields, nValue;
     455                 :     double      dValue;
     456                 :     const char *pszValue;
     457                 : #ifdef MITAB_USE_OFTDATETIME
     458                 :     int nYear, nMonth, nDay, nHour, nMin, nSec, nMS, status;
     459              53 :     nYear = nMonth = nDay = nHour = nMin = nSec = nMS = 0;
     460                 : #endif
     461                 : 
     462              53 :     CPLAssert(poDATFile);
     463                 : 
     464              53 :     numFields = poDATFile->GetNumFields();
     465                 : 
     466             206 :     for(iField=0; iField<numFields; iField++)
     467                 :     {
     468             153 :         switch(poDATFile->GetFieldType(iField))
     469                 :         {
     470                 :           case TABFChar:
     471                 :             pszValue = poDATFile->ReadCharField(poDATFile->
     472              53 :                                                 GetFieldWidth(iField));
     473              53 :             SetField(iField, pszValue);
     474              53 :             break;
     475                 :           case TABFDecimal:
     476                 :             dValue = poDATFile->ReadDecimalField(poDATFile->
     477               0 :                                                  GetFieldWidth(iField));
     478               0 :             SetField(iField, dValue);
     479               0 :             break;
     480                 :           case TABFInteger:
     481                 :             nValue = poDATFile->ReadIntegerField(poDATFile->
     482              50 :                                                  GetFieldWidth(iField));
     483              50 :             SetField(iField, nValue);
     484              50 :             break;
     485                 :           case TABFSmallInt:
     486                 :             nValue = poDATFile->ReadSmallIntField(poDATFile->
     487               0 :                                                  GetFieldWidth(iField));
     488               0 :             SetField(iField, nValue);
     489               0 :             break;
     490                 :           case TABFFloat:
     491                 :             dValue = poDATFile->ReadFloatField(poDATFile->
     492              50 :                                                  GetFieldWidth(iField));
     493              50 :             SetField(iField, dValue);
     494              50 :             break;
     495                 :           case TABFLogical:
     496                 :             pszValue = poDATFile->ReadLogicalField(poDATFile->
     497               0 :                                                  GetFieldWidth(iField));
     498               0 :             SetField(iField, pszValue);
     499               0 :             break;
     500                 :           case TABFDate:
     501                 : #ifdef MITAB_USE_OFTDATETIME
     502               0 :              if ((status = poDATFile->ReadDateField(poDATFile->GetFieldWidth(iField),
     503                 :                                                     &nYear, &nMonth, &nDay)) == 0)
     504                 :              {
     505               0 :                 SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
     506                 :              }
     507                 : #else
     508                 :             pszValue = poDATFile->ReadDateField(poDATFile->
     509                 :                                             GetFieldWidth(iField));
     510                 :             SetField(iField, pszValue);
     511                 : #endif
     512               0 :             break;
     513                 :           case TABFTime:
     514                 : #ifdef MITAB_USE_OFTDATETIME
     515               0 :              if ((status = poDATFile->ReadTimeField(poDATFile->GetFieldWidth(iField),
     516                 :                                                     &nHour, &nMin, &nSec, &nMS)) == 0)
     517                 :              {
     518               0 :                 SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
     519                 :              }
     520                 : #else
     521                 :              pszValue = poDATFile->ReadTimeField(poDATFile->
     522                 :                                                      GetFieldWidth(iField));
     523                 :              SetField(iField, pszValue);
     524                 : #endif
     525               0 :             break;
     526                 :           case TABFDateTime:
     527                 : #ifdef MITAB_USE_OFTDATETIME
     528               0 :             if ((status = poDATFile->ReadDateTimeField(poDATFile->GetFieldWidth(iField),
     529                 :                                                        &nYear, &nMonth, &nDay,
     530                 :                                                        &nHour, &nMin, &nSec, &nMS)) == 0)
     531                 :             {
     532               0 :                SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
     533                 :             }
     534                 : #else
     535                 :             pszValue = poDATFile->ReadDateTimeField(poDATFile->
     536                 :                                                     GetFieldWidth(iField));
     537                 :             SetField(iField, pszValue);
     538                 : #endif
     539               0 :             break;
     540                 :           default:
     541                 :             // Other type???  Impossible!
     542                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     543               0 :                      "Unsupported field type!");
     544                 :         }
     545                 :         
     546                 :     }
     547                 : 
     548              53 :     return 0;
     549                 : }
     550                 : 
     551                 : /**********************************************************************
     552                 :  *                   TABFeature::WriteRecordToDATFile()
     553                 :  *
     554                 :  * Write the attribute part of the feature to the .DAT file.
     555                 :  *
     556                 :  * It is assumed that poDATFile currently points to the beginning of
     557                 :  * the table record and that this feature's OGRFeatureDefn has been 
     558                 :  * properly initialized for this table.
     559                 :  *
     560                 :  * Returns 0 on success, -1 on error.
     561                 :  **********************************************************************/
     562              14 : int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
     563                 :                                      TABINDFile *poINDFile, int *panIndexNo)
     564                 : {
     565              14 :     int         iField, numFields, nStatus=0;
     566                 : #ifdef MITAB_USE_OFTDATETIME
     567                 :     int         nYear, nMon, nDay, nHour, nMin, nSec, nTZFlag;
     568              14 :     nYear = nMon = nDay = nHour = nMin = nSec = nTZFlag = 0;
     569                 : #endif
     570                 : 
     571              14 :     CPLAssert(poDATFile);
     572              14 :     CPLAssert(panIndexNo || GetDefnRef()->GetFieldCount() == 0);
     573                 : 
     574              14 :     numFields = poDATFile->GetNumFields();
     575                 : 
     576              51 :     for(iField=0; nStatus == 0 && iField<numFields; iField++)
     577                 :     {
     578                 :         // Hack for "extra" introduced field.
     579              37 :         if( iField >= GetDefnRef()->GetFieldCount() )
     580                 :         {
     581                 :             CPLAssert( poDATFile->GetFieldType(iField) == TABFInteger 
     582               0 :                        && iField == 0 );
     583               0 :             nStatus = poDATFile->WriteIntegerField( GetFID(), poINDFile, 0 );
     584               0 :             continue;
     585                 :         }
     586                 : 
     587              37 :         switch(poDATFile->GetFieldType(iField))
     588                 :         {
     589                 :           case TABFChar:
     590                 :             nStatus = poDATFile->WriteCharField(GetFieldAsString(iField),
     591                 :                                       poDATFile->GetFieldWidth(iField),
     592              13 :                                                 poINDFile, panIndexNo[iField]);
     593              13 :             break;
     594                 :           case TABFDecimal:
     595                 :             nStatus = poDATFile->WriteDecimalField(GetFieldAsDouble(iField),
     596                 :                                       poDATFile->GetFieldWidth(iField),
     597                 :                                       poDATFile->GetFieldPrecision(iField),
     598               1 :                                              poINDFile, panIndexNo[iField]);
     599               1 :             break;
     600                 :           case TABFInteger:
     601                 :             nStatus = poDATFile->WriteIntegerField(GetFieldAsInteger(iField),
     602              12 :                                                 poINDFile, panIndexNo[iField]);
     603              12 :             break;
     604                 :           case TABFSmallInt:
     605                 :             nStatus = poDATFile->WriteSmallIntField((GInt16)GetFieldAsInteger(iField),
     606               0 :                                                 poINDFile, panIndexNo[iField]);
     607               0 :             break;
     608                 :           case TABFFloat:
     609                 :             nStatus = poDATFile->WriteFloatField(GetFieldAsDouble(iField),
     610              11 :                                                 poINDFile, panIndexNo[iField]);
     611              11 :             break;
     612                 :           case TABFLogical:
     613                 :             nStatus = poDATFile->WriteLogicalField(GetFieldAsString(iField),
     614               0 :                                                 poINDFile, panIndexNo[iField]);
     615               0 :             break;
     616                 :           case TABFDate:
     617                 : #ifdef MITAB_USE_OFTDATETIME
     618               0 :              if (IsFieldSet(iField))
     619                 :              {
     620                 :                 GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
     621               0 :                                    &nHour, &nMin, &nSec, &nTZFlag);
     622                 :              }
     623                 :              else
     624               0 :                  nYear = nMon = nDay = 0;
     625                 : 
     626                 :              nStatus = poDATFile->WriteDateField(nYear, nMon, nDay,
     627               0 :                                                  poINDFile, panIndexNo[iField]);
     628                 : #else
     629                 :              nStatus = poDATFile->WriteDateField(GetFieldAsString(iField),
     630                 :                                                  poINDFile, panIndexNo[iField]);
     631                 : #endif
     632               0 :             break;
     633                 :           case TABFTime:
     634                 : #ifdef MITAB_USE_OFTDATETIME
     635               0 :              if (IsFieldSet(iField))
     636                 :              {
     637                 :                 GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
     638               0 :                                    &nHour, &nMin, &nSec, &nTZFlag);
     639                 :              }
     640                 :              else
     641                 :              {
     642               0 :                 nHour = nMin = nSec = -1;
     643                 :              }
     644                 :              nStatus = poDATFile->WriteTimeField(nHour, nMin, nSec, 0,
     645               0 :                                                     poINDFile, panIndexNo[iField]);
     646                 :              
     647                 : #else
     648                 :              nStatus = poDATFile->WriteTimeField(GetFieldAsString(iField),
     649                 :                                                  poINDFile, panIndexNo[iField]);
     650                 : #endif
     651               0 :             break;
     652                 :           case TABFDateTime:
     653                 : #ifdef MITAB_USE_OFTDATETIME
     654               0 :              if (IsFieldSet(iField))
     655                 :              {
     656                 :                 GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
     657               0 :                                    &nHour, &nMin, &nSec, &nTZFlag);
     658                 :              }
     659                 :              else
     660               0 :                  nYear = nMon = nDay = nHour = nMin = nSec = 0;
     661                 : 
     662                 :              nStatus = poDATFile->WriteDateTimeField(nYear, nMon, nDay, 
     663                 :                                                      nHour, nMin, nSec, 0,
     664               0 :                                                      poINDFile, panIndexNo[iField]);
     665                 : #else
     666                 :              nStatus = poDATFile->WriteDateTimeField(GetFieldAsString(iField),
     667                 :                                                      poINDFile, panIndexNo[iField]);
     668                 : #endif
     669               0 :             break;
     670                 :           default:
     671                 :             // Other type???  Impossible!
     672                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
     673               0 :                      "Unsupported field type!");
     674                 :         }
     675                 : 
     676                 :     }
     677                 : 
     678              14 :     if (poDATFile->CommitRecordToFile() != 0)
     679               0 :         return -1;
     680                 : 
     681              14 :     return 0;
     682                 : }
     683                 : 
     684                 : /**********************************************************************
     685                 :  *                   TABFeature::ReadGeometryFromMAPFile()
     686                 :  *
     687                 :  * In derived classes, this method should be reimplemented to
     688                 :  * fill the geometry and representation (color, etc...) part of the
     689                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
     690                 :  *
     691                 :  * It is assumed that before calling ReadGeometryFromMAPFile(), poMAPFile
     692                 :  * currently points to the beginning of a map object.
     693                 :  *
     694                 :  * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
     695                 :  * the CoordBlock data during splitting of object blocks. In this case we
     696                 :  * need to process only the information related to the CoordBlock. One 
     697                 :  * important thing to avoid is reading/writing pen/brush/symbol definitions
     698                 :  * as that would screw up their ref counters.
     699                 :  *
     700                 :  * ppoCoordBlock is used by TABCollection and by index splitting code
     701                 :  * to provide a CoordBlock to use instead of the one from the poMAPFile and
     702                 :  * return the current pointer at the end of the call.
     703                 :  *
     704                 :  * The current implementation does nothing since instances of TABFeature
     705                 :  * objects contain no geometry (i.e. TAB_GEOM_NONE).
     706                 :  * 
     707                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
     708                 :  * been called.
     709                 :  **********************************************************************/
     710               1 : int TABFeature::ReadGeometryFromMAPFile(TABMAPFile * /*poMapFile*/,
     711                 :                                         TABMAPObjHdr * /*poObjHdr*/,
     712                 :                                         GBool /*bCoordBlockDataOnly=FALSE*/, 
     713                 :                                         TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
     714                 : {
     715                 :     /*-----------------------------------------------------------------
     716                 :      * Nothing to do... instances of TABFeature objects contain no geometry.
     717                 :      *----------------------------------------------------------------*/
     718                 : 
     719               1 :     return 0;
     720                 : }
     721                 : 
     722                 : 
     723                 : /**********************************************************************
     724                 :  *                   TABFeature::UpdateMBR()
     725                 :  *
     726                 :  * Fetch envelope of poGeom and update MBR.
     727                 :  * Integer coord MBR is updated only if poMapFile is not NULL.
     728                 :  *
     729                 :  * Returns 0 on success, or -1 if there is no geometry in object
     730                 :  **********************************************************************/
     731              12 : int TABFeature::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
     732                 : {
     733                 :     OGRGeometry *poGeom;
     734                 : 
     735              12 :     poGeom = GetGeometryRef();
     736                 : 
     737              12 :     if (poGeom)
     738                 :     {
     739              12 :         OGREnvelope oEnv;
     740              12 :         poGeom->getEnvelope(&oEnv);
     741                 : 
     742              12 :         m_dXMin = oEnv.MinX;
     743              12 :         m_dYMin = oEnv.MinY;
     744              12 :         m_dXMax = oEnv.MaxX;
     745              12 :         m_dYMax = oEnv.MaxY;
     746                 : 
     747              12 :         if (poMapFile)
     748                 :         {
     749              12 :             poMapFile->Coordsys2Int(oEnv.MinX, oEnv.MinY, m_nXMin, m_nYMin);
     750              12 :             poMapFile->Coordsys2Int(oEnv.MaxX, oEnv.MaxY, m_nXMax, m_nYMax);
     751                 :         }
     752                 : 
     753              12 :         return 0;
     754                 :     }
     755                 : 
     756               0 :     return -1;
     757                 : }
     758                 : 
     759                 : /**********************************************************************
     760                 :  *                   TABFeature::ValidateCoordType()
     761                 :  *
     762                 :  * Checks the feature envelope to establish if the feature should be
     763                 :  * written using Compressed coordinates or not and adjust m_nMapInfoType
     764                 :  * accordingly. Calling this method also sets (initializes) m_nXMin, m_nYMin, 
     765                 :  * m_nXMax, m_nYMax
     766                 :  *
     767                 :  * This function should be used only by the ValidateMapInfoType() 
     768                 :  * implementations.
     769                 :  *
     770                 :  * Returns TRUE if coord. should be compressed, FALSE otherwise
     771                 :  **********************************************************************/
     772              11 : GBool TABFeature::ValidateCoordType(TABMAPFile * poMapFile)
     773                 : {
     774              11 :     GBool bCompr = FALSE;
     775                 : 
     776                 :     /*-------------------------------------------------------------
     777                 :      * Decide if coordinates should be compressed or not.
     778                 :      *------------------------------------------------------------*/
     779              11 :     if (UpdateMBR(poMapFile) == 0)
     780                 :     {
     781                 :         /* Test for max range < 65535 here instead of < 65536 to avoid
     782                 :          * compressed coordinate overflows in some boundary situations
     783                 :          */
     784              11 :         if ((m_nXMax - m_nXMin) < 65535 && (m_nYMax-m_nYMin) < 65535)
     785                 :         {
     786              10 :             bCompr = TRUE;
     787                 :         }
     788              11 :         m_nComprOrgX = (m_nXMin + m_nXMax) / 2;
     789              11 :         m_nComprOrgY = (m_nYMin + m_nYMax) / 2;
     790                 :     }
     791                 : 
     792                 :     /*-------------------------------------------------------------
     793                 :      * Adjust native type
     794                 :      *------------------------------------------------------------*/
     795              21 :     if (bCompr && ((m_nMapInfoType%3) == 2))
     796              10 :         m_nMapInfoType--;  // compr = 1, 4, 7, ...
     797               1 :     else if (!bCompr && ((m_nMapInfoType%3) == 1))
     798               0 :         m_nMapInfoType++;  // non-compr = 2, 5, 8, ...
     799                 : 
     800              11 :     return bCompr;
     801                 : }
     802                 : 
     803                 : /**********************************************************************
     804                 :  *                   TABFeature::ForceCoordTypeAndOrigin()
     805                 :  *
     806                 :  * This function is used by TABCollection::ValidateMapInfoType() to force 
     807                 :  * the coord type and compressed origin of all members of a collection 
     808                 :  * to be the same. (A replacement for ValidateCoordType() for this 
     809                 :  * specific case)
     810                 :  **********************************************************************/
     811               0 : void TABFeature::ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
     812                 :                                          GInt32 nComprOrgX, GInt32 nComprOrgY,
     813                 :                                          GInt32 nXMin, GInt32 nYMin, 
     814                 :                                          GInt32 nXMax, GInt32 nYMax)
     815                 : {
     816                 :     /*-------------------------------------------------------------
     817                 :      * Set Compressed Origin and adjust native type
     818                 :      *------------------------------------------------------------*/
     819               0 :     m_nComprOrgX = nComprOrgX;
     820               0 :     m_nComprOrgY = nComprOrgY;
     821                 : 
     822               0 :     m_nMapInfoType = nMapInfoType;
     823                 : 
     824               0 :     if (bCompr && ((m_nMapInfoType%3) == 2))
     825               0 :         m_nMapInfoType--;  // compr = 1, 4, 7, ...
     826               0 :     else if (!bCompr && ((m_nMapInfoType%3) == 1))
     827               0 :         m_nMapInfoType++;  // non-compr = 2, 5, 8, ...
     828                 : 
     829               0 :     m_nXMin = nXMin;
     830               0 :     m_nYMin = nYMin;
     831               0 :     m_nXMax = nXMax;
     832               0 :     m_nYMax = nYMax;
     833               0 : }
     834                 : 
     835                 : /**********************************************************************
     836                 :  *                   TABFeature::WriteGeometryToMAPFile()
     837                 :  *
     838                 :  *
     839                 :  * In derived classes, this method should be reimplemented to
     840                 :  * write the geometry and representation (color, etc...) part of the
     841                 :  * feature to the .MAP object pointed to by poMAPFile.
     842                 :  *
     843                 :  * It is assumed that before calling WriteGeometryToMAPFile(), poMAPFile
     844                 :  * currently points to a valid map object.
     845                 :  *
     846                 :  * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
     847                 :  * the CoordBlock data during splitting of object blocks. In this case we
     848                 :  * need to process only the information related to the CoordBlock. One 
     849                 :  * important thing to avoid is reading/writing pen/brush/symbol definitions
     850                 :  * as that would screw up their ref counters.
     851                 :  *
     852                 :  * ppoCoordBlock is used by TABCollection and by index splitting code
     853                 :  * to provide a CoordBlock to use instead of the one from the poMAPFile and
     854                 :  * return the current pointer at the end of the call.
     855                 :  *
     856                 :  * The current implementation does nothing since instances of TABFeature
     857                 :  * objects contain no geometry (i.e. TAB_GEOM_NONE).
     858                 :  * 
     859                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
     860                 :  * been called.
     861                 :  **********************************************************************/
     862               2 : int TABFeature::WriteGeometryToMAPFile(TABMAPFile * /* poMapFile*/,
     863                 :                                        TABMAPObjHdr * /*poObjHdr*/,
     864                 :                                        GBool /*bCoordBlockDataOnly=FALSE*/, 
     865                 :                                        TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
     866                 : {
     867                 :     /*-----------------------------------------------------------------
     868                 :      * Nothing to do... instances of TABFeature objects contain no geometry.
     869                 :      *----------------------------------------------------------------*/
     870                 : 
     871               2 :     return 0;
     872                 : }
     873                 : 
     874                 : /**********************************************************************
     875                 :  *                   TABFeature::DumpMID()
     876                 :  *
     877                 :  * Dump feature attributes in a format similar to .MID data records.
     878                 :  **********************************************************************/
     879               0 : void TABFeature::DumpMID(FILE *fpOut /*=NULL*/)
     880                 : {
     881               0 :     OGRFeatureDefn      *poDefn = GetDefnRef();
     882                 : 
     883               0 :     if (fpOut == NULL)
     884               0 :         fpOut = stdout;
     885                 : 
     886               0 :     for( int iField = 0; iField < GetFieldCount(); iField++ )
     887                 :     {
     888               0 :         OGRFieldDefn    *poFDefn = poDefn->GetFieldDefn(iField);
     889                 :         
     890                 :         fprintf( fpOut, "  %s (%s) = %s\n",
     891                 :                  poFDefn->GetNameRef(),
     892                 :                  OGRFieldDefn::GetFieldTypeName(poFDefn->GetType()),
     893               0 :                  GetFieldAsString( iField ) );
     894                 :     }
     895                 : 
     896               0 :     fflush(fpOut);
     897               0 : }
     898                 : 
     899                 : /**********************************************************************
     900                 :  *                   TABFeature::DumpMIF()
     901                 :  *
     902                 :  * Dump feature geometry in a format similar to .MIF files.
     903                 :  **********************************************************************/
     904               0 : void TABFeature::DumpMIF(FILE *fpOut /*=NULL*/)
     905                 : {
     906               0 :     if (fpOut == NULL)
     907               0 :         fpOut = stdout;
     908                 : 
     909                 :     /*-----------------------------------------------------------------
     910                 :      * Generate output... not much to do, feature contains no geometry.
     911                 :      *----------------------------------------------------------------*/
     912               0 :     fprintf(fpOut, "NONE\n" );
     913                 : 
     914               0 :     fflush(fpOut);
     915               0 : }
     916                 : 
     917                 : 
     918                 : /*=====================================================================
     919                 :  *                      class TABPoint
     920                 :  *====================================================================*/
     921                 : 
     922                 : 
     923                 : /**********************************************************************
     924                 :  *                   TABPoint::TABPoint()
     925                 :  *
     926                 :  * Constructor.
     927                 :  **********************************************************************/
     928               8 : TABPoint::TABPoint(OGRFeatureDefn *poDefnIn):
     929               8 :               TABFeature(poDefnIn)
     930                 : {
     931               8 : }
     932                 : 
     933                 : /**********************************************************************
     934                 :  *                   TABPoint::~TABPoint()
     935                 :  *
     936                 :  * Destructor.
     937                 :  **********************************************************************/
     938               8 : TABPoint::~TABPoint()
     939                 : {
     940               8 : }
     941                 : 
     942                 : /**********************************************************************
     943                 :  *                     TABPoint::CloneTABFeature()
     944                 :  *
     945                 :  * Duplicate feature, including stuff specific to each TABFeature type.
     946                 :  *
     947                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
     948                 :  * then copies any members specific to its own type.
     949                 :  **********************************************************************/
     950               0 : TABFeature *TABPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
     951                 : {
     952                 :     /*-----------------------------------------------------------------
     953                 :      * Alloc new feature and copy the base stuff
     954                 :      *----------------------------------------------------------------*/
     955               0 :     TABPoint *poNew = new TABPoint(poNewDefn ? poNewDefn : GetDefnRef());
     956                 : 
     957               0 :     CopyTABFeatureBase(poNew);
     958                 : 
     959                 :     /*-----------------------------------------------------------------
     960                 :      * And members specific to this class
     961                 :      *----------------------------------------------------------------*/
     962                 :     // ITABFeatureSymbol
     963               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
     964                 : 
     965               0 :     return poNew;
     966                 : }
     967                 : 
     968                 : 
     969                 : /**********************************************************************
     970                 :  *                   TABPoint::ValidateMapInfoType()
     971                 :  *
     972                 :  * Check the feature's geometry part and return the corresponding
     973                 :  * mapinfo object type code.  The m_nMapInfoType member will also
     974                 :  * be updated for further calls to GetMapInfoType();
     975                 :  *
     976                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
     977                 :  * is expected for this object class.
     978                 :  **********************************************************************/
     979               0 : int  TABPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
     980                 : {
     981                 :     OGRGeometry *poGeom;
     982                 : 
     983                 :     /*-----------------------------------------------------------------
     984                 :      * Fetch and validate geometry 
     985                 :      * __TODO__ For now we always write in uncompressed format (until we 
     986                 :      * find that this is not correct... note that at this point the
     987                 :      * decision to use compressed/uncompressed will likely be based on
     988                 :      * the distance between the point and the object block center in
     989                 :      * integer coordinates being > 32767 or not... remains to be verified)
     990                 :      *----------------------------------------------------------------*/
     991               0 :     poGeom = GetGeometryRef();
     992               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
     993                 :     {
     994               0 :         switch(GetFeatureClass())
     995                 :         {
     996                 :           case TABFCFontPoint:
     997               0 :             m_nMapInfoType = TAB_GEOM_FONTSYMBOL;
     998               0 :             break;
     999                 :           case TABFCCustomPoint:
    1000               0 :             m_nMapInfoType = TAB_GEOM_CUSTOMSYMBOL;
    1001               0 :             break;
    1002                 :           case TABFCPoint:
    1003                 :           default:
    1004               0 :             m_nMapInfoType = TAB_GEOM_SYMBOL;
    1005                 :             break;
    1006                 :         }
    1007                 :     }
    1008                 :     else
    1009                 :     {
    1010                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1011               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1012               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    1013                 :     }
    1014                 : 
    1015               0 :     UpdateMBR(poMapFile);
    1016                 : 
    1017               0 :     return m_nMapInfoType;
    1018                 : }
    1019                 : 
    1020                 : /**********************************************************************
    1021                 :  *                   TABPoint::ReadGeometryFromMAPFile()
    1022                 :  *
    1023                 :  * Fill the geometry and representation (color, etc...) part of the
    1024                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    1025                 :  *
    1026                 :  * It is assumed that poMAPFile currently points to the beginning of
    1027                 :  * a map object.
    1028                 :  *
    1029                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1030                 :  * been called.
    1031                 :  **********************************************************************/
    1032               0 : int TABPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    1033                 :                                       TABMAPObjHdr *poObjHdr,
    1034                 :                                       GBool bCoordBlockDataOnly /*=FALSE*/, 
    1035                 :                                       TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1036                 : {
    1037                 :     double              dX, dY;
    1038                 :     OGRGeometry         *poGeometry;
    1039                 : 
    1040                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1041               0 :     if (bCoordBlockDataOnly)
    1042               0 :         return 0;
    1043                 : 
    1044                 :     /*-----------------------------------------------------------------
    1045                 :      * Fetch and validate geometry type
    1046                 :      *----------------------------------------------------------------*/
    1047               0 :     m_nMapInfoType = poObjHdr->m_nType;
    1048                 : 
    1049               0 :     if (m_nMapInfoType != TAB_GEOM_SYMBOL &&
    1050                 :         m_nMapInfoType != TAB_GEOM_SYMBOL_C )
    1051                 :     {
    1052                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1053                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    1054               0 :                  m_nMapInfoType, m_nMapInfoType);
    1055               0 :         return -1;
    1056                 :     }
    1057                 : 
    1058                 :     /*-----------------------------------------------------------------
    1059                 :      * Read object information
    1060                 :      *----------------------------------------------------------------*/
    1061               0 :     TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
    1062                 : 
    1063               0 :     m_nSymbolDefIndex = poPointHdr->m_nSymbolId;   // Symbol index
    1064                 : 
    1065               0 :     poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
    1066                 :     
    1067                 :     /*-----------------------------------------------------------------
    1068                 :      * Create and fill geometry object
    1069                 :      *----------------------------------------------------------------*/
    1070               0 :     poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
    1071               0 :     poGeometry = new OGRPoint(dX, dY);
    1072                 :     
    1073               0 :     SetGeometryDirectly(poGeometry);
    1074                 : 
    1075               0 :     SetMBR(dX, dY, dX, dY);
    1076                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    1077               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    1078                 : 
    1079               0 :     return 0;
    1080                 : }
    1081                 : 
    1082                 : /**********************************************************************
    1083                 :  *                   TABPoint::WriteGeometryToMAPFile()
    1084                 :  *
    1085                 :  * Write the geometry and representation (color, etc...) part of the
    1086                 :  * feature to the .MAP object pointed to by poMAPFile.
    1087                 :  *
    1088                 :  * It is assumed that poMAPFile currently points to a valid map object.
    1089                 :  *
    1090                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1091                 :  * been called.
    1092                 :  **********************************************************************/
    1093               0 : int TABPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    1094                 :                                      TABMAPObjHdr *poObjHdr,
    1095                 :                                      GBool bCoordBlockDataOnly /*=FALSE*/, 
    1096                 :                                      TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1097                 : {
    1098                 :     GInt32              nX, nY;
    1099                 :     OGRGeometry         *poGeom;
    1100                 :     OGRPoint            *poPoint;
    1101                 : 
    1102                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1103               0 :     if (bCoordBlockDataOnly)
    1104               0 :         return 0;
    1105                 : 
    1106                 :     /*-----------------------------------------------------------------
    1107                 :      * We assume that ValidateMapInfoType() was called already and that
    1108                 :      * the type in poObjHdr->m_nType is valid.
    1109                 :      *----------------------------------------------------------------*/
    1110               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    1111                 : 
    1112                 :     /*-----------------------------------------------------------------
    1113                 :      * Fetch and validate geometry
    1114                 :      *----------------------------------------------------------------*/
    1115               0 :     poGeom = GetGeometryRef();
    1116               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1117               0 :         poPoint = (OGRPoint*)poGeom;
    1118                 :     else
    1119                 :     {
    1120                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1121               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1122               0 :         return -1;
    1123                 :     }
    1124                 : 
    1125               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    1126                 : 
    1127                 :     /*-----------------------------------------------------------------
    1128                 :      * Copy object information
    1129                 :      *----------------------------------------------------------------*/
    1130               0 :     TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
    1131                 : 
    1132               0 :     poPointHdr->m_nX = nX;
    1133               0 :     poPointHdr->m_nY = nY;
    1134               0 :     poPointHdr->SetMBR(nX, nY, nX, nY);
    1135                 : 
    1136               0 :     m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
    1137               0 :     poPointHdr->m_nSymbolId = (GByte)m_nSymbolDefIndex;      // Symbol index
    1138                 : 
    1139               0 :     if (CPLGetLastErrorNo() != 0)
    1140               0 :         return -1;
    1141                 : 
    1142               0 :     return 0;
    1143                 : }
    1144                 : 
    1145                 : 
    1146                 : /**********************************************************************
    1147                 :  *                   TABPoint::GetX()
    1148                 :  *
    1149                 :  * Return this point's X coordinate.
    1150                 :  **********************************************************************/
    1151               0 : double TABPoint::GetX()
    1152                 : {
    1153                 :     OGRGeometry *poGeom;
    1154               0 :     OGRPoint    *poPoint=NULL;
    1155                 : 
    1156                 :     /*-----------------------------------------------------------------
    1157                 :      * Fetch and validate geometry
    1158                 :      *----------------------------------------------------------------*/
    1159               0 :     poGeom = GetGeometryRef();
    1160               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1161               0 :         poPoint = (OGRPoint*)poGeom;
    1162                 :     else
    1163                 :     {
    1164                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1165               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1166               0 :         return 0.0;
    1167                 :     }
    1168                 : 
    1169               0 :     return poPoint->getX();
    1170                 : }
    1171                 : 
    1172                 : /**********************************************************************
    1173                 :  *                   TABPoint::GetY()
    1174                 :  *
    1175                 :  * Return this point's Y coordinate.
    1176                 :  **********************************************************************/
    1177               0 : double TABPoint::GetY()
    1178                 : {
    1179                 :     OGRGeometry *poGeom;
    1180               0 :     OGRPoint    *poPoint=NULL;
    1181                 : 
    1182                 :     /*-----------------------------------------------------------------
    1183                 :      * Fetch and validate geometry
    1184                 :      *----------------------------------------------------------------*/
    1185               0 :     poGeom = GetGeometryRef();
    1186               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1187               0 :         poPoint = (OGRPoint*)poGeom;
    1188                 :     else
    1189                 :     {
    1190                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1191               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1192               0 :         return 0.0;
    1193                 :     }
    1194                 : 
    1195               0 :     return poPoint->getY();
    1196                 : }
    1197                 : 
    1198                 : 
    1199                 : /**********************************************************************
    1200                 :  *                   TABPoint::GetStyleString()
    1201                 :  *
    1202                 :  * Return style string for this feature.
    1203                 :  *
    1204                 :  * Style String is built only once during the first call to GetStyleString().
    1205                 :  **********************************************************************/
    1206               0 : const char *TABPoint::GetStyleString()
    1207                 : {
    1208               0 :     if (m_pszStyleString == NULL)
    1209                 :     {
    1210               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    1211                 :     }
    1212                 : 
    1213               0 :     return m_pszStyleString;
    1214                 : }
    1215                 : 
    1216                 : 
    1217                 : /**********************************************************************
    1218                 :  *                   TABPoint::DumpMIF()
    1219                 :  *
    1220                 :  * Dump feature geometry in a format similar to .MIF POINTs.
    1221                 :  **********************************************************************/
    1222               0 : void TABPoint::DumpMIF(FILE *fpOut /*=NULL*/)
    1223                 : {
    1224                 :     OGRGeometry *poGeom;
    1225                 :     OGRPoint    *poPoint;
    1226                 : 
    1227               0 :     if (fpOut == NULL)
    1228               0 :         fpOut = stdout;
    1229                 : 
    1230                 :     /*-----------------------------------------------------------------
    1231                 :      * Fetch and validate geometry
    1232                 :      *----------------------------------------------------------------*/
    1233               0 :     poGeom = GetGeometryRef();
    1234               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1235               0 :         poPoint = (OGRPoint*)poGeom;
    1236                 :     else
    1237                 :     {
    1238                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1239               0 :                  "TABPoint: Missing or Invalid Geometry!");
    1240               0 :         return;
    1241                 :     }
    1242                 : 
    1243                 :     /*-----------------------------------------------------------------
    1244                 :      * Generate output
    1245                 :      *----------------------------------------------------------------*/
    1246               0 :     fprintf(fpOut, "POINT %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
    1247                 : 
    1248               0 :     DumpSymbolDef(fpOut);
    1249                 : 
    1250                 :     /*-----------------------------------------------------------------
    1251                 :      * Handle stuff specific to derived classes
    1252                 :      *----------------------------------------------------------------*/
    1253               0 :     if (GetFeatureClass() == TABFCFontPoint)
    1254                 :     {
    1255               0 :         TABFontPoint *poFeature = (TABFontPoint *)this;
    1256                 :         fprintf(fpOut, "  m_nFontStyle     = 0x%2.2x (%d)\n", 
    1257                 :                 poFeature->GetFontStyleTABValue(),
    1258               0 :                 poFeature->GetFontStyleTABValue());
    1259                 : 
    1260               0 :         poFeature->DumpFontDef(fpOut);
    1261                 :     }
    1262               0 :     if (GetFeatureClass() == TABFCCustomPoint)
    1263                 :     {
    1264               0 :         TABCustomPoint *poFeature = (TABCustomPoint *)this;
    1265                 : 
    1266                 :         fprintf(fpOut, "  m_nUnknown_      = 0x%2.2x (%d)\n", 
    1267               0 :                 poFeature->m_nUnknown_, poFeature->m_nUnknown_);
    1268                 :         fprintf(fpOut, "  m_nCustomStyle   = 0x%2.2x (%d)\n", 
    1269                 :                 poFeature->GetCustomSymbolStyle(), 
    1270               0 :                 poFeature->GetCustomSymbolStyle());
    1271                 : 
    1272               0 :         poFeature->DumpFontDef(fpOut);
    1273                 :     }
    1274                 : 
    1275               0 :     fflush(fpOut);
    1276                 : }
    1277                 : 
    1278                 : /*=====================================================================
    1279                 :  *                      class TABFontPoint
    1280                 :  *====================================================================*/
    1281                 : 
    1282                 : 
    1283                 : /**********************************************************************
    1284                 :  *                   TABFontPoint::TABFontPoint()
    1285                 :  *
    1286                 :  * Constructor.
    1287                 :  **********************************************************************/
    1288               0 : TABFontPoint::TABFontPoint(OGRFeatureDefn *poDefnIn):
    1289               0 :               TABPoint(poDefnIn)
    1290                 : {
    1291               0 :     m_nFontStyle = 0;
    1292               0 :     m_dAngle = 0.0;
    1293               0 : }
    1294                 : 
    1295                 : /**********************************************************************
    1296                 :  *                   TABFontPoint::~TABFontPoint()
    1297                 :  *
    1298                 :  * Destructor.
    1299                 :  **********************************************************************/
    1300               0 : TABFontPoint::~TABFontPoint()
    1301                 : {
    1302               0 : }
    1303                 : 
    1304                 : /**********************************************************************
    1305                 :  *                     TABFontPoint::CloneTABFeature()
    1306                 :  *
    1307                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    1308                 :  *
    1309                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    1310                 :  * then copies any members specific to its own type.
    1311                 :  **********************************************************************/
    1312               0 : TABFeature *TABFontPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
    1313                 : {
    1314                 :     /*-----------------------------------------------------------------
    1315                 :      * Alloc new feature and copy the base stuff
    1316                 :      *----------------------------------------------------------------*/
    1317                 :     TABFontPoint *poNew = new TABFontPoint(poNewDefn ? poNewDefn : 
    1318               0 :                                                        GetDefnRef());
    1319                 : 
    1320               0 :     CopyTABFeatureBase(poNew);
    1321                 : 
    1322                 :     /*-----------------------------------------------------------------
    1323                 :      * And members specific to this class
    1324                 :      *----------------------------------------------------------------*/
    1325                 :     // ITABFeatureSymbol
    1326               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
    1327                 : 
    1328                 :     // ITABFeatureFont
    1329               0 :     *(poNew->GetFontDefRef()) = *GetFontDefRef();
    1330                 : 
    1331               0 :     poNew->SetSymbolAngle( GetSymbolAngle() );
    1332               0 :     poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
    1333                 : 
    1334               0 :     return poNew;
    1335                 : }
    1336                 : 
    1337                 : /**********************************************************************
    1338                 :  *                   TABFontPoint::ReadGeometryFromMAPFile()
    1339                 :  *
    1340                 :  * Fill the geometry and representation (color, etc...) part of the
    1341                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    1342                 :  *
    1343                 :  * It is assumed that poMAPFile currently points to the beginning of
    1344                 :  * a map object.
    1345                 :  *
    1346                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1347                 :  * been called.
    1348                 :  **********************************************************************/
    1349               0 : int TABFontPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    1350                 :                                           TABMAPObjHdr *poObjHdr,
    1351                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    1352                 :                                           TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1353                 : {
    1354                 :     double              dX, dY;
    1355                 :     OGRGeometry         *poGeometry;
    1356                 : 
    1357                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1358               0 :     if (bCoordBlockDataOnly)
    1359               0 :         return 0;
    1360                 : 
    1361                 :     /*-----------------------------------------------------------------
    1362                 :      * Fetch and validate geometry type
    1363                 :      *----------------------------------------------------------------*/
    1364               0 :     m_nMapInfoType = poObjHdr->m_nType;
    1365                 : 
    1366               0 :     if (m_nMapInfoType != TAB_GEOM_FONTSYMBOL &&
    1367                 :         m_nMapInfoType != TAB_GEOM_FONTSYMBOL_C )
    1368                 :     {
    1369                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1370                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    1371               0 :                  m_nMapInfoType, m_nMapInfoType);
    1372               0 :         return -1;
    1373                 :     }
    1374                 : 
    1375                 :     /*-----------------------------------------------------------------
    1376                 :      * Read object information
    1377                 :      * NOTE: This symbol type does not contain a reference to a
    1378                 :      * SymbolDef block in the file, but we still use the m_sSymbolDef
    1379                 :      * structure to store the information inside the class so that the
    1380                 :      * ITABFeatureSymbol methods work properly for the class user.
    1381                 :      *----------------------------------------------------------------*/
    1382               0 :     TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
    1383                 : 
    1384               0 :     m_nSymbolDefIndex = -1;
    1385               0 :     m_sSymbolDef.nRefCount = 0;
    1386                 : 
    1387               0 :     m_sSymbolDef.nSymbolNo  = poPointHdr->m_nSymbolId;  // shape
    1388               0 :     m_sSymbolDef.nPointSize = poPointHdr->m_nPointSize; // point size
    1389                 : 
    1390               0 :     m_nFontStyle            = poPointHdr->m_nFontStyle; // font style
    1391                 : 
    1392                 :     m_sSymbolDef.rgbColor   = (poPointHdr->m_nR*256*256 +
    1393                 :                                poPointHdr->m_nG*256 +
    1394               0 :                                poPointHdr->m_nB);
    1395                 : 
    1396                 :     /*-------------------------------------------------------------
    1397                 :      * Symbol Angle, in thenths of degree.
    1398                 :      * Contrary to arc start/end angles, no conversion based on 
    1399                 :      * origin quadrant is required here
    1400                 :      *------------------------------------------------------------*/
    1401               0 :     m_dAngle       = poPointHdr->m_nAngle/10.0;
    1402                 : 
    1403               0 :     m_nFontDefIndex = poPointHdr->m_nFontId;      // Font name index
    1404                 : 
    1405               0 :     poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
    1406                 : 
    1407                 :     /*-----------------------------------------------------------------
    1408                 :      * Create and fill geometry object
    1409                 :      *----------------------------------------------------------------*/
    1410               0 :     poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
    1411               0 :     poGeometry = new OGRPoint(dX, dY);
    1412                 :     
    1413               0 :     SetGeometryDirectly(poGeometry);
    1414                 : 
    1415               0 :     SetMBR(dX, dY, dX, dY);
    1416                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    1417               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    1418                 : 
    1419               0 :     return 0;
    1420                 : }
    1421                 : 
    1422                 : /**********************************************************************
    1423                 :  *                   TABFontPoint::WriteGeometryToMAPFile()
    1424                 :  *
    1425                 :  * Write the geometry and representation (color, etc...) part of the
    1426                 :  * feature to the .MAP object pointed to by poMAPFile.
    1427                 :  *
    1428                 :  * It is assumed that poMAPFile currently points to a valid map object.
    1429                 :  *
    1430                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1431                 :  * been called.
    1432                 :  **********************************************************************/
    1433               0 : int TABFontPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    1434                 :                                          TABMAPObjHdr *poObjHdr,
    1435                 :                                          GBool bCoordBlockDataOnly /*=FALSE*/, 
    1436                 :                                          TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1437                 : {
    1438                 :     GInt32              nX, nY;
    1439                 :     OGRGeometry         *poGeom;
    1440                 :     OGRPoint            *poPoint;
    1441                 : 
    1442                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1443               0 :     if (bCoordBlockDataOnly)
    1444               0 :         return 0;
    1445                 : 
    1446                 :     /*-----------------------------------------------------------------
    1447                 :      * We assume that ValidateMapInfoType() was called already and that
    1448                 :      * the type in poObjHdr->m_nType is valid.
    1449                 :      *----------------------------------------------------------------*/
    1450               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    1451                 : 
    1452                 :     /*-----------------------------------------------------------------
    1453                 :      * Fetch and validate geometry
    1454                 :      *----------------------------------------------------------------*/
    1455               0 :     poGeom = GetGeometryRef();
    1456               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1457               0 :         poPoint = (OGRPoint*)poGeom;
    1458                 :     else
    1459                 :     {
    1460                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1461               0 :                  "TABFontPoint: Missing or Invalid Geometry!");
    1462               0 :         return -1;
    1463                 :     }
    1464                 : 
    1465               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    1466                 : 
    1467                 :     /*-----------------------------------------------------------------
    1468                 :      * Copy object information
    1469                 :      * NOTE: This symbol type does not contain a reference to a
    1470                 :      * SymbolDef block in the file, but we still use the m_sSymbolDef
    1471                 :      * structure to store the information inside the class so that the
    1472                 :      * ITABFeatureSymbol methods work properly for the class user.
    1473                 :      *----------------------------------------------------------------*/
    1474               0 :     TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
    1475                 : 
    1476               0 :     poPointHdr->m_nX = nX;
    1477               0 :     poPointHdr->m_nY = nY;
    1478               0 :     poPointHdr->SetMBR(nX, nY, nX, nY);
    1479                 : 
    1480               0 :     poPointHdr->m_nSymbolId = (GByte)m_sSymbolDef.nSymbolNo;    // shape
    1481               0 :     poPointHdr->m_nPointSize = (GByte)m_sSymbolDef.nPointSize;  // point size
    1482               0 :     poPointHdr->m_nFontStyle = m_nFontStyle;                    // font style
    1483                 : 
    1484               0 :     poPointHdr->m_nR = (GByte)COLOR_R(m_sSymbolDef.rgbColor);
    1485               0 :     poPointHdr->m_nG = (GByte)COLOR_G(m_sSymbolDef.rgbColor);
    1486               0 :     poPointHdr->m_nB = (GByte)COLOR_B(m_sSymbolDef.rgbColor);
    1487                 : 
    1488                 :     /*-------------------------------------------------------------
    1489                 :      * Symbol Angle, in thenths of degree.
    1490                 :      * Contrary to arc start/end angles, no conversion based on 
    1491                 :      * origin quadrant is required here
    1492                 :      *------------------------------------------------------------*/
    1493               0 :     poPointHdr->m_nAngle = (GInt16)ROUND_INT(m_dAngle * 10.0);
    1494                 : 
    1495                 :     // Write Font Def
    1496               0 :     m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
    1497               0 :     poPointHdr->m_nFontId = (GByte)m_nFontDefIndex;      // Font name index
    1498                 : 
    1499               0 :     if (CPLGetLastErrorNo() != 0)
    1500               0 :         return -1;
    1501                 : 
    1502               0 :     return 0;
    1503                 : }
    1504                 : 
    1505                 : /**********************************************************************
    1506                 :  *                   TABFontPoint::QueryFontStyle()
    1507                 :  *
    1508                 :  * Return TRUE if the specified font style attribute is turned ON,
    1509                 :  * or FALSE otherwise.  See enum TABFontStyle for the list of styles
    1510                 :  * that can be queried on.
    1511                 :  **********************************************************************/
    1512               0 : GBool TABFontPoint::QueryFontStyle(TABFontStyle eStyleToQuery)
    1513                 : {
    1514               0 :     return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
    1515                 : }
    1516                 : 
    1517               0 : void TABFontPoint::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
    1518                 : {
    1519               0 :     if (bStyleOn)
    1520               0 :         m_nFontStyle |=  (int)eStyleToToggle;
    1521                 :     else
    1522               0 :         m_nFontStyle &=  ~(int)eStyleToToggle;
    1523               0 : }
    1524                 : 
    1525                 : /**********************************************************************
    1526                 :  *                   TABFontPoint::GetFontStyleMIFValue()
    1527                 :  *
    1528                 :  * Return the Font Style value for this object using the style values
    1529                 :  * that are used in a MIF FONT() clause.  See MIF specs (appendix A).
    1530                 :  *
    1531                 :  * The reason why we have to differentiate between the TAB and the MIF font
    1532                 :  * style values is that in TAB, TABFSBox is included in the style value
    1533                 :  * as code 0x100, but in MIF it is not included, instead it is implied by
    1534                 :  * the presence of the BG color in the FONT() clause (the BG color is 
    1535                 :  * present only when TABFSBox or TABFSHalo is set).
    1536                 :  * This also has the effect of shifting all the other style values > 0x100
    1537                 :  * by 1 byte.
    1538                 :  *
    1539                 :  * NOTE: Even if there is no BG color for font symbols, we inherit this
    1540                 :  * problem because Font Point styles use the same codes as Text Font styles.
    1541                 :  **********************************************************************/
    1542               0 : int TABFontPoint::GetFontStyleMIFValue()
    1543                 : {
    1544                 :     // The conversion is simply to remove bit 0x100 from the value and shift
    1545                 :     // down all values past this bit.
    1546               0 :     return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
    1547                 : }
    1548                 : 
    1549               0 : void TABFontPoint:: SetFontStyleMIFValue(int nStyle)
    1550                 : {
    1551               0 :     m_nFontStyle = (GByte)((nStyle & 0xff) + (nStyle & 0x7f00)*2);
    1552               0 : }
    1553                 : 
    1554                 : /**********************************************************************
    1555                 :  *                   TABFontPoint::SetSymbolAngle()
    1556                 :  *
    1557                 :  * Set the symbol angle value in degrees, making sure the value is
    1558                 :  * always in the range [0..360]
    1559                 :  **********************************************************************/
    1560               0 : void TABFontPoint::SetSymbolAngle(double dAngle)
    1561                 : {
    1562               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    1563               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    1564                 : 
    1565               0 :     m_dAngle = dAngle;
    1566               0 : }
    1567                 : 
    1568                 : 
    1569                 : /**********************************************************************
    1570                 :  *                   TABFontPoint::GetStyleString()
    1571                 :  *
    1572                 :  * Return style string for this feature.
    1573                 :  *
    1574                 :  * Style String is built only once during the first call to GetStyleString().
    1575                 :  **********************************************************************/
    1576               0 : const char *TABFontPoint::GetStyleString()
    1577                 : {
    1578               0 :     if (m_pszStyleString == NULL)
    1579                 :     {
    1580                 :         /* Get the SymbolStyleString, and add the outline Color 
    1581                 :            (halo/border in MapInfo Symbol terminology) */
    1582               0 :         char *pszSymbolStyleString = CPLStrdup(GetSymbolStyleString(GetSymbolAngle()));
    1583               0 :         int nStyleStringlen = strlen(pszSymbolStyleString);
    1584               0 :         pszSymbolStyleString[nStyleStringlen-1] = '\0';
    1585                 : 
    1586                 :         const char *outlineColor;
    1587               0 :         if (m_nFontStyle & 16)
    1588               0 :             outlineColor = ",o:#000000";
    1589               0 :         else if (m_nFontStyle & 512)
    1590               0 :             outlineColor = ",o:#ffffff";
    1591                 :         else
    1592               0 :             outlineColor = "";
    1593                 : 
    1594                 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s%s)",
    1595                 :                                                 pszSymbolStyleString,
    1596               0 :                                                 outlineColor));
    1597               0 :         CPLFree(pszSymbolStyleString);
    1598                 :     }
    1599                 : 
    1600               0 :     return m_pszStyleString;
    1601                 : }
    1602                 : 
    1603                 : 
    1604                 : /*=====================================================================
    1605                 :  *                      class TABCustomPoint
    1606                 :  *====================================================================*/
    1607                 : 
    1608                 : 
    1609                 : /**********************************************************************
    1610                 :  *                   TABCustomPoint::TABCustomPoint()
    1611                 :  *
    1612                 :  * Constructor.
    1613                 :  **********************************************************************/
    1614               0 : TABCustomPoint::TABCustomPoint(OGRFeatureDefn *poDefnIn):
    1615               0 :                     TABPoint(poDefnIn)
    1616                 : {
    1617               0 :     m_nUnknown_ = m_nCustomStyle = 0;
    1618               0 : }
    1619                 : 
    1620                 : /**********************************************************************
    1621                 :  *                   TABCustomPoint::~TABCustomPoint()
    1622                 :  *
    1623                 :  * Destructor.
    1624                 :  **********************************************************************/
    1625               0 : TABCustomPoint::~TABCustomPoint()
    1626                 : {
    1627               0 : }
    1628                 : 
    1629                 : /**********************************************************************
    1630                 :  *                     TABCustomPoint::CloneTABFeature()
    1631                 :  *
    1632                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    1633                 :  *
    1634                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    1635                 :  * then copies any members specific to its own type.
    1636                 :  **********************************************************************/
    1637               0 : TABFeature *TABCustomPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    1638                 : {
    1639                 :     /*-----------------------------------------------------------------
    1640                 :      * Alloc new feature and copy the base stuff
    1641                 :      *----------------------------------------------------------------*/
    1642                 :     TABCustomPoint *poNew = new TABCustomPoint(poNewDefn ? poNewDefn : 
    1643               0 :                                                            GetDefnRef());
    1644                 : 
    1645               0 :     CopyTABFeatureBase(poNew);
    1646                 : 
    1647                 :     /*-----------------------------------------------------------------
    1648                 :      * And members specific to this class
    1649                 :      *----------------------------------------------------------------*/
    1650                 :     // ITABFeatureSymbol
    1651               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
    1652                 : 
    1653                 :     // ITABFeatureFont
    1654               0 :     *(poNew->GetFontDefRef()) = *GetFontDefRef();
    1655                 : 
    1656               0 :     poNew->SetCustomSymbolStyle( GetCustomSymbolStyle() );
    1657                 : 
    1658               0 :     return poNew;
    1659                 : }
    1660                 : 
    1661                 : /**********************************************************************
    1662                 :  *                   TABCustomPoint::ReadGeometryFromMAPFile()
    1663                 :  *
    1664                 :  * Fill the geometry and representation (color, etc...) part of the
    1665                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    1666                 :  *
    1667                 :  * It is assumed that poMAPFile currently points to the beginning of
    1668                 :  * a map object.
    1669                 :  *
    1670                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1671                 :  * been called.
    1672                 :  **********************************************************************/
    1673               0 : int TABCustomPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    1674                 :                                             TABMAPObjHdr *poObjHdr,
    1675                 :                                             GBool bCoordBlockDataOnly /*=FALSE*/,
    1676                 :                                             TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1677                 : {
    1678                 :     double              dX, dY;
    1679                 :     OGRGeometry         *poGeometry;
    1680                 : 
    1681                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1682               0 :     if (bCoordBlockDataOnly)
    1683               0 :         return 0;
    1684                 : 
    1685                 :     /*-----------------------------------------------------------------
    1686                 :      * Fetch and validate geometry type
    1687                 :      *----------------------------------------------------------------*/
    1688               0 :     m_nMapInfoType = poObjHdr->m_nType;
    1689                 : 
    1690               0 :     if (m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL &&
    1691                 :         m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL_C )
    1692                 :     {
    1693                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1694                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    1695               0 :                  m_nMapInfoType, m_nMapInfoType);
    1696               0 :         return -1;
    1697                 :     }
    1698                 : 
    1699                 :     /*-----------------------------------------------------------------
    1700                 :      * Read object information
    1701                 :      *----------------------------------------------------------------*/
    1702               0 :     TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
    1703                 : 
    1704               0 :     m_nUnknown_    = poPointHdr->m_nUnknown_;   // ??? 
    1705               0 :     m_nCustomStyle = poPointHdr->m_nCustomStyle;// 0x01=Show BG,
    1706                 :                                                 // 0x02=Apply Color
    1707                 : 
    1708               0 :     m_nSymbolDefIndex = poPointHdr->m_nSymbolId;   // Symbol index
    1709               0 :     poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
    1710                 : 
    1711               0 :     m_nFontDefIndex = poPointHdr->m_nFontId;    // Font index
    1712               0 :     poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
    1713                 : 
    1714                 :     /*-----------------------------------------------------------------
    1715                 :      * Create and fill geometry object
    1716                 :      *----------------------------------------------------------------*/
    1717               0 :     poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
    1718               0 :     poGeometry = new OGRPoint(dX, dY);
    1719                 :     
    1720               0 :     SetGeometryDirectly(poGeometry);
    1721                 : 
    1722               0 :     SetMBR(dX, dY, dX, dY);
    1723                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    1724               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    1725                 : 
    1726               0 :     return 0;
    1727                 : }
    1728                 : 
    1729                 : /**********************************************************************
    1730                 :  *                   TABCustomPoint::WriteGeometryToMAPFile()
    1731                 :  *
    1732                 :  * Write the geometry and representation (color, etc...) part of the
    1733                 :  * feature to the .MAP object pointed to by poMAPFile.
    1734                 :  *
    1735                 :  * It is assumed that poMAPFile currently points to a valid map object.
    1736                 :  *
    1737                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    1738                 :  * been called.
    1739                 :  **********************************************************************/
    1740               0 : int TABCustomPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    1741                 :                                            TABMAPObjHdr *poObjHdr,
    1742                 :                                            GBool bCoordBlockDataOnly /*=FALSE*/,
    1743                 :                                            TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    1744                 : {
    1745                 :     GInt32              nX, nY;
    1746                 :     OGRGeometry         *poGeom;
    1747                 :     OGRPoint            *poPoint;
    1748                 : 
    1749                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    1750               0 :     if (bCoordBlockDataOnly)
    1751               0 :         return 0;
    1752                 : 
    1753                 :     /*-----------------------------------------------------------------
    1754                 :      * We assume that ValidateMapInfoType() was called already and that
    1755                 :      * the type in poObjHdr->m_nType is valid.
    1756                 :      *----------------------------------------------------------------*/
    1757               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    1758                 : 
    1759                 :     /*-----------------------------------------------------------------
    1760                 :      * Fetch and validate geometry
    1761                 :      *----------------------------------------------------------------*/
    1762               0 :     poGeom = GetGeometryRef();
    1763               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    1764               0 :         poPoint = (OGRPoint*)poGeom;
    1765                 :     else
    1766                 :     {
    1767                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    1768               0 :                  "TABCustomPoint: Missing or Invalid Geometry!");
    1769               0 :         return -1;
    1770                 :     }
    1771                 : 
    1772               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    1773                 : 
    1774                 :     /*-----------------------------------------------------------------
    1775                 :      * Copy object information
    1776                 :      *----------------------------------------------------------------*/
    1777               0 :     TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
    1778                 : 
    1779               0 :     poPointHdr->m_nX = nX;
    1780               0 :     poPointHdr->m_nY = nY;
    1781               0 :     poPointHdr->SetMBR(nX, nY, nX, nY);
    1782               0 :     poPointHdr->m_nUnknown_ = m_nUnknown_;
    1783               0 :     poPointHdr->m_nCustomStyle = m_nCustomStyle;// 0x01=Show BG,
    1784                 :                                                // 0x02=Apply Color
    1785                 : 
    1786               0 :     m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
    1787               0 :     poPointHdr->m_nSymbolId = (GByte)m_nSymbolDefIndex;      // Symbol index
    1788                 : 
    1789               0 :     m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
    1790               0 :     poPointHdr->m_nFontId = (GByte)m_nFontDefIndex;      // Font index
    1791                 : 
    1792               0 :     if (CPLGetLastErrorNo() != 0)
    1793               0 :         return -1;
    1794                 : 
    1795               0 :     return 0;
    1796                 : }
    1797                 : 
    1798                 : 
    1799                 : /**********************************************************************
    1800                 :  *                   TABCustomPoint::GetStyleString()
    1801                 :  *
    1802                 :  * Return style string for this feature.
    1803                 :  *
    1804                 :  * Style String is built only once during the first call to GetStyleString().
    1805                 :  **********************************************************************/
    1806               0 : const char *TABCustomPoint::GetStyleString()
    1807                 : {
    1808               0 :     if (m_pszStyleString == NULL)
    1809                 :     {
    1810               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    1811                 :     }
    1812                 : 
    1813               0 :     return m_pszStyleString;
    1814                 : }
    1815                 : 
    1816                 : /*=====================================================================
    1817                 :  *                      class TABPolyline
    1818                 :  *====================================================================*/
    1819                 : 
    1820                 : 
    1821                 : /**********************************************************************
    1822                 :  *                   TABPolyline::TABPolyline()
    1823                 :  *
    1824                 :  * Constructor.
    1825                 :  **********************************************************************/
    1826               2 : TABPolyline::TABPolyline(OGRFeatureDefn *poDefnIn):
    1827               2 :               TABFeature(poDefnIn)
    1828                 : {
    1829               2 :     m_bCenterIsSet = FALSE;
    1830               2 :     m_bSmooth = FALSE;
    1831               2 :     m_bWriteTwoPointLineAsPolyline = FALSE;
    1832               2 : }
    1833                 : 
    1834                 : /**********************************************************************
    1835                 :  *                   TABPolyline::~TABPolyline()
    1836                 :  *
    1837                 :  * Destructor.
    1838                 :  **********************************************************************/
    1839               2 : TABPolyline::~TABPolyline()
    1840                 : {
    1841               2 : }
    1842                 : 
    1843                 : /**********************************************************************
    1844                 :  *                     TABPolyline::CloneTABFeature()
    1845                 :  *
    1846                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    1847                 :  *
    1848                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    1849                 :  * then copies any members specific to its own type.
    1850                 :  **********************************************************************/
    1851               0 : TABFeature *TABPolyline::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    1852                 : {
    1853                 :     /*-----------------------------------------------------------------
    1854                 :      * Alloc new feature and copy the base stuff
    1855                 :      *----------------------------------------------------------------*/
    1856               0 :     TABPolyline *poNew = new TABPolyline(poNewDefn ? poNewDefn : GetDefnRef());
    1857                 : 
    1858               0 :     CopyTABFeatureBase(poNew);
    1859                 : 
    1860                 :     /*-----------------------------------------------------------------
    1861                 :      * And members specific to this class
    1862                 :      *----------------------------------------------------------------*/
    1863                 :     // ITABFeaturePen
    1864               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    1865                 : 
    1866               0 :     poNew->m_bSmooth = m_bSmooth;
    1867               0 :     poNew->m_bCenterIsSet = m_bCenterIsSet;
    1868               0 :     poNew->m_dCenterX = m_dCenterX;
    1869               0 :     poNew->m_dCenterY = m_dCenterY;
    1870                 : 
    1871               0 :     return poNew;
    1872                 : }
    1873                 : 
    1874                 : /**********************************************************************
    1875                 :  *                   TABPolyline::GetNumParts()
    1876                 :  *
    1877                 :  * Return the total number of parts in this object.
    1878                 :  *
    1879                 :  * Returns 0 if the geometry contained in the object is invalid or missing.
    1880                 :  **********************************************************************/
    1881               0 : int TABPolyline::GetNumParts()
    1882                 : {
    1883                 :     OGRGeometry         *poGeom;
    1884               0 :     int                 numParts = 0;
    1885                 : 
    1886               0 :     poGeom = GetGeometryRef();
    1887               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    1888                 :     {
    1889                 :         /*-------------------------------------------------------------
    1890                 :          * Simple polyline
    1891                 :          *------------------------------------------------------------*/
    1892               0 :         numParts = 1;
    1893                 :     }
    1894               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    1895                 :     {
    1896                 :         /*-------------------------------------------------------------
    1897                 :          * Multiple polyline
    1898                 :          *------------------------------------------------------------*/
    1899               0 :         OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
    1900               0 :         numParts = poMultiLine->getNumGeometries();
    1901                 :     }
    1902                 : 
    1903               0 :     return numParts;
    1904                 : }
    1905                 : 
    1906                 : /**********************************************************************
    1907                 :  *                   TABPolyline::GetPartRef()
    1908                 :  *
    1909                 :  * Returns a reference to the specified OGRLineString number, hiding the
    1910                 :  * complexity of dealing with OGRMultiLineString vs OGRLineString cases.
    1911                 :  *
    1912                 :  * Returns NULL if the geometry contained in the object is invalid or 
    1913                 :  * missing or if the specified part index is invalid.
    1914                 :  **********************************************************************/
    1915               0 : OGRLineString *TABPolyline::GetPartRef(int nPartIndex)
    1916                 : {
    1917                 :     OGRGeometry         *poGeom;
    1918                 : 
    1919               0 :     poGeom = GetGeometryRef();
    1920               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString && nPartIndex==0)
    1921                 :     {
    1922                 :         /*-------------------------------------------------------------
    1923                 :          * Simple polyline
    1924                 :          *------------------------------------------------------------*/
    1925               0 :         return (OGRLineString *)poGeom;
    1926                 :     }
    1927               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    1928                 :     {
    1929                 :         /*-------------------------------------------------------------
    1930                 :          * Multiple polyline
    1931                 :          *------------------------------------------------------------*/
    1932               0 :         OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
    1933               0 :         if (nPartIndex >= 0 &&
    1934                 :             nPartIndex < poMultiLine->getNumGeometries())
    1935                 :         {
    1936               0 :             return (OGRLineString*)poMultiLine->getGeometryRef(nPartIndex);
    1937                 :         }
    1938                 :         else
    1939               0 :             return NULL;
    1940                 :     }
    1941                 : 
    1942               0 :     return NULL;
    1943                 : }
    1944                 : 
    1945                 : /**********************************************************************
    1946                 :  *                   TABPolyline::ValidateMapInfoType()
    1947                 :  *
    1948                 :  * Check the feature's geometry part and return the corresponding
    1949                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    1950                 :  * be updated for further calls to GetMapInfoType();
    1951                 :  *
    1952                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    1953                 :  * is expected for this object class.
    1954                 :  **********************************************************************/
    1955               1 : int  TABPolyline::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    1956                 : {
    1957                 :     OGRGeometry   *poGeom;
    1958               1 :     OGRMultiLineString *poMultiLine = NULL;
    1959                 : 
    1960                 :     /*-----------------------------------------------------------------
    1961                 :      * Fetch and validate geometry
    1962                 :      *----------------------------------------------------------------*/
    1963               1 :     poGeom = GetGeometryRef();
    1964               1 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    1965                 :     {
    1966                 :         /*-------------------------------------------------------------
    1967                 :          * Simple polyline
    1968                 :          *------------------------------------------------------------*/
    1969               1 :         OGRLineString *poLine = (OGRLineString*)poGeom;
    1970               1 :         if ( TAB_REGION_PLINE_REQUIRES_V800(1, poLine->getNumPoints()) )
    1971                 :         {
    1972               0 :             m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
    1973                 :         }
    1974               1 :         else if ( poLine->getNumPoints() > TAB_REGION_PLINE_300_MAX_VERTICES)
    1975                 :         {
    1976               0 :             m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
    1977                 :         }
    1978               1 :         else if ( poLine->getNumPoints() > 2 )
    1979                 :         {
    1980               0 :             m_nMapInfoType = TAB_GEOM_PLINE;
    1981                 :         }
    1982               1 :         else if ( (poLine->getNumPoints() == 2) && 
    1983                 :                   (m_bWriteTwoPointLineAsPolyline == TRUE) )
    1984                 :         {
    1985               0 :            m_nMapInfoType = TAB_GEOM_PLINE;
    1986                 :         }
    1987               1 :         else if ( (poLine->getNumPoints() == 2) && 
    1988                 :                   (m_bWriteTwoPointLineAsPolyline == FALSE) )
    1989                 :         {
    1990               1 :             m_nMapInfoType = TAB_GEOM_LINE;
    1991                 :         }
    1992                 :         else
    1993                 :         {
    1994                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    1995               0 :                      "TABPolyline: Geometry must contain at least 2 points.");
    1996               0 :             m_nMapInfoType = TAB_GEOM_NONE;
    1997                 :         }
    1998                 :     }
    1999               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2000                 :     {
    2001                 :         /*-------------------------------------------------------------
    2002                 :          * Multiple polyline... validate all components
    2003                 :          *------------------------------------------------------------*/
    2004                 :         int iLine, numLines;
    2005               0 :         GInt32 numPointsTotal = 0;
    2006               0 :         poMultiLine = (OGRMultiLineString*)poGeom;
    2007               0 :         numLines = poMultiLine->getNumGeometries();
    2008                 : 
    2009               0 :         m_nMapInfoType = TAB_GEOM_MULTIPLINE;
    2010                 : 
    2011               0 :         for(iLine=0; iLine < numLines; iLine++)
    2012                 :         {
    2013               0 :             poGeom = poMultiLine->getGeometryRef(iLine);
    2014               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) != wkbLineString)
    2015                 :             {
    2016                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2017               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2018               0 :                 m_nMapInfoType = TAB_GEOM_NONE;
    2019               0 :                 numPointsTotal = 0;
    2020               0 :                 break;
    2021                 :             }
    2022               0 :             OGRLineString *poLine = (OGRLineString*)poGeom;
    2023               0 :             numPointsTotal += poLine->getNumPoints();
    2024                 :         }
    2025                 : 
    2026               0 :         if ( TAB_REGION_PLINE_REQUIRES_V800(numLines, numPointsTotal) )
    2027               0 :             m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
    2028               0 :         else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
    2029               0 :             m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
    2030                 :     }
    2031                 :     else
    2032                 :     {
    2033                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2034               0 :                  "TABPolyline: Missing or Invalid Geometry!");
    2035               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    2036                 :     }
    2037                 : 
    2038                 :     /*-----------------------------------------------------------------
    2039                 :      * Decide if coordinates should be compressed or not.
    2040                 :      *
    2041                 :      * __TODO__ We never write type LINE (2 points line) as compressed
    2042                 :      * for the moment.  If we ever do it, then the decision to write
    2043                 :      * a 2 point line in compressed coordinates or not should take into
    2044                 :      * account the location of the object block MBR, so this would be
    2045                 :      * better handled directly by TABMAPObjLine::WriteObject() since the
    2046                 :      * object block center is not known until it is written to disk.
    2047                 :      *----------------------------------------------------------------*/
    2048               1 :     if (m_nMapInfoType != TAB_GEOM_LINE)
    2049                 :     {
    2050               0 :         ValidateCoordType(poMapFile);
    2051                 :     }
    2052                 :     else
    2053                 :     {
    2054               1 :         UpdateMBR(poMapFile);
    2055                 :     }
    2056                 : 
    2057               1 :     return m_nMapInfoType;
    2058                 : }
    2059                 : 
    2060                 : 
    2061                 : /**********************************************************************
    2062                 :  *                   TABPolyline::ReadGeometryFromMAPFile()
    2063                 :  *
    2064                 :  * Fill the geometry and representation (color, etc...) part of the
    2065                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    2066                 :  *
    2067                 :  * It is assumed that poMAPFile currently points to the beginning of
    2068                 :  * a map object.
    2069                 :  *
    2070                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    2071                 :  * been called.
    2072                 :  **********************************************************************/
    2073               1 : int TABPolyline::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    2074                 :                                          TABMAPObjHdr *poObjHdr,
    2075                 :                                          GBool bCoordBlockDataOnly /*=FALSE*/,
    2076                 :                                          TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    2077                 : {
    2078                 :     GInt32              nX, nY;
    2079                 :     double              dX, dY, dXMin, dYMin, dXMax, dYMax;
    2080                 :     OGRGeometry         *poGeometry;
    2081                 :     OGRLineString       *poLine;
    2082               1 :     GBool               bComprCoord = poObjHdr->IsCompressedType();
    2083               1 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    2084                 : 
    2085                 :     /*-----------------------------------------------------------------
    2086                 :      * Fetch and validate geometry type
    2087                 :      *----------------------------------------------------------------*/
    2088               1 :     m_nMapInfoType = poObjHdr->m_nType;
    2089                 : 
    2090               2 :     if (m_nMapInfoType == TAB_GEOM_LINE ||
    2091                 :         m_nMapInfoType == TAB_GEOM_LINE_C )
    2092                 :     {
    2093                 :         /*=============================================================
    2094                 :          * LINE (2 vertices)
    2095                 :          *============================================================*/
    2096               1 :         TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
    2097                 : 
    2098               1 :         m_bSmooth = FALSE;
    2099                 : 
    2100               1 :         poGeometry = poLine = new OGRLineString();
    2101               1 :         poLine->setNumPoints(2);
    2102                 : 
    2103                 :         poMapFile->Int2Coordsys(poLineHdr->m_nX1, poLineHdr->m_nY1, 
    2104               1 :                                 dXMin, dYMin);
    2105               1 :         poLine->setPoint(0, dXMin, dYMin);
    2106                 : 
    2107                 :         poMapFile->Int2Coordsys(poLineHdr->m_nX2, poLineHdr->m_nY2,
    2108               1 :                                 dXMax, dYMax);
    2109               1 :         poLine->setPoint(1, dXMax, dYMax);
    2110                 : 
    2111               1 :         if (!bCoordBlockDataOnly)
    2112                 :         {
    2113               1 :             m_nPenDefIndex = poLineHdr->m_nPenId;      // Pen index
    2114               1 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    2115                 :         }
    2116                 :     }
    2117               0 :     else if (m_nMapInfoType == TAB_GEOM_PLINE ||
    2118                 :              m_nMapInfoType == TAB_GEOM_PLINE_C )
    2119                 :     {
    2120                 :         /*=============================================================
    2121                 :          * PLINE ( > 2 vertices)
    2122                 :          *============================================================*/
    2123                 :         int     i, numPoints, nStatus;
    2124                 :         GUInt32 nCoordDataSize;
    2125                 :         GInt32  nCoordBlockPtr;
    2126                 : 
    2127                 :         /*-------------------------------------------------------------
    2128                 :          * Copy data from poObjHdr
    2129                 :          *------------------------------------------------------------*/
    2130               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2131                 : 
    2132               0 :         nCoordBlockPtr  = poPLineHdr->m_nCoordBlockPtr;
    2133               0 :         nCoordDataSize  = poPLineHdr->m_nCoordDataSize;
    2134                 :         //numLineSections = poPLineHdr->m_numLineSections; // Always 1
    2135               0 :         m_bSmooth       = poPLineHdr->m_bSmooth;
    2136                 : 
    2137                 :         // Centroid/label point
    2138                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY, 
    2139               0 :                                 dX, dY);
    2140               0 :         SetCenter(dX, dY);
    2141                 : 
    2142                 :         // Compressed coordinate origin (useful only in compressed case!)
    2143               0 :         m_nComprOrgX = poPLineHdr->m_nComprOrgX;
    2144               0 :         m_nComprOrgY = poPLineHdr->m_nComprOrgY;
    2145                 : 
    2146                 :         // MBR
    2147                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY, 
    2148               0 :                                 dXMin, dYMin);
    2149                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY, 
    2150               0 :                                 dXMax, dYMax);
    2151                 : 
    2152               0 :         if (!bCoordBlockDataOnly)
    2153                 :         {
    2154               0 :             m_nPenDefIndex = poPLineHdr->m_nPenId;        // Pen index
    2155               0 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    2156                 :         }
    2157                 : 
    2158                 :         /*-------------------------------------------------------------
    2159                 :          * Create Geometry and read coordinates
    2160                 :          *------------------------------------------------------------*/
    2161               0 :         numPoints = nCoordDataSize/(bComprCoord?4:8);
    2162                 : 
    2163               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2164               0 :             poCoordBlock = *ppoCoordBlock;
    2165                 :         else
    2166               0 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    2167               0 :         if (poCoordBlock == NULL)
    2168                 :         {
    2169                 :             CPLError(CE_Failure, CPLE_FileIO,
    2170                 :                      "Can't access coordinate block at offset %d", 
    2171               0 :                      nCoordBlockPtr);
    2172               0 :             return -1;
    2173                 :         }
    2174                 : 
    2175               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2176                 : 
    2177               0 :         poGeometry = poLine = new OGRLineString();
    2178               0 :         poLine->setNumPoints(numPoints);
    2179                 : 
    2180               0 :         nStatus = 0;
    2181               0 :         for(i=0; nStatus == 0 && i<numPoints; i++)
    2182                 :         {
    2183               0 :             nStatus = poCoordBlock->ReadIntCoord(bComprCoord, nX, nY);
    2184               0 :             if (nStatus != 0)
    2185               0 :                 break;
    2186               0 :             poMapFile->Int2Coordsys(nX, nY, dX, dY);
    2187               0 :             poLine->setPoint(i, dX, dY);
    2188                 :         }
    2189                 : 
    2190               0 :         if (nStatus != 0)
    2191                 :         {
    2192                 :             // Failed ... error message has already been produced
    2193               0 :             delete poGeometry;
    2194               0 :             return nStatus;
    2195                 :         }   
    2196                 : 
    2197                 :     }
    2198               0 :     else if (m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
    2199                 :              m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
    2200                 :              m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
    2201                 :              m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
    2202                 :              m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
    2203                 :              m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C )
    2204                 :     {
    2205                 :         /*=============================================================
    2206                 :          * PLINE MULTIPLE
    2207                 :          *============================================================*/
    2208                 :         int     i, iSection;
    2209                 :         GInt32  nCoordBlockPtr, numLineSections;
    2210                 :         GInt32  nCoordDataSize, numPointsTotal, *panXY;
    2211                 :         OGRMultiLineString      *poMultiLine;
    2212                 :         TABMAPCoordSecHdr       *pasSecHdrs;
    2213               0 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    2214                 : 
    2215                 :         /*-------------------------------------------------------------
    2216                 :          * Copy data from poObjHdr
    2217                 :          *------------------------------------------------------------*/
    2218               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2219                 : 
    2220               0 :         nCoordBlockPtr  = poPLineHdr->m_nCoordBlockPtr;
    2221               0 :         nCoordDataSize  = poPLineHdr->m_nCoordDataSize;
    2222               0 :         numLineSections = poPLineHdr->m_numLineSections;
    2223               0 :         m_bSmooth       = poPLineHdr->m_bSmooth;
    2224                 : 
    2225                 :         // Centroid/label point
    2226                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY, 
    2227               0 :                                 dX, dY);
    2228               0 :         SetCenter(dX, dY);
    2229                 : 
    2230                 :         // Compressed coordinate origin (useful only in compressed case!)
    2231               0 :         m_nComprOrgX = poPLineHdr->m_nComprOrgX;
    2232               0 :         m_nComprOrgY = poPLineHdr->m_nComprOrgY;
    2233                 : 
    2234                 :         // MBR
    2235                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY, 
    2236               0 :                                 dXMin, dYMin);
    2237                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY, 
    2238               0 :                                 dXMax, dYMax);
    2239                 : 
    2240               0 :         if (!bCoordBlockDataOnly)
    2241                 :         {
    2242               0 :             m_nPenDefIndex = poPLineHdr->m_nPenId;        // Pen index
    2243               0 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    2244                 :         }
    2245                 : 
    2246                 :         /*-------------------------------------------------------------
    2247                 :          * Read data from the coord. block
    2248                 :          *------------------------------------------------------------*/
    2249                 :         pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
    2250               0 :                                                    sizeof(TABMAPCoordSecHdr));
    2251                 : 
    2252               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2253               0 :             poCoordBlock = *ppoCoordBlock;
    2254                 :         else
    2255               0 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    2256                 : 
    2257               0 :         if (poCoordBlock == NULL ||
    2258                 :             poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion, 
    2259                 :                                            numLineSections,
    2260                 :                                            pasSecHdrs, numPointsTotal) != 0)
    2261                 :         {
    2262                 :             CPLError(CE_Failure, CPLE_FileIO,
    2263                 :                      "Failed reading coordinate data at offset %d", 
    2264               0 :                      nCoordBlockPtr);
    2265               0 :             CPLFree(pasSecHdrs);
    2266               0 :             return -1;
    2267                 :         }
    2268                 : 
    2269               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2270                 : 
    2271               0 :         panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
    2272                 : 
    2273               0 :         if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
    2274                 :         {
    2275                 :             CPLError(CE_Failure, CPLE_FileIO,
    2276                 :                      "Failed reading coordinate data at offset %d", 
    2277               0 :                      nCoordBlockPtr);
    2278               0 :             CPLFree(pasSecHdrs);
    2279               0 :             CPLFree(panXY);
    2280               0 :             return -1;
    2281                 :         }
    2282                 : 
    2283                 :         /*-------------------------------------------------------------
    2284                 :          * Create a Geometry collection with one line geometry for
    2285                 :          * each coordinates section
    2286                 :          * If object contains only one section, then return a simple LineString
    2287                 :          *------------------------------------------------------------*/
    2288               0 :         if (numLineSections > 1)
    2289               0 :             poGeometry = poMultiLine = new OGRMultiLineString();
    2290                 :         else
    2291               0 :             poGeometry = poMultiLine = NULL;
    2292                 : 
    2293               0 :         for(iSection=0; iSection<numLineSections; iSection++)
    2294                 :         {
    2295                 :             GInt32 *pnXYPtr;
    2296                 :             int     numSectionVertices;
    2297                 : 
    2298               0 :             numSectionVertices = pasSecHdrs[iSection].numVertices;
    2299               0 :             pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
    2300                 : 
    2301               0 :             poLine = new OGRLineString();
    2302               0 :             poLine->setNumPoints(numSectionVertices);
    2303                 : 
    2304               0 :             for(i=0; i<numSectionVertices; i++)
    2305                 :             {
    2306               0 :                 poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
    2307               0 :                 poLine->setPoint(i, dX, dY);
    2308               0 :                 pnXYPtr += 2;
    2309                 :             }
    2310                 : 
    2311               0 :             if (poGeometry==NULL)
    2312               0 :                 poGeometry = poLine;
    2313               0 :             else if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
    2314                 :             {
    2315               0 :                 CPLAssert(FALSE); // Just in case lower-level lib is modified
    2316                 :             }
    2317               0 :             poLine = NULL;
    2318                 :         }
    2319                 : 
    2320               0 :         CPLFree(pasSecHdrs);
    2321               0 :         CPLFree(panXY);
    2322                 :     }
    2323                 :     else
    2324                 :     {
    2325                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2326                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    2327               0 :                  m_nMapInfoType, m_nMapInfoType);
    2328               0 :         return -1;
    2329                 :     }
    2330                 : 
    2331               1 :     SetGeometryDirectly(poGeometry);
    2332                 : 
    2333               1 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    2334                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    2335               1 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    2336                 : 
    2337                 :     /* Return a ref to coord block so that caller can continue reading
    2338                 :      * after the end of this object (used by TABCollection and index splitting)
    2339                 :      */
    2340               1 :     if (ppoCoordBlock)
    2341               0 :         *ppoCoordBlock = poCoordBlock;
    2342                 : 
    2343               1 :     return 0;
    2344                 : }
    2345                 : 
    2346                 : /**********************************************************************
    2347                 :  *                   TABPolyline::WriteGeometryToMAPFile()
    2348                 :  *
    2349                 :  * Write the geometry and representation (color, etc...) part of the
    2350                 :  * feature to the .MAP object pointed to by poMAPFile.
    2351                 :  *
    2352                 :  * It is assumed that poMAPFile currently points to a valid map object.
    2353                 :  *
    2354                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    2355                 :  * been called.
    2356                 :  **********************************************************************/
    2357               1 : int TABPolyline::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    2358                 :                                         TABMAPObjHdr *poObjHdr,
    2359                 :                                         GBool bCoordBlockDataOnly /*=FALSE*/,
    2360                 :                                         TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    2361                 : {
    2362                 :     GInt32              nX, nY;
    2363                 :     OGRGeometry         *poGeom;
    2364               1 :     OGRLineString       *poLine=NULL;
    2365               1 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    2366                 : 
    2367                 :     /*-----------------------------------------------------------------
    2368                 :      * We assume that ValidateMapInfoType() was called already and that
    2369                 :      * the type in poObjHdr->m_nType is valid.
    2370                 :      *----------------------------------------------------------------*/
    2371               1 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    2372               1 :     CPLErrorReset();
    2373                 : 
    2374                 :     /*-----------------------------------------------------------------
    2375                 :      * Fetch and validate geometry
    2376                 :      *----------------------------------------------------------------*/
    2377               1 :     poGeom = GetGeometryRef();
    2378                 : 
    2379               2 :     if ((m_nMapInfoType == TAB_GEOM_LINE || 
    2380                 :          m_nMapInfoType == TAB_GEOM_LINE_C ) &&
    2381               1 :         poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString &&
    2382                 :         (poLine = (OGRLineString*)poGeom)->getNumPoints() == 2)
    2383                 :     {
    2384                 :         /*=============================================================
    2385                 :          * LINE (2 vertices)
    2386                 :          *============================================================*/
    2387               1 :         TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
    2388                 : 
    2389                 :         poMapFile->Coordsys2Int(poLine->getX(0), poLine->getY(0), 
    2390               1 :                                 poLineHdr->m_nX1, poLineHdr->m_nY1);
    2391                 :         poMapFile->Coordsys2Int(poLine->getX(1), poLine->getY(1), 
    2392               1 :                                 poLineHdr->m_nX2, poLineHdr->m_nY2);
    2393                 :         poLineHdr->SetMBR(poLineHdr->m_nX1, poLineHdr->m_nY1,
    2394               1 :                           poLineHdr->m_nX2, poLineHdr->m_nY2 );
    2395                 : 
    2396               1 :         if (!bCoordBlockDataOnly)
    2397                 :         {
    2398               1 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    2399               1 :             poLineHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    2400                 :         }
    2401                 : 
    2402                 :     }
    2403               0 :     else if ((m_nMapInfoType == TAB_GEOM_PLINE ||
    2404                 :               m_nMapInfoType == TAB_GEOM_PLINE_C ) &&
    2405               0 :              poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
    2406                 :     {
    2407                 :         /*=============================================================
    2408                 :          * PLINE ( > 2 vertices and less than 32767 vertices)
    2409                 :          *============================================================*/
    2410                 :         int     i, numPoints, nStatus;
    2411                 :         GUInt32 nCoordDataSize;
    2412                 :         GInt32  nCoordBlockPtr;
    2413               0 :         GBool   bCompressed = poObjHdr->IsCompressedType();
    2414                 : 
    2415                 :         /*-------------------------------------------------------------
    2416                 :          * Process geometry first...
    2417                 :          *------------------------------------------------------------*/
    2418               0 :         poLine = (OGRLineString*)poGeom;
    2419               0 :         numPoints = poLine->getNumPoints();
    2420               0 :         CPLAssert(numPoints <= TAB_REGION_PLINE_300_MAX_VERTICES);
    2421                 : 
    2422               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2423               0 :             poCoordBlock = *ppoCoordBlock;
    2424                 :         else
    2425               0 :             poCoordBlock = poMapFile->GetCurCoordBlock();
    2426               0 :         poCoordBlock->StartNewFeature();
    2427               0 :         nCoordBlockPtr = poCoordBlock->GetCurAddress();
    2428               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2429                 : 
    2430               0 :         nStatus = 0;
    2431               0 :         for(i=0; nStatus == 0 && i<numPoints; i++)
    2432                 :         {
    2433               0 :             poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i), nX, nY);
    2434               0 :             if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY, 
    2435                 :                                                        bCompressed)) != 0)
    2436                 :             {
    2437                 :                 // Failed ... error message has already been produced
    2438               0 :                 return nStatus;
    2439                 :             }   
    2440                 :         }
    2441                 : 
    2442               0 :         nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    2443                 : 
    2444                 :         /*-------------------------------------------------------------
    2445                 :          * Copy info to poObjHdr
    2446                 :          *------------------------------------------------------------*/
    2447               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2448                 : 
    2449               0 :         poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
    2450               0 :         poPLineHdr->m_nCoordDataSize = nCoordDataSize;
    2451               0 :         poPLineHdr->m_numLineSections = 1;
    2452                 : 
    2453               0 :         poPLineHdr->m_bSmooth = m_bSmooth;
    2454                 : 
    2455                 :         // MBR
    2456               0 :         poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    2457                 : 
    2458                 :         // Polyline center/label point
    2459                 :         double dX, dY;
    2460               0 :         if (GetCenter(dX, dY) != -1)
    2461                 :         {
    2462                 :             poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX, 
    2463               0 :                                     poPLineHdr->m_nLabelY);
    2464                 :         }
    2465                 :         else
    2466                 :         {
    2467               0 :             poPLineHdr->m_nLabelX = m_nComprOrgX;
    2468               0 :             poPLineHdr->m_nLabelY = m_nComprOrgY;
    2469                 :         }
    2470                 :         
    2471                 :         // Compressed coordinate origin (useful only in compressed case!)
    2472               0 :         poPLineHdr->m_nComprOrgX = m_nComprOrgX;
    2473               0 :         poPLineHdr->m_nComprOrgY = m_nComprOrgY;
    2474                 : 
    2475               0 :         if (!bCoordBlockDataOnly)
    2476                 :         {
    2477               0 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    2478               0 :             poPLineHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    2479                 :         }
    2480                 : 
    2481                 :     }
    2482               0 :     else if ((m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
    2483                 :               m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
    2484                 :               m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
    2485                 :               m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
    2486                 :               m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
    2487                 :               m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C) &&
    2488               0 :              poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
    2489               0 :                         wkbFlatten(poGeom->getGeometryType()) == wkbLineString) )
    2490                 :     {
    2491                 :         /*=============================================================
    2492                 :          * PLINE MULTIPLE (or single PLINE with more than 32767 vertices)
    2493                 :          *============================================================*/
    2494               0 :         int     nStatus=0, i, iLine;
    2495                 :         GInt32  numPointsTotal, numPoints;
    2496                 :         GUInt32 nCoordDataSize;
    2497                 :         GInt32  nCoordBlockPtr, numLines;
    2498               0 :         OGRMultiLineString      *poMultiLine=NULL;
    2499                 :         TABMAPCoordSecHdr       *pasSecHdrs;
    2500               0 :         OGREnvelope             sEnvelope;
    2501               0 :         GBool   bCompressed = poObjHdr->IsCompressedType();
    2502                 : 
    2503                 :         CPLAssert(m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
    2504                 :                   m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
    2505                 :                   m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
    2506                 :                   m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
    2507                 :                   m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
    2508               0 :                   m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C);
    2509                 :         /*-------------------------------------------------------------
    2510                 :          * Process geometry first...
    2511                 :          *------------------------------------------------------------*/
    2512               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    2513               0 :             poCoordBlock = *ppoCoordBlock;
    2514                 :         else
    2515               0 :             poCoordBlock = poMapFile->GetCurCoordBlock();
    2516               0 :         poCoordBlock->StartNewFeature();
    2517               0 :         nCoordBlockPtr = poCoordBlock->GetCurAddress();
    2518               0 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    2519                 : 
    2520               0 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2521                 :         {
    2522               0 :             poMultiLine = (OGRMultiLineString*)poGeom;
    2523               0 :             numLines = poMultiLine->getNumGeometries();
    2524                 :         }
    2525                 :         else
    2526                 :         {
    2527               0 :             poMultiLine = NULL;
    2528               0 :             numLines = 1;
    2529                 :         }
    2530                 : 
    2531                 :         /*-------------------------------------------------------------
    2532                 :          * Build and write array of coord sections headers
    2533                 :          *------------------------------------------------------------*/
    2534                 :         pasSecHdrs = (TABMAPCoordSecHdr*)CPLCalloc(numLines,
    2535               0 :                                                    sizeof(TABMAPCoordSecHdr));
    2536                 : 
    2537                 :         /*-------------------------------------------------------------
    2538                 :          * In calculation of nDataOffset, we have to take into account that
    2539                 :          * V450 header section uses int32 instead of int16 for numVertices
    2540                 :          * and we add another 2 bytes to align with a 4 bytes boundary.
    2541                 :          *------------------------------------------------------------*/
    2542               0 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    2543                 : 
    2544                 :         int nTotalHdrSizeUncompressed;
    2545               0 :         if (nVersion >= 450)
    2546               0 :             nTotalHdrSizeUncompressed = 28 * numLines;
    2547                 :         else
    2548               0 :             nTotalHdrSizeUncompressed = 24 * numLines;
    2549                 : 
    2550               0 :         numPointsTotal = 0;
    2551               0 :         for(iLine=0; iLine < numLines; iLine++)
    2552                 :         {
    2553               0 :             if (poMultiLine)
    2554               0 :                 poGeom = poMultiLine->getGeometryRef(iLine);
    2555                 :                 
    2556               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2557                 :             {
    2558               0 :                 poLine = (OGRLineString*)poGeom;
    2559               0 :                 numPoints = poLine->getNumPoints();
    2560               0 :                 poLine->getEnvelope(&sEnvelope);
    2561                 : 
    2562               0 :                 pasSecHdrs[iLine].numVertices = poLine->getNumPoints();
    2563               0 :                 pasSecHdrs[iLine].numHoles = 0; // It's a line!
    2564                 : 
    2565                 :                 poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
    2566               0 :                                         pasSecHdrs[iLine].nXMin,
    2567               0 :                                         pasSecHdrs[iLine].nYMin);
    2568                 :                 poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
    2569               0 :                                         pasSecHdrs[iLine].nXMax,
    2570               0 :                                         pasSecHdrs[iLine].nYMax);
    2571               0 :                 pasSecHdrs[iLine].nDataOffset = nTotalHdrSizeUncompressed +
    2572               0 :                                                 numPointsTotal*4*2;
    2573               0 :                 pasSecHdrs[iLine].nVertexOffset = numPointsTotal;
    2574                 : 
    2575               0 :                 numPointsTotal += numPoints;
    2576                 :             }
    2577                 :             else
    2578                 :             {
    2579                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2580               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2581               0 :                 nStatus = -1;
    2582                 :             }
    2583                 : 
    2584                 :         }
    2585                 :          
    2586               0 :         if (nStatus == 0)
    2587                 :             nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numLines, 
    2588               0 :                                                       pasSecHdrs, bCompressed);
    2589                 : 
    2590               0 :         CPLFree(pasSecHdrs);
    2591               0 :         pasSecHdrs = NULL;
    2592                 : 
    2593               0 :         if (nStatus != 0)
    2594               0 :             return nStatus;  // Error has already been reported.
    2595                 : 
    2596                 :         /*-------------------------------------------------------------
    2597                 :          * Then write the coordinates themselves...
    2598                 :          *------------------------------------------------------------*/
    2599               0 :         for(iLine=0; nStatus == 0 && iLine < numLines; iLine++)
    2600                 :         {
    2601               0 :             if (poMultiLine)
    2602               0 :                 poGeom = poMultiLine->getGeometryRef(iLine);
    2603                 : 
    2604               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2605                 :             {
    2606               0 :                 poLine = (OGRLineString*)poGeom;
    2607               0 :                 numPoints = poLine->getNumPoints();
    2608                 : 
    2609               0 :                 for(i=0; nStatus == 0 && i<numPoints; i++)
    2610                 :                 {
    2611                 :                     poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i),
    2612               0 :                                             nX, nY);
    2613               0 :                     if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
    2614                 :                                                            bCompressed)) != 0)
    2615                 :                     {
    2616                 :                         // Failed ... error message has already been produced
    2617               0 :                         return nStatus;
    2618                 :                     }   
    2619                 :                 }
    2620                 :             }
    2621                 :             else
    2622                 :             {
    2623                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2624               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2625               0 :                 return -1;
    2626                 :             }
    2627                 : 
    2628                 :         }
    2629                 : 
    2630               0 :         nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    2631                 : 
    2632                 :         /*-------------------------------------------------------------
    2633                 :          * ... and finally copy info to poObjHdr
    2634                 :          *------------------------------------------------------------*/
    2635               0 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    2636                 : 
    2637               0 :         poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
    2638               0 :         poPLineHdr->m_nCoordDataSize = nCoordDataSize;
    2639               0 :         poPLineHdr->m_numLineSections = numLines;
    2640                 : 
    2641               0 :         poPLineHdr->m_bSmooth = m_bSmooth;
    2642                 : 
    2643                 :         // MBR
    2644               0 :         poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    2645                 : 
    2646                 :         // Polyline center/label point
    2647                 :         double dX, dY;
    2648               0 :         if (GetCenter(dX, dY) != -1)
    2649                 :         {
    2650                 :             poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX, 
    2651               0 :                                     poPLineHdr->m_nLabelY);
    2652                 :         }
    2653                 :         else
    2654                 :         {
    2655               0 :             poPLineHdr->m_nLabelX = m_nComprOrgX;
    2656               0 :             poPLineHdr->m_nLabelY = m_nComprOrgY;
    2657                 :         }
    2658                 :         
    2659                 :         // Compressed coordinate origin (useful only in compressed case!)
    2660               0 :         poPLineHdr->m_nComprOrgX = m_nComprOrgX;
    2661               0 :         poPLineHdr->m_nComprOrgY = m_nComprOrgY;
    2662                 : 
    2663               0 :         if (!bCoordBlockDataOnly)
    2664                 :         {
    2665               0 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    2666               0 :             poPLineHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    2667                 :         }
    2668                 : 
    2669                 :     }
    2670                 :     else
    2671                 :     {
    2672                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2673               0 :                  "TABPolyline: Object contains an invalid Geometry!");
    2674               0 :         return -1;
    2675                 :     }
    2676                 : 
    2677               1 :     if (CPLGetLastErrorType() == CE_Failure )
    2678               0 :         return -1;
    2679                 : 
    2680                 :     /* Return a ref to coord block so that caller can continue writing
    2681                 :      * after the end of this object (used by index splitting)
    2682                 :      */
    2683               1 :     if (ppoCoordBlock)
    2684               0 :         *ppoCoordBlock = poCoordBlock;
    2685                 : 
    2686               1 :     return 0;
    2687                 : }
    2688                 : 
    2689                 : /**********************************************************************
    2690                 :  *                   TABPolyline::GetStyleString()
    2691                 :  *
    2692                 :  * Return style string for this feature.
    2693                 :  *
    2694                 :  * Style String is built only once during the first call to GetStyleString().
    2695                 :  **********************************************************************/
    2696               0 : const char *TABPolyline::GetStyleString()
    2697                 : {
    2698               0 :     if (m_pszStyleString == NULL)
    2699                 :     {
    2700               0 :         m_pszStyleString = CPLStrdup(GetPenStyleString());
    2701                 :     }
    2702                 : 
    2703               0 :     return m_pszStyleString;
    2704                 : }
    2705                 : 
    2706                 : 
    2707                 : /**********************************************************************
    2708                 :  *                   TABPolyline::DumpMIF()
    2709                 :  *
    2710                 :  * Dump feature geometry in a format similar to .MIF PLINEs.
    2711                 :  **********************************************************************/
    2712               0 : void TABPolyline::DumpMIF(FILE *fpOut /*=NULL*/)
    2713                 : {
    2714                 :     OGRGeometry   *poGeom;
    2715               0 :     OGRMultiLineString *poMultiLine = NULL;
    2716               0 :     OGRLineString *poLine = NULL;
    2717                 :     int i, numPoints;
    2718                 : 
    2719               0 :     if (fpOut == NULL)
    2720               0 :         fpOut = stdout;
    2721                 : 
    2722                 :     /*-----------------------------------------------------------------
    2723                 :      * Fetch and validate geometry
    2724                 :      *----------------------------------------------------------------*/
    2725               0 :     poGeom = GetGeometryRef();
    2726               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2727                 :     {
    2728                 :         /*-------------------------------------------------------------
    2729                 :          * Generate output for simple polyline
    2730                 :          *------------------------------------------------------------*/
    2731               0 :         poLine = (OGRLineString*)poGeom;
    2732               0 :         numPoints = poLine->getNumPoints();
    2733               0 :         fprintf(fpOut, "PLINE %d\n", numPoints);
    2734               0 :         for(i=0; i<numPoints; i++)
    2735               0 :             fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
    2736                 :     }
    2737               0 :     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2738                 :     {
    2739                 :         /*-------------------------------------------------------------
    2740                 :          * Generate output for multiple polyline
    2741                 :          *------------------------------------------------------------*/
    2742                 :         int iLine, numLines;
    2743               0 :         poMultiLine = (OGRMultiLineString*)poGeom;
    2744               0 :         numLines = poMultiLine->getNumGeometries();
    2745               0 :         fprintf(fpOut, "PLINE MULTIPLE %d\n", numLines);
    2746               0 :         for(iLine=0; iLine < numLines; iLine++)
    2747                 :         {
    2748               0 :             poGeom = poMultiLine->getGeometryRef(iLine);
    2749               0 :             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2750                 :             {
    2751               0 :                 poLine = (OGRLineString*)poGeom;
    2752               0 :                 numPoints = poLine->getNumPoints();
    2753               0 :                 fprintf(fpOut, " %d\n", numPoints);
    2754               0 :                 for(i=0; i<numPoints; i++)
    2755               0 :                     fprintf(fpOut, "%.15g %.15g\n",poLine->getX(i),poLine->getY(i));
    2756                 :             }
    2757                 :             else
    2758                 :             {
    2759                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    2760               0 :                          "TABPolyline: Object contains an invalid Geometry!");
    2761               0 :                 return;
    2762                 :             }
    2763                 : 
    2764                 :         }
    2765                 :     }
    2766                 :     else
    2767                 :     {
    2768                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2769               0 :                  "TABPolyline: Missing or Invalid Geometry!");
    2770               0 :         return;
    2771                 :     }
    2772                 : 
    2773               0 :     if (m_bCenterIsSet)
    2774               0 :         fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
    2775                 : 
    2776                 :     // Finish with PEN/BRUSH/etc. clauses
    2777               0 :     DumpPenDef();
    2778                 : 
    2779               0 :     fflush(fpOut);
    2780                 : }
    2781                 : 
    2782                 : /**********************************************************************
    2783                 :  *                   TABPolyline::GetCenter()
    2784                 :  *
    2785                 :  * Returns the center point of the line.  Compute one if it was not 
    2786                 :  * explicitly set:
    2787                 :  *
    2788                 :  * In MapInfo, for a simple or multiple polyline (pline), the center point 
    2789                 :  * in the object definition is supposed to be either the center point of 
    2790                 :  * the pline or the first section of a multiple pline (if an odd number of 
    2791                 :  * points in the pline or first section), or the midway point between the 
    2792                 :  * two central points (if an even number of points involved). 
    2793                 :  *
    2794                 :  * Returns 0 on success, -1 on error.
    2795                 :  **********************************************************************/
    2796               0 : int TABPolyline::GetCenter(double &dX, double &dY)
    2797                 : {
    2798               0 :     if (!m_bCenterIsSet)
    2799                 :     {
    2800                 :         OGRGeometry     *poGeom;
    2801               0 :         OGRLineString   *poLine = NULL;
    2802                 : 
    2803               0 :         poGeom = GetGeometryRef();
    2804               0 :         if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    2805                 :         {
    2806               0 :             poLine = (OGRLineString *)poGeom;
    2807                 :         }
    2808               0 :         else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
    2809                 :         {
    2810               0 :             OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
    2811               0 :             if (poMultiLine->getNumGeometries() > 0)
    2812               0 :                 poLine = (OGRLineString *)poMultiLine->getGeometryRef(0);
    2813                 :         }
    2814                 : 
    2815               0 :         if (poLine && poLine->getNumPoints() > 0)
    2816                 :         {
    2817               0 :             int i = poLine->getNumPoints()/2;
    2818               0 :             if (poLine->getNumPoints() % 2 == 0)
    2819                 :             {
    2820                 :                 // Return the midway between the 2 center points
    2821               0 :                 m_dCenterX = (poLine->getX(i-1) + poLine->getX(i))/2.0;
    2822               0 :                 m_dCenterY = (poLine->getY(i-1) + poLine->getY(i))/2.0;
    2823                 :             }
    2824                 :             else
    2825                 :             {
    2826                 :                 // Return the center point
    2827               0 :                 m_dCenterX = poLine->getX(i);
    2828               0 :                 m_dCenterY = poLine->getY(i);
    2829                 :             }
    2830               0 :             m_bCenterIsSet = TRUE;
    2831                 :         }
    2832                 :     }
    2833                 : 
    2834               0 :     if (!m_bCenterIsSet)
    2835               0 :         return -1;
    2836                 : 
    2837               0 :     dX = m_dCenterX;
    2838               0 :     dY = m_dCenterY;
    2839               0 :     return 0;
    2840                 : }
    2841                 : 
    2842                 : /**********************************************************************
    2843                 :  *                   TABPolyline::SetCenter()
    2844                 :  *
    2845                 :  * Set the X,Y coordinates to use as center point for the line.
    2846                 :  **********************************************************************/
    2847               0 : void TABPolyline::SetCenter(double dX, double dY)
    2848                 : {
    2849               0 :     m_dCenterX = dX;
    2850               0 :     m_dCenterY = dY;
    2851               0 :     m_bCenterIsSet = TRUE;
    2852               0 : }
    2853                 : 
    2854                 : /**********************************************************************
    2855                 :  *                   TABPolyline::TwoPointLineAsPolyline()
    2856                 :  *
    2857                 :  * Returns the value of m_bWriteTwoPointLineAsPolyline
    2858                 :  **********************************************************************/
    2859               0 : GBool TABPolyline::TwoPointLineAsPolyline()
    2860                 : {
    2861               0 :     return m_bWriteTwoPointLineAsPolyline;
    2862                 : }
    2863                 : 
    2864                 : /**********************************************************************
    2865                 : *                   TABPolyline::TwoPointLineAsPolyline()
    2866                 : *
    2867                 : * Sets the value of m_bWriteTwoPointLineAsPolyline
    2868                 : **********************************************************************/
    2869               0 : void TABPolyline::TwoPointLineAsPolyline(GBool bTwoPointLineAsPolyline)
    2870                 : {
    2871               0 :     m_bWriteTwoPointLineAsPolyline = bTwoPointLineAsPolyline;
    2872               0 : }
    2873                 : 
    2874                 : 
    2875                 : /*=====================================================================
    2876                 :  *                      class TABRegion
    2877                 :  *====================================================================*/
    2878                 : 
    2879                 : /**********************************************************************
    2880                 :  *                   TABRegion::TABRegion()
    2881                 :  *
    2882                 :  * Constructor.
    2883                 :  **********************************************************************/
    2884             100 : TABRegion::TABRegion(OGRFeatureDefn *poDefnIn):
    2885             100 :               TABFeature(poDefnIn)
    2886                 : {
    2887             100 :     m_bCenterIsSet = FALSE;
    2888             100 :     m_bSmooth = FALSE;
    2889             100 : }
    2890                 : 
    2891                 : /**********************************************************************
    2892                 :  *                   TABRegion::~TABRegion()
    2893                 :  *
    2894                 :  * Destructor.
    2895                 :  **********************************************************************/
    2896             100 : TABRegion::~TABRegion()
    2897                 : {
    2898             100 : }
    2899                 : 
    2900                 : /**********************************************************************
    2901                 :  *                     TABRegion::CloneTABFeature()
    2902                 :  *
    2903                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    2904                 :  *
    2905                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    2906                 :  * then copies any members specific to its own type.
    2907                 :  **********************************************************************/
    2908               0 : TABFeature *TABRegion::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    2909                 : {
    2910                 :     /*-----------------------------------------------------------------
    2911                 :      * Alloc new feature and copy the base stuff
    2912                 :      *----------------------------------------------------------------*/
    2913               0 :     TABRegion *poNew = new TABRegion(poNewDefn ? poNewDefn : GetDefnRef());
    2914                 : 
    2915               0 :     CopyTABFeatureBase(poNew);
    2916                 : 
    2917                 :     /*-----------------------------------------------------------------
    2918                 :      * And members specific to this class
    2919                 :      *----------------------------------------------------------------*/
    2920                 :     // ITABFeaturePen
    2921               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    2922                 : 
    2923                 :     // ITABFeatureBrush
    2924               0 :     *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
    2925                 : 
    2926               0 :     poNew->m_bSmooth = m_bSmooth;
    2927               0 :     poNew->m_bCenterIsSet = m_bCenterIsSet;
    2928               0 :     poNew->m_dCenterX = m_dCenterX;
    2929               0 :     poNew->m_dCenterY = m_dCenterY;
    2930                 : 
    2931               0 :     return poNew;
    2932                 : }
    2933                 : 
    2934                 : /**********************************************************************
    2935                 :  *                   TABRegion::ValidateMapInfoType()
    2936                 :  *
    2937                 :  * Check the feature's geometry part and return the corresponding
    2938                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    2939                 :  * be updated for further calls to GetMapInfoType();
    2940                 :  *
    2941                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    2942                 :  * is expected for this object class.
    2943                 :  **********************************************************************/
    2944              11 : int  TABRegion::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    2945                 : {
    2946                 :     OGRGeometry *poGeom;
    2947                 : 
    2948                 :     /*-----------------------------------------------------------------
    2949                 :      * Fetch and validate geometry
    2950                 :      *----------------------------------------------------------------*/
    2951              11 :     poGeom = GetGeometryRef();
    2952              11 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    2953               0 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    2954                 :     {
    2955              11 :         GInt32 numPointsTotal=0, numRings=GetNumRings();
    2956              22 :         for(int i=0; i<numRings; i++)
    2957                 :         {
    2958              11 :             OGRLinearRing *poRing = GetRingRef(i);
    2959              11 :             if (poRing)
    2960              11 :                 numPointsTotal += poRing->getNumPoints();
    2961                 :         }
    2962              11 :         if ( TAB_REGION_PLINE_REQUIRES_V800(numRings, numPointsTotal) )
    2963               0 :             m_nMapInfoType = TAB_GEOM_V800_REGION;
    2964              11 :          else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
    2965               0 :             m_nMapInfoType = TAB_GEOM_V450_REGION;
    2966                 :         else
    2967              11 :             m_nMapInfoType = TAB_GEOM_REGION;
    2968                 : 
    2969                 :     }
    2970                 :     else
    2971                 :     {
    2972                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    2973               0 :                  "TABRegion: Missing or Invalid Geometry!");
    2974               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    2975                 :     }
    2976                 : 
    2977                 :     /*-----------------------------------------------------------------
    2978                 :      * Decide if coordinates should be compressed or not.
    2979                 :      *----------------------------------------------------------------*/
    2980              11 :     ValidateCoordType(poMapFile);
    2981                 : 
    2982              11 :     return m_nMapInfoType;
    2983                 : }
    2984                 : 
    2985                 : /**********************************************************************
    2986                 :  *                   TABRegion::ReadGeometryFromMAPFile()
    2987                 :  *
    2988                 :  * Fill the geometry and representation (color, etc...) part of the
    2989                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    2990                 :  *
    2991                 :  * It is assumed that poMAPFile currently points to the beginning of
    2992                 :  * a map object.
    2993                 :  *
    2994                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    2995                 :  * been called.
    2996                 :  **********************************************************************/
    2997              51 : int TABRegion::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    2998                 :                                        TABMAPObjHdr *poObjHdr,
    2999                 :                                        GBool bCoordBlockDataOnly /*=FALSE*/,
    3000                 :                                        TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    3001                 : {
    3002                 :     double              dX, dY, dXMin, dYMin, dXMax, dYMax;
    3003                 :     OGRGeometry         *poGeometry;
    3004                 :     OGRLinearRing       *poRing;
    3005              51 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    3006                 : 
    3007                 :     /*-----------------------------------------------------------------
    3008                 :      * Fetch and validate geometry type
    3009                 :      *----------------------------------------------------------------*/
    3010              51 :     m_nMapInfoType = poObjHdr->m_nType;
    3011                 : 
    3012              51 :     if (m_nMapInfoType == TAB_GEOM_REGION ||
    3013                 :         m_nMapInfoType == TAB_GEOM_REGION_C ||
    3014                 :         m_nMapInfoType == TAB_GEOM_V450_REGION ||
    3015                 :         m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
    3016                 :         m_nMapInfoType == TAB_GEOM_V800_REGION ||
    3017                 :         m_nMapInfoType == TAB_GEOM_V800_REGION_C )
    3018                 :     {
    3019                 :         /*=============================================================
    3020                 :          * REGION (Similar to PLINE MULTIPLE)
    3021                 :          *============================================================*/
    3022                 :         int     i, iSection;
    3023                 :         GInt32  nCoordBlockPtr, numLineSections;
    3024                 :         GInt32  nCoordDataSize, numPointsTotal, *panXY;
    3025              51 :         OGRMultiPolygon         *poMultiPolygon = NULL;
    3026              51 :         OGRPolygon              *poPolygon = NULL;
    3027                 :         TABMAPCoordSecHdr       *pasSecHdrs;
    3028              51 :         GBool                   bComprCoord = poObjHdr->IsCompressedType();
    3029              51 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    3030                 : 
    3031                 :         /*-------------------------------------------------------------
    3032                 :          * Copy data from poObjHdr
    3033                 :          *------------------------------------------------------------*/
    3034              51 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    3035                 : 
    3036              51 :         nCoordBlockPtr  = poPLineHdr->m_nCoordBlockPtr;
    3037              51 :         nCoordDataSize  = poPLineHdr->m_nCoordDataSize;
    3038              51 :         numLineSections = poPLineHdr->m_numLineSections;
    3039              51 :         m_bSmooth       = poPLineHdr->m_bSmooth;
    3040                 : 
    3041                 :         // Centroid/label point
    3042                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY, 
    3043              51 :                                 dX, dY);
    3044              51 :         SetCenter(dX, dY);
    3045                 : 
    3046                 :         // Compressed coordinate origin (useful only in compressed case!)
    3047              51 :         m_nComprOrgX = poPLineHdr->m_nComprOrgX;
    3048              51 :         m_nComprOrgY = poPLineHdr->m_nComprOrgY;
    3049                 : 
    3050                 :         // MBR
    3051                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY, 
    3052              51 :                                 dXMin, dYMin);
    3053                 :         poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY, 
    3054              51 :                                 dXMax, dYMax);
    3055                 : 
    3056              51 :         if (!bCoordBlockDataOnly)
    3057                 :         {
    3058              51 :             m_nPenDefIndex = poPLineHdr->m_nPenId;        // Pen index
    3059              51 :             poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    3060              51 :             m_nBrushDefIndex = poPLineHdr->m_nBrushId;    // Brush index
    3061              51 :             poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
    3062                 :         }
    3063                 : 
    3064                 :         /*-------------------------------------------------------------
    3065                 :          * Read data from the coord. block
    3066                 :          *------------------------------------------------------------*/
    3067                 :         pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
    3068              51 :                                                    sizeof(TABMAPCoordSecHdr));
    3069                 : 
    3070              51 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    3071               0 :             poCoordBlock = *ppoCoordBlock;
    3072                 :         else
    3073              51 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    3074                 : 
    3075              51 :         if (poCoordBlock)
    3076              51 :             poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    3077                 : 
    3078              51 :         if (poCoordBlock == NULL ||
    3079                 :             poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion,
    3080                 :                                            numLineSections,
    3081                 :                                            pasSecHdrs, numPointsTotal) != 0)
    3082                 :         {
    3083                 :             CPLError(CE_Failure, CPLE_FileIO,
    3084                 :                      "Failed reading coordinate data at offset %d", 
    3085               0 :                      nCoordBlockPtr);
    3086               0 :             CPLFree(pasSecHdrs);
    3087               0 :             return -1;
    3088                 :         }
    3089                 : 
    3090              51 :         panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
    3091                 : 
    3092              51 :         if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
    3093                 :         {
    3094                 :             CPLError(CE_Failure, CPLE_FileIO,
    3095                 :                      "Failed reading coordinate data at offset %d", 
    3096               0 :                      nCoordBlockPtr);
    3097               0 :             CPLFree(pasSecHdrs);
    3098               0 :             CPLFree(panXY);
    3099               0 :             return -1;
    3100                 :         }
    3101                 : 
    3102                 :         /*-------------------------------------------------------------
    3103                 :          * Decide if we should return an OGRPolygon or an OGRMultiPolygon
    3104                 :          * depending on the number of outer rings found in CoordSecHdr blocks.
    3105                 :          * The CoodSecHdr block for each outer ring in the region has a flag
    3106                 :          * indicating the number of inner rings that follow.
    3107                 :          * In older versions of the format, the count of inner rings was 
    3108                 :          * always zero, so in this case we would always return MultiPolygons.
    3109                 :          *
    3110                 :          * Note: The current implementation assumes that there cannot be
    3111                 :          * holes inside holes (i.e. multiple levels of inner rings)... if
    3112                 :          * that case was encountered then we would return an OGRMultiPolygon
    3113                 :          * in which the topological relationship between the rings would
    3114                 :          * be lost.
    3115                 :          *------------------------------------------------------------*/
    3116              51 :         int numOuterRings = 0;
    3117             102 :         for(iSection=0; iSection<numLineSections; iSection++)
    3118                 :         {
    3119                 :             // Count this as an outer ring.
    3120              51 :             numOuterRings++;
    3121                 :             // Skip inner rings... so loop continues on an outer ring.
    3122              51 :             iSection += pasSecHdrs[iSection].numHoles;
    3123                 :         }
    3124                 : 
    3125              51 :         if (numOuterRings > 1)
    3126               0 :             poGeometry = poMultiPolygon = new OGRMultiPolygon;
    3127                 :         else
    3128              51 :             poGeometry = NULL;  // Will be set later
    3129                 : 
    3130                 :         /*-------------------------------------------------------------
    3131                 :          * OK, build the OGRGeometry object.
    3132                 :          *------------------------------------------------------------*/
    3133              51 :         int numHolesToRead = 0;
    3134              51 :         poPolygon = NULL;
    3135             102 :         for(iSection=0; iSection<numLineSections; iSection++)
    3136                 :         {
    3137                 :             GInt32 *pnXYPtr;
    3138                 :             int     numSectionVertices;
    3139                 : 
    3140              51 :             if (poPolygon == NULL)
    3141              51 :                 poPolygon = new OGRPolygon();
    3142                 : 
    3143              51 :             if (numHolesToRead < 1)
    3144              51 :                 numHolesToRead = pasSecHdrs[iSection].numHoles;
    3145                 :             else
    3146               0 :                 numHolesToRead--;
    3147                 : 
    3148              51 :             numSectionVertices = pasSecHdrs[iSection].numVertices;
    3149              51 :             pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
    3150                 : 
    3151              51 :             poRing = new OGRLinearRing();
    3152              51 :             poRing->setNumPoints(numSectionVertices);
    3153                 : 
    3154            1281 :             for(i=0; i<numSectionVertices; i++)
    3155                 :             {
    3156            1230 :                 poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
    3157            1230 :                 poRing->setPoint(i, dX, dY);
    3158            1230 :                 pnXYPtr += 2;
    3159                 :             }
    3160                 : 
    3161              51 :             poPolygon->addRingDirectly(poRing);
    3162              51 :             poRing = NULL;
    3163                 : 
    3164              51 :             if (numHolesToRead < 1)
    3165                 :             {
    3166              51 :                 if (numOuterRings > 1)
    3167                 :                 {
    3168               0 :                     poMultiPolygon->addGeometryDirectly(poPolygon);
    3169                 :                 }
    3170                 :                 else
    3171                 :                 {
    3172              51 :                     poGeometry = poPolygon;
    3173              51 :                     CPLAssert(iSection == numLineSections-1);
    3174                 :                 }
    3175                 : 
    3176              51 :                 poPolygon = NULL;  // We'll alloc a new polygon next loop.
    3177                 :             }
    3178                 : 
    3179                 :         }
    3180                 : 
    3181              51 :         CPLFree(pasSecHdrs);
    3182              51 :         CPLFree(panXY);
    3183                 :     }
    3184                 :     else
    3185                 :     {
    3186                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3187                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    3188               0 :                  m_nMapInfoType, m_nMapInfoType);
    3189               0 :         return -1;
    3190                 :     }
    3191                 : 
    3192              51 :     SetGeometryDirectly(poGeometry);
    3193                 : 
    3194              51 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    3195                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    3196              51 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    3197                 : 
    3198                 :     /* Return a ref to coord block so that caller can continue reading
    3199                 :      * after the end of this object (used by TABCollection and index splitting)
    3200                 :      */
    3201              51 :     if (ppoCoordBlock)
    3202               0 :         *ppoCoordBlock = poCoordBlock;
    3203                 : 
    3204              51 :     return 0;
    3205                 : }
    3206                 : 
    3207                 : /**********************************************************************
    3208                 :  *                   TABRegion::WriteGeometryToMAPFile()
    3209                 :  *
    3210                 :  * Write the geometry and representation (color, etc...) part of the
    3211                 :  * feature to the .MAP object pointed to by poMAPFile.
    3212                 :  *
    3213                 :  * It is assumed that poMAPFile currently points to a valid map object.
    3214                 :  *
    3215                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    3216                 :  * been called.
    3217                 :  **********************************************************************/
    3218              11 : int TABRegion::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    3219                 :                                       TABMAPObjHdr *poObjHdr,
    3220                 :                                       GBool bCoordBlockDataOnly /*=FALSE*/,
    3221                 :                                       TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    3222                 : {
    3223                 :     GInt32              nX, nY;
    3224                 :     OGRGeometry         *poGeom;
    3225              11 :     TABMAPCoordBlock    *poCoordBlock=NULL;
    3226                 : 
    3227                 :     /*-----------------------------------------------------------------
    3228                 :      * We assume that ValidateMapInfoType() was called already and that
    3229                 :      * the type in poObjHdr->m_nType is valid.
    3230                 :      *----------------------------------------------------------------*/
    3231              11 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    3232                 : 
    3233                 :     /*-----------------------------------------------------------------
    3234                 :      * Fetch and validate geometry
    3235                 :      *----------------------------------------------------------------*/
    3236              11 :     poGeom = GetGeometryRef();
    3237                 : 
    3238              22 :     if ((m_nMapInfoType == TAB_GEOM_REGION ||
    3239                 :          m_nMapInfoType == TAB_GEOM_REGION_C ||
    3240                 :          m_nMapInfoType == TAB_GEOM_V450_REGION ||
    3241                 :          m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
    3242                 :          m_nMapInfoType == TAB_GEOM_V800_REGION ||
    3243                 :          m_nMapInfoType == TAB_GEOM_V800_REGION_C) &&
    3244              11 :         poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3245               0 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3246                 :     {
    3247                 :         /*=============================================================
    3248                 :          * REGIONs are similar to PLINE MULTIPLE
    3249                 :          *
    3250                 :          * We accept both OGRPolygons (with one or multiple rings) and 
    3251                 :          * OGRMultiPolygons as input.
    3252                 :          *============================================================*/
    3253              11 :         int     nStatus=0, i, iRing;
    3254                 :         int     numRingsTotal;
    3255                 :         GUInt32 nCoordDataSize;
    3256                 :         GInt32  nCoordBlockPtr;
    3257              11 :         TABMAPCoordSecHdr       *pasSecHdrs = NULL;
    3258              11 :         GBool   bCompressed = poObjHdr->IsCompressedType();
    3259                 : 
    3260                 :         /*-------------------------------------------------------------
    3261                 :          * Process geometry first...
    3262                 :          *------------------------------------------------------------*/
    3263              11 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    3264               0 :             poCoordBlock = *ppoCoordBlock;
    3265                 :         else
    3266              11 :             poCoordBlock = poMapFile->GetCurCoordBlock();
    3267              11 :         poCoordBlock->StartNewFeature();
    3268              11 :         nCoordBlockPtr = poCoordBlock->GetCurAddress();
    3269              11 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    3270                 : 
    3271                 : #ifdef TABDUMP
    3272                 :     printf("TABRegion::WriteGeometryToMAPFile(): ComprOrgX,Y= (%d,%d)\n",
    3273                 :            m_nComprOrgX, m_nComprOrgY);
    3274                 : #endif
    3275                 :         /*-------------------------------------------------------------
    3276                 :          * Fetch total number of rings and build array of coord 
    3277                 :          * sections headers.
    3278                 :          *------------------------------------------------------------*/
    3279              11 :         numRingsTotal = ComputeNumRings(&pasSecHdrs, poMapFile);
    3280              11 :         if (numRingsTotal == 0)
    3281               0 :             nStatus = -1;
    3282                 : 
    3283                 :         /*-------------------------------------------------------------
    3284                 :          * Write the Coord. Section Header
    3285                 :          *------------------------------------------------------------*/
    3286              11 :         int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    3287                 : 
    3288              11 :         if (nStatus == 0)
    3289                 :             nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numRingsTotal, 
    3290              11 :                                                       pasSecHdrs, bCompressed);
    3291                 : 
    3292              11 :         CPLFree(pasSecHdrs);
    3293              11 :         pasSecHdrs = NULL;
    3294                 : 
    3295              11 :         if (nStatus != 0)
    3296               0 :             return nStatus;  // Error has already been reported.
    3297                 : 
    3298                 :         /*-------------------------------------------------------------
    3299                 :          * Go through all the rings in our OGRMultiPolygon or OGRPolygon
    3300                 :          * to write the coordinates themselves...
    3301                 :          *------------------------------------------------------------*/
    3302                 : 
    3303              22 :         for(iRing=0; iRing < numRingsTotal; iRing++)
    3304                 :         {
    3305                 :             OGRLinearRing       *poRing;
    3306                 : 
    3307              11 :             poRing = GetRingRef(iRing);
    3308              11 :             if (poRing == NULL)
    3309                 :             {
    3310                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    3311               0 :                          "TABRegion: Object Geometry contains NULL rings!");
    3312               0 :                 return -1;
    3313                 :             }
    3314                 : 
    3315              11 :             int numPoints = poRing->getNumPoints();
    3316                 :             
    3317             261 :             for(i=0; nStatus == 0 && i<numPoints; i++)
    3318                 :             {
    3319                 :                 poMapFile->Coordsys2Int(poRing->getX(i), poRing->getY(i),
    3320             250 :                                         nX, nY);
    3321             250 :                 if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
    3322                 :                                                          bCompressed)) != 0)
    3323                 :                 {
    3324                 :                     // Failed ... error message has already been produced
    3325               0 :                     return nStatus;
    3326                 :                 }   
    3327                 :             }
    3328                 :         }/* for iRing*/
    3329                 : 
    3330              11 :         nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    3331                 : 
    3332                 :         /*-------------------------------------------------------------
    3333                 :          * ... and finally copy info to poObjHdr
    3334                 :          *------------------------------------------------------------*/
    3335              11 :         TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
    3336                 : 
    3337              11 :         poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
    3338              11 :         poPLineHdr->m_nCoordDataSize = nCoordDataSize;
    3339              11 :         poPLineHdr->m_numLineSections = numRingsTotal;
    3340                 : 
    3341              11 :         poPLineHdr->m_bSmooth = m_bSmooth;
    3342                 : 
    3343                 :         // MBR
    3344              11 :         poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    3345                 : 
    3346                 :         // Region center/label point
    3347                 :         double dX, dY;
    3348              11 :         if (GetCenter(dX, dY) != -1)
    3349                 :         {
    3350                 :             poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX, 
    3351              11 :                                     poPLineHdr->m_nLabelY);
    3352                 :         }
    3353                 :         else
    3354                 :         {
    3355               0 :             poPLineHdr->m_nLabelX = m_nComprOrgX;
    3356               0 :             poPLineHdr->m_nLabelY = m_nComprOrgY;
    3357                 :         }
    3358                 :         
    3359                 :         // Compressed coordinate origin (useful only in compressed case!)
    3360              11 :         poPLineHdr->m_nComprOrgX = m_nComprOrgX;
    3361              11 :         poPLineHdr->m_nComprOrgY = m_nComprOrgY;
    3362                 : 
    3363              11 :         if (!bCoordBlockDataOnly)
    3364                 :         {
    3365              11 :             m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    3366              11 :             poPLineHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    3367                 : 
    3368              11 :             m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
    3369              11 :             poPLineHdr->m_nBrushId = (GByte)m_nBrushDefIndex;  // Brush index
    3370                 :         }
    3371                 :     }
    3372                 :     else
    3373                 :     {
    3374                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3375               0 :                  "TABRegion: Object contains an invalid Geometry!");
    3376               0 :         return -1;
    3377                 :     }
    3378                 : 
    3379              11 :     if (CPLGetLastErrorNo() != 0)
    3380               0 :         return -1;
    3381                 : 
    3382                 :     /* Return a ref to coord block so that caller can continue writing
    3383                 :      * after the end of this object (used by index splitting)
    3384                 :      */
    3385              11 :     if (ppoCoordBlock)
    3386               0 :         *ppoCoordBlock = poCoordBlock;
    3387                 : 
    3388              11 :     return 0;
    3389                 : }
    3390                 : 
    3391                 : 
    3392                 : /**********************************************************************
    3393                 :  *                   TABRegion::GetNumRings()
    3394                 :  *
    3395                 :  * Return the total number of rings in this object making it look like
    3396                 :  * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
    3397                 :  * of rings... hides the complexity of handling OGRMultiPolygons vs 
    3398                 :  * OGRPolygons, etc.
    3399                 :  *
    3400                 :  * Returns 0 if the geometry contained in the object is invalid or missing.
    3401                 :  **********************************************************************/
    3402              21 : int TABRegion::GetNumRings()
    3403                 : {
    3404              21 :     return ComputeNumRings(NULL, NULL);
    3405                 : }
    3406                 : 
    3407              32 : int TABRegion::ComputeNumRings(TABMAPCoordSecHdr **ppasSecHdrs,
    3408                 :                                TABMAPFile *poMapFile)
    3409                 : {
    3410                 :     OGRGeometry         *poGeom;
    3411              32 :     int                 numRingsTotal = 0, iLastSect = 0;
    3412                 : 
    3413              32 :     if (ppasSecHdrs)
    3414              11 :         *ppasSecHdrs = NULL;
    3415              32 :     poGeom = GetGeometryRef();
    3416                 : 
    3417              32 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3418               0 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3419                 :     {
    3420                 :         /*-------------------------------------------------------------
    3421                 :          * Calculate total number of rings...
    3422                 :          *------------------------------------------------------------*/
    3423              32 :         OGRPolygon      *poPolygon=NULL;
    3424              32 :         OGRMultiPolygon *poMultiPolygon = NULL;
    3425                 : 
    3426              32 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3427                 :         {
    3428               0 :             poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3429               0 :             for(int iPoly=0; iPoly<poMultiPolygon->getNumGeometries(); iPoly++)
    3430                 :             {
    3431                 :                 // We are guaranteed that all parts are OGRPolygons
    3432               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
    3433               0 :                 if (poPolygon  == NULL)
    3434               0 :                     continue;
    3435                 : 
    3436               0 :                 numRingsTotal += poPolygon->getNumInteriorRings()+1;
    3437                 : 
    3438               0 :                 if (ppasSecHdrs)
    3439                 :                 {
    3440               0 :                     if (AppendSecHdrs(poPolygon, *ppasSecHdrs, 
    3441                 :                                       poMapFile, iLastSect) != 0)
    3442               0 :                         return 0; // An error happened, return count=0
    3443                 :                 }
    3444                 : 
    3445                 :             }/*for*/
    3446                 :         }
    3447                 :         else
    3448                 :         {
    3449              32 :             poPolygon = (OGRPolygon*)poGeom;
    3450              32 :             numRingsTotal = poPolygon->getNumInteriorRings()+1;
    3451                 : 
    3452              32 :             if (ppasSecHdrs)
    3453                 :             {
    3454              11 :                 if (AppendSecHdrs(poPolygon, *ppasSecHdrs, 
    3455                 :                                   poMapFile, iLastSect) != 0)
    3456               0 :                     return 0;  // An error happened, return count=0
    3457                 :             }
    3458                 :         }
    3459                 :     }
    3460                 : 
    3461                 :     /*-----------------------------------------------------------------
    3462                 :      * If we're generating section header blocks, then init the 
    3463                 :      * coordinate offset values.
    3464                 :      *
    3465                 :      * In calculation of nDataOffset, we have to take into account that
    3466                 :      * V450 header section uses int32 instead of int16 for numVertices
    3467                 :      * and we add another 2 bytes to align with a 4 bytes boundary.
    3468                 :      *------------------------------------------------------------*/
    3469                 :     int nTotalHdrSizeUncompressed;
    3470              32 :     if (m_nMapInfoType == TAB_GEOM_V450_REGION ||
    3471                 :         m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
    3472                 :         m_nMapInfoType == TAB_GEOM_V800_REGION ||
    3473                 :         m_nMapInfoType == TAB_GEOM_V800_REGION_C)
    3474               0 :         nTotalHdrSizeUncompressed = 28 * numRingsTotal;
    3475                 :     else
    3476              32 :         nTotalHdrSizeUncompressed = 24 * numRingsTotal;
    3477                 : 
    3478              32 :     if (ppasSecHdrs)
    3479                 :     {
    3480              11 :         int numPointsTotal = 0;
    3481              11 :         CPLAssert(iLastSect == numRingsTotal);
    3482              22 :         for (int iRing=0; iRing<numRingsTotal; iRing++)
    3483                 :         {
    3484              11 :             (*ppasSecHdrs)[iRing].nDataOffset = nTotalHdrSizeUncompressed +
    3485              11 :                                                    numPointsTotal*4*2;
    3486              11 :             (*ppasSecHdrs)[iRing].nVertexOffset = numPointsTotal;
    3487                 : 
    3488              11 :             numPointsTotal += (*ppasSecHdrs)[iRing].numVertices;
    3489                 :         }
    3490                 :     }
    3491                 : 
    3492              32 :     return numRingsTotal;
    3493                 : }
    3494                 : 
    3495                 : 
    3496                 : /**********************************************************************
    3497                 :  *                   TABRegion::AppendSecHdrs()
    3498                 :  *
    3499                 :  * (Private method)
    3500                 :  *
    3501                 :  * Add a TABMAPCoordSecHdr for each ring in the specified polygon.
    3502                 :  **********************************************************************/
    3503              11 : int TABRegion::AppendSecHdrs(OGRPolygon *poPolygon,
    3504                 :                              TABMAPCoordSecHdr * &pasSecHdrs,
    3505                 :                              TABMAPFile *poMapFile,
    3506                 :                              int &iLastRing)
    3507                 : {
    3508                 :     int iRing, numRingsInPolygon;
    3509                 :     /*-------------------------------------------------------------
    3510                 :      * Add a pasSecHdrs[] entry for each ring in this polygon.
    3511                 :      * Note that the structs won't be fully initialized.
    3512                 :      *------------------------------------------------------------*/
    3513              11 :     numRingsInPolygon = poPolygon->getNumInteriorRings()+1;
    3514                 : 
    3515                 :     pasSecHdrs = (TABMAPCoordSecHdr*)CPLRealloc(pasSecHdrs,
    3516                 :                                                 (iLastRing+numRingsInPolygon)*
    3517              11 :                                                 sizeof(TABMAPCoordSecHdr));
    3518                 : 
    3519              22 :     for(iRing=0; iRing < numRingsInPolygon; iRing++)
    3520                 :     {
    3521                 :         OGRLinearRing   *poRing;
    3522              11 :         OGREnvelope     sEnvelope;
    3523                 : 
    3524              11 :         if (iRing == 0)
    3525              11 :             poRing = poPolygon->getExteriorRing();
    3526                 :         else 
    3527               0 :             poRing = poPolygon->getInteriorRing(iRing-1);
    3528                 : 
    3529              11 :         if (poRing == NULL)
    3530                 :         {
    3531                 :             CPLError(CE_Failure, CPLE_AssertionFailed, 
    3532               0 :                      "Assertion Failed: Encountered NULL ring in OGRPolygon");
    3533               0 :             return -1;
    3534                 :         }
    3535                 : 
    3536              11 :         poRing->getEnvelope(&sEnvelope);
    3537                 :             
    3538              11 :         pasSecHdrs[iLastRing].numVertices = poRing->getNumPoints();
    3539                 : 
    3540              11 :         if (iRing == 0)
    3541              11 :             pasSecHdrs[iLastRing].numHoles = numRingsInPolygon-1;
    3542                 :         else 
    3543               0 :             pasSecHdrs[iLastRing].numHoles = 0;
    3544                 : 
    3545                 :         poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
    3546              11 :                                 pasSecHdrs[iLastRing].nXMin,
    3547              22 :                                 pasSecHdrs[iLastRing].nYMin);
    3548                 :         poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
    3549              11 :                                 pasSecHdrs[iLastRing].nXMax,
    3550              22 :                                 pasSecHdrs[iLastRing].nYMax);
    3551                 : 
    3552              11 :         iLastRing++;
    3553                 :     }/* for iRing*/
    3554                 : 
    3555              11 :     return 0;
    3556                 : }
    3557                 : 
    3558                 : /**********************************************************************
    3559                 :  *                   TABRegion::GetRingRef()
    3560                 :  *
    3561                 :  * Returns a reference to the specified ring number making it look like
    3562                 :  * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
    3563                 :  * of rings... hides the complexity of handling OGRMultiPolygons vs 
    3564                 :  * OGRPolygons, etc.
    3565                 :  *
    3566                 :  * Returns NULL if the geometry contained in the object is invalid or 
    3567                 :  * missing or if the specified ring index is invalid.
    3568                 :  **********************************************************************/
    3569              32 : OGRLinearRing *TABRegion::GetRingRef(int nRequestedRingIndex)
    3570                 : {
    3571                 :     OGRGeometry     *poGeom;
    3572              32 :     OGRLinearRing   *poRing = NULL;
    3573                 : 
    3574              32 :     poGeom = GetGeometryRef();
    3575                 : 
    3576              32 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3577               0 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3578                 :     {
    3579                 :         /*-------------------------------------------------------------
    3580                 :          * Establish number of polygons based on geometry type
    3581                 :          *------------------------------------------------------------*/
    3582              32 :         OGRPolygon      *poPolygon=NULL;
    3583              32 :         OGRMultiPolygon *poMultiPolygon = NULL;
    3584              32 :         int             iCurRing = 0;
    3585              32 :         int             numOGRPolygons = 0;
    3586                 : 
    3587              32 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3588                 :         {
    3589               0 :             poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3590               0 :             numOGRPolygons = poMultiPolygon->getNumGeometries();
    3591                 :         }
    3592                 :         else
    3593                 :         {
    3594              32 :             poPolygon = (OGRPolygon*)poGeom;
    3595              32 :             numOGRPolygons = 1;
    3596                 :         }
    3597                 : 
    3598                 :         /*-------------------------------------------------------------
    3599                 :          * Loop through polygons until we find the requested ring.
    3600                 :          *------------------------------------------------------------*/
    3601              32 :         iCurRing = 0;
    3602              64 :         for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
    3603                 :         {
    3604              32 :             if (poMultiPolygon)
    3605               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
    3606                 :             else
    3607              32 :                 poPolygon = (OGRPolygon*)poGeom;
    3608                 : 
    3609              32 :             int numIntRings = poPolygon->getNumInteriorRings();
    3610                 : 
    3611              32 :             if (iCurRing == nRequestedRingIndex)
    3612                 :             {
    3613              32 :                 poRing = poPolygon->getExteriorRing();
    3614                 :             }
    3615               0 :             else if (nRequestedRingIndex > iCurRing &&
    3616                 :                      nRequestedRingIndex-(iCurRing+1) < numIntRings)
    3617                 :            {
    3618                 :                 poRing = poPolygon->getInteriorRing(nRequestedRingIndex-
    3619               0 :                                                                 (iCurRing+1) );
    3620                 :             }
    3621              32 :             iCurRing += numIntRings+1;
    3622                 :         }
    3623                 :     }
    3624                 : 
    3625              32 :     return poRing;
    3626                 : }
    3627                 : 
    3628                 : /**********************************************************************
    3629                 :  *                   TABRegion::RingIsHole()
    3630                 :  *
    3631                 :  * Return false if the requested ring index is the first of a polygon
    3632                 :  **********************************************************************/
    3633               0 : GBool TABRegion::IsInteriorRing(int nRequestedRingIndex)
    3634                 : {
    3635                 :     OGRGeometry     *poGeom;
    3636               0 :     OGRLinearRing   *poRing = NULL;
    3637                 : 
    3638               0 :     poGeom = GetGeometryRef();
    3639                 : 
    3640               0 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3641               0 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3642                 :     {
    3643                 :         /*-------------------------------------------------------------
    3644                 :          * Establish number of polygons based on geometry type
    3645                 :          *------------------------------------------------------------*/
    3646               0 :         OGRPolygon      *poPolygon=NULL;
    3647               0 :         OGRMultiPolygon *poMultiPolygon = NULL;
    3648               0 :         int             iCurRing = 0;
    3649               0 :         int             numOGRPolygons = 0;
    3650                 : 
    3651               0 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3652                 :         {
    3653               0 :             poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3654               0 :             numOGRPolygons = poMultiPolygon->getNumGeometries();
    3655                 :         }
    3656                 :         else
    3657                 :         {
    3658               0 :             poPolygon = (OGRPolygon*)poGeom;
    3659               0 :             numOGRPolygons = 1;
    3660                 :         }
    3661                 : 
    3662                 :         /*-------------------------------------------------------------
    3663                 :          * Loop through polygons until we find the requested ring.
    3664                 :          *------------------------------------------------------------*/
    3665               0 :         iCurRing = 0;
    3666               0 :         for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
    3667                 :         {
    3668               0 :             if (poMultiPolygon)
    3669               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
    3670                 :             else
    3671               0 :                 poPolygon = (OGRPolygon*)poGeom;
    3672                 : 
    3673               0 :             int numIntRings = poPolygon->getNumInteriorRings();
    3674                 : 
    3675               0 :             if (iCurRing == nRequestedRingIndex)
    3676                 :             {
    3677               0 :                 return FALSE;
    3678                 :             }
    3679               0 :             else if (nRequestedRingIndex > iCurRing &&
    3680                 :                      nRequestedRingIndex-(iCurRing+1) < numIntRings)
    3681                 :            {
    3682               0 :                 return TRUE;
    3683                 :             }
    3684               0 :             iCurRing += numIntRings+1;
    3685                 :         }
    3686                 :     }
    3687                 : 
    3688               0 :     return FALSE;
    3689                 : }
    3690                 : 
    3691                 : /**********************************************************************
    3692                 :  *                   TABRegion::GetStyleString()
    3693                 :  *
    3694                 :  * Return style string for this feature.
    3695                 :  *
    3696                 :  * Style String is built only once during the first call to GetStyleString().
    3697                 :  **********************************************************************/
    3698              11 : const char *TABRegion::GetStyleString()
    3699                 : {
    3700              11 :     if (m_pszStyleString == NULL)
    3701                 :     {
    3702                 :         // Since GetPen/BrushStyleString() use CPLSPrintf(), we need 
    3703                 :         // to use temporary buffers
    3704               7 :         char *pszPen = CPLStrdup(GetPenStyleString());
    3705               7 :         char *pszBrush = CPLStrdup(GetBrushStyleString());
    3706                 : 
    3707               7 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
    3708                 : 
    3709               7 :         CPLFree(pszPen);
    3710               7 :         CPLFree(pszBrush);
    3711                 :     }
    3712                 : 
    3713              11 :     return m_pszStyleString;
    3714                 : }
    3715                 : 
    3716                 : 
    3717                 : 
    3718                 : /**********************************************************************
    3719                 :  *                   TABRegion::DumpMIF()
    3720                 :  *
    3721                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    3722                 :  **********************************************************************/
    3723               0 : void TABRegion::DumpMIF(FILE *fpOut /*=NULL*/)
    3724                 : {
    3725                 :     OGRGeometry   *poGeom;
    3726                 :     int i, numPoints;
    3727                 : 
    3728               0 :     if (fpOut == NULL)
    3729               0 :         fpOut = stdout;
    3730                 : 
    3731                 :     /*-----------------------------------------------------------------
    3732                 :      * Fetch and validate geometry
    3733                 :      *----------------------------------------------------------------*/
    3734               0 :     poGeom = GetGeometryRef();
    3735               0 :     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    3736               0 :                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
    3737                 :     {
    3738                 :         /*-------------------------------------------------------------
    3739                 :          * Generate output for region
    3740                 :          *
    3741                 :          * Note that we want to handle both OGRPolygons and OGRMultiPolygons
    3742                 :          * that's why we use the GetNumRings()/GetRingRef() interface.
    3743                 :          *------------------------------------------------------------*/
    3744               0 :         int iRing, numRingsTotal = GetNumRings();
    3745                 : 
    3746               0 :         fprintf(fpOut, "REGION %d\n", numRingsTotal);
    3747                 : 
    3748               0 :         for(iRing=0; iRing < numRingsTotal; iRing++)
    3749                 :         {
    3750                 :             OGRLinearRing       *poRing;
    3751                 : 
    3752               0 :             poRing = GetRingRef(iRing);
    3753                 : 
    3754               0 :             if (poRing == NULL)
    3755                 :             {
    3756                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    3757               0 :                          "TABRegion: Object Geometry contains NULL rings!");
    3758               0 :                 return;
    3759                 :             }
    3760                 : 
    3761               0 :             numPoints = poRing->getNumPoints();
    3762               0 :             fprintf(fpOut, " %d\n", numPoints);
    3763               0 :             for(i=0; i<numPoints; i++)
    3764               0 :                 fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
    3765                 :         }
    3766                 :     }
    3767                 :     else
    3768                 :     {
    3769                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3770               0 :                  "TABRegion: Missing or Invalid Geometry!");
    3771               0 :         return;
    3772                 :     }
    3773                 : 
    3774               0 :     if (m_bCenterIsSet)
    3775               0 :         fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
    3776                 : 
    3777                 :     // Finish with PEN/BRUSH/etc. clauses
    3778               0 :     DumpPenDef();
    3779               0 :     DumpBrushDef();
    3780                 : 
    3781               0 :     fflush(fpOut);
    3782                 : }
    3783                 : 
    3784                 : /**********************************************************************
    3785                 :  *                   TABRegion::GetCenter()
    3786                 :  *
    3787                 :  * Returns the center/label point of the region.  
    3788                 :  * Compute one using OGRPolygonLabelPoint() if it was not explicitly set 
    3789                 :  * before.
    3790                 :  *
    3791                 :  * Returns 0 on success, -1 on error.
    3792                 :  **********************************************************************/
    3793              11 : int TABRegion::GetCenter(double &dX, double &dY)
    3794                 : {
    3795              11 :     if (!m_bCenterIsSet)
    3796                 :     {
    3797                 :         /*-------------------------------------------------------------
    3798                 :          * Calculate label point.  If we have a multipolygon then we use 
    3799                 :          * the first OGRPolygon in the feature to calculate the point.
    3800                 :          *------------------------------------------------------------*/
    3801              11 :         OGRPoint        oLabelPoint;
    3802              11 :         OGRPolygon      *poPolygon=NULL;
    3803                 :         OGRGeometry     *poGeom;
    3804                 : 
    3805              11 :         poGeom = GetGeometryRef();
    3806              11 :         if (poGeom == NULL)
    3807               0 :             return -1;
    3808                 : 
    3809              11 :         if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
    3810                 :         {
    3811               0 :             OGRMultiPolygon *poMultiPolygon = (OGRMultiPolygon *)poGeom;
    3812               0 :             if (poMultiPolygon->getNumGeometries() > 0)
    3813               0 :                 poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(0);
    3814                 :         }
    3815              11 :         else if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    3816                 :         {
    3817              11 :             poPolygon = (OGRPolygon*)poGeom;
    3818                 :         }
    3819                 : 
    3820              11 :         if (poPolygon != NULL &&
    3821                 :             OGRPolygonLabelPoint(poPolygon, &oLabelPoint) == OGRERR_NONE)
    3822                 :         {
    3823              11 :             m_dCenterX = oLabelPoint.getX();
    3824              11 :             m_dCenterY = oLabelPoint.getY();
    3825                 :         }
    3826                 :         else
    3827                 :         {
    3828               0 :             OGREnvelope oEnv;
    3829               0 :             poGeom->getEnvelope(&oEnv);
    3830               0 :             m_dCenterX = (oEnv.MaxX + oEnv.MinX)/2.0;
    3831               0 :             m_dCenterY = (oEnv.MaxY + oEnv.MinY)/2.0;
    3832                 :         }
    3833                 : 
    3834              11 :         m_bCenterIsSet = TRUE;
    3835                 :     }
    3836                 : 
    3837              11 :     if (!m_bCenterIsSet)
    3838               0 :         return -1;
    3839                 : 
    3840              11 :     dX = m_dCenterX;
    3841              11 :     dY = m_dCenterY;
    3842              11 :     return 0;
    3843                 : }
    3844                 : 
    3845                 : /**********************************************************************
    3846                 :  *                   TABRegion::SetCenter()
    3847                 :  *
    3848                 :  * Set the X,Y coordinates to use as center/label point for the region.
    3849                 :  **********************************************************************/
    3850              51 : void TABRegion::SetCenter(double dX, double dY)
    3851                 : {
    3852              51 :     m_dCenterX = dX;
    3853              51 :     m_dCenterY = dY;
    3854              51 :     m_bCenterIsSet = TRUE;
    3855              51 : }
    3856                 : 
    3857                 : 
    3858                 : /*=====================================================================
    3859                 :  *                      class TABRectangle
    3860                 :  *====================================================================*/
    3861                 : 
    3862                 : /**********************************************************************
    3863                 :  *                   TABRectangle::TABRectangle()
    3864                 :  *
    3865                 :  * Constructor.
    3866                 :  **********************************************************************/
    3867               0 : TABRectangle::TABRectangle(OGRFeatureDefn *poDefnIn):
    3868               0 :               TABFeature(poDefnIn)
    3869                 : {
    3870               0 :     m_bRoundCorners = FALSE;
    3871               0 :     m_dRoundXRadius = m_dRoundYRadius = 0.0;
    3872               0 : }
    3873                 : 
    3874                 : /**********************************************************************
    3875                 :  *                   TABRectangle::~TABRectangle()
    3876                 :  *
    3877                 :  * Destructor.
    3878                 :  **********************************************************************/
    3879               0 : TABRectangle::~TABRectangle()
    3880                 : {
    3881               0 : }
    3882                 : 
    3883                 : /**********************************************************************
    3884                 :  *                     TABRectangle::CloneTABFeature()
    3885                 :  *
    3886                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    3887                 :  *
    3888                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    3889                 :  * then copies any members specific to its own type.
    3890                 :  **********************************************************************/
    3891               0 : TABFeature *TABRectangle::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    3892                 : {
    3893                 :     /*-----------------------------------------------------------------
    3894                 :      * Alloc new feature and copy the base stuff
    3895                 :      *----------------------------------------------------------------*/
    3896                 :     TABRectangle *poNew = new TABRectangle(poNewDefn ? poNewDefn : 
    3897               0 :                                                        GetDefnRef());
    3898                 : 
    3899               0 :     CopyTABFeatureBase(poNew);
    3900                 : 
    3901                 :     /*-----------------------------------------------------------------
    3902                 :      * And members specific to this class
    3903                 :      *----------------------------------------------------------------*/
    3904                 :     // ITABFeaturePen
    3905               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    3906                 : 
    3907                 :     // ITABFeatureBrush
    3908               0 :     *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
    3909                 : 
    3910               0 :     poNew->m_bRoundCorners = m_bRoundCorners;
    3911               0 :     poNew->m_dRoundXRadius = m_dRoundXRadius;
    3912               0 :     poNew->m_dRoundYRadius = m_dRoundYRadius;
    3913                 : 
    3914               0 :     return poNew;
    3915                 : }
    3916                 : 
    3917                 : /**********************************************************************
    3918                 :  *                   TABRectangle::ValidateMapInfoType()
    3919                 :  *
    3920                 :  * Check the feature's geometry part and return the corresponding
    3921                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    3922                 :  * be updated for further calls to GetMapInfoType();
    3923                 :  *
    3924                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    3925                 :  * is expected for this object class.
    3926                 :  **********************************************************************/
    3927               0 : int  TABRectangle::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    3928                 : {
    3929                 :     OGRGeometry *poGeom;
    3930                 : 
    3931                 :     /*-----------------------------------------------------------------
    3932                 :      * Fetch and validate geometry
    3933                 :      *----------------------------------------------------------------*/
    3934               0 :     poGeom = GetGeometryRef();
    3935               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    3936                 :     {
    3937               0 :         if (m_bRoundCorners && m_dRoundXRadius!=0.0 && m_dRoundYRadius!=0.0)
    3938               0 :             m_nMapInfoType = TAB_GEOM_ROUNDRECT;
    3939                 :         else
    3940               0 :             m_nMapInfoType = TAB_GEOM_RECT;
    3941                 :     }
    3942                 :     else
    3943                 :     {
    3944                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3945               0 :                  "TABRectangle: Missing or Invalid Geometry!");
    3946               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    3947                 :     }
    3948                 : 
    3949                 :     /*-----------------------------------------------------------------
    3950                 :      * Decide if coordinates should be compressed or not.
    3951                 :      *----------------------------------------------------------------*/
    3952                 :     // __TODO__ For now we always write uncompressed for this class...
    3953                 :     // ValidateCoordType(poMapFile);    
    3954               0 :     UpdateMBR(poMapFile);
    3955                 : 
    3956               0 :     return m_nMapInfoType;
    3957                 : }
    3958                 : 
    3959                 : /**********************************************************************
    3960                 :  *                   TABRectangle::UpdateMBR()
    3961                 :  *
    3962                 :  * Update the feature MBR members using the geometry
    3963                 :  *
    3964                 :  * Returns 0 on success, or -1 if there is no geometry in object
    3965                 :  **********************************************************************/
    3966               0 : int TABRectangle::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    3967                 : {
    3968                 :     OGRGeometry *poGeom;
    3969               0 :     OGREnvelope sEnvelope;
    3970                 : 
    3971                 :     /*-----------------------------------------------------------------
    3972                 :      * Fetch and validate geometry
    3973                 :      *----------------------------------------------------------------*/
    3974               0 :     poGeom = GetGeometryRef();
    3975               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    3976               0 :         poGeom->getEnvelope(&sEnvelope);
    3977                 :     else
    3978                 :     {
    3979                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    3980               0 :                  "TABRectangle: Missing or Invalid Geometry!");
    3981               0 :         return -1;
    3982                 :     }
    3983                 : 
    3984                 :     /*-----------------------------------------------------------------
    3985                 :      * Note that we will simply use the rectangle's MBR and don't really 
    3986                 :      * read the polygon geometry... this should be OK unless the 
    3987                 :      * polygon geometry was not really a rectangle.
    3988                 :      *----------------------------------------------------------------*/
    3989               0 :     m_dXMin = sEnvelope.MinX;
    3990               0 :     m_dYMin = sEnvelope.MinY;
    3991               0 :     m_dXMax = sEnvelope.MaxX;
    3992               0 :     m_dYMax = sEnvelope.MaxY;
    3993                 : 
    3994               0 :     if (poMapFile)
    3995                 :     {
    3996               0 :         poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    3997               0 :         poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    3998                 :     }
    3999                 : 
    4000               0 :     return 0;
    4001                 : }
    4002                 : 
    4003                 : /**********************************************************************
    4004                 :  *                   TABRectangle::ReadGeometryFromMAPFile()
    4005                 :  *
    4006                 :  * Fill the geometry and representation (color, etc...) part of the
    4007                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    4008                 :  *
    4009                 :  * It is assumed that poMAPFile currently points to the beginning of
    4010                 :  * a map object.
    4011                 :  *
    4012                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4013                 :  * been called.
    4014                 :  **********************************************************************/
    4015               0 : int TABRectangle::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    4016                 :                                           TABMAPObjHdr *poObjHdr,
    4017                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    4018                 :                                           TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4019                 : {
    4020                 :     double              dXMin, dYMin, dXMax, dYMax;
    4021                 :     OGRPolygon          *poPolygon;
    4022                 :     OGRLinearRing       *poRing;
    4023                 : 
    4024                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4025               0 :     if (bCoordBlockDataOnly)
    4026               0 :         return 0;
    4027                 : 
    4028                 :     /*-----------------------------------------------------------------
    4029                 :      * Fetch and validate geometry type
    4030                 :      *----------------------------------------------------------------*/
    4031               0 :     m_nMapInfoType = poObjHdr->m_nType;
    4032                 : 
    4033               0 :     if (m_nMapInfoType != TAB_GEOM_RECT &&
    4034                 :         m_nMapInfoType != TAB_GEOM_RECT_C &&
    4035                 :         m_nMapInfoType != TAB_GEOM_ROUNDRECT &&
    4036                 :         m_nMapInfoType != TAB_GEOM_ROUNDRECT_C)
    4037                 :     {
    4038                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4039                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    4040               0 :                  m_nMapInfoType, m_nMapInfoType);
    4041               0 :         return -1;
    4042                 :     }
    4043                 : 
    4044                 :     /*-----------------------------------------------------------------
    4045                 :      * Read object information
    4046                 :      *----------------------------------------------------------------*/
    4047               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4048                 : 
    4049                 :     // Read the corners radius
    4050                 : 
    4051               0 :     if (m_nMapInfoType == TAB_GEOM_ROUNDRECT ||
    4052                 :         m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
    4053                 :     {
    4054                 :         // Read the corner's diameters
    4055                 :         poMapFile->Int2CoordsysDist(poRectHdr->m_nCornerWidth, 
    4056                 :                                     poRectHdr->m_nCornerHeight,
    4057               0 :                                     m_dRoundXRadius, m_dRoundYRadius);
    4058                 : 
    4059                 :         // Divide by 2 since we store the corner's radius
    4060               0 :         m_dRoundXRadius /= 2.0;
    4061               0 :         m_dRoundYRadius /= 2.0;
    4062                 : 
    4063               0 :         m_bRoundCorners = TRUE;
    4064                 :     }
    4065                 :     else
    4066                 :     {
    4067               0 :         m_bRoundCorners = FALSE;
    4068               0 :         m_dRoundXRadius = m_dRoundYRadius = 0.0;
    4069                 :     }
    4070                 : 
    4071                 :     // A rectangle is defined by its MBR
    4072                 : 
    4073                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY, 
    4074               0 :                             dXMin, dYMin);
    4075                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY, 
    4076               0 :                             dXMax, dYMax);
    4077                 : 
    4078               0 :     m_nPenDefIndex = poRectHdr->m_nPenId;       // Pen index
    4079               0 :     poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    4080                 : 
    4081               0 :     m_nBrushDefIndex = poRectHdr->m_nBrushId;   // Brush index
    4082               0 :     poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
    4083                 : 
    4084                 :     /*-----------------------------------------------------------------
    4085                 :      * Call SetMBR() and GetMBR() now to make sure that min values are
    4086                 :      * really smaller than max values.
    4087                 :      *----------------------------------------------------------------*/
    4088               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    4089               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    4090                 : 
    4091                 :     /* Copy int MBR to feature class members */
    4092                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    4093               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    4094                 : 
    4095                 :     /*-----------------------------------------------------------------
    4096                 :      * Create and fill geometry object
    4097                 :      *----------------------------------------------------------------*/
    4098               0 :     poPolygon = new OGRPolygon;
    4099               0 :     poRing = new OGRLinearRing();
    4100               0 :     if (m_bRoundCorners && m_dRoundXRadius != 0.0 && m_dRoundYRadius != 0.0)
    4101                 :     {
    4102                 :         /*-------------------------------------------------------------
    4103                 :          * For rounded rectangles, we generate arcs with 45 line
    4104                 :          * segments for each corner.  We start with lower-left corner 
    4105                 :          * and proceed counterclockwise
    4106                 :          * We also have to make sure that rounding radius is not too
    4107                 :          * large for the MBR in the generated polygon... however, we 
    4108                 :          * always return the true X/Y radius (not adjusted) since this
    4109                 :          * is the way MapInfo seems to do it when a radius bigger than
    4110                 :          * the MBR is passed from TBA to MIF.
    4111                 :          *------------------------------------------------------------*/
    4112               0 :         double dXRadius = MIN(m_dRoundXRadius, (dXMax-dXMin)/2.0);
    4113               0 :         double dYRadius = MIN(m_dRoundYRadius, (dYMax-dYMin)/2.0);
    4114                 :         TABGenerateArc(poRing, 45, 
    4115                 :                        dXMin + dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
    4116               0 :                        PI, 3.0*PI/2.0);
    4117                 :         TABGenerateArc(poRing, 45, 
    4118                 :                        dXMax - dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
    4119               0 :                        3.0*PI/2.0, 2.0*PI);
    4120                 :         TABGenerateArc(poRing, 45, 
    4121                 :                        dXMax - dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
    4122               0 :                        0.0, PI/2.0);
    4123                 :         TABGenerateArc(poRing, 45, 
    4124                 :                        dXMin + dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
    4125               0 :                        PI/2.0, PI);
    4126                 :                        
    4127               0 :         TABCloseRing(poRing);
    4128                 :     }
    4129                 :     else
    4130                 :     {
    4131               0 :         poRing->addPoint(dXMin, dYMin);
    4132               0 :         poRing->addPoint(dXMax, dYMin);
    4133               0 :         poRing->addPoint(dXMax, dYMax);
    4134               0 :         poRing->addPoint(dXMin, dYMax);
    4135               0 :         poRing->addPoint(dXMin, dYMin);
    4136                 :     }
    4137                 : 
    4138               0 :     poPolygon->addRingDirectly(poRing);
    4139               0 :     SetGeometryDirectly(poPolygon);
    4140                 : 
    4141               0 :     return 0;
    4142                 : }
    4143                 : 
    4144                 : /**********************************************************************
    4145                 :  *                   TABRectangle::WriteGeometryToMAPFile()
    4146                 :  *
    4147                 :  * Write the geometry and representation (color, etc...) part of the
    4148                 :  * feature to the .MAP object pointed to by poMAPFile.
    4149                 :  *
    4150                 :  * It is assumed that poMAPFile currently points to a valid map object.
    4151                 :  *
    4152                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4153                 :  * been called.
    4154                 :  **********************************************************************/
    4155               0 : int TABRectangle::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    4156                 :                                          TABMAPObjHdr *poObjHdr,
    4157                 :                                          GBool bCoordBlockDataOnly /*=FALSE*/, 
    4158                 :                                          TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4159                 : {
    4160                 : 
    4161                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4162               0 :     if (bCoordBlockDataOnly)
    4163               0 :         return 0;
    4164                 : 
    4165                 :     /*-----------------------------------------------------------------
    4166                 :      * We assume that ValidateMapInfoType() was called already and that
    4167                 :      * the type in poObjHdr->m_nType is valid.
    4168                 :      *----------------------------------------------------------------*/
    4169               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    4170                 : 
    4171                 :     /*-----------------------------------------------------------------
    4172                 :      * Fetch and validate geometry and update MBR
    4173                 :      * Note that we will simply use the geometry's MBR and don't really 
    4174                 :      * read the polygon geometry... this should be OK unless the 
    4175                 :      * polygon geometry was not really a rectangle.
    4176                 :      *----------------------------------------------------------------*/
    4177               0 :     if (UpdateMBR(poMapFile) != 0)
    4178               0 :         return -1;  /* Error already reported */
    4179                 : 
    4180                 :     /*-----------------------------------------------------------------
    4181                 :      * Copy object information
    4182                 :      *----------------------------------------------------------------*/
    4183               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4184                 : 
    4185               0 :     if (m_nMapInfoType == TAB_GEOM_ROUNDRECT || 
    4186                 :         m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
    4187                 :     {
    4188                 :         poMapFile->Coordsys2IntDist(m_dRoundXRadius*2.0, m_dRoundYRadius*2.0,
    4189                 :                                     poRectHdr->m_nCornerWidth,
    4190               0 :                                     poRectHdr->m_nCornerHeight);
    4191                 :     }
    4192                 :     else
    4193                 :     {
    4194               0 :         poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
    4195                 :     }
    4196                 : 
    4197                 :     // A rectangle is defined by its MBR (values were set in UpdateMBR())
    4198               0 :     poRectHdr->m_nMinX = m_nXMin;
    4199               0 :     poRectHdr->m_nMinY = m_nYMin;
    4200               0 :     poRectHdr->m_nMaxX = m_nXMax;
    4201               0 :     poRectHdr->m_nMaxY = m_nYMax;
    4202                 : 
    4203               0 :     m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    4204               0 :     poRectHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    4205                 : 
    4206               0 :     m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
    4207               0 :     poRectHdr->m_nBrushId = (GByte)m_nBrushDefIndex;      // Brush index
    4208                 : 
    4209               0 :     if (CPLGetLastErrorNo() != 0)
    4210               0 :         return -1;
    4211                 : 
    4212               0 :     return 0;
    4213                 : }
    4214                 : 
    4215                 : /**********************************************************************
    4216                 :  *                   TABRectangle::GetStyleString()
    4217                 :  *
    4218                 :  * Return style string for this feature.
    4219                 :  *
    4220                 :  * Style String is built only once during the first call to GetStyleString().
    4221                 :  **********************************************************************/
    4222               0 : const char *TABRectangle::GetStyleString()
    4223                 : {
    4224               0 :     if (m_pszStyleString == NULL)
    4225                 :     {
    4226                 :         // Since GetPen/BrushStyleString() use CPLSPrintf(), we need 
    4227                 :         // to use temporary buffers
    4228               0 :         char *pszPen = CPLStrdup(GetPenStyleString());
    4229               0 :         char *pszBrush = CPLStrdup(GetBrushStyleString());
    4230                 : 
    4231               0 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
    4232                 : 
    4233               0 :         CPLFree(pszPen);
    4234               0 :         CPLFree(pszBrush);
    4235                 :     }
    4236                 : 
    4237               0 :     return m_pszStyleString;
    4238                 : }
    4239                 : 
    4240                 : /**********************************************************************
    4241                 :  *                   TABRectangle::DumpMIF()
    4242                 :  *
    4243                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    4244                 :  **********************************************************************/
    4245               0 : void TABRectangle::DumpMIF(FILE *fpOut /*=NULL*/)
    4246                 : {
    4247                 :     OGRGeometry   *poGeom;
    4248               0 :     OGRPolygon    *poPolygon = NULL;
    4249                 :     int i, numPoints;
    4250                 : 
    4251               0 :     if (fpOut == NULL)
    4252               0 :         fpOut = stdout;
    4253                 : 
    4254                 :     /*-----------------------------------------------------------------
    4255                 :      * Output RECT or ROUNDRECT parameters
    4256                 :      *----------------------------------------------------------------*/
    4257                 :     double dXMin, dYMin, dXMax, dYMax;
    4258               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    4259               0 :     if (m_bRoundCorners)
    4260                 :         fprintf(fpOut, "(ROUNDRECT %.15g %.15g %.15g %.15g    %.15g %.15g)\n", 
    4261                 :                 dXMin, dYMin, dXMax, dYMax, 
    4262               0 :                 m_dRoundXRadius, m_dRoundYRadius);
    4263                 :     else
    4264               0 :         fprintf(fpOut, "(RECT %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
    4265                 : 
    4266                 :     /*-----------------------------------------------------------------
    4267                 :      * Fetch and validate geometry
    4268                 :      *----------------------------------------------------------------*/
    4269               0 :     poGeom = GetGeometryRef();
    4270               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    4271                 :     {
    4272                 :         /*-------------------------------------------------------------
    4273                 :          * Generate rectangle output as a region
    4274                 :          * We could also output as a RECT or ROUNDRECT in a real MIF generator
    4275                 :          *------------------------------------------------------------*/
    4276                 :         int iRing, numIntRings;
    4277               0 :         poPolygon = (OGRPolygon*)poGeom;
    4278               0 :         numIntRings = poPolygon->getNumInteriorRings();
    4279               0 :         fprintf(fpOut, "REGION %d\n", numIntRings+1);
    4280                 :         // In this loop, iRing=-1 for the outer ring.
    4281               0 :         for(iRing=-1; iRing < numIntRings; iRing++)
    4282                 :         {
    4283                 :             OGRLinearRing       *poRing;
    4284                 : 
    4285               0 :             if (iRing == -1)
    4286               0 :                 poRing = poPolygon->getExteriorRing();
    4287                 :             else
    4288               0 :                 poRing = poPolygon->getInteriorRing(iRing);
    4289                 : 
    4290               0 :             if (poRing == NULL)
    4291                 :             {
    4292                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    4293               0 :                          "TABRectangle: Object Geometry contains NULL rings!");
    4294               0 :                 return;
    4295                 :             }
    4296                 : 
    4297               0 :             numPoints = poRing->getNumPoints();
    4298               0 :             fprintf(fpOut, " %d\n", numPoints);
    4299               0 :             for(i=0; i<numPoints; i++)
    4300               0 :                 fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
    4301                 :         }
    4302                 :     }
    4303                 :     else
    4304                 :     {
    4305                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4306               0 :                  "TABRectangle: Missing or Invalid Geometry!");
    4307               0 :         return;
    4308                 :     }
    4309                 : 
    4310                 :     // Finish with PEN/BRUSH/etc. clauses
    4311               0 :     DumpPenDef();
    4312               0 :     DumpBrushDef();
    4313                 : 
    4314               0 :     fflush(fpOut);
    4315                 : }
    4316                 : 
    4317                 : 
    4318                 : /*=====================================================================
    4319                 :  *                      class TABEllipse
    4320                 :  *====================================================================*/
    4321                 : 
    4322                 : /**********************************************************************
    4323                 :  *                   TABEllipse::TABEllipse()
    4324                 :  *
    4325                 :  * Constructor.
    4326                 :  **********************************************************************/
    4327               0 : TABEllipse::TABEllipse(OGRFeatureDefn *poDefnIn):
    4328               0 :               TABFeature(poDefnIn)
    4329                 : {
    4330               0 : }
    4331                 : 
    4332                 : /**********************************************************************
    4333                 :  *                   TABEllipse::~TABEllipse()
    4334                 :  *
    4335                 :  * Destructor.
    4336                 :  **********************************************************************/
    4337               0 : TABEllipse::~TABEllipse()
    4338                 : {
    4339               0 : }
    4340                 : 
    4341                 : /**********************************************************************
    4342                 :  *                     TABEllipse::CloneTABFeature()
    4343                 :  *
    4344                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    4345                 :  *
    4346                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    4347                 :  * then copies any members specific to its own type.
    4348                 :  **********************************************************************/
    4349               0 : TABFeature *TABEllipse::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    4350                 : {
    4351                 :     /*-----------------------------------------------------------------
    4352                 :      * Alloc new feature and copy the base stuff
    4353                 :      *----------------------------------------------------------------*/
    4354                 :     TABEllipse *poNew = new TABEllipse(poNewDefn ? poNewDefn : 
    4355               0 :                                                    GetDefnRef());
    4356                 : 
    4357               0 :     CopyTABFeatureBase(poNew);
    4358                 : 
    4359                 :     /*-----------------------------------------------------------------
    4360                 :      * And members specific to this class
    4361                 :      *----------------------------------------------------------------*/
    4362                 :     // ITABFeaturePen
    4363               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    4364                 : 
    4365                 :     // ITABFeatureBrush
    4366               0 :     *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
    4367                 : 
    4368               0 :     poNew->m_dCenterX = m_dCenterX;
    4369               0 :     poNew->m_dCenterY = m_dCenterY;
    4370               0 :     poNew->m_dXRadius = m_dXRadius;
    4371               0 :     poNew->m_dYRadius = m_dYRadius;
    4372                 : 
    4373               0 :     return poNew;
    4374                 : }
    4375                 : 
    4376                 : /**********************************************************************
    4377                 :  *                   TABEllipse::ValidateMapInfoType()
    4378                 :  *
    4379                 :  * Check the feature's geometry part and return the corresponding
    4380                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    4381                 :  * be updated for further calls to GetMapInfoType();
    4382                 :  *
    4383                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    4384                 :  * is expected for this object class.
    4385                 :  **********************************************************************/
    4386               0 : int  TABEllipse::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    4387                 : {
    4388                 :     OGRGeometry *poGeom;
    4389                 : 
    4390                 :     /*-----------------------------------------------------------------
    4391                 :      * Fetch and validate geometry
    4392                 :      *----------------------------------------------------------------*/
    4393               0 :     poGeom = GetGeometryRef();
    4394               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
    4395               0 :          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
    4396                 :     {
    4397               0 :         m_nMapInfoType = TAB_GEOM_ELLIPSE;
    4398                 :     }
    4399                 :     else
    4400                 :     {
    4401                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4402               0 :                  "TABEllipse: Missing or Invalid Geometry!");
    4403               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    4404                 :     }
    4405                 : 
    4406                 :     /*-----------------------------------------------------------------
    4407                 :      * Decide if coordinates should be compressed or not.
    4408                 :      *----------------------------------------------------------------*/
    4409                 :     // __TODO__ For now we always write uncompressed for this class...
    4410                 :     // ValidateCoordType(poMapFile);
    4411               0 :     UpdateMBR(poMapFile);
    4412                 : 
    4413               0 :     return m_nMapInfoType;
    4414                 : }
    4415                 : 
    4416                 : /**********************************************************************
    4417                 :  *                   TABEllipse::UpdateMBR()
    4418                 :  *
    4419                 :  * Update the feature MBR members using the geometry
    4420                 :  *
    4421                 :  * Returns 0 on success, or -1 if there is no geometry in object
    4422                 :  **********************************************************************/
    4423               0 : int TABEllipse::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    4424                 : {
    4425                 :     OGRGeometry *poGeom;
    4426               0 :     OGREnvelope sEnvelope;
    4427                 : 
    4428                 :     /*-----------------------------------------------------------------
    4429                 :      * Fetch and validate geometry... Polygon and point are accepted.
    4430                 :      * Note that we will simply use the ellipse's MBR and don't really 
    4431                 :      * read the polygon geometry... this should be OK unless the 
    4432                 :      * polygon geometry was not really an ellipse.
    4433                 :      *----------------------------------------------------------------*/
    4434               0 :     poGeom = GetGeometryRef();
    4435               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
    4436               0 :          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint )  )
    4437               0 :         poGeom->getEnvelope(&sEnvelope);
    4438                 :     else
    4439                 :     {
    4440                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4441               0 :                  "TABEllipse: Missing or Invalid Geometry!");
    4442               0 :         return -1;
    4443                 :     }
    4444                 : 
    4445                 :     /*-----------------------------------------------------------------
    4446                 :      * We use the center of the MBR as the ellipse center, and the 
    4447                 :      * X/Y radius to define the MBR size.  If X/Y radius are null then
    4448                 :      * we'll try to use the MBR to recompute them.
    4449                 :      *----------------------------------------------------------------*/
    4450                 :     double      dXCenter, dYCenter;
    4451               0 :     dXCenter = (sEnvelope.MaxX + sEnvelope.MinX)/2.0;
    4452               0 :     dYCenter = (sEnvelope.MaxY + sEnvelope.MinY)/2.0;
    4453               0 :     if (m_dXRadius == 0.0 && m_dYRadius == 0.0)
    4454                 :     {
    4455               0 :         m_dXRadius = ABS(sEnvelope.MaxX - sEnvelope.MinX) / 2.0;
    4456               0 :         m_dYRadius = ABS(sEnvelope.MaxY - sEnvelope.MinY) / 2.0;
    4457                 :     }
    4458                 : 
    4459               0 :     m_dXMin = dXCenter - m_dXRadius;
    4460               0 :     m_dYMin = dYCenter - m_dYRadius;
    4461               0 :     m_dXMax = dXCenter + m_dXRadius;
    4462               0 :     m_dYMax = dYCenter + m_dYRadius;
    4463                 : 
    4464               0 :     if (poMapFile)
    4465                 :     {
    4466               0 :         poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    4467               0 :         poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    4468                 :     }
    4469                 : 
    4470               0 :     return 0;
    4471                 : }
    4472                 : 
    4473                 : /**********************************************************************
    4474                 :  *                   TABEllipse::ReadGeometryFromMAPFile()
    4475                 :  *
    4476                 :  * Fill the geometry and representation (color, etc...) part of the
    4477                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    4478                 :  *
    4479                 :  * It is assumed that poMAPFile currently points to the beginning of
    4480                 :  * a map object.
    4481                 :  *
    4482                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4483                 :  * been called.
    4484                 :  **********************************************************************/
    4485               0 : int TABEllipse::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    4486                 :                                         TABMAPObjHdr *poObjHdr,
    4487                 :                                         GBool bCoordBlockDataOnly /*=FALSE*/,
    4488                 :                                         TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4489                 : {
    4490                 :     double              dXMin, dYMin, dXMax, dYMax;
    4491                 :     OGRPolygon          *poPolygon;
    4492                 :     OGRLinearRing       *poRing;
    4493                 : 
    4494                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4495               0 :     if (bCoordBlockDataOnly)
    4496               0 :         return 0;
    4497                 : 
    4498                 :     /*-----------------------------------------------------------------
    4499                 :      * Fetch and validate geometry type
    4500                 :      *----------------------------------------------------------------*/
    4501               0 :     m_nMapInfoType = poObjHdr->m_nType;
    4502                 : 
    4503               0 :     if (m_nMapInfoType != TAB_GEOM_ELLIPSE &&
    4504                 :         m_nMapInfoType != TAB_GEOM_ELLIPSE_C )
    4505                 :     {
    4506                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4507                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    4508               0 :                  m_nMapInfoType, m_nMapInfoType);
    4509               0 :         return -1;
    4510                 :     }
    4511                 : 
    4512                 :     /*-----------------------------------------------------------------
    4513                 :      * Read object information
    4514                 :      *----------------------------------------------------------------*/
    4515               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4516                 : 
    4517                 :     // An ellipse is defined by its MBR
    4518                 : 
    4519                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY, 
    4520               0 :                             dXMin, dYMin);
    4521                 :     poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY, 
    4522               0 :                             dXMax, dYMax);
    4523                 : 
    4524               0 :     m_nPenDefIndex = poRectHdr->m_nPenId;       // Pen index
    4525               0 :     poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    4526                 : 
    4527               0 :     m_nBrushDefIndex = poRectHdr->m_nBrushId;   // Brush index
    4528               0 :     poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
    4529                 : 
    4530                 :     /*-----------------------------------------------------------------
    4531                 :      * Save info about the ellipse def. inside class members
    4532                 :      *----------------------------------------------------------------*/
    4533               0 :     m_dCenterX = (dXMin + dXMax) / 2.0;
    4534               0 :     m_dCenterY = (dYMin + dYMax) / 2.0;
    4535               0 :     m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
    4536               0 :     m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
    4537                 : 
    4538               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    4539                 : 
    4540                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    4541               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    4542                 : 
    4543                 :     /*-----------------------------------------------------------------
    4544                 :      * Create and fill geometry object
    4545                 :      *----------------------------------------------------------------*/
    4546               0 :     poPolygon = new OGRPolygon;
    4547               0 :     poRing = new OGRLinearRing();
    4548                 : 
    4549                 : 
    4550                 :     /*-----------------------------------------------------------------
    4551                 :      * For the OGR geometry, we generate an ellipse with 2 degrees line
    4552                 :      * segments.
    4553                 :      *----------------------------------------------------------------*/
    4554                 :     TABGenerateArc(poRing, 180, 
    4555                 :                    m_dCenterX, m_dCenterY,
    4556                 :                    m_dXRadius, m_dYRadius,
    4557               0 :                    0.0, 2.0*PI);
    4558               0 :     TABCloseRing(poRing);
    4559                 : 
    4560               0 :     poPolygon->addRingDirectly(poRing);
    4561               0 :     SetGeometryDirectly(poPolygon);
    4562                 : 
    4563               0 :     return 0;
    4564                 : }
    4565                 : 
    4566                 : /**********************************************************************
    4567                 :  *                   TABEllipse::WriteGeometryToMAPFile()
    4568                 :  *
    4569                 :  * Write the geometry and representation (color, etc...) part of the
    4570                 :  * feature to the .MAP object pointed to by poMAPFile.
    4571                 :  *
    4572                 :  * It is assumed that poMAPFile currently points to a valid map object.
    4573                 :  *
    4574                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4575                 :  * been called.
    4576                 :  **********************************************************************/
    4577               0 : int TABEllipse::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    4578                 :                                        TABMAPObjHdr *poObjHdr,
    4579                 :                                        GBool bCoordBlockDataOnly /*=FALSE*/, 
    4580                 :                                        TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4581                 : {
    4582                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4583               0 :     if (bCoordBlockDataOnly)
    4584               0 :         return 0;
    4585                 : 
    4586                 :     /*-----------------------------------------------------------------
    4587                 :      * We assume that ValidateMapInfoType() was called already and that
    4588                 :      * the type in poObjHdr->m_nType is valid.
    4589                 :      *----------------------------------------------------------------*/
    4590               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    4591                 : 
    4592                 :     /*-----------------------------------------------------------------
    4593                 :      * Fetch and validate geometry... Polygon and point are accepted.
    4594                 :      * Note that we will simply use the ellipse's MBR and don't really 
    4595                 :      * read the polygon geometry... this should be OK unless the 
    4596                 :      * polygon geometry was not really an ellipse.
    4597                 :      *
    4598                 :      * We use the center of the MBR as the ellipse center, and the 
    4599                 :      * X/Y radius to define the MBR size.  If X/Y radius are null then
    4600                 :      * we'll try to use the MBR to recompute them.
    4601                 :      *----------------------------------------------------------------*/
    4602               0 :     if (UpdateMBR(poMapFile) != 0)
    4603               0 :         return -1;  /* Error already reported */
    4604                 : 
    4605                 :     /*-----------------------------------------------------------------
    4606                 :      * Copy object information
    4607                 :      *----------------------------------------------------------------*/
    4608               0 :     TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
    4609                 : 
    4610                 :     // Reset RoundRect Corner members... just in case (unused for ellipse)
    4611               0 :     poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
    4612                 : 
    4613                 :     // An ellipse is defined by its MBR (values were set in UpdateMBR())
    4614               0 :     poRectHdr->m_nMinX = m_nXMin;
    4615               0 :     poRectHdr->m_nMinY = m_nYMin;
    4616               0 :     poRectHdr->m_nMaxX = m_nXMax;
    4617               0 :     poRectHdr->m_nMaxY = m_nYMax;
    4618                 : 
    4619               0 :     m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    4620               0 :     poRectHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    4621                 : 
    4622               0 :     m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
    4623               0 :     poRectHdr->m_nBrushId = (GByte)m_nBrushDefIndex;      // Brush index
    4624                 : 
    4625               0 :     if (CPLGetLastErrorNo() != 0)
    4626               0 :         return -1;
    4627                 : 
    4628               0 :     return 0;
    4629                 : }
    4630                 : 
    4631                 : /**********************************************************************
    4632                 :  *                   TABEllipse::GetStyleString()
    4633                 :  *
    4634                 :  * Return style string for this feature.
    4635                 :  *
    4636                 :  * Style String is built only once during the first call to GetStyleString().
    4637                 :  **********************************************************************/
    4638               0 : const char *TABEllipse::GetStyleString()
    4639                 : {
    4640               0 :     if (m_pszStyleString == NULL)
    4641                 :     {
    4642                 :         // Since GetPen/BrushStyleString() use CPLSPrintf(), we need 
    4643                 :         // to use temporary buffers
    4644               0 :         char *pszPen = CPLStrdup(GetPenStyleString());
    4645               0 :         char *pszBrush = CPLStrdup(GetBrushStyleString());
    4646                 : 
    4647               0 :         m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
    4648                 : 
    4649               0 :         CPLFree(pszPen);
    4650               0 :         CPLFree(pszBrush);
    4651                 :     }
    4652                 : 
    4653               0 :     return m_pszStyleString;
    4654                 : }
    4655                 : 
    4656                 : 
    4657                 : /**********************************************************************
    4658                 :  *                   TABEllipse::DumpMIF()
    4659                 :  *
    4660                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    4661                 :  **********************************************************************/
    4662               0 : void TABEllipse::DumpMIF(FILE *fpOut /*=NULL*/)
    4663                 : {
    4664                 :     OGRGeometry   *poGeom;
    4665               0 :     OGRPolygon    *poPolygon = NULL;
    4666                 :     int i, numPoints;
    4667                 : 
    4668               0 :     if (fpOut == NULL)
    4669               0 :         fpOut = stdout;
    4670                 : 
    4671                 :     /*-----------------------------------------------------------------
    4672                 :      * Output ELLIPSE parameters
    4673                 :      *----------------------------------------------------------------*/
    4674                 :     double dXMin, dYMin, dXMax, dYMax;
    4675               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    4676               0 :     fprintf(fpOut, "(ELLIPSE %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
    4677                 : 
    4678                 :     /*-----------------------------------------------------------------
    4679                 :      * Fetch and validate geometry
    4680                 :      *----------------------------------------------------------------*/
    4681               0 :     poGeom = GetGeometryRef();
    4682               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
    4683                 :     {
    4684                 :         /*-------------------------------------------------------------
    4685                 :          * Generate ellipse output as a region
    4686                 :          * We could also output as an ELLIPSE in a real MIF generator
    4687                 :          *------------------------------------------------------------*/
    4688                 :         int iRing, numIntRings;
    4689               0 :         poPolygon = (OGRPolygon*)poGeom;
    4690               0 :         numIntRings = poPolygon->getNumInteriorRings();
    4691               0 :         fprintf(fpOut, "REGION %d\n", numIntRings+1);
    4692                 :         // In this loop, iRing=-1 for the outer ring.
    4693               0 :         for(iRing=-1; iRing < numIntRings; iRing++)
    4694                 :         {
    4695                 :             OGRLinearRing       *poRing;
    4696                 : 
    4697               0 :             if (iRing == -1)
    4698               0 :                 poRing = poPolygon->getExteriorRing();
    4699                 :             else
    4700               0 :                 poRing = poPolygon->getInteriorRing(iRing);
    4701                 : 
    4702               0 :             if (poRing == NULL)
    4703                 :             {
    4704                 :                 CPLError(CE_Failure, CPLE_AssertionFailed,
    4705               0 :                          "TABEllipse: Object Geometry contains NULL rings!");
    4706               0 :                 return;
    4707                 :             }
    4708                 : 
    4709               0 :             numPoints = poRing->getNumPoints();
    4710               0 :             fprintf(fpOut, " %d\n", numPoints);
    4711               0 :             for(i=0; i<numPoints; i++)
    4712               0 :                 fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
    4713                 :         }
    4714                 :     }
    4715                 :     else
    4716                 :     {
    4717                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4718               0 :                  "TABEllipse: Missing or Invalid Geometry!");
    4719               0 :         return;
    4720                 :     }
    4721                 : 
    4722                 :     // Finish with PEN/BRUSH/etc. clauses
    4723               0 :     DumpPenDef();
    4724               0 :     DumpBrushDef();
    4725                 : 
    4726               0 :     fflush(fpOut);
    4727                 : }
    4728                 : 
    4729                 : 
    4730                 : /*=====================================================================
    4731                 :  *                      class TABArc
    4732                 :  *====================================================================*/
    4733                 : 
    4734                 : /**********************************************************************
    4735                 :  *                   TABArc::TABArc()
    4736                 :  *
    4737                 :  * Constructor.
    4738                 :  **********************************************************************/
    4739               0 : TABArc::TABArc(OGRFeatureDefn *poDefnIn):
    4740               0 :               TABFeature(poDefnIn)
    4741                 : {
    4742               0 :     m_dStartAngle = m_dEndAngle = 0.0;
    4743               0 :     m_dCenterX = m_dCenterY = m_dXRadius = m_dYRadius = 0.0;
    4744                 : 
    4745               0 : }
    4746                 : 
    4747                 : /**********************************************************************
    4748                 :  *                   TABArc::~TABArc()
    4749                 :  *
    4750                 :  * Destructor.
    4751                 :  **********************************************************************/
    4752               0 : TABArc::~TABArc()
    4753                 : {
    4754               0 : }
    4755                 : 
    4756                 : /**********************************************************************
    4757                 :  *                     TABArc::CloneTABFeature()
    4758                 :  *
    4759                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    4760                 :  *
    4761                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    4762                 :  * then copies any members specific to its own type.
    4763                 :  **********************************************************************/
    4764               0 : TABFeature *TABArc::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    4765                 : {
    4766                 :     /*-----------------------------------------------------------------
    4767                 :      * Alloc new feature and copy the base stuff
    4768                 :      *----------------------------------------------------------------*/
    4769               0 :     TABArc *poNew = new TABArc(poNewDefn ? poNewDefn : GetDefnRef());
    4770                 : 
    4771               0 :     CopyTABFeatureBase(poNew);
    4772                 : 
    4773                 :     /*-----------------------------------------------------------------
    4774                 :      * And members specific to this class
    4775                 :      *----------------------------------------------------------------*/
    4776                 :     // ITABFeaturePen
    4777               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    4778                 : 
    4779               0 :     poNew->SetStartAngle( GetStartAngle() );
    4780               0 :     poNew->SetEndAngle( GetEndAngle() );
    4781                 : 
    4782               0 :     poNew->m_dCenterX = m_dCenterX;
    4783               0 :     poNew->m_dCenterY = m_dCenterY;
    4784               0 :     poNew->m_dXRadius = m_dXRadius;
    4785               0 :     poNew->m_dYRadius = m_dYRadius;
    4786                 : 
    4787               0 :     return poNew;
    4788                 : }
    4789                 : 
    4790                 : /**********************************************************************
    4791                 :  *                   TABArc::ValidateMapInfoType()
    4792                 :  *
    4793                 :  * Check the feature's geometry part and return the corresponding
    4794                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    4795                 :  * be updated for further calls to GetMapInfoType();
    4796                 :  *
    4797                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    4798                 :  * is expected for this object class.
    4799                 :  **********************************************************************/
    4800               0 : int  TABArc::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    4801                 : {
    4802                 :     OGRGeometry *poGeom;
    4803                 : 
    4804                 :     /*-----------------------------------------------------------------
    4805                 :      * Fetch and validate geometry
    4806                 :      *----------------------------------------------------------------*/
    4807               0 :     poGeom = GetGeometryRef();
    4808               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) ||
    4809               0 :          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
    4810                 :     {
    4811               0 :         m_nMapInfoType = TAB_GEOM_ARC;
    4812                 :     }
    4813                 :     else
    4814                 :     {
    4815                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4816               0 :                  "TABArc: Missing or Invalid Geometry!");
    4817               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    4818                 :     }
    4819                 : 
    4820                 :     /*-----------------------------------------------------------------
    4821                 :      * Decide if coordinates should be compressed or not.
    4822                 :      *----------------------------------------------------------------*/
    4823                 :     // __TODO__ For now we always write uncompressed for this class...
    4824                 :     // ValidateCoordType(poMapFile);
    4825               0 :     UpdateMBR(poMapFile);
    4826                 : 
    4827               0 :     return m_nMapInfoType;
    4828                 : }
    4829                 : 
    4830                 : /**********************************************************************
    4831                 :  *                   TABArc::UpdateMBR()
    4832                 :  *
    4833                 :  * Update the feature MBR members using the geometry
    4834                 :  *
    4835                 :  * Returns 0 on success, or -1 if there is no geometry in object
    4836                 :  **********************************************************************/
    4837               0 : int TABArc::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    4838                 : {
    4839                 :     OGRGeometry *poGeom;
    4840               0 :     OGREnvelope sEnvelope;
    4841                 : 
    4842               0 :     poGeom = GetGeometryRef();
    4843               0 :     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) )
    4844                 :     {
    4845                 :         /*-------------------------------------------------------------
    4846                 :          * POLYGON geometry:
    4847                 :          * Note that we will simply use the ellipse's MBR and don't really 
    4848                 :          * read the polygon geometry... this should be OK unless the 
    4849                 :          * polygon geometry was not really an ellipse.
    4850                 :          * In the case of a polygon geometry. the m_dCenterX/Y values MUST
    4851                 :          * have been set by the caller.
    4852                 :          *------------------------------------------------------------*/
    4853               0 :         poGeom->getEnvelope(&sEnvelope);
    4854                 :     }
    4855               0 :     else if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) ) 
    4856                 :     {
    4857                 :         /*-------------------------------------------------------------
    4858                 :          * In the case of a POINT GEOMETRY, we will make sure the the 
    4859                 :          * feature's m_dCenterX/Y are in sync with the point's X,Y coords.
    4860                 :          *
    4861                 :          * In this case we have to reconstruct the arc inside a temporary
    4862                 :          * geometry object in order to find its real MBR.
    4863                 :          *------------------------------------------------------------*/
    4864               0 :         OGRPoint *poPoint = (OGRPoint *)poGeom;
    4865               0 :         m_dCenterX = poPoint->getX();
    4866               0 :         m_dCenterY = poPoint->getY();
    4867                 : 
    4868               0 :         OGRLineString oTmpLine;
    4869               0 :         int numPts=0;
    4870               0 :         if (m_dEndAngle < m_dStartAngle)
    4871               0 :             numPts = (int) ABS( ((m_dEndAngle+360)-m_dStartAngle)/2 ) + 1;
    4872                 :         else
    4873               0 :             numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2 ) + 1;
    4874               0 :         numPts = MAX(2, numPts);
    4875                 : 
    4876                 :         TABGenerateArc(&oTmpLine, numPts,
    4877                 :                        m_dCenterX, m_dCenterY,
    4878                 :                        m_dXRadius, m_dYRadius,
    4879               0 :                        m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
    4880                 : 
    4881               0 :         oTmpLine.getEnvelope(&sEnvelope);
    4882                 :     }
    4883                 :     else
    4884                 :     {
    4885                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4886               0 :                  "TABArc: Missing or Invalid Geometry!");
    4887               0 :         return -1;
    4888                 :     }
    4889                 : 
    4890                 :     // Update the Arc's MBR
    4891               0 :     m_dXMin = sEnvelope.MinX;
    4892               0 :     m_dYMin = sEnvelope.MinY;
    4893               0 :     m_dXMax = sEnvelope.MaxX;
    4894               0 :     m_dYMax = sEnvelope.MaxY;
    4895                 : 
    4896               0 :     if (poMapFile)
    4897                 :     {
    4898               0 :         poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    4899               0 :         poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    4900                 :     }
    4901                 : 
    4902               0 :     return 0;
    4903                 : }
    4904                 : 
    4905                 : /**********************************************************************
    4906                 :  *                   TABArc::ReadGeometryFromMAPFile()
    4907                 :  *
    4908                 :  * Fill the geometry and representation (color, etc...) part of the
    4909                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    4910                 :  *
    4911                 :  * It is assumed that poMAPFile currently points to the beginning of
    4912                 :  * a map object.
    4913                 :  *
    4914                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    4915                 :  * been called.
    4916                 :  **********************************************************************/
    4917               0 : int TABArc::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    4918                 :                                     TABMAPObjHdr *poObjHdr,
    4919                 :                                     GBool bCoordBlockDataOnly /*=FALSE*/, 
    4920                 :                                     TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    4921                 : {
    4922                 :     double              dXMin, dYMin, dXMax, dYMax;
    4923                 :     OGRLineString       *poLine;
    4924                 :     int                 numPts;
    4925                 : 
    4926                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    4927               0 :     if (bCoordBlockDataOnly)
    4928               0 :         return 0;
    4929                 : 
    4930                 :     /*-----------------------------------------------------------------
    4931                 :      * Fetch and validate geometry type
    4932                 :      *----------------------------------------------------------------*/
    4933               0 :     m_nMapInfoType = poObjHdr->m_nType;
    4934                 : 
    4935               0 :     if (m_nMapInfoType != TAB_GEOM_ARC &&
    4936                 :         m_nMapInfoType != TAB_GEOM_ARC_C )
    4937                 :     {
    4938                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    4939                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    4940               0 :                  m_nMapInfoType, m_nMapInfoType);
    4941               0 :         return -1;
    4942                 :     }
    4943                 : 
    4944                 : 
    4945                 :     /*-----------------------------------------------------------------
    4946                 :      * Read object information
    4947                 :      *----------------------------------------------------------------*/
    4948               0 :     TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
    4949                 : 
    4950                 :     /*-------------------------------------------------------------
    4951                 :      * Start/End angles
    4952                 :      * Since the angles are specified for integer coordinates, and
    4953                 :      * that these coordinates can have the X axis reversed, we have to
    4954                 :      * adjust the angle values for the change in the X axis
    4955                 :      * direction.
    4956                 :      *
    4957                 :      * This should be necessary only when X axis is flipped.
    4958                 :      * __TODO__ Why is order of start/end values reversed as well???
    4959                 :      *------------------------------------------------------------*/
    4960                 : 
    4961                 :     /*-------------------------------------------------------------
    4962                 :      * OK, Arc angles again!!!!!!!!!!!!
    4963                 :      * After some tests in 1999-11, it appeared that the angle values
    4964                 :      * ALWAYS had to be flipped (read order= end angle followed by 
    4965                 :      * start angle), no matter which quadrant the file is in.
    4966                 :      * This does not make any sense, so I suspect that there is something
    4967                 :      * that we are missing here!
    4968                 :      *
    4969                 :      * 2000-01-14.... Again!!!  Based on some sample data files:
    4970                 :      *  File         Ver Quadr  ReflXAxis  Read_Order   Adjust_Angle
    4971                 :      * test_symb.tab 300    2        1      end,start    X=yes Y=no
    4972                 :      * alltypes.tab: 300    1        0      start,end    X=no  Y=no
    4973                 :      * arcs.tab:     300    2        0      end,start    X=yes Y=no
    4974                 :      *
    4975                 :      * Until we prove it wrong, the rule would be:
    4976                 :      *  -> Quadrant 1 and 3, angles order = start, end
    4977                 :      *  -> Quadrant 2 and 4, angles order = end, start
    4978                 :      * + Always adjust angles for x and y axis based on quadrant.
    4979                 :      *
    4980                 :      * This was confirmed using some more files in which the quadrant was 
    4981                 :      * manually changed, but whether these are valid results is 
    4982                 :      * discutable.
    4983                 :      *
    4984                 :      * The ReflectXAxis flag seems to have no effect here...
    4985                 :      *------------------------------------------------------------*/
    4986                 : 
    4987                 :     /*-------------------------------------------------------------
    4988                 :      * In version 100 .tab files (version 400 .map), it is possible
    4989                 :      * to have a quadrant value of 0 and it should be treated the 
    4990                 :      * same way as quadrant 3
    4991                 :      *------------------------------------------------------------*/
    4992               0 :     if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==1 ||
    4993                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
    4994                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0  )
    4995                 :     {
    4996                 :         // Quadrants 1 and 3 ... read order = start, end
    4997               0 :         m_dStartAngle = poArcHdr->m_nStartAngle/10.0;
    4998               0 :         m_dEndAngle = poArcHdr->m_nEndAngle/10.0;
    4999                 :     }
    5000                 :     else
    5001                 :     {
    5002                 :         // Quadrants 2 and 4 ... read order = end, start
    5003               0 :         m_dStartAngle = poArcHdr->m_nEndAngle/10.0;
    5004               0 :         m_dEndAngle = poArcHdr->m_nStartAngle/10.0;
    5005                 :     }
    5006                 : 
    5007               0 :     if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==2 ||
    5008                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
    5009                 :          poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
    5010                 :     {
    5011                 :         // X axis direction is flipped... adjust angle
    5012                 :         m_dStartAngle = (m_dStartAngle<=180.0) ? (180.0-m_dStartAngle):
    5013               0 :             (540.0-m_dStartAngle);
    5014                 :         m_dEndAngle   = (m_dEndAngle<=180.0) ? (180.0-m_dEndAngle):
    5015               0 :             (540.0-m_dEndAngle);
    5016                 :     }
    5017                 : 
    5018               0 :     if (poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
    5019                 :         poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==4 ||
    5020                 :         poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
    5021                 :     {
    5022                 :         // Y axis direction is flipped... this reverses angle direction
    5023                 :         // Unfortunately we never found any file that contains this case,
    5024                 :         // but this should be the behavior to expect!!!
    5025                 :         //
    5026                 :         // 2000-01-14: some files in which quadrant was set to 3 and 4
    5027                 :         // manually seemed to confirm that this is the right thing to do.
    5028               0 :         m_dStartAngle = 360.0 - m_dStartAngle;
    5029               0 :         m_dEndAngle = 360.0 - m_dEndAngle;
    5030                 :     }
    5031                 : 
    5032                 :     // An arc is defined by its defining ellipse's MBR:
    5033                 : 
    5034                 :     poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMinX, 
    5035               0 :                             poArcHdr->m_nArcEllipseMinY , dXMin, dYMin);
    5036                 :     poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMaxX, 
    5037               0 :                             poArcHdr->m_nArcEllipseMaxY , dXMax, dYMax);
    5038                 : 
    5039               0 :     m_dCenterX = (dXMin + dXMax) / 2.0;
    5040               0 :     m_dCenterY = (dYMin + dYMax) / 2.0;
    5041               0 :     m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
    5042               0 :     m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
    5043                 : 
    5044                 :     // Read the Arc's MBR and use that as this feature's MBR
    5045                 :     poMapFile->Int2Coordsys(poArcHdr->m_nMinX, poArcHdr->m_nMinY, 
    5046               0 :                             dXMin, dYMin);
    5047                 :     poMapFile->Int2Coordsys(poArcHdr->m_nMaxX, poArcHdr->m_nMaxY, 
    5048               0 :                             dXMax, dYMax);
    5049               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    5050                 : 
    5051               0 :     m_nPenDefIndex = poArcHdr->m_nPenId;        // Pen index
    5052               0 :     poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    5053                 : 
    5054                 : 
    5055                 :     /*-----------------------------------------------------------------
    5056                 :      * Create and fill geometry object
    5057                 :      * For the OGR geometry, we generate an arc with 2 degrees line
    5058                 :      * segments.
    5059                 :      *----------------------------------------------------------------*/
    5060               0 :     poLine = new OGRLineString;
    5061                 : 
    5062               0 :     if (m_dEndAngle < m_dStartAngle)
    5063               0 :         numPts = (int) ABS( ((m_dEndAngle+360.0)-m_dStartAngle)/2.0 ) + 1;
    5064                 :     else
    5065               0 :         numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2.0 ) + 1;
    5066               0 :     numPts = MAX(2, numPts);
    5067                 : 
    5068                 :     TABGenerateArc(poLine, numPts,
    5069                 :                    m_dCenterX, m_dCenterY,
    5070                 :                    m_dXRadius, m_dYRadius,
    5071               0 :                    m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
    5072                 : 
    5073               0 :     SetGeometryDirectly(poLine);
    5074                 : 
    5075               0 :     return 0;
    5076                 : }
    5077                 : 
    5078                 : /**********************************************************************
    5079                 :  *                   TABArc::WriteGeometryToMAPFile()
    5080                 :  *
    5081                 :  * Write the geometry and representation (color, etc...) part of the
    5082                 :  * feature to the .MAP object pointed to by poMAPFile.
    5083                 :  *
    5084                 :  * It is assumed that poMAPFile currently points to a valid map object.
    5085                 :  *
    5086                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    5087                 :  * been called.
    5088                 :  **********************************************************************/
    5089               0 : int TABArc::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    5090                 :                                    TABMAPObjHdr *poObjHdr,
    5091                 :                                    GBool bCoordBlockDataOnly /*=FALSE*/, 
    5092                 :                                    TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    5093                 : {
    5094                 :     /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
    5095               0 :     if (bCoordBlockDataOnly)
    5096               0 :         return 0;
    5097                 : 
    5098                 :     /*-----------------------------------------------------------------
    5099                 :      * We assume that ValidateMapInfoType() was called already and that
    5100                 :      * the type in poObjHdr->m_nType is valid.
    5101                 :      *----------------------------------------------------------------*/
    5102               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    5103                 : 
    5104                 :     /*-----------------------------------------------------------------
    5105                 :      * Fetch and validate geometry
    5106                 :      * In the case of ARCs, this is all done inside UpdateMBR()
    5107                 :      *----------------------------------------------------------------*/
    5108               0 :     if (UpdateMBR(poMapFile) != 0)
    5109               0 :         return -1;  /* Error already reported */
    5110                 : 
    5111                 :     /*-----------------------------------------------------------------
    5112                 :      * Copy object information
    5113                 :      *----------------------------------------------------------------*/
    5114               0 :     TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
    5115                 : 
    5116                 :     /*-------------------------------------------------------------
    5117                 :      * Start/End angles
    5118                 :      * Since we ALWAYS produce files in quadrant 1 then we can
    5119                 :      * ignore the special angle conversion required by flipped axis.
    5120                 :      *
    5121                 :      * See the notes about Arc angles in TABArc::ReadGeometryFromMAPFile()
    5122                 :      *------------------------------------------------------------*/
    5123               0 :     CPLAssert(poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant == 1);
    5124                 : 
    5125               0 :     poArcHdr->m_nStartAngle = ROUND_INT(m_dStartAngle*10.0);
    5126               0 :     poArcHdr->m_nEndAngle = ROUND_INT(m_dEndAngle*10.0);
    5127                 :     
    5128                 :     // An arc is defined by its defining ellipse's MBR:
    5129                 :     poMapFile->Coordsys2Int(m_dCenterX-m_dXRadius, m_dCenterY-m_dYRadius,
    5130                 :                             poArcHdr->m_nArcEllipseMinX, 
    5131               0 :                             poArcHdr->m_nArcEllipseMinY);
    5132                 :     poMapFile->Coordsys2Int(m_dCenterX+m_dXRadius, m_dCenterY+m_dYRadius,
    5133                 :                             poArcHdr->m_nArcEllipseMaxX, 
    5134               0 :                             poArcHdr->m_nArcEllipseMaxY);
    5135                 : 
    5136                 :     // Pass the Arc's actual MBR (values were set in UpdateMBR())
    5137               0 :     poArcHdr->m_nMinX = m_nXMin;
    5138               0 :     poArcHdr->m_nMinY = m_nYMin;
    5139               0 :     poArcHdr->m_nMaxX = m_nXMax;
    5140               0 :     poArcHdr->m_nMaxY = m_nYMax;
    5141                 : 
    5142               0 :     m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    5143               0 :     poArcHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index
    5144                 : 
    5145               0 :     if (CPLGetLastErrorNo() != 0)
    5146               0 :         return -1;
    5147                 : 
    5148               0 :     return 0;
    5149                 : }
    5150                 : 
    5151                 : /**********************************************************************
    5152                 :  *                   TABArc::SetStart/EndAngle()
    5153                 :  *
    5154                 :  * Set the start/end angle values in degrees, making sure the values are
    5155                 :  * always in the range [0..360]
    5156                 :  **********************************************************************/
    5157               0 : void TABArc::SetStartAngle(double dAngle)
    5158                 : {
    5159               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    5160               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    5161                 : 
    5162               0 :     m_dStartAngle = dAngle;
    5163               0 : }
    5164                 : 
    5165               0 : void TABArc::SetEndAngle(double dAngle)
    5166                 : {
    5167               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    5168               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    5169                 : 
    5170               0 :     m_dEndAngle = dAngle;
    5171               0 : }
    5172                 : 
    5173                 : 
    5174                 : /**********************************************************************
    5175                 :  *                   TABArc::GetStyleString()
    5176                 :  *
    5177                 :  * Return style string for this feature.
    5178                 :  *
    5179                 :  * Style String is built only once during the first call to GetStyleString().
    5180                 :  **********************************************************************/
    5181               0 : const char *TABArc::GetStyleString()
    5182                 : {
    5183               0 :     if (m_pszStyleString == NULL)
    5184                 :     {
    5185               0 :         m_pszStyleString = CPLStrdup(GetPenStyleString());
    5186                 :     }
    5187                 : 
    5188               0 :     return m_pszStyleString;
    5189                 : }
    5190                 : 
    5191                 : /**********************************************************************
    5192                 :  *                   TABArc::DumpMIF()
    5193                 :  *
    5194                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    5195                 :  **********************************************************************/
    5196               0 : void TABArc::DumpMIF(FILE *fpOut /*=NULL*/)
    5197                 : {
    5198                 :     OGRGeometry   *poGeom;
    5199               0 :     OGRLineString *poLine = NULL;
    5200                 :     int i, numPoints;
    5201                 : 
    5202               0 :     if (fpOut == NULL)
    5203               0 :         fpOut = stdout;
    5204                 : 
    5205                 :     /*-----------------------------------------------------------------
    5206                 :      * Output ARC parameters
    5207                 :      *----------------------------------------------------------------*/
    5208                 :     fprintf(fpOut, "(ARC %.15g %.15g %.15g %.15g   %d %d)\n",
    5209                 :             m_dCenterX - m_dXRadius, m_dCenterY - m_dYRadius,
    5210                 :             m_dCenterX + m_dXRadius, m_dCenterY + m_dYRadius,
    5211               0 :             (int)m_dStartAngle, (int)m_dEndAngle);
    5212                 : 
    5213                 :     /*-----------------------------------------------------------------
    5214                 :      * Fetch and validate geometry
    5215                 :      *----------------------------------------------------------------*/
    5216               0 :     poGeom = GetGeometryRef();
    5217               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
    5218                 :     {
    5219                 :         /*-------------------------------------------------------------
    5220                 :          * Generate arc output as a simple polyline
    5221                 :          * We could also output as an ELLIPSE in a real MIF generator
    5222                 :          *------------------------------------------------------------*/
    5223               0 :         poLine = (OGRLineString*)poGeom;
    5224               0 :         numPoints = poLine->getNumPoints();
    5225               0 :         fprintf(fpOut, "PLINE %d\n", numPoints);
    5226               0 :         for(i=0; i<numPoints; i++)
    5227               0 :             fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
    5228                 :     }
    5229                 :     else
    5230                 :     {
    5231                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5232               0 :                  "TABArc: Missing or Invalid Geometry!");
    5233               0 :         return;
    5234                 :     }
    5235                 : 
    5236                 :     // Finish with PEN/BRUSH/etc. clauses
    5237               0 :     DumpPenDef();
    5238                 : 
    5239               0 :     fflush(fpOut);
    5240                 : }
    5241                 : 
    5242                 : 
    5243                 : 
    5244                 : /*=====================================================================
    5245                 :  *                      class TABText
    5246                 :  *====================================================================*/
    5247                 : 
    5248                 : /**********************************************************************
    5249                 :  *                   TABText::TABText()
    5250                 :  *
    5251                 :  * Constructor.
    5252                 :  **********************************************************************/
    5253               0 : TABText::TABText(OGRFeatureDefn *poDefnIn):
    5254               0 :               TABFeature(poDefnIn)
    5255                 : {
    5256               0 :     m_pszString = NULL;
    5257                 : 
    5258               0 :     m_dAngle = m_dHeight = 0.0;
    5259               0 :     m_dfLineEndX = m_dfLineEndY = 0.0;
    5260               0 :     m_bLineEndSet = FALSE;
    5261                 : 
    5262               0 :     m_rgbForeground = 0x000000;
    5263               0 :     m_rgbBackground = 0xffffff;
    5264               0 :     m_rgbOutline    = 0xffffff;
    5265               0 :     m_rgbShadow     = 0x808080;
    5266                 : 
    5267               0 :     m_nTextAlignment = 0;
    5268               0 :     m_nFontStyle = 0;
    5269               0 :     m_dWidth = 0;
    5270               0 : }
    5271                 : 
    5272                 : /**********************************************************************
    5273                 :  *                   TABText::~TABText()
    5274                 :  *
    5275                 :  * Destructor.
    5276                 :  **********************************************************************/
    5277               0 : TABText::~TABText()
    5278                 : {
    5279               0 :     CPLFree(m_pszString);
    5280               0 : }
    5281                 : 
    5282                 : /**********************************************************************
    5283                 :  *                     TABText::CloneTABFeature()
    5284                 :  *
    5285                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    5286                 :  *
    5287                 :  * This method calls the generic TABFeature::CopyTABFeatureBase() and 
    5288                 :  * then copies any members specific to its own type.
    5289                 :  **********************************************************************/
    5290               0 : TABFeature *TABText::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
    5291                 : {
    5292                 :     /*-----------------------------------------------------------------
    5293                 :      * Alloc new feature and copy the base stuff
    5294                 :      *----------------------------------------------------------------*/
    5295               0 :     TABText *poNew = new TABText(poNewDefn ? poNewDefn : GetDefnRef());
    5296                 : 
    5297               0 :     CopyTABFeatureBase(poNew);
    5298                 : 
    5299                 :     /*-----------------------------------------------------------------
    5300                 :      * And members specific to this class
    5301                 :      *----------------------------------------------------------------*/
    5302                 :     // ITABFeaturePen
    5303               0 :     *(poNew->GetPenDefRef()) = *GetPenDefRef();
    5304                 : 
    5305                 :     // ITABFeatureFont
    5306               0 :     *(poNew->GetFontDefRef()) = *GetFontDefRef();
    5307                 : 
    5308                 : 
    5309               0 :     poNew->SetTextString( GetTextString() );
    5310               0 :     poNew->SetTextAngle( GetTextAngle() );
    5311               0 :     poNew->SetTextBoxHeight( GetTextBoxHeight() );
    5312               0 :     poNew->SetTextBoxWidth( GetTextBoxWidth() );
    5313               0 :     poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
    5314               0 :     poNew->SetFontBGColor( GetFontBGColor() );
    5315               0 :     poNew->SetFontFGColor( GetFontFGColor() );
    5316               0 :     poNew->SetFontOColor( GetFontOColor() );
    5317               0 :     poNew->SetFontSColor( GetFontSColor() );
    5318                 : 
    5319               0 :     poNew->SetTextJustification( GetTextJustification() );
    5320               0 :     poNew->SetTextSpacing( GetTextSpacing() );
    5321                 :     // Note: Text arrow/line coordinates are not transported... but 
    5322                 :     //       we ignore them most of the time anyways.
    5323               0 :     poNew->SetTextLineType( TABTLNoLine );
    5324                 : 
    5325               0 :     return poNew;
    5326                 : }
    5327                 : 
    5328                 : /**********************************************************************
    5329                 :  *                   TABText::ValidateMapInfoType()
    5330                 :  *
    5331                 :  * Check the feature's geometry part and return the corresponding
    5332                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    5333                 :  * be updated for further calls to GetMapInfoType();
    5334                 :  *
    5335                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    5336                 :  * is expected for this object class.
    5337                 :  **********************************************************************/
    5338               0 : int  TABText::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    5339                 : {
    5340                 :     OGRGeometry *poGeom;
    5341                 : 
    5342                 :     /*-----------------------------------------------------------------
    5343                 :      * Fetch and validate geometry
    5344                 :      *----------------------------------------------------------------*/
    5345               0 :     poGeom = GetGeometryRef();
    5346               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    5347                 :     {
    5348               0 :         m_nMapInfoType = TAB_GEOM_TEXT;
    5349                 :     }
    5350                 :     else
    5351                 :     {
    5352                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5353               0 :                  "TABText: Missing or Invalid Geometry!");
    5354               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    5355                 :     }
    5356                 : 
    5357                 :     /*-----------------------------------------------------------------
    5358                 :      * Decide if coordinates should be compressed or not.
    5359                 :      *----------------------------------------------------------------*/
    5360                 :     // __TODO__ For now we always write uncompressed for this class...
    5361                 :     // ValidateCoordType(poMapFile);
    5362               0 :     UpdateMBR(poMapFile);
    5363                 : 
    5364               0 :     return m_nMapInfoType;
    5365                 : }
    5366                 : 
    5367                 : /**********************************************************************
    5368                 :  *                   TABText::ReadGeometryFromMAPFile()
    5369                 :  *
    5370                 :  * Fill the geometry and representation (color, etc...) part of the
    5371                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    5372                 :  *
    5373                 :  * It is assumed that poMAPFile currently points to the beginning of
    5374                 :  * a map object.
    5375                 :  *
    5376                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    5377                 :  * been called.
    5378                 :  **********************************************************************/
    5379               0 : int TABText::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    5380                 :                                      TABMAPObjHdr *poObjHdr,
    5381                 :                                      GBool bCoordBlockDataOnly /*=FALSE*/,
    5382                 :                                      TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    5383                 : {
    5384                 :     double              dXMin, dYMin, dXMax, dYMax;
    5385                 :     OGRGeometry         *poGeometry;
    5386                 : 
    5387                 :     /*-----------------------------------------------------------------
    5388                 :      * Fetch and validate geometry type
    5389                 :      *----------------------------------------------------------------*/
    5390               0 :     m_nMapInfoType = poObjHdr->m_nType;
    5391                 : 
    5392               0 :     if (m_nMapInfoType != TAB_GEOM_TEXT &&
    5393                 :         m_nMapInfoType != TAB_GEOM_TEXT_C )
    5394                 :     {
    5395                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5396                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    5397               0 :                  m_nMapInfoType, m_nMapInfoType);
    5398               0 :         return -1;
    5399                 :     }
    5400                 : 
    5401                 :     /*=============================================================
    5402                 :      * TEXT
    5403                 :      *============================================================*/
    5404                 :     int     nStringLen;
    5405                 :     GInt32  nCoordBlockPtr;
    5406                 :     double  dJunk;
    5407                 : 
    5408                 :     /*-----------------------------------------------------------------
    5409                 :      * Read object information
    5410                 :      *----------------------------------------------------------------*/
    5411               0 :     TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
    5412                 : 
    5413               0 :     nCoordBlockPtr = poTextHdr->m_nCoordBlockPtr;   // String position
    5414               0 :     nStringLen      = poTextHdr->m_nCoordDataSize;   // String length
    5415               0 :     m_nTextAlignment = poTextHdr->m_nTextAlignment; // just./spacing/arrow
    5416                 : 
    5417                 :     /*-------------------------------------------------------------
    5418                 :      * Text Angle, in thenths of degree.
    5419                 :      * Contrary to arc start/end angles, no conversion based on 
    5420                 :      * origin quadrant is required here
    5421                 :      *------------------------------------------------------------*/
    5422               0 :     m_dAngle       = poTextHdr->m_nAngle/10.0;
    5423                 : 
    5424               0 :     m_nFontStyle   = poTextHdr->m_nFontStyle;          // Font style
    5425                 : 
    5426                 :     m_rgbForeground = (poTextHdr->m_nFGColorR*256*256 +
    5427                 :                        poTextHdr->m_nFGColorG*256 +
    5428               0 :                        poTextHdr->m_nFGColorB);
    5429                 :     m_rgbBackground = (poTextHdr->m_nBGColorR*256*256 +
    5430                 :                        poTextHdr->m_nBGColorG*256 +
    5431               0 :                        poTextHdr->m_nBGColorB);
    5432               0 :     m_rgbOutline =  m_rgbBackground;
    5433                 :     // In MapInfo, the shadow color is always gray (128,128,128)
    5434               0 :     m_rgbShadow     = 0x808080;
    5435                 : 
    5436                 :     // arrow endpoint
    5437                 :     poMapFile->Int2Coordsys(poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY, 
    5438               0 :                             m_dfLineEndX, m_dfLineEndY);
    5439               0 :     m_bLineEndSet = TRUE;
    5440                 : 
    5441                 :     // Text Height
    5442               0 :     poMapFile->Int2CoordsysDist(0, poTextHdr->m_nHeight, dJunk, m_dHeight);
    5443                 : 
    5444               0 :     if (!bCoordBlockDataOnly)
    5445                 :     {
    5446               0 :         m_nFontDefIndex = poTextHdr->m_nFontId;      // Font name index
    5447               0 :         poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
    5448                 :     }
    5449                 : 
    5450                 :     // MBR after rotation
    5451                 :     poMapFile->Int2Coordsys(poTextHdr->m_nMinX, poTextHdr->m_nMinY, 
    5452               0 :                             dXMin, dYMin);
    5453                 :     poMapFile->Int2Coordsys(poTextHdr->m_nMaxX, poTextHdr->m_nMaxY, 
    5454               0 :                             dXMax, dYMax);
    5455                 : 
    5456               0 :     if (!bCoordBlockDataOnly)
    5457                 :     {
    5458               0 :         m_nPenDefIndex = poTextHdr->m_nPenId;      // Pen index for line
    5459               0 :         poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
    5460                 :     }
    5461                 : 
    5462                 :     /*-------------------------------------------------------------
    5463                 :      * Read text string from the coord. block
    5464                 :      * Note that the string may contain binary '\n' and '\\' chars
    5465                 :      * that we keep to an unescaped form internally. This is to
    5466                 :      * be like OGR drivers. See bug 1107 for details.
    5467                 :      *------------------------------------------------------------*/
    5468               0 :     char *pszTmpString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
    5469                 : 
    5470               0 :     if (nStringLen > 0)
    5471                 :     {
    5472                 :         TABMAPCoordBlock        *poCoordBlock;
    5473               0 :         CPLAssert(nCoordBlockPtr > 0);
    5474               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    5475               0 :             poCoordBlock = *ppoCoordBlock;
    5476                 :         else
    5477               0 :             poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
    5478               0 :         if (poCoordBlock == NULL ||
    5479               0 :             poCoordBlock->ReadBytes(nStringLen,(GByte*)pszTmpString) != 0)
    5480                 :         {
    5481                 :             CPLError(CE_Failure, CPLE_FileIO,
    5482                 :                      "Failed reading text string at offset %d", 
    5483               0 :                      nCoordBlockPtr);
    5484               0 :             CPLFree(pszTmpString);                
    5485               0 :             return -1;
    5486                 :         }
    5487                 : 
    5488                 :         /* Return a ref to coord block so that caller can continue reading
    5489                 :          * after the end of this object (used by index splitting)
    5490                 :          */
    5491               0 :         if (ppoCoordBlock)
    5492               0 :             *ppoCoordBlock = poCoordBlock;
    5493                 :     }
    5494                 : 
    5495               0 :     pszTmpString[nStringLen] = '\0';
    5496                 : 
    5497               0 :     CPLFree(m_pszString);
    5498               0 :     m_pszString = pszTmpString; // This string was Escaped before 20050714
    5499                 : 
    5500                 : 
    5501                 :     /* Set/retrieve the MBR to make sure Mins are smaller than Maxs
    5502                 :      */
    5503               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    5504               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    5505                 : 
    5506                 :     /* Copy int MBR to feature class members */
    5507                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    5508               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    5509                 : 
    5510                 :     /*-----------------------------------------------------------------
    5511                 :      * Create an OGRPoint Geometry... 
    5512                 :      * The point X,Y values will be the coords of the lower-left corner before
    5513                 :      * rotation is applied.  (Note that the rotation in MapInfo is done around
    5514                 :      * the upper-left corner)
    5515                 :      * We need to calculate the true lower left corner of the text based
    5516                 :      * on the MBR after rotation, the text height and the rotation angle.
    5517                 :      *----------------------------------------------------------------*/
    5518                 :     double dCos, dSin, dX, dY;
    5519               0 :     dSin = sin(m_dAngle*PI/180.0);
    5520               0 :     dCos = cos(m_dAngle*PI/180.0);
    5521               0 :     if (dSin > 0.0  && dCos > 0.0)
    5522                 :     {
    5523               0 :         dX = dXMin + m_dHeight * dSin;
    5524               0 :         dY = dYMin;
    5525                 :     }
    5526               0 :     else if (dSin > 0.0  && dCos < 0.0)
    5527                 :     {
    5528               0 :         dX = dXMax;
    5529               0 :         dY = dYMin - m_dHeight * dCos;
    5530                 :     }
    5531               0 :     else if (dSin < 0.0  && dCos < 0.0)
    5532                 :     {
    5533               0 :         dX = dXMax + m_dHeight * dSin;
    5534               0 :         dY = dYMax;
    5535                 :     }
    5536                 :     else  // dSin < 0 && dCos > 0
    5537                 :     {   
    5538               0 :         dX = dXMin;
    5539               0 :         dY = dYMax - m_dHeight * dCos;
    5540                 :     }
    5541                 : 
    5542               0 :     poGeometry = new OGRPoint(dX, dY);
    5543                 : 
    5544               0 :     SetGeometryDirectly(poGeometry);
    5545                 : 
    5546                 :     /*-----------------------------------------------------------------
    5547                 :      * Compute Text Width: the width of the Text MBR before rotation 
    5548                 :      * in ground units... unfortunately this value is not stored in the
    5549                 :      * file, so we have to compute it with the MBR after rotation and 
    5550                 :      * the height of the MBR before rotation:
    5551                 :      * With  W = Width of MBR before rotation
    5552                 :      *       H = Height of MBR before rotation
    5553                 :      *       dX = Width of MBR after rotation
    5554                 :      *       dY = Height of MBR after rotation
    5555                 :      *       teta = rotation angle
    5556                 :      *
    5557                 :      *  For [-PI/4..teta..+PI/4] or [3*PI/4..teta..5*PI/4], we'll use:
    5558                 :      *   W = H * (dX - H * sin(teta)) / (H * cos(teta))
    5559                 :      *
    5560                 :      * and for other teta values, use:
    5561                 :      *   W = H * (dY - H * cos(teta)) / (H * sin(teta))
    5562                 :      *----------------------------------------------------------------*/
    5563               0 :     dSin = ABS(dSin);
    5564               0 :     dCos = ABS(dCos);
    5565               0 :     if (m_dHeight == 0.0)
    5566               0 :         m_dWidth = 0.0;
    5567               0 :     else if ( dCos > dSin )
    5568                 :         m_dWidth = m_dHeight * ((dXMax-dXMin) - m_dHeight*dSin) / 
    5569               0 :                                                         (m_dHeight*dCos);
    5570                 :     else
    5571                 :         m_dWidth = m_dHeight * ((dYMax-dYMin) - m_dHeight*dCos) /
    5572               0 :                                                         (m_dHeight*dSin);
    5573               0 :     m_dWidth = ABS(m_dWidth);
    5574                 : 
    5575               0 :     return 0;
    5576                 : }
    5577                 : 
    5578                 : /**********************************************************************
    5579                 :  *                   TABText::WriteGeometryToMAPFile()
    5580                 :  *
    5581                 :  * Write the geometry and representation (color, etc...) part of the
    5582                 :  * feature to the .MAP object pointed to by poMAPFile.
    5583                 :  *
    5584                 :  * It is assumed that poMAPFile currently points to a valid map object.
    5585                 :  *
    5586                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    5587                 :  * been called.
    5588                 :  **********************************************************************/
    5589               0 : int TABText::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    5590                 :                                     TABMAPObjHdr *poObjHdr,
    5591                 :                                     GBool bCoordBlockDataOnly /*=FALSE*/,
    5592                 :                                     TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    5593                 : {
    5594                 :     GInt32              nX, nY, nXMin, nYMin, nXMax, nYMax;
    5595                 :     OGRGeometry         *poGeom;
    5596                 :     OGRPoint            *poPoint;
    5597                 :     GInt32              nCoordBlockPtr;
    5598                 :     TABMAPCoordBlock    *poCoordBlock;
    5599                 :     int                 nStringLen;
    5600                 :   
    5601                 :     /*-----------------------------------------------------------------
    5602                 :      * We assume that ValidateMapInfoType() was called already and that
    5603                 :      * the type in poObjHdr->m_nType is valid.
    5604                 :      *----------------------------------------------------------------*/
    5605               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    5606                 : 
    5607                 :     /*-----------------------------------------------------------------
    5608                 :      * Fetch and validate geometry
    5609                 :      *----------------------------------------------------------------*/
    5610               0 :     poGeom = GetGeometryRef();
    5611               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    5612               0 :         poPoint = (OGRPoint*)poGeom;
    5613                 :     else
    5614                 :     {
    5615                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    5616               0 :                  "TABText: Missing or Invalid Geometry!");
    5617               0 :         return -1;
    5618                 :     }
    5619                 : 
    5620               0 :     poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    5621                 : 
    5622                 :     /*-----------------------------------------------------------------
    5623                 :      * Write string to a coord block first...
    5624                 :      * Note that the string may contain unescaped '\n' and '\\'
    5625                 :      * that we have to keep like that for the MAP file.
    5626                 :      * See MapTools bug 1107 for more details. 
    5627                 :      *----------------------------------------------------------------*/
    5628               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    5629               0 :         poCoordBlock = *ppoCoordBlock;
    5630                 :     else
    5631               0 :         poCoordBlock = poMapFile->GetCurCoordBlock();
    5632               0 :     poCoordBlock->StartNewFeature();
    5633               0 :     nCoordBlockPtr = poCoordBlock->GetCurAddress();
    5634                 : 
    5635                 :     // This string was escaped before 20050714
    5636               0 :     char *pszTmpString = m_pszString;
    5637                 : 
    5638               0 :     nStringLen = strlen(pszTmpString);
    5639                 : 
    5640               0 :     if (nStringLen > 0)
    5641                 :     {
    5642               0 :         poCoordBlock->WriteBytes(nStringLen, (GByte *)pszTmpString);
    5643                 :     }
    5644                 :     else
    5645                 :     {
    5646               0 :         nCoordBlockPtr = 0;
    5647                 :     }
    5648                 : 
    5649               0 :     pszTmpString = NULL;
    5650                 : 
    5651                 :     /*-----------------------------------------------------------------
    5652                 :      * Copy object information
    5653                 :      *----------------------------------------------------------------*/
    5654               0 :     TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
    5655                 : 
    5656               0 :     poTextHdr->m_nCoordBlockPtr = nCoordBlockPtr;     // String position
    5657               0 :     poTextHdr->m_nCoordDataSize = nStringLen;         // String length
    5658               0 :     poTextHdr->m_nTextAlignment = m_nTextAlignment;   // just./spacing/arrow
    5659                 : 
    5660                 :     /*-----------------------------------------------------------------
    5661                 :      * Text Angle, (written in thenths of degrees)
    5662                 :      * Contrary to arc start/end angles, no conversion based on 
    5663                 :      * origin quadrant is required here
    5664                 :      *----------------------------------------------------------------*/
    5665               0 :     poTextHdr->m_nAngle = ROUND_INT(m_dAngle*10.0);
    5666                 : 
    5667               0 :     poTextHdr->m_nFontStyle = m_nFontStyle;          // Font style/effect
    5668                 : 
    5669               0 :     poTextHdr->m_nFGColorR = (GByte)COLOR_R(m_rgbForeground);
    5670               0 :     poTextHdr->m_nFGColorG = (GByte)COLOR_G(m_rgbForeground);
    5671               0 :     poTextHdr->m_nFGColorB = (GByte)COLOR_B(m_rgbForeground);
    5672                 : 
    5673               0 :     poTextHdr->m_nBGColorR = (GByte)COLOR_R(m_rgbBackground);
    5674               0 :     poTextHdr->m_nBGColorG = (GByte)COLOR_G(m_rgbBackground);
    5675               0 :     poTextHdr->m_nBGColorB = (GByte)COLOR_B(m_rgbBackground);
    5676                 : 
    5677                 :     /*-----------------------------------------------------------------
    5678                 :      * The OGRPoint's X,Y values were the coords of the lower-left corner
    5679                 :      * before rotation was applied.  (Note that the rotation in MapInfo is
    5680                 :      * done around the upper-left corner)
    5681                 :      * The Feature's MBR is the MBR of the text after rotation... that's
    5682                 :      * what MapInfo uses to define the text location.
    5683                 :      *----------------------------------------------------------------*/
    5684                 :     double dXMin, dYMin, dXMax, dYMax;
    5685                 :     // Make sure Feature MBR is in sync with other params
    5686                 :  
    5687               0 :     UpdateMBR();
    5688               0 :     GetMBR(dXMin, dYMin, dXMax, dYMax);
    5689                 : 
    5690               0 :     poMapFile->Coordsys2Int(dXMin, dYMin, nXMin, nYMin);
    5691               0 :     poMapFile->Coordsys2Int(dXMax, dYMax, nXMax, nYMax);
    5692                 : 
    5693                 :     // Label line end point
    5694                 :     double dX, dY;
    5695               0 :     GetTextLineEndPoint(dX, dY); // Make sure a default line end point is set
    5696                 :     poMapFile->Coordsys2Int(m_dfLineEndX, m_dfLineEndY, 
    5697               0 :                            poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY);
    5698                 : 
    5699                 :     // Text Height
    5700               0 :     poMapFile->Coordsys2IntDist(0.0, m_dHeight, nX, nY);
    5701               0 :     poTextHdr->m_nHeight = nY;
    5702                 : 
    5703               0 :     if (!bCoordBlockDataOnly)
    5704                 :     {
    5705                 :         // Font name
    5706               0 :         m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
    5707               0 :         poTextHdr->m_nFontId = (GByte)m_nFontDefIndex;      // Font name index
    5708                 :     }
    5709                 : 
    5710                 :     // MBR after rotation
    5711               0 :     poTextHdr->SetMBR(nXMin, nYMin, nXMax, nYMax);
    5712                 : 
    5713               0 :     if (!bCoordBlockDataOnly)
    5714                 :     {
    5715               0 :         m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
    5716               0 :         poTextHdr->m_nPenId = (GByte)m_nPenDefIndex;      // Pen index for line/arrow
    5717                 :     }
    5718                 : 
    5719               0 :     if (CPLGetLastErrorNo() != 0)
    5720               0 :         return -1;
    5721                 : 
    5722                 :     /* Return a ref to coord block so that caller can continue writing
    5723                 :      * after the end of this object (used by index splitting)
    5724                 :      */
    5725               0 :     if (ppoCoordBlock)
    5726               0 :         *ppoCoordBlock = poCoordBlock;
    5727                 : 
    5728               0 :     return 0;
    5729                 : }
    5730                 : 
    5731                 : 
    5732                 : /**********************************************************************
    5733                 :  *                   TABText::GetTextString()
    5734                 :  *
    5735                 :  * Return ref to text string value.
    5736                 :  *
    5737                 :  * Returned string is a reference to the internal string buffer and should
    5738                 :  * not be modified or freed by the caller.
    5739                 :  **********************************************************************/
    5740               0 : const char *TABText::GetTextString()
    5741                 : {
    5742               0 :     if (m_pszString == NULL)
    5743               0 :         return "";
    5744                 : 
    5745               0 :     return m_pszString;
    5746                 : }
    5747                 : 
    5748                 : /**********************************************************************
    5749                 :  *                   TABText::SetTextString()
    5750                 :  *
    5751                 :  * Set new text string value.
    5752                 :  *
    5753                 :  * Note: The text string may contain "\n" chars or "\\" chars
    5754                 :  * and we expect to receive them in a 2 chars escaped form as 
    5755                 :  * described in the MIF format specs.
    5756                 :  **********************************************************************/
    5757               0 : void TABText::SetTextString(const char *pszNewStr)
    5758                 : {
    5759               0 :     CPLFree(m_pszString);
    5760               0 :     m_pszString = CPLStrdup(pszNewStr);
    5761               0 : }
    5762                 : 
    5763                 : /**********************************************************************
    5764                 :  *                   TABText::GetTextAngle()
    5765                 :  *
    5766                 :  * Return text angle in degrees.
    5767                 :  **********************************************************************/
    5768               0 : double TABText::GetTextAngle()
    5769                 : {
    5770               0 :     return m_dAngle;
    5771                 : }
    5772                 : 
    5773               0 : void TABText::SetTextAngle(double dAngle)
    5774                 : {
    5775                 :     // Make sure angle is in the range [0..360]
    5776               0 :     while(dAngle < 0.0)   dAngle += 360.0;
    5777               0 :     while(dAngle > 360.0) dAngle -= 360.0;
    5778               0 :     m_dAngle = dAngle;
    5779               0 :     UpdateMBR();
    5780               0 : }
    5781                 : 
    5782                 : /**********************************************************************
    5783                 :  *                   TABText::GetTextBoxHeight()
    5784                 :  *
    5785                 :  * Return text height in Y axis coord. units of the text box before rotation.
    5786                 :  **********************************************************************/
    5787               0 : double TABText::GetTextBoxHeight()
    5788                 : {
    5789               0 :     return m_dHeight;
    5790                 : }
    5791                 : 
    5792               0 : void TABText::SetTextBoxHeight(double dHeight)
    5793                 : {
    5794               0 :     m_dHeight = dHeight;
    5795               0 :     UpdateMBR();
    5796               0 : }
    5797                 : 
    5798                 : /**********************************************************************
    5799                 :  *                   TABText::GetTextBoxWidth()
    5800                 :  *
    5801                 :  * Return text width in X axis coord. units. of the text box before rotation.
    5802                 :  *
    5803                 :  * If value has not been set, then we force a default value that assumes
    5804                 :  * that one char's box width is 60% of its height... and we ignore
    5805                 :  * the multiline case.  This should not matter when the user PROPERLY sets
    5806                 :  * the value.
    5807                 :  **********************************************************************/
    5808               0 : double TABText::GetTextBoxWidth()
    5809                 : {
    5810               0 :     if (m_dWidth == 0.0 && m_pszString)
    5811                 :     {
    5812               0 :         m_dWidth = 0.6 * m_dHeight * strlen(m_pszString);
    5813                 :     }
    5814               0 :     return m_dWidth;
    5815                 : }
    5816                 : 
    5817               0 : void TABText::SetTextBoxWidth(double dWidth)
    5818                 : {
    5819               0 :     m_dWidth = dWidth;
    5820               0 :     UpdateMBR();
    5821               0 : }
    5822                 : 
    5823                 : /**********************************************************************
    5824                 :  *                   TABText::GetTextLineEndPoint()
    5825                 :  *
    5826                 :  * Return X,Y coordinates of the text label line end point.
    5827                 :  * Default is the center of the text MBR.
    5828                 :  **********************************************************************/
    5829               0 : void TABText::GetTextLineEndPoint(double &dX, double &dY)
    5830                 : {
    5831               0 :     if (!m_bLineEndSet)
    5832                 :     {
    5833                 :         // Set default location at center of text MBR
    5834                 :         double dXMin, dYMin, dXMax, dYMax;
    5835               0 :         UpdateMBR();
    5836               0 :         GetMBR(dXMin, dYMin, dXMax, dYMax);
    5837               0 :         m_dfLineEndX = (dXMin + dXMax) /2.0;
    5838               0 :         m_dfLineEndY = (dYMin + dYMax) /2.0;
    5839               0 :         m_bLineEndSet = TRUE;
    5840                 :     }
    5841                 : 
    5842                 :     // Return values
    5843               0 :     dX = m_dfLineEndX;
    5844               0 :     dY = m_dfLineEndY;
    5845               0 : }
    5846                 : 
    5847               0 : void TABText::SetTextLineEndPoint(double dX, double dY)
    5848                 : {
    5849               0 :     m_dfLineEndX = dX;
    5850               0 :     m_dfLineEndY = dY;
    5851               0 :     m_bLineEndSet = TRUE;
    5852               0 : }
    5853                 : 
    5854                 : /**********************************************************************
    5855                 :  *                   TABText::UpdateMBR()
    5856                 :  *
    5857                 :  * Update the feature MBR using the text origin (OGRPoint geometry), the
    5858                 :  * rotation angle, and the Width/height before rotation.
    5859                 :  *
    5860                 :  * This function cannot perform properly unless all the above have been set.
    5861                 :  *
    5862                 :  * Returns 0 on success, or -1 if there is no geometry in object
    5863                 :  **********************************************************************/
    5864               0 : int TABText::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
    5865                 : {
    5866                 :     OGRGeometry *poGeom;
    5867               0 :     OGRPoint *poPoint=NULL;
    5868                 : 
    5869               0 :     poGeom = GetGeometryRef();
    5870               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    5871                 :     {
    5872                 :         double dSin, dCos, dX0, dY0, dX1, dY1;
    5873                 :         double dX[4], dY[4];
    5874               0 :         poPoint = (OGRPoint *)poGeom;
    5875                 : 
    5876               0 :         dX0 = poPoint->getX();
    5877               0 :         dY0 = poPoint->getY();
    5878                 : 
    5879               0 :         dSin = sin(m_dAngle*PI/180.0);
    5880               0 :         dCos = cos(m_dAngle*PI/180.0);
    5881                 : 
    5882               0 :         GetTextBoxWidth();  // Force default width value if necessary.
    5883                 :         
    5884               0 :         dX[0] = dX0;
    5885               0 :         dY[0] = dY0;
    5886               0 :         dX[1] = dX0 + m_dWidth;
    5887               0 :         dY[1] = dY0;
    5888               0 :         dX[2] = dX0 + m_dWidth;
    5889               0 :         dY[2] = dY0 + m_dHeight;
    5890               0 :         dX[3] = dX0;
    5891               0 :         dY[3] = dY0 + m_dHeight;
    5892                 : 
    5893               0 :         SetMBR(dX0, dY0, dX0, dY0);
    5894               0 :         for(int i=0; i<4; i++)
    5895                 :         {
    5896                 :             // Rotate one of the box corners
    5897               0 :             dX1 = dX0 + (dX[i]-dX0)*dCos - (dY[i]-dY0)*dSin;
    5898               0 :             dY1 = dY0 + (dX[i]-dX0)*dSin + (dY[i]-dY0)*dCos;
    5899                 : 
    5900                 :             // And update feature MBR with rotated coordinate
    5901               0 :             if (dX1 < m_dXMin) m_dXMin = dX1;
    5902               0 :             if (dX1 > m_dXMax) m_dXMax = dX1;
    5903               0 :             if (dY1 < m_dYMin) m_dYMin = dY1;
    5904               0 :             if (dY1 > m_dYMax) m_dYMax = dY1;
    5905                 :         }
    5906                 : 
    5907               0 :         if (poMapFile)
    5908                 :         {
    5909               0 :             poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
    5910               0 :             poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
    5911                 :         }
    5912                 : 
    5913               0 :         return 0;
    5914                 :     }
    5915                 : 
    5916               0 :     return -1;
    5917                 : }
    5918                 : 
    5919                 : /**********************************************************************
    5920                 :  *                   TABText::GetFontBGColor()
    5921                 :  *
    5922                 :  * Return background color.
    5923                 :  **********************************************************************/
    5924               0 : GInt32 TABText::GetFontBGColor()
    5925                 : {
    5926               0 :     return m_rgbBackground;
    5927                 : }
    5928                 : 
    5929               0 : void TABText::SetFontBGColor(GInt32 rgbColor)
    5930                 : {
    5931               0 :     m_rgbBackground = rgbColor;
    5932               0 : }
    5933                 : 
    5934                 : /**********************************************************************
    5935                 :  *                   TABText::GetFontOColor()
    5936                 :  *
    5937                 :  * Return outline color.
    5938                 :  **********************************************************************/
    5939               0 : GInt32 TABText::GetFontOColor()
    5940                 : {
    5941               0 :     return m_rgbOutline;
    5942                 : }
    5943                 : 
    5944               0 : void TABText::SetFontOColor(GInt32 rgbColor)
    5945                 : {
    5946               0 :     m_rgbOutline = rgbColor;
    5947               0 : }
    5948                 : 
    5949                 : /**********************************************************************
    5950                 :  *                   TABText::GetFontSColor()
    5951                 :  *
    5952                 :  * Return shadow color.
    5953                 :  **********************************************************************/
    5954               0 : GInt32 TABText::GetFontSColor()
    5955                 : {
    5956               0 :     return m_rgbShadow;
    5957                 : }
    5958                 : 
    5959               0 : void TABText::SetFontSColor(GInt32 rgbColor)
    5960                 : {
    5961               0 :     m_rgbShadow = rgbColor;
    5962               0 : }
    5963                 : 
    5964                 : /**********************************************************************
    5965                 :  *                   TABText::GetFontFGColor()
    5966                 :  *
    5967                 :  * Return foreground color.
    5968                 :  **********************************************************************/
    5969               0 : GInt32 TABText::GetFontFGColor()
    5970                 : {
    5971               0 :     return m_rgbForeground;
    5972                 : }
    5973                 : 
    5974               0 : void TABText::SetFontFGColor(GInt32 rgbColor)
    5975                 : {
    5976               0 :     m_rgbForeground = rgbColor;
    5977               0 : }
    5978                 : 
    5979                 : /**********************************************************************
    5980                 :  *                   TABText::GetTextJustification()
    5981                 :  *
    5982                 :  * Return text justification.  Default is TABTJLeft
    5983                 :  **********************************************************************/
    5984               0 : TABTextJust TABText::GetTextJustification()
    5985                 : {
    5986               0 :     TABTextJust eJust = TABTJLeft;
    5987                 : 
    5988               0 :     if (m_nTextAlignment & 0x0200)
    5989               0 :         eJust = TABTJCenter;
    5990               0 :     else if (m_nTextAlignment & 0x0400)
    5991               0 :         eJust = TABTJRight;
    5992                 : 
    5993               0 :     return eJust;
    5994                 : }
    5995                 : 
    5996               0 : void TABText::SetTextJustification(TABTextJust eJustification)
    5997                 : {
    5998                 :     // Flush current value... default is TABTJLeft
    5999               0 :     m_nTextAlignment &= ~ 0x0600;
    6000                 :     // ... and set new one.
    6001               0 :     if (eJustification == TABTJCenter)
    6002               0 :         m_nTextAlignment |= 0x0200;
    6003               0 :     else if (eJustification == TABTJRight)
    6004               0 :         m_nTextAlignment |= 0x0400;
    6005               0 : }
    6006                 : 
    6007                 : /**********************************************************************
    6008                 :  *                   TABText::GetTextSpacing()
    6009                 :  *
    6010                 :  * Return text vertical spacing factor.  Default is TABTSSingle
    6011                 :  **********************************************************************/
    6012               0 : TABTextSpacing TABText::GetTextSpacing()
    6013                 : {
    6014               0 :     TABTextSpacing eSpacing = TABTSSingle;
    6015                 : 
    6016               0 :     if (m_nTextAlignment & 0x0800)
    6017               0 :         eSpacing = TABTS1_5;
    6018               0 :     else if (m_nTextAlignment & 0x1000)
    6019               0 :         eSpacing = TABTSDouble;
    6020                 : 
    6021               0 :     return eSpacing;
    6022                 : }
    6023                 : 
    6024               0 : void TABText::SetTextSpacing(TABTextSpacing eSpacing)
    6025                 : {
    6026                 :     // Flush current value... default is TABTSSingle
    6027               0 :     m_nTextAlignment &= ~ 0x1800;
    6028                 :     // ... and set new one.
    6029               0 :     if (eSpacing == TABTS1_5)
    6030               0 :         m_nTextAlignment |= 0x0800;
    6031               0 :     else if (eSpacing == TABTSDouble)
    6032               0 :         m_nTextAlignment |= 0x1000;
    6033               0 : }
    6034                 : 
    6035                 : /**********************************************************************
    6036                 :  *                   TABText::GetTextLineType()
    6037                 :  *
    6038                 :  * Return text line (arrow) type.  Default is TABTLNoLine
    6039                 :  **********************************************************************/
    6040               0 : TABTextLineType TABText::GetTextLineType()
    6041                 : {
    6042               0 :     TABTextLineType eLine = TABTLNoLine;
    6043                 : 
    6044               0 :     if (m_nTextAlignment & 0x2000)
    6045               0 :         eLine = TABTLSimple;
    6046               0 :     else if (m_nTextAlignment & 0x4000)
    6047               0 :         eLine = TABTLArrow;
    6048                 : 
    6049               0 :     return eLine;
    6050                 : }
    6051                 : 
    6052               0 : void TABText::SetTextLineType(TABTextLineType eLineType)
    6053                 : {
    6054                 :     // Flush current value... default is TABTLNoLine
    6055               0 :     m_nTextAlignment &= ~ 0x6000;
    6056                 :     // ... and set new one.
    6057               0 :     if (eLineType == TABTLSimple)
    6058               0 :         m_nTextAlignment |= 0x2000;
    6059               0 :     else if (eLineType == TABTLArrow)
    6060               0 :         m_nTextAlignment |= 0x4000;
    6061               0 : }
    6062                 : 
    6063                 : /**********************************************************************
    6064                 :  *                   TABText::QueryFontStyle()
    6065                 :  *
    6066                 :  * Return TRUE if the specified font style attribute is turned ON,
    6067                 :  * or FALSE otherwise.  See enum TABFontStyle for the list of styles
    6068                 :  * that can be queried on.
    6069                 :  **********************************************************************/
    6070               0 : GBool TABText::QueryFontStyle(TABFontStyle eStyleToQuery)
    6071                 : {
    6072               0 :     return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
    6073                 : }
    6074                 : 
    6075               0 : void TABText::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
    6076                 : {
    6077               0 :     if (bStyleOn)
    6078               0 :         m_nFontStyle |=  (int)eStyleToToggle;
    6079                 :     else
    6080               0 :         m_nFontStyle &=  ~ (int)eStyleToToggle;
    6081               0 : }
    6082                 : 
    6083                 : 
    6084                 : /**********************************************************************
    6085                 :  *                   TABText::GetFontStyleMIFValue()
    6086                 :  *
    6087                 :  * Return the Font Style value for this object using the style values
    6088                 :  * that are used in a MIF FONT() clause.  See MIF specs (appendix A).
    6089                 :  *
    6090                 :  * The reason why we have to differentiate between the TAB and the MIF font
    6091                 :  * style values is that in TAB, TABFSBox is included in the style value
    6092                 :  * as code 0x100, but in MIF it is not included, instead it is implied by
    6093                 :  * the presence of the BG color in the FONT() clause (the BG color is 
    6094                 :  * present only when TABFSBox or TABFSHalo is set).
    6095                 :  * This also has the effect of shifting all the other style values > 0x100
    6096                 :  * by 1 byte.
    6097                 :  **********************************************************************/
    6098               0 : int TABText::GetFontStyleMIFValue()
    6099                 : {
    6100                 :     // The conversion is simply to remove bit 0x100 from the value and shift
    6101                 :     // down all values past this bit.
    6102               0 :     return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
    6103                 : }
    6104                 : 
    6105               0 : void TABText:: SetFontStyleMIFValue(int nStyle, GBool bBGColorSet)
    6106                 : {
    6107               0 :     m_nFontStyle = (GInt16)((nStyle & 0xff) + (nStyle & 0x7f00)*2);
    6108                 :     // When BG color is set, then either BOX or HALO should be set.
    6109               0 :     if (bBGColorSet && !QueryFontStyle(TABFSHalo))
    6110               0 :         ToggleFontStyle(TABFSBox, TRUE);
    6111               0 : }
    6112                 : 
    6113               0 : int TABText::IsFontBGColorUsed()
    6114                 : {
    6115                 :     // Font BG color is used only when BOX is set.
    6116               0 :     return (QueryFontStyle(TABFSBox));
    6117                 : }
    6118                 : 
    6119               0 : int TABText::IsFontOColorUsed()
    6120                 : {
    6121                 :     // Font outline color is used only when HALO is set.
    6122               0 :     return (QueryFontStyle(TABFSHalo));
    6123                 : }
    6124                 : 
    6125               0 : int TABText::IsFontSColorUsed()
    6126                 : {
    6127                 :     // Font shadow color is used only when Shadow is set.
    6128               0 :     return (QueryFontStyle(TABFSShadow));
    6129                 : }
    6130                 : 
    6131               0 : int TABText::IsFontBold()
    6132                 : {
    6133                 :     // Font bold is used only when Bold is set.
    6134               0 :     return (QueryFontStyle(TABFSBold));
    6135                 : }
    6136                 : 
    6137               0 : int TABText::IsFontItalic()
    6138                 : {
    6139                 :     // Font italic is used only when Italic is set.
    6140               0 :     return (QueryFontStyle(TABFSItalic));
    6141                 : }
    6142                 : 
    6143               0 : int TABText::IsFontUnderline()
    6144                 : {
    6145                 :     // Font underline is used only when Underline is set.
    6146               0 :     return (QueryFontStyle(TABFSUnderline));
    6147                 : }
    6148                 : 
    6149                 : /**********************************************************************
    6150                 :  *                   TABText::GetLabelStyleString()
    6151                 :  *
    6152                 :  * This is not the correct location, it should be in ITABFeatureFont,
    6153                 :  * but it's really more easy to put it here.  This fct return a complete
    6154                 :  * string for the representation with the string to display
    6155                 :  **********************************************************************/
    6156               0 : const char *TABText::GetLabelStyleString()
    6157                 : {
    6158               0 :     const char *pszStyle = NULL;
    6159               0 :     int nStringLen = strlen(GetTextString());
    6160                 :     // ALL Caps, Extpanded need to modify the string value
    6161               0 :     char *pszTextString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
    6162                 :     char szPattern[20];
    6163               0 :     int nJustification = 1;
    6164                 :     
    6165               0 :     strcpy(pszTextString, GetTextString());
    6166               0 :     szPattern[0] = '\0';
    6167                 :     
    6168                 : 
    6169               0 :     switch(GetTextJustification())
    6170                 :     {
    6171                 :       case TABTJCenter:
    6172               0 :         nJustification = 2;
    6173               0 :         break;
    6174                 :       case TABTJRight:
    6175               0 :         nJustification = 3;
    6176               0 :         break;
    6177                 :       case TABTJLeft:
    6178                 :       default:
    6179               0 :         nJustification = 1;
    6180                 :         break;
    6181                 :     }
    6182                 :     
    6183                 :     // Compute real font size, taking number of lines ("\\n", "\n") and line
    6184                 :     // spacing into account.
    6185               0 :     int numLines = 1;
    6186               0 :     for (int i=0; pszTextString[i];
    6187               0 :          numLines += ((pszTextString[i]=='\n' ||
    6188               0 :                        (pszTextString[i]=='\\' && pszTextString[i+1]=='n')) &&
    6189               0 :                       pszTextString[i+1] != '\0' ),++i);
    6190                 :     
    6191               0 :     double dHeight = GetTextBoxHeight()/numLines;
    6192                 : 
    6193                 :     // In all cases, take out 20% of font height to account for line spacing
    6194               0 :     if (numLines > 1)
    6195                 :     {
    6196               0 :         switch(GetTextSpacing())
    6197                 :         {
    6198                 :           case TABTS1_5:
    6199               0 :             dHeight *= (0.80 * 0.69);
    6200               0 :             break;
    6201                 :           case TABTSDouble:
    6202               0 :             dHeight *= (0.66 * 0.69);
    6203               0 :             break;
    6204                 :           default:
    6205               0 :             dHeight *= 0.69;
    6206                 :         }
    6207                 :     }
    6208                 :     else
    6209                 :     {
    6210               0 :         dHeight *= 0.69;
    6211                 :     }
    6212                 : 
    6213               0 :     if (QueryFontStyle(TABFSAllCaps))
    6214               0 :         for (int i=0; pszTextString[i];++i)
    6215               0 :             if (isalpha(pszTextString[i])) 
    6216               0 :                 pszTextString[i] = (char)toupper(pszTextString[i]);
    6217                 :     
    6218                 :     /* Escape the double quote chars and expand the text */
    6219                 :     char *pszTmpTextString;
    6220               0 :     int j = 0;
    6221                 : 
    6222               0 :     if  (QueryFontStyle(TABFSExpanded))
    6223               0 :         pszTmpTextString = (char*)CPLMalloc(((nStringLen*4)+1)*sizeof(char));
    6224                 :     else
    6225               0 :         pszTmpTextString = (char*)CPLMalloc(((nStringLen*2)+1)*sizeof(char));
    6226                 :     
    6227               0 :     for (int i =0; i < nStringLen; ++i,++j)
    6228                 :     { 
    6229               0 :         if (pszTextString[i] == '"') 
    6230                 :         {
    6231               0 :             pszTmpTextString[j] = '\\';
    6232               0 :             pszTmpTextString[j+1] = pszTextString[i];
    6233               0 :             ++j;
    6234                 :         }
    6235                 :         else
    6236               0 :             pszTmpTextString[j] = pszTextString[i];
    6237                 : 
    6238               0 :         if  (QueryFontStyle(TABFSExpanded))
    6239                 :         {
    6240               0 :             pszTmpTextString[j+1] = ' ';
    6241               0 :             ++j;
    6242                 :         }
    6243                 :     }  
    6244                 :       
    6245               0 :     pszTmpTextString[j] = '\0';
    6246               0 :     CPLFree(pszTextString);
    6247               0 :     pszTextString = (char*)CPLMalloc((strlen(pszTmpTextString)+1)*sizeof(char));
    6248               0 :     strcpy(pszTextString, pszTmpTextString);
    6249               0 :     CPLFree(pszTmpTextString);
    6250                 : 
    6251                 :     const char *pszBGColor = IsFontBGColorUsed() ? CPLSPrintf(",b:#%6.6x",
    6252               0 :                                                               GetFontBGColor()) :"";
    6253                 :     const char *pszOColor =  IsFontOColorUsed() ? CPLSPrintf(",o:#%6.6x",
    6254               0 :                                                              GetFontOColor()) :"";
    6255                 :     const char *pszSColor = IsFontSColorUsed() ? CPLSPrintf(",h:#%6.6x",
    6256               0 :                                                               GetFontSColor()) :"";
    6257               0 :     const char *pszBold = IsFontBold() ? ",bo:1" :"";
    6258               0 :     const char *pszItalic = IsFontItalic() ? ",it:1" :"";
    6259               0 :     const char *pszUnderline = IsFontUnderline() ? ",un:1" : "";
    6260                 :     
    6261                 :     pszStyle=CPLSPrintf("LABEL(t:\"%s\",a:%f,s:%fg,c:#%6.6x%s%s%s%s%s%s,p:%d,f:\"%s\")",
    6262                 :                         pszTextString,GetTextAngle(), dHeight,
    6263                 :                         GetFontFGColor(),pszBGColor,pszOColor,pszSColor,
    6264               0 :                         pszBold,pszItalic,pszUnderline,nJustification,GetFontNameRef());
    6265                 :      
    6266               0 :     CPLFree(pszTextString);
    6267               0 :     return pszStyle;
    6268                 :     
    6269                 : }  
    6270                 : 
    6271                 : /**********************************************************************
    6272                 :  *                   TABText::GetStyleString()
    6273                 :  *
    6274                 :  * Return style string for this feature.
    6275                 :  *
    6276                 :  * Style String is built only once during the first call to GetStyleString().
    6277                 :  **********************************************************************/
    6278               0 : const char *TABText::GetStyleString()
    6279                 : {
    6280               0 :     if (m_pszStyleString == NULL)
    6281                 :     {
    6282               0 :         m_pszStyleString = CPLStrdup(GetLabelStyleString());
    6283                 :     }
    6284                 : 
    6285               0 :     return m_pszStyleString;
    6286                 : }
    6287                 : 
    6288                 : 
    6289                 : 
    6290                 : /**********************************************************************
    6291                 :  *                   TABText::DumpMIF()
    6292                 :  *
    6293                 :  * Dump feature geometry in a format similar to .MIF REGIONs.
    6294                 :  **********************************************************************/
    6295               0 : void TABText::DumpMIF(FILE *fpOut /*=NULL*/)
    6296                 : {
    6297                 :     OGRGeometry   *poGeom;
    6298               0 :     OGRPoint      *poPoint = NULL;
    6299                 : 
    6300               0 :     if (fpOut == NULL)
    6301               0 :         fpOut = stdout;
    6302                 : 
    6303                 :     /*-----------------------------------------------------------------
    6304                 :      * Fetch and validate geometry
    6305                 :      *----------------------------------------------------------------*/
    6306               0 :     poGeom = GetGeometryRef();
    6307               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    6308                 :     {
    6309                 :         /*-------------------------------------------------------------
    6310                 :          * Generate output for text object
    6311                 :          *------------------------------------------------------------*/
    6312               0 :         poPoint = (OGRPoint*)poGeom;
    6313                 : 
    6314                 :         fprintf(fpOut, "TEXT \"%s\" %.15g %.15g\n", m_pszString?m_pszString:"",
    6315               0 :                 poPoint->getX(), poPoint->getY());
    6316                 : 
    6317               0 :         fprintf(fpOut, "  m_pszString = '%s'\n", m_pszString);
    6318               0 :         fprintf(fpOut, "  m_dAngle    = %.15g\n",   m_dAngle);
    6319               0 :         fprintf(fpOut, "  m_dHeight   = %.15g\n",   m_dHeight);
    6320                 :         fprintf(fpOut, "  m_rgbForeground  = 0x%6.6x (%d)\n", 
    6321               0 :                                              m_rgbForeground, m_rgbForeground);
    6322                 :         fprintf(fpOut, "  m_rgbBackground  = 0x%6.6x (%d)\n", 
    6323               0 :                                              m_rgbBackground, m_rgbBackground);
    6324               0 :         fprintf(fpOut, "  m_nTextAlignment = 0x%4.4x\n",  m_nTextAlignment);
    6325               0 :         fprintf(fpOut, "  m_nFontStyle     = 0x%4.4x\n",  m_nFontStyle);
    6326                 :     }
    6327                 :     else
    6328                 :     {
    6329                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6330               0 :                  "TABText: Missing or Invalid Geometry!");
    6331               0 :         return;
    6332                 :     }
    6333                 : 
    6334                 :     // Finish with PEN/BRUSH/etc. clauses
    6335               0 :     DumpPenDef();
    6336               0 :     DumpFontDef();
    6337                 : 
    6338               0 :     fflush(fpOut);
    6339                 : }
    6340                 : 
    6341                 : /*=====================================================================
    6342                 :  *                      class TABMultiPoint
    6343                 :  *====================================================================*/
    6344                 : 
    6345                 : /**********************************************************************
    6346                 :  *                   TABMultiPoint::TABMultiPoint()
    6347                 :  *
    6348                 :  * Constructor.
    6349                 :  **********************************************************************/
    6350               0 : TABMultiPoint::TABMultiPoint(OGRFeatureDefn *poDefnIn):
    6351               0 :               TABFeature(poDefnIn)
    6352                 : {
    6353               0 :     m_bCenterIsSet = FALSE;
    6354               0 : }
    6355                 : 
    6356                 : /**********************************************************************
    6357                 :  *                   TABMultiPoint::~TABMultiPoint()
    6358                 :  *
    6359                 :  * Destructor.
    6360                 :  **********************************************************************/
    6361               0 : TABMultiPoint::~TABMultiPoint()
    6362                 : {
    6363               0 : }
    6364                 : 
    6365                 : /**********************************************************************
    6366                 :  *                     TABMultiPoint::CloneTABFeature()
    6367                 :  *
    6368                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    6369                 :  *
    6370                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    6371                 :  * then copies any members specific to its own type.
    6372                 :  **********************************************************************/
    6373               0 : TABFeature *TABMultiPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
    6374                 : {
    6375                 :     /*-----------------------------------------------------------------
    6376                 :      * Alloc new feature and copy the base stuff
    6377                 :      *----------------------------------------------------------------*/
    6378               0 :     TABMultiPoint *poNew = new TABMultiPoint(poNewDefn?poNewDefn:GetDefnRef());
    6379                 : 
    6380               0 :     CopyTABFeatureBase(poNew);
    6381                 : 
    6382                 :     /*-----------------------------------------------------------------
    6383                 :      * And members specific to this class
    6384                 :      *----------------------------------------------------------------*/
    6385                 :     // ITABFeatureSymbol
    6386               0 :     *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
    6387                 : 
    6388               0 :     poNew->m_bCenterIsSet = m_bCenterIsSet;
    6389               0 :     poNew->m_dCenterX = m_dCenterX;
    6390               0 :     poNew->m_dCenterY = m_dCenterY;
    6391                 : 
    6392               0 :     return poNew;
    6393                 : }
    6394                 : 
    6395                 : 
    6396                 : /**********************************************************************
    6397                 :  *                   TABMultiPoint::ValidateMapInfoType()
    6398                 :  *
    6399                 :  * Check the feature's geometry part and return the corresponding
    6400                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    6401                 :  * be updated for further calls to GetMapInfoType();
    6402                 :  *
    6403                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    6404                 :  * is expected for this object class.
    6405                 :  **********************************************************************/
    6406               0 : int  TABMultiPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    6407                 : {
    6408                 :     OGRGeometry *poGeom;
    6409                 : 
    6410                 :     /*-----------------------------------------------------------------
    6411                 :      * Fetch and validate geometry 
    6412                 :      *----------------------------------------------------------------*/
    6413               0 :     poGeom = GetGeometryRef();
    6414               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6415                 :     {
    6416               0 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
    6417                 : 
    6418               0 :         if (poMPoint->getNumGeometries() > TAB_MULTIPOINT_650_MAX_VERTICES)
    6419               0 :             m_nMapInfoType = TAB_GEOM_V800_MULTIPOINT;
    6420                 :         else
    6421               0 :             m_nMapInfoType = TAB_GEOM_MULTIPOINT;
    6422                 :     }
    6423                 :     else
    6424                 :     {
    6425                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6426               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6427               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    6428                 :     }
    6429                 : 
    6430                 :     /*-----------------------------------------------------------------
    6431                 :      * Decide if coordinates should be compressed or not.
    6432                 :      *----------------------------------------------------------------*/
    6433               0 :     ValidateCoordType(poMapFile);
    6434                 : 
    6435               0 :     return m_nMapInfoType;
    6436                 : }
    6437                 : 
    6438                 : 
    6439                 : 
    6440                 : /**********************************************************************
    6441                 :  *                   TABMultiPoint::ReadGeometryFromMAPFile()
    6442                 :  *
    6443                 :  * Fill the geometry and representation (color, etc...) part of the
    6444                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    6445                 :  *
    6446                 :  * It is assumed that poMAPFile currently points to the beginning of
    6447                 :  * a map object.
    6448                 :  *
    6449                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    6450                 :  * been called.
    6451                 :  **********************************************************************/
    6452               0 : int TABMultiPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    6453                 :                                            TABMAPObjHdr *poObjHdr,
    6454                 :                                            GBool bCoordBlockDataOnly /*=FALSE*/,
    6455                 :                                            TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    6456                 : {
    6457                 :     GInt32              nX, nY;
    6458                 :     double              dX, dY, dXMin, dYMin, dXMax, dYMax;
    6459               0 :     OGRGeometry         *poGeometry=NULL;
    6460               0 :     GBool               bComprCoord = poObjHdr->IsCompressedType();
    6461               0 :     TABMAPCoordBlock    *poCoordBlock = NULL;
    6462                 : 
    6463                 :     /*-----------------------------------------------------------------
    6464                 :      * Fetch and validate geometry type
    6465                 :      *----------------------------------------------------------------*/
    6466               0 :     m_nMapInfoType = poObjHdr->m_nType;
    6467                 : 
    6468                 :     /*-----------------------------------------------------------------
    6469                 :      * Read object information
    6470                 :      *----------------------------------------------------------------*/
    6471               0 :     if (m_nMapInfoType == TAB_GEOM_MULTIPOINT ||
    6472                 :         m_nMapInfoType == TAB_GEOM_MULTIPOINT_C ||
    6473                 :         m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT ||
    6474                 :         m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT_C )
    6475                 :     {
    6476                 :         /*-------------------------------------------------------------
    6477                 :          * Copy data from poObjHdr
    6478                 :          *------------------------------------------------------------*/
    6479               0 :         TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
    6480                 : 
    6481                 :         // MBR
    6482                 :         poMapFile->Int2Coordsys(poMPointHdr->m_nMinX, poMPointHdr->m_nMinY, 
    6483               0 :                                 dXMin, dYMin);
    6484                 :         poMapFile->Int2Coordsys(poMPointHdr->m_nMaxX, poMPointHdr->m_nMaxY, 
    6485               0 :                                 dXMax, dYMax);
    6486                 : 
    6487               0 :         if (!bCoordBlockDataOnly)
    6488                 :         {
    6489               0 :             m_nSymbolDefIndex = poMPointHdr->m_nSymbolId;   // Symbol index
    6490               0 :             poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
    6491                 :         }
    6492                 : 
    6493                 :         // Centroid/label point
    6494                 :         poMapFile->Int2Coordsys(poMPointHdr->m_nLabelX, poMPointHdr->m_nLabelY,
    6495               0 :                                 dX, dY);
    6496               0 :         SetCenter(dX, dY);
    6497                 : 
    6498                 :         // Compressed coordinate origin (useful only in compressed case!)
    6499               0 :         m_nComprOrgX = poMPointHdr->m_nComprOrgX;
    6500               0 :         m_nComprOrgY = poMPointHdr->m_nComprOrgY;
    6501                 : 
    6502                 :         /*-------------------------------------------------------------
    6503                 :          * Read Point Coordinates
    6504                 :          *------------------------------------------------------------*/
    6505                 :         OGRMultiPoint   *poMultiPoint;
    6506               0 :         poGeometry = poMultiPoint = new OGRMultiPoint();
    6507                 : 
    6508               0 :         if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    6509               0 :             poCoordBlock = *ppoCoordBlock;
    6510                 :         else
    6511               0 :             poCoordBlock = poMapFile->GetCoordBlock(poMPointHdr->m_nCoordBlockPtr);
    6512                 :         poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, 
    6513               0 :                                           m_nComprOrgY);
    6514                 : 
    6515               0 :         for(int iPoint=0; iPoint<poMPointHdr->m_nNumPoints; iPoint++)
    6516                 :         {
    6517               0 :             if (poCoordBlock->ReadIntCoord(bComprCoord, nX, nY) != 0)
    6518                 :             {
    6519                 :                 CPLError(CE_Failure, CPLE_FileIO,
    6520                 :                          "Failed reading coordinate data at offset %d", 
    6521               0 :                          poMPointHdr->m_nCoordBlockPtr);
    6522               0 :                 return -1;
    6523                 :             }
    6524                 : 
    6525               0 :             poMapFile->Int2Coordsys(nX, nY, dX, dY);
    6526               0 :             OGRPoint *poPoint = new OGRPoint(dX, dY);
    6527                 :     
    6528               0 :             if (poMultiPoint->addGeometryDirectly(poPoint) != OGRERR_NONE)
    6529                 :             {
    6530               0 :                 CPLAssert(FALSE); // Just in case lower-level lib is modified
    6531                 :             }
    6532                 :         }
    6533                 : 
    6534                 :     }
    6535                 :     else
    6536                 :     {
    6537                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6538                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    6539               0 :                  m_nMapInfoType, m_nMapInfoType);
    6540               0 :         return -1;
    6541                 :     }
    6542                 : 
    6543               0 :     SetGeometryDirectly(poGeometry);
    6544                 : 
    6545               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    6546                 : 
    6547                 :     /* Copy int MBR to feature class members */
    6548                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    6549               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    6550                 : 
    6551                 :     /* Return a ref to coord block so that caller can continue reading
    6552                 :      * after the end of this object (used by TABCollection and index splitting)
    6553                 :      */
    6554               0 :     if (ppoCoordBlock)
    6555               0 :         *ppoCoordBlock = poCoordBlock;
    6556                 : 
    6557               0 :     return 0;
    6558                 : }
    6559                 : 
    6560                 : /**********************************************************************
    6561                 :  *                   TABMultiPoint::WriteGeometryToMAPFile()
    6562                 :  *
    6563                 :  * Write the geometry and representation (color, etc...) part of the
    6564                 :  * feature to the .MAP object pointed to by poMAPFile.
    6565                 :  *
    6566                 :  * It is assumed that poMAPFile currently points to a valid map object.
    6567                 :  *
    6568                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    6569                 :  * been called.
    6570                 :  **********************************************************************/
    6571               0 : int TABMultiPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    6572                 :                                           TABMAPObjHdr *poObjHdr,
    6573                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    6574                 :                                           TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    6575                 : {
    6576                 :     GInt32              nX, nY;
    6577                 :     OGRGeometry         *poGeom;
    6578                 :     OGRMultiPoint       *poMPoint;
    6579                 : 
    6580                 :     /*-----------------------------------------------------------------
    6581                 :      * We assume that ValidateMapInfoType() was called already and that
    6582                 :      * the type in poObjHdr->m_nType is valid.
    6583                 :      *----------------------------------------------------------------*/
    6584               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    6585                 : 
    6586               0 :     TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
    6587                 : 
    6588                 :     /*-----------------------------------------------------------------
    6589                 :      * Fetch and validate geometry
    6590                 :      *----------------------------------------------------------------*/
    6591               0 :     poGeom = GetGeometryRef();
    6592               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6593               0 :         poMPoint = (OGRMultiPoint*)poGeom;
    6594                 :     else
    6595                 :     {
    6596                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6597               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6598               0 :         return -1;
    6599                 :     }
    6600                 : 
    6601               0 :     poMPointHdr->m_nNumPoints = poMPoint->getNumGeometries();
    6602                 : 
    6603                 :     /*-----------------------------------------------------------------
    6604                 :      * Write data to coordinate block
    6605                 :      *----------------------------------------------------------------*/
    6606                 :     int iPoint, nStatus;
    6607                 :     TABMAPCoordBlock *poCoordBlock;
    6608               0 :     GBool   bCompressed = poObjHdr->IsCompressedType();
    6609                 : 
    6610               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    6611               0 :         poCoordBlock = *ppoCoordBlock;
    6612                 :     else
    6613               0 :         poCoordBlock = poMapFile->GetCurCoordBlock();
    6614               0 :     poCoordBlock->StartNewFeature();
    6615               0 :     poMPointHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    6616               0 :     poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    6617                 : 
    6618                 : 
    6619               0 :     for(iPoint=0, nStatus=0; 
    6620                 :         nStatus == 0 && iPoint < poMPointHdr->m_nNumPoints; iPoint++)
    6621                 :     {
    6622               0 :         poGeom = poMPoint->getGeometryRef(iPoint);
    6623                 : 
    6624               0 :         if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    6625                 :         {
    6626               0 :             OGRPoint *poPoint = (OGRPoint*)poGeom;
    6627                 : 
    6628               0 :             poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
    6629               0 :             if (iPoint == 0)
    6630                 :             {
    6631                 :                 // Default to the first point, we may use explicit value below
    6632               0 :                 poMPointHdr->m_nLabelX = nX;
    6633               0 :                 poMPointHdr->m_nLabelY = nY;
    6634                 :             }
    6635                 : 
    6636               0 :             if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY, 
    6637                 :                                                        bCompressed)) != 0)
    6638                 :             {
    6639                 :                 // Failed ... error message has already been produced
    6640               0 :                 return nStatus;
    6641                 :             }   
    6642                 : 
    6643                 :         }
    6644                 :         else
    6645                 :         {
    6646                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    6647               0 :                      "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
    6648               0 :             return -1;
    6649                 :         }
    6650                 :     }
    6651                 : 
    6652                 :     /*-----------------------------------------------------------------
    6653                 :      * Copy object information
    6654                 :      *----------------------------------------------------------------*/
    6655                 : 
    6656                 :     // Compressed coordinate origin (useful only in compressed case!)
    6657               0 :     poMPointHdr->m_nComprOrgX = m_nComprOrgX;
    6658               0 :     poMPointHdr->m_nComprOrgY = m_nComprOrgY;
    6659                 : 
    6660               0 :     poMPointHdr->m_nCoordDataSize = poCoordBlock->GetFeatureDataSize();
    6661               0 :     poMPointHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    6662                 : 
    6663                 :     // Center/label point (default value already set above)
    6664                 :     double dX, dY;
    6665               0 :     if (GetCenter(dX, dY) != -1)
    6666                 :     {
    6667                 :         poMapFile->Coordsys2Int(dX, dY, poMPointHdr->m_nLabelX, 
    6668               0 :                                 poMPointHdr->m_nLabelY);
    6669                 :     }
    6670                 : 
    6671               0 :     if (!bCoordBlockDataOnly)
    6672                 :     {
    6673               0 :         m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
    6674               0 :         poMPointHdr->m_nSymbolId = (GByte)m_nSymbolDefIndex;      // Symbol index
    6675                 :     }
    6676                 : 
    6677               0 :     if (CPLGetLastErrorNo() != 0)
    6678               0 :         return -1;
    6679                 : 
    6680                 :     /* Return a ref to coord block so that caller can continue writing
    6681                 :      * after the end of this object (used by index splitting)
    6682                 :      */
    6683               0 :     if (ppoCoordBlock)
    6684               0 :         *ppoCoordBlock = poCoordBlock;
    6685                 : 
    6686               0 :     return 0;
    6687                 : }
    6688                 : 
    6689                 : 
    6690                 : /**********************************************************************
    6691                 :  *                   TABMultiPoint::GetXY()
    6692                 :  *
    6693                 :  * Return this point's X,Y coordinates.
    6694                 :  **********************************************************************/
    6695               0 : int TABMultiPoint::GetXY(int i, double &dX, double &dY)
    6696                 : {
    6697                 :     OGRGeometry *poGeom;
    6698                 : 
    6699                 :     /*-----------------------------------------------------------------
    6700                 :      * Fetch and validate geometry
    6701                 :      *----------------------------------------------------------------*/
    6702               0 :     poGeom = GetGeometryRef();
    6703               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6704                 :     {
    6705               0 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
    6706                 : 
    6707               0 :         if (i >= 0 && i < poMPoint->getNumGeometries() &&
    6708                 :             (poGeom = poMPoint->getGeometryRef(i)) != NULL &&
    6709               0 :             wkbFlatten(poGeom->getGeometryType()) == wkbPoint )
    6710                 :         {
    6711               0 :             OGRPoint *poPoint = (OGRPoint*)poGeom;
    6712                 : 
    6713               0 :             dX = poPoint->getX();
    6714               0 :             dY = poPoint->getY();
    6715                 :         }
    6716                 :     }
    6717                 :     else
    6718                 :     {
    6719                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6720               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6721               0 :         dX = dY = 0.0;
    6722               0 :         return -1;
    6723                 :     }
    6724                 : 
    6725               0 :     return 0;
    6726                 : }
    6727                 : 
    6728                 : /**********************************************************************
    6729                 :  *                   TABMultiPoint::GetNumPoints()
    6730                 :  *
    6731                 :  * Return the number of points in this multipoint object
    6732                 :  **********************************************************************/
    6733               0 : int TABMultiPoint::GetNumPoints()
    6734                 : {
    6735                 :     OGRGeometry *poGeom;
    6736                 : 
    6737                 :     /*-----------------------------------------------------------------
    6738                 :      * Fetch and validate geometry
    6739                 :      *----------------------------------------------------------------*/
    6740               0 :     poGeom = GetGeometryRef();
    6741               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6742                 :     {
    6743               0 :         OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
    6744                 : 
    6745               0 :         return poMPoint->getNumGeometries();
    6746                 :     }
    6747                 :     else
    6748                 :     {
    6749                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6750               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6751               0 :         return 0;
    6752                 :     }
    6753                 : 
    6754                 :     return 0;
    6755                 : }
    6756                 : 
    6757                 : 
    6758                 : /**********************************************************************
    6759                 :  *                   TABMultiPoint::GetStyleString()
    6760                 :  *
    6761                 :  * Return style string for this feature.
    6762                 :  *
    6763                 :  * Style String is built only once during the first call to GetStyleString().
    6764                 :  **********************************************************************/
    6765               0 : const char *TABMultiPoint::GetStyleString()
    6766                 : {
    6767               0 :     if (m_pszStyleString == NULL)
    6768                 :     {
    6769               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    6770                 :     }
    6771                 : 
    6772               0 :     return m_pszStyleString;
    6773                 : }
    6774                 : 
    6775                 : /**********************************************************************
    6776                 :  *                   TABMultiPoint::GetCenter()
    6777                 :  *
    6778                 :  * Returns the center point (or label point?) of the object.  Compute one 
    6779                 :  * if it was not explicitly set:
    6780                 :  *
    6781                 :  * The default seems to be to use the first point in the collection as
    6782                 :  * the center.. so we'll use that.
    6783                 :  *
    6784                 :  * Returns 0 on success, -1 on error.
    6785                 :  **********************************************************************/
    6786               0 : int TABMultiPoint::GetCenter(double &dX, double &dY)
    6787                 : {
    6788               0 :     if (!m_bCenterIsSet && GetNumPoints() > 0)
    6789                 :     {
    6790                 :         // The default seems to be to use the first point in the collection
    6791                 :         // as the center... so we'll use that.
    6792               0 :         if (GetXY(0, m_dCenterX, m_dCenterY) == 0)
    6793               0 :             m_bCenterIsSet = TRUE;
    6794                 :     }
    6795                 : 
    6796               0 :     if (!m_bCenterIsSet)
    6797               0 :         return -1;
    6798                 : 
    6799               0 :     dX = m_dCenterX;
    6800               0 :     dY = m_dCenterY;
    6801               0 :     return 0;
    6802                 : }
    6803                 : 
    6804                 : /**********************************************************************
    6805                 :  *                   TABMultiPoint::SetCenter()
    6806                 :  *
    6807                 :  * Set the X,Y coordinates to use as center point (or label point?)
    6808                 :  **********************************************************************/
    6809               0 : void TABMultiPoint::SetCenter(double dX, double dY)
    6810                 : {
    6811               0 :     m_dCenterX = dX;
    6812               0 :     m_dCenterY = dY;
    6813               0 :     m_bCenterIsSet = TRUE;
    6814               0 : }
    6815                 : 
    6816                 : 
    6817                 : /**********************************************************************
    6818                 :  *                   TABMultiPoint::DumpMIF()
    6819                 :  *
    6820                 :  * Dump feature geometry in a format similar to .MIF POINTs.
    6821                 :  **********************************************************************/
    6822               0 : void TABMultiPoint::DumpMIF(FILE *fpOut /*=NULL*/)
    6823                 : {
    6824                 :     OGRGeometry *poGeom;
    6825                 :     OGRMultiPoint *poMPoint;
    6826                 : 
    6827               0 :     if (fpOut == NULL)
    6828               0 :         fpOut = stdout;
    6829                 : 
    6830                 :     /*-----------------------------------------------------------------
    6831                 :      * Fetch and validate geometry
    6832                 :      *----------------------------------------------------------------*/
    6833               0 :     poGeom = GetGeometryRef();
    6834               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
    6835               0 :         poMPoint = (OGRMultiPoint*)poGeom;
    6836                 :     else
    6837                 :     {
    6838                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6839               0 :                  "TABMultiPoint: Missing or Invalid Geometry!");
    6840               0 :         return;
    6841                 :     }
    6842                 : 
    6843                 :     /*-----------------------------------------------------------------
    6844                 :      * Generate output
    6845                 :      *----------------------------------------------------------------*/
    6846               0 :     fprintf(fpOut, "MULTIPOINT %d\n", poMPoint->getNumGeometries());
    6847                 : 
    6848               0 :     for (int iPoint=0; iPoint < poMPoint->getNumGeometries(); iPoint++)
    6849                 :     {
    6850               0 :         poGeom = poMPoint->getGeometryRef(iPoint);
    6851                 : 
    6852               0 :         if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
    6853                 :         {
    6854               0 :             OGRPoint *poPoint = (OGRPoint*)poGeom;
    6855               0 :             fprintf(fpOut, "  %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
    6856                 :         }
    6857                 :         else
    6858                 :         {
    6859                 :             CPLError(CE_Failure, CPLE_AssertionFailed,
    6860               0 :                      "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
    6861               0 :             return;
    6862                 :         }
    6863                 :     }
    6864                 : 
    6865               0 :     DumpSymbolDef(fpOut);
    6866                 : 
    6867               0 :     if (m_bCenterIsSet)
    6868               0 :         fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
    6869                 : 
    6870               0 :     fflush(fpOut);
    6871                 : }
    6872                 : 
    6873                 : /*=====================================================================
    6874                 :  *                      class TABCollection
    6875                 :  *====================================================================*/
    6876                 : 
    6877                 : /**********************************************************************
    6878                 :  *                   TABCollection::TABCollection()
    6879                 :  *
    6880                 :  * Constructor.
    6881                 :  **********************************************************************/
    6882               0 : TABCollection::TABCollection(OGRFeatureDefn *poDefnIn):
    6883               0 :               TABFeature(poDefnIn)
    6884                 : {
    6885               0 :     m_poRegion = NULL;
    6886               0 :     m_poPline = NULL;
    6887               0 :     m_poMpoint = NULL;
    6888               0 : }
    6889                 : 
    6890                 : /**********************************************************************
    6891                 :  *                   TABCollection::~TABCollection()
    6892                 :  *
    6893                 :  * Destructor.
    6894                 :  **********************************************************************/
    6895               0 : TABCollection::~TABCollection()
    6896                 : {
    6897               0 :     EmptyCollection();
    6898               0 : }
    6899                 : 
    6900                 : /**********************************************************************
    6901                 :  *                   TABCollection::EmptyCollection()
    6902                 :  *
    6903                 :  * Delete/free all collection components.
    6904                 :  **********************************************************************/
    6905               0 : void TABCollection::EmptyCollection()
    6906                 : {
    6907                 : 
    6908               0 :     if (m_poRegion)
    6909                 :     {
    6910               0 :         delete m_poRegion;
    6911               0 :         m_poRegion = NULL;
    6912                 :     }
    6913                 : 
    6914               0 :     if (m_poPline)
    6915                 :     {
    6916               0 :         delete m_poPline;
    6917               0 :         m_poPline = NULL;
    6918                 :     }
    6919                 : 
    6920               0 :     if (m_poMpoint)
    6921                 :     {
    6922               0 :         delete m_poMpoint;
    6923               0 :         m_poMpoint = NULL;
    6924                 :     }
    6925                 : 
    6926                 :     // Empty OGR Geometry Collection as well
    6927               0 :     SyncOGRGeometryCollection(TRUE, TRUE, TRUE);
    6928                 : 
    6929               0 : }
    6930                 : 
    6931                 : /**********************************************************************
    6932                 :  *                     TABCollection::CloneTABFeature()
    6933                 :  *
    6934                 :  * Duplicate feature, including stuff specific to each TABFeature type.
    6935                 :  *
    6936                 :  * This method calls the generic TABFeature::CloneTABFeature() and 
    6937                 :  * then copies any members specific to its own type.
    6938                 :  **********************************************************************/
    6939               0 : TABFeature *TABCollection::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
    6940                 : {
    6941                 :     /*-----------------------------------------------------------------
    6942                 :      * Alloc new feature and copy the base stuff
    6943                 :      *----------------------------------------------------------------*/
    6944               0 :     TABCollection *poNew = new TABCollection(poNewDefn?poNewDefn:GetDefnRef());
    6945                 : 
    6946               0 :     CopyTABFeatureBase(poNew);
    6947                 : 
    6948                 :     /*-----------------------------------------------------------------
    6949                 :      * And members specific to this class
    6950                 :      *----------------------------------------------------------------*/
    6951                 : 
    6952               0 :     if (m_poRegion)
    6953               0 :         poNew->SetRegionDirectly((TABRegion*)m_poRegion->CloneTABFeature());
    6954                 : 
    6955               0 :     if (m_poPline)
    6956               0 :         poNew->SetPolylineDirectly((TABPolyline*)m_poPline->CloneTABFeature());
    6957                 : 
    6958               0 :     if (m_poMpoint)
    6959               0 :         poNew->SetMultiPointDirectly((TABMultiPoint*)m_poMpoint->CloneTABFeature());
    6960                 : 
    6961               0 :     return poNew;
    6962                 : }
    6963                 : 
    6964                 : 
    6965                 : /**********************************************************************
    6966                 :  *                   TABCollection::ValidateMapInfoType()
    6967                 :  *
    6968                 :  * Check the feature's geometry part and return the corresponding
    6969                 :  * mapinfo object type code.  The m_nMapInfoType member will also
    6970                 :  * be updated for further calls to GetMapInfoType();
    6971                 :  *
    6972                 :  * Returns TAB_GEOM_NONE if the geometry is not compatible with what
    6973                 :  * is expected for this object class.
    6974                 :  **********************************************************************/
    6975               0 : int  TABCollection::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
    6976                 : {
    6977                 :     OGRGeometry *poGeom;
    6978               0 :     int nRegionType=TAB_GEOM_NONE, nPLineType=TAB_GEOM_NONE, 
    6979               0 :         nMPointType=TAB_GEOM_NONE, nVersion = 650;
    6980                 : 
    6981                 :     /*-----------------------------------------------------------------
    6982                 :      * Fetch and validate geometry 
    6983                 :      *----------------------------------------------------------------*/
    6984               0 :     poGeom = GetGeometryRef();
    6985               0 :     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
    6986                 :     {
    6987               0 :         m_nMapInfoType = TAB_GEOM_COLLECTION;
    6988                 :     }
    6989                 :     else
    6990                 :     {
    6991                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    6992               0 :                  "TABCollection: Missing or Invalid Geometry!");
    6993               0 :         m_nMapInfoType = TAB_GEOM_NONE;
    6994                 :     }
    6995                 : 
    6996                 :     /*-----------------------------------------------------------------
    6997                 :      * Decide if coordinates should be compressed or not.
    6998                 :      *----------------------------------------------------------------*/
    6999               0 :     GBool bComprCoord = ValidateCoordType(poMapFile);
    7000                 : 
    7001                 :     /*-----------------------------------------------------------------
    7002                 :      * Since all members of the collection share the same compressed coord
    7003                 :      * origin, we should force the compressed origin in all components
    7004                 :      * to be the same. 
    7005                 :      * This also implies that ValidateMapInfoType() should *NOT* be called
    7006                 :      * again until the collection components are written by WriteGeom...()
    7007                 :      *----------------------------------------------------------------*/
    7008                 : 
    7009                 :     // First pass to figure collection type...
    7010               0 :     if (m_poRegion)
    7011                 :     {
    7012               0 :         m_poRegion->ValidateCoordType(poMapFile);
    7013               0 :         nRegionType = m_poRegion->ValidateMapInfoType(poMapFile);
    7014               0 :         if (TAB_GEOM_GET_VERSION(nRegionType) > nVersion)
    7015               0 :             nVersion = TAB_GEOM_GET_VERSION(nRegionType);
    7016                 :     }
    7017                 : 
    7018               0 :     if (m_poPline)
    7019                 :     {
    7020               0 :         m_poPline->ValidateCoordType(poMapFile);
    7021               0 :         nPLineType = m_poPline->ValidateMapInfoType(poMapFile);
    7022               0 :         if (TAB_GEOM_GET_VERSION(nPLineType) > nVersion)
    7023               0 :             nVersion = TAB_GEOM_GET_VERSION(nPLineType);
    7024                 :     }
    7025                 : 
    7026               0 :     if (m_poMpoint)
    7027                 :     {
    7028               0 :         m_poMpoint->ValidateCoordType(poMapFile);
    7029               0 :         nMPointType = m_poMpoint->ValidateMapInfoType(poMapFile);
    7030               0 :         if (TAB_GEOM_GET_VERSION(nMPointType) > nVersion)
    7031               0 :             nVersion = TAB_GEOM_GET_VERSION(nMPointType);
    7032                 :     }
    7033                 : 
    7034                 :     // Need to upgrade native type of collection?
    7035               0 :     if (nVersion == 800)
    7036                 :     {
    7037               0 :         m_nMapInfoType = TAB_GEOM_V800_COLLECTION;
    7038                 :     }
    7039                 : 
    7040                 :     // Make another pass updating native type and coordinates type and origin
    7041                 :     // of each component
    7042               0 :     if (m_poRegion && nRegionType != TAB_GEOM_NONE)
    7043                 :     {
    7044               0 :         GInt32 nXMin=0, nYMin=0, nXMax=0, nYMax=0;
    7045               0 :         m_poRegion->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
    7046                 :         m_poRegion->ForceCoordTypeAndOrigin((nVersion == 800 ? 
    7047                 :                                              TAB_GEOM_V800_REGION:
    7048                 :                                              TAB_GEOM_V450_REGION),
    7049                 :                                             bComprCoord,
    7050                 :                                             m_nComprOrgX, m_nComprOrgY,
    7051               0 :                                             nXMin, nYMin, nXMax, nYMax);
    7052                 :     }
    7053                 : 
    7054                 : 
    7055               0 :     if (m_poPline && nPLineType != TAB_GEOM_NONE)
    7056                 :     {
    7057                 :         GInt32 nXMin, nYMin, nXMax, nYMax;
    7058               0 :         m_poPline->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
    7059                 :         m_poPline->ForceCoordTypeAndOrigin((nVersion == 800 ? 
    7060                 :                                             TAB_GEOM_V800_MULTIPLINE:
    7061                 :                                             TAB_GEOM_V450_MULTIPLINE),
    7062                 :                                            bComprCoord,
    7063                 :                                            m_nComprOrgX, m_nComprOrgY,
    7064               0 :                                            nXMin, nYMin, nXMax, nYMax);
    7065                 :     }
    7066                 : 
    7067               0 :     if (m_poMpoint && nMPointType != TAB_GEOM_NONE)
    7068                 :     {
    7069                 :         GInt32 nXMin, nYMin, nXMax, nYMax;
    7070               0 :         m_poMpoint->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
    7071                 :         m_poMpoint->ForceCoordTypeAndOrigin((nVersion == 800 ? 
    7072                 :                                              TAB_GEOM_V800_MULTIPOINT:
    7073                 :                                              TAB_GEOM_MULTIPOINT),
    7074                 :                                             bComprCoord,
    7075                 :                                             m_nComprOrgX, m_nComprOrgY,
    7076               0 :                                             nXMin, nYMin, nXMax, nYMax);
    7077                 :     }
    7078                 : 
    7079                 : 
    7080               0 :     return m_nMapInfoType;
    7081                 : }
    7082                 : 
    7083                 : 
    7084                 : /**********************************************************************
    7085                 :  *                   TABCollection::ReadLabelAndMBR()
    7086                 :  *
    7087                 :  * Reads the label and MBR elements of the header of a collection component
    7088                 :  *
    7089                 :  * Returns 0 on success, -1 on failure.
    7090                 :  **********************************************************************/
    7091               0 : int  TABCollection::ReadLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
    7092                 :                                     GBool bComprCoord,
    7093                 :                                     GInt32 nComprOrgX, GInt32 nComprOrgY,
    7094                 :                                     GInt32 &pnMinX, GInt32 &pnMinY,
    7095                 :                                     GInt32 &pnMaxX, GInt32 &pnMaxY,
    7096                 :                                     GInt32 &pnLabelX, GInt32 &pnLabelY )
    7097                 : {
    7098                 :     //
    7099                 :     // The sections in the collection's coord blocks start with center/label
    7100                 :     // point + MBR that are normally found in the object data blocks 
    7101                 :     // of regular region/pline/mulitpoint objects.
    7102                 :     //
    7103                 : 
    7104               0 :     if (bComprCoord)
    7105                 :     {
    7106                 :         // Region center/label point, relative to compr. coord. origin
    7107                 :         // No it's not relative to the Object block center
    7108               0 :         pnLabelX = poCoordBlock->ReadInt16();
    7109               0 :         pnLabelY = poCoordBlock->ReadInt16();
    7110                 : 
    7111               0 :         pnLabelX += nComprOrgX;
    7112               0 :         pnLabelY += nComprOrgY;
    7113                 : 
    7114               0 :         pnMinX = nComprOrgX + poCoordBlock->ReadInt16(); // Read MBR
    7115               0 :         pnMinY = nComprOrgY + poCoordBlock->ReadInt16();
    7116               0 :         pnMaxX = nComprOrgX + poCoordBlock->ReadInt16();
    7117               0 :         pnMaxY = nComprOrgY + poCoordBlock->ReadInt16();
    7118                 :     }
    7119                 :     else
    7120                 :     {
    7121                 :         // Region center/label point, relative to compr. coord. origin
    7122                 :         // No it's not relative to the Object block center
    7123               0 :         pnLabelX = poCoordBlock->ReadInt32();
    7124               0 :         pnLabelY = poCoordBlock->ReadInt32();
    7125                 : 
    7126               0 :         pnMinX = poCoordBlock->ReadInt32();    // Read MBR
    7127               0 :         pnMinY = poCoordBlock->ReadInt32();
    7128               0 :         pnMaxX = poCoordBlock->ReadInt32();
    7129               0 :         pnMaxY = poCoordBlock->ReadInt32();
    7130                 :     }
    7131                 : 
    7132               0 :     return 0;
    7133                 : }
    7134                 : 
    7135                 : /**********************************************************************
    7136                 :  *                   TABCollection::WriteLabelAndMBR()
    7137                 :  *
    7138                 :  * Writes the label and MBR elements of the header of a collection component
    7139                 :  *
    7140                 :  * Returns 0 on success, -1 on failure.
    7141                 :  **********************************************************************/
    7142               0 : int  TABCollection::WriteLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
    7143                 :                                      GBool bComprCoord,
    7144                 :                                      GInt32 nMinX, GInt32 nMinY,
    7145                 :                                      GInt32 nMaxX, GInt32 nMaxY,
    7146                 :                                      GInt32 nLabelX, GInt32 nLabelY )
    7147                 : {
    7148                 :     int nStatus;
    7149                 : 
    7150                 :     //
    7151                 :     // The sections in the collection's coord blocks start with center/label
    7152                 :     // point + MBR that are normally found in the object data blocks 
    7153                 :     // of regular region/pline/mulitpoint objects.
    7154                 :     //
    7155                 : 
    7156               0 :     if ((nStatus = poCoordBlock->WriteIntCoord(nLabelX, nLabelY, 
    7157                 :                                                bComprCoord)) != 0 ||
    7158                 :         (nStatus = poCoordBlock->WriteIntCoord(nMinX, nMinY, 
    7159                 :                                                bComprCoord)) != 0 ||
    7160                 :         (nStatus = poCoordBlock->WriteIntCoord(nMaxX, nMaxY, 
    7161                 :                                                bComprCoord)) != 0   )
    7162                 :     {
    7163                 :         // Failed ... error message has already been produced
    7164               0 :         return nStatus;
    7165                 :     }   
    7166                 : 
    7167               0 :     return 0;
    7168                 : }
    7169                 : 
    7170                 : 
    7171                 : /**********************************************************************
    7172                 :  *                   TABCollection::ReadGeometryFromMAPFile()
    7173                 :  *
    7174                 :  * Fill the geometry and representation (color, etc...) part of the
    7175                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    7176                 :  *
    7177                 :  * It is assumed that poMAPFile currently points to the beginning of
    7178                 :  * a map object.
    7179                 :  *
    7180                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    7181                 :  * been called.
    7182                 :  **********************************************************************/
    7183               0 : int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    7184                 :                                            TABMAPObjHdr *poObjHdr,
    7185                 :                                            GBool bCoordBlockDataOnly /*=FALSE*/,
    7186                 :                                            TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    7187                 : {
    7188                 :     double              dXMin, dYMin, dXMax, dYMax;
    7189               0 :     GBool               bComprCoord = poObjHdr->IsCompressedType();
    7190               0 :     TABMAPCoordBlock*   poCoordBlock = NULL;
    7191                 :     int                 nCurCoordBlockPtr;
    7192                 : 
    7193                 :     /*-----------------------------------------------------------------
    7194                 :      * Fetch and validate geometry type
    7195                 :      *----------------------------------------------------------------*/
    7196               0 :     m_nMapInfoType = poObjHdr->m_nType;
    7197                 : 
    7198               0 :     if (m_nMapInfoType != TAB_GEOM_COLLECTION &&
    7199                 :         m_nMapInfoType != TAB_GEOM_COLLECTION_C &&
    7200                 :         m_nMapInfoType != TAB_GEOM_V800_COLLECTION &&
    7201                 :         m_nMapInfoType != TAB_GEOM_V800_COLLECTION_C )
    7202                 :     {
    7203                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    7204                 :            "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
    7205               0 :                  m_nMapInfoType, m_nMapInfoType);
    7206               0 :         return -1;
    7207                 :     }
    7208                 : 
    7209               0 :     int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    7210                 : 
    7211                 :     // Make sure collection is empty
    7212               0 :     EmptyCollection();
    7213                 : 
    7214                 :     /*-------------------------------------------------------------
    7215                 :      * Copy data from poObjHdr
    7216                 :      *------------------------------------------------------------*/
    7217               0 :     TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
    7218                 : 
    7219                 :     // MBR
    7220                 :     poMapFile->Int2Coordsys(poCollHdr->m_nMinX, poCollHdr->m_nMinY, 
    7221               0 :                             dXMin, dYMin);
    7222                 :     poMapFile->Int2Coordsys(poCollHdr->m_nMaxX, poCollHdr->m_nMaxY, 
    7223               0 :                             dXMax, dYMax);
    7224                 : 
    7225               0 :     SetMBR(dXMin, dYMin, dXMax, dYMax);
    7226                 : 
    7227                 :     SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY, 
    7228               0 :               poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
    7229                 : 
    7230               0 :     nCurCoordBlockPtr = poCollHdr->m_nCoordBlockPtr;
    7231               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    7232               0 :         poCoordBlock = *ppoCoordBlock;
    7233                 :     else
    7234               0 :         poCoordBlock = poMapFile->GetCoordBlock(nCurCoordBlockPtr);
    7235                 : 
    7236                 :     // Compressed coordinate origin (useful only in compressed case!)
    7237               0 :     m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7238               0 :     m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7239                 : 
    7240                 :     /*-----------------------------------------------------------------
    7241                 :      * Region Component
    7242                 :      *----------------------------------------------------------------*/
    7243               0 :     if(poCollHdr->m_nNumRegSections > 0)
    7244                 :     {
    7245                 :         //
    7246                 :         // Build fake coord section header to pass to TABRegion::ReadGeom...()
    7247                 :         //
    7248               0 :         TABMAPObjPLine      oRegionHdr;
    7249                 : 
    7250               0 :         oRegionHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7251               0 :         oRegionHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7252                 : 
    7253                 :         //
    7254                 :         // The region section in the coord block starts with center/label
    7255                 :         // point + MBR that are normally found in the object data blocks 
    7256                 :         // of regular region objects.
    7257                 :         //
    7258                 : 
    7259                 :         // In V800 the mini-header starts with a copy of num_parts
    7260               0 :         if (nVersion >= 800)
    7261                 :         {
    7262                 :             int numParts;
    7263               0 :             numParts = poCoordBlock->ReadInt32();
    7264               0 :             CPLAssert(numParts == poCollHdr->m_nNumRegSections);
    7265                 :         }
    7266                 : 
    7267                 :         ReadLabelAndMBR(poCoordBlock, bComprCoord,
    7268                 :                         oRegionHdr.m_nComprOrgX, oRegionHdr.m_nComprOrgY,
    7269                 :                         oRegionHdr.m_nMinX, oRegionHdr.m_nMinY,
    7270                 :                         oRegionHdr.m_nMaxX, oRegionHdr.m_nMaxY,
    7271               0 :                         oRegionHdr.m_nLabelX, oRegionHdr.m_nLabelY);
    7272                 : 
    7273                 :         // Set CoordBlockPtr so that TABRegion continues reading here
    7274               0 :         oRegionHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7275                 : 
    7276               0 :         if (bComprCoord)
    7277               0 :             oRegionHdr.m_nType = TAB_GEOM_V450_REGION_C;
    7278                 :         else
    7279               0 :             oRegionHdr.m_nType = TAB_GEOM_V450_REGION;
    7280               0 :         if (nVersion == 800)
    7281               0 :             oRegionHdr.m_nType += (TAB_GEOM_V800_REGION - TAB_GEOM_V450_REGION);
    7282                 : 
    7283               0 :         oRegionHdr.m_numLineSections = poCollHdr->m_nNumRegSections;
    7284               0 :         oRegionHdr.m_nPenId = poCollHdr->m_nRegionPenId;
    7285               0 :         oRegionHdr.m_nBrushId = poCollHdr->m_nRegionBrushId;
    7286               0 :         oRegionHdr.m_bSmooth = 0;       // TODO
    7287                 : 
    7288                 :         //
    7289                 :         // Use a TABRegion to read/store the Region coord data
    7290                 :         //
    7291               0 :         m_poRegion = new TABRegion(GetDefnRef());
    7292               0 :         if (m_poRegion->ReadGeometryFromMAPFile(poMapFile, &oRegionHdr, 
    7293                 :                                                 bCoordBlockDataOnly, 
    7294               0 :                                                 &poCoordBlock) != 0)
    7295               0 :             return -1;
    7296                 : 
    7297                 :         // Set new coord block ptr for next object
    7298               0 :         if (poCoordBlock)
    7299               0 :             nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
    7300                 :     }
    7301                 : 
    7302                 : 
    7303                 :     /*-----------------------------------------------------------------
    7304                 :      * PLine Component
    7305                 :      *----------------------------------------------------------------*/
    7306               0 :     if(poCollHdr->m_nNumPLineSections > 0)
    7307                 :     {
    7308                 :         //
    7309                 :         // Build fake coord section header to pass to TABPolyline::ReadGeom..()
    7310                 :         //
    7311               0 :         TABMAPObjPLine      oPLineHdr;
    7312                 : 
    7313               0 :         oPLineHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7314               0 :         oPLineHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7315                 : 
    7316                 :         //
    7317                 :         // The pline section in the coord block starts with center/label
    7318                 :         // point + MBR that are normally found in the object data blocks 
    7319                 :         // of regular pline objects.
    7320                 :         //
    7321                 : 
    7322                 :         // In V800 the mini-header starts with a copy of num_parts
    7323               0 :         if (nVersion >= 800)
    7324                 :         {
    7325                 :             int numParts;
    7326               0 :             numParts = poCoordBlock->ReadInt32();
    7327               0 :             CPLAssert(numParts == poCollHdr->m_nNumPLineSections);
    7328                 :         }
    7329                 : 
    7330                 :         ReadLabelAndMBR(poCoordBlock, bComprCoord,
    7331                 :                         oPLineHdr.m_nComprOrgX, oPLineHdr.m_nComprOrgY,
    7332                 :                         oPLineHdr.m_nMinX, oPLineHdr.m_nMinY,
    7333                 :                         oPLineHdr.m_nMaxX, oPLineHdr.m_nMaxY,
    7334               0 :                         oPLineHdr.m_nLabelX, oPLineHdr.m_nLabelY);
    7335                 : 
    7336                 :         // Set CoordBlockPtr so that TABRegion continues reading here
    7337               0 :         oPLineHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7338                 : 
    7339               0 :         if (bComprCoord)
    7340               0 :             oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE_C;
    7341                 :         else
    7342               0 :             oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE;
    7343               0 :         if (nVersion == 800)
    7344                 :             oPLineHdr.m_nType += (TAB_GEOM_V800_MULTIPLINE - 
    7345               0 :                                   TAB_GEOM_V450_MULTIPLINE);
    7346                 : 
    7347               0 :         oPLineHdr.m_numLineSections = poCollHdr->m_nNumPLineSections;
    7348               0 :         oPLineHdr.m_nPenId = poCollHdr->m_nPolylinePenId;
    7349               0 :         oPLineHdr.m_bSmooth = 0;        // TODO
    7350                 : 
    7351                 :         //
    7352                 :         // Use a TABPolyline to read/store the Polyline coord data
    7353                 :         //
    7354               0 :         m_poPline = new TABPolyline(GetDefnRef());
    7355               0 :         if (m_poPline->ReadGeometryFromMAPFile(poMapFile, &oPLineHdr, 
    7356                 :                                                bCoordBlockDataOnly,
    7357               0 :                                                &poCoordBlock) != 0)
    7358               0 :             return -1;
    7359                 : 
    7360                 :         // Set new coord block ptr for next object
    7361               0 :         if (poCoordBlock)
    7362               0 :             nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
    7363                 :     }
    7364                 : 
    7365                 :     /*-----------------------------------------------------------------
    7366                 :      * MultiPoint Component
    7367                 :      *----------------------------------------------------------------*/
    7368               0 :     if(poCollHdr->m_nNumMultiPoints > 0)
    7369                 :     {
    7370                 :         //
    7371                 :         // Build fake coord section header to pass to TABMultiPoint::ReadGeom()
    7372                 :         //
    7373               0 :         TABMAPObjMultiPoint oMPointHdr;
    7374                 : 
    7375               0 :         oMPointHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
    7376               0 :         oMPointHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
    7377                 : 
    7378                 :         //
    7379                 :         // The pline section in the coord block starts with center/label
    7380                 :         // point + MBR that are normally found in the object data blocks 
    7381                 :         // of regular pline objects.
    7382                 :         //
    7383                 :         ReadLabelAndMBR(poCoordBlock, bComprCoord,
    7384                 :                         oMPointHdr.m_nComprOrgX, oMPointHdr.m_nComprOrgY,
    7385                 :                         oMPointHdr.m_nMinX, oMPointHdr.m_nMinY,
    7386                 :                         oMPointHdr.m_nMaxX, oMPointHdr.m_nMaxY,
    7387               0 :                         oMPointHdr.m_nLabelX, oMPointHdr.m_nLabelY);
    7388                 : 
    7389                 :         // Set CoordBlockPtr so that TABRegion continues reading here
    7390               0 :         oMPointHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7391                 : 
    7392               0 :         if (bComprCoord)
    7393               0 :             oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT_C;
    7394                 :         else
    7395               0 :             oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT;
    7396               0 :         if (nVersion == 800)
    7397                 :             oMPointHdr.m_nType += (TAB_GEOM_V800_MULTIPOINT - 
    7398               0 :                                    TAB_GEOM_MULTIPOINT);
    7399                 : 
    7400               0 :         oMPointHdr.m_nNumPoints = poCollHdr->m_nNumMultiPoints;
    7401               0 :         oMPointHdr.m_nSymbolId = poCollHdr->m_nMultiPointSymbolId;
    7402                 : 
    7403                 :         //
    7404                 :         // Use a TABMultiPoint to read/store the coord data
    7405                 :         //
    7406               0 :         m_poMpoint = new TABMultiPoint(GetDefnRef());
    7407               0 :         if (m_poMpoint->ReadGeometryFromMAPFile(poMapFile, &oMPointHdr, 
    7408                 :                                                 bCoordBlockDataOnly,
    7409               0 :                                                 &poCoordBlock) != 0)
    7410               0 :             return -1;
    7411                 : 
    7412                 :         // Set new coord block ptr for next object (not really useful here)
    7413               0 :         if (poCoordBlock)
    7414               0 :             nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
    7415                 :     }
    7416                 :     
    7417                 :     /*-----------------------------------------------------------------
    7418                 :      * Set the main OGRFeature Geometry 
    7419                 :      * (this is actually duplicating geometries from each member)
    7420                 :      *----------------------------------------------------------------*/
    7421               0 :     if (SyncOGRGeometryCollection(TRUE, TRUE, TRUE) != 0)
    7422               0 :         return -1;
    7423                 : 
    7424                 :     /* Return a ref to coord block so that caller can continue reading
    7425                 :      * after the end of this object (used by index splitting)
    7426                 :      */
    7427               0 :     if (ppoCoordBlock)
    7428               0 :         *ppoCoordBlock = poCoordBlock;
    7429                 : 
    7430               0 :     return 0;
    7431                 : }
    7432                 : 
    7433                 : /**********************************************************************
    7434                 :  *                   TABCollection::WriteGeometryToMAPFile()
    7435                 :  *
    7436                 :  * Write the geometry and representation (color, etc...) part of the
    7437                 :  * feature to the .MAP object pointed to by poMAPFile.
    7438                 :  *
    7439                 :  * It is assumed that poMAPFile currently points to a valid map object.
    7440                 :  *
    7441                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    7442                 :  * been called.
    7443                 :  **********************************************************************/
    7444               0 : int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
    7445                 :                                           TABMAPObjHdr *poObjHdr,
    7446                 :                                           GBool bCoordBlockDataOnly /*=FALSE*/,
    7447                 :                                           TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
    7448                 : {
    7449                 :     /*-----------------------------------------------------------------
    7450                 :      * Note that the current implementation does not allow setting the
    7451                 :      * Geometry via OGRFeature::SetGeometry(). The geometries must be set
    7452                 :      * via the SetRegion/Pline/MpointDirectly() methods which will take 
    7453                 :      * care of keeping the OGRFeature's geometry in sync.
    7454                 :      * 
    7455                 :      * TODO: If we ever want to support sync'ing changes from the OGRFeature's
    7456                 :      * geometry to the m_poRegion/Pline/Mpoint then a call should be added
    7457                 :      * here, or perhaps in ValidateMapInfoType(), or even better in 
    7458                 :      * custom TABCollection::SetGeometry*()... but then this last option
    7459                 :      * won't work unless OGRFeature::SetGeometry*() are made virtual in OGR.
    7460                 :      *----------------------------------------------------------------*/
    7461                 : 
    7462                 : 
    7463                 :     /*-----------------------------------------------------------------
    7464                 :      * We assume that ValidateMapInfoType() was called already and that
    7465                 :      * the type in poObjHdr->m_nType is valid.
    7466                 :      *----------------------------------------------------------------*/
    7467               0 :     CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
    7468                 : 
    7469               0 :     TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
    7470                 : 
    7471                 :     /*-----------------------------------------------------------------
    7472                 :      * Write data to coordinate block for each component...
    7473                 :      *
    7474                 :      * Note that at this point, the caller (TABFile) has called 
    7475                 :      * TABCollection::ValidateMapInfoType() which in turn has called
    7476                 :      * each component's respective ValidateMapInfoType() and
    7477                 :      * ForceCoordTypeAndCoordOrigin() so the objects are ready to have
    7478                 :      * their respective WriteGeometryToMapFile() called.
    7479                 :      *----------------------------------------------------------------*/
    7480                 :     TABMAPCoordBlock *poCoordBlock;
    7481               0 :     GBool   bCompressed = poObjHdr->IsCompressedType();
    7482                 :     // TODO: ??? Do we need to track overall collection coord data size???
    7483               0 :     int     nTotalFeatureDataSize = 0;
    7484                 : 
    7485               0 :     int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
    7486                 : 
    7487               0 :     if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
    7488               0 :         poCoordBlock = *ppoCoordBlock;
    7489                 :     else
    7490               0 :         poCoordBlock = poMapFile->GetCurCoordBlock();
    7491               0 :     poCoordBlock->StartNewFeature();
    7492               0 :     poCollHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
    7493               0 :     poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
    7494                 : 
    7495                 :     /*-----------------------------------------------------------------
    7496                 :      * Region component
    7497                 :      *----------------------------------------------------------------*/
    7498               0 :     if (m_poRegion && m_poRegion->GetMapInfoType() != TAB_GEOM_NONE)
    7499                 :     {
    7500               0 :         CPLAssert(m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION ||
    7501                 :                   m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION_C ||
    7502                 :                   m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION ||
    7503               0 :                   m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION_C );
    7504                 : 
    7505                 :         TABMAPObjPLine *poRegionHdr = (TABMAPObjPLine *)
    7506               0 :             TABMAPObjHdr::NewObj((GByte)m_poRegion->GetMapInfoType(), -1);
    7507                 : 
    7508                 :         // Update count of objects by type in header
    7509               0 :         if (!bCoordBlockDataOnly)
    7510               0 :             poMapFile->UpdateMapHeaderInfo((GByte)m_poRegion->GetMapInfoType());
    7511                 : 
    7512                 :         // Write a placeholder for centroid/label point and MBR mini-header
    7513                 :         // and we'll come back later to write the real values.
    7514                 :         //
    7515                 :         // Note that the call to WriteGeometryToMAPFile() below will call 
    7516                 :         // StartNewFeature() as well, so we need to track the current 
    7517                 :         // value before calling it
    7518                 : 
    7519               0 :         poCoordBlock->StartNewFeature();
    7520               0 :         int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
    7521                 : 
    7522                 :         // In V800 the mini-header starts with a copy of num_parts
    7523               0 :         if (nVersion >= 800)
    7524                 :         {
    7525               0 :             poCoordBlock->WriteInt32(0);
    7526                 :         }
    7527                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7528               0 :                          0, 0, 0, 0, 0, 0);
    7529               0 :         nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
    7530                 : 
    7531               0 :         if (m_poRegion->WriteGeometryToMAPFile(poMapFile, poRegionHdr,
    7532                 :                                                bCoordBlockDataOnly,
    7533               0 :                                                &poCoordBlock) != 0)
    7534                 :         {
    7535                 :             CPLError(CE_Failure, CPLE_FileIO,
    7536               0 :                      "Failed writing Region part in collection.");
    7537               0 :             delete poRegionHdr;
    7538               0 :             return -1;
    7539                 :         }
    7540                 : 
    7541               0 :         nTotalFeatureDataSize += poRegionHdr->m_nCoordDataSize;
    7542                 : 
    7543                 :         // Come back to write the real values in the mini-header
    7544               0 :         int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
    7545               0 :         poCoordBlock->StartNewFeature();
    7546                 : 
    7547               0 :         if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
    7548                 :         {
    7549               0 :             delete poRegionHdr;
    7550               0 :             return -1;
    7551                 :         }
    7552                 : 
    7553                 :         // In V800 the mini-header starts with a copy of num_parts
    7554               0 :         if (nVersion >= 800)
    7555                 :         {
    7556               0 :             poCoordBlock->WriteInt32(poRegionHdr->m_numLineSections);
    7557                 :         }
    7558                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7559                 :                          poRegionHdr->m_nMinX, poRegionHdr->m_nMinY, 
    7560                 :                          poRegionHdr->m_nMaxX, poRegionHdr->m_nMaxY,
    7561               0 :                          poRegionHdr->m_nLabelX, poRegionHdr->m_nLabelY);
    7562                 : 
    7563                 :         // And finally move the pointer back to the end of this component
    7564               0 :         if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
    7565                 :         {
    7566               0 :             delete poRegionHdr;
    7567               0 :             return -1;
    7568                 :         }
    7569                 : 
    7570                 :         // Copy other header members to the main collection header
    7571                 :         // TODO: Does m_nRegionDataSize need to include the centroid+mbr
    7572                 :         //       mini-header???
    7573               0 :         poCollHdr->m_nRegionDataSize = poRegionHdr->m_nCoordDataSize;
    7574               0 :         poCollHdr->m_nNumRegSections = poRegionHdr->m_numLineSections;
    7575                 : 
    7576               0 :         if (!bCoordBlockDataOnly)
    7577                 :         {
    7578               0 :             poCollHdr->m_nRegionPenId    = poRegionHdr->m_nPenId;
    7579               0 :             poCollHdr->m_nRegionBrushId  = poRegionHdr->m_nBrushId;
    7580                 :             // TODO: Smooth flag         = poRegionHdr->m_bSmooth;
    7581                 :         }
    7582                 :         
    7583               0 :         delete poRegionHdr;
    7584                 :     }
    7585                 :     else
    7586                 :     {
    7587                 :         // No Region component. Set corresponding header fields to 0
    7588                 : 
    7589               0 :         poCollHdr->m_nRegionDataSize = 0;
    7590               0 :         poCollHdr->m_nNumRegSections = 0;
    7591               0 :         poCollHdr->m_nRegionPenId = 0;
    7592               0 :         poCollHdr->m_nRegionBrushId = 0;
    7593                 :     }
    7594                 : 
    7595                 :     /*-----------------------------------------------------------------
    7596                 :      * PLine component
    7597                 :      *----------------------------------------------------------------*/
    7598               0 :     if (m_poPline && m_poPline->GetMapInfoType() != TAB_GEOM_NONE)
    7599                 :     {
    7600               0 :         CPLAssert(m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE ||
    7601                 :                   m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE_C ||
    7602                 :                   m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE ||
    7603               0 :                   m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE_C );
    7604                 : 
    7605                 :         TABMAPObjPLine *poPlineHdr = (TABMAPObjPLine *)
    7606               0 :             TABMAPObjHdr::NewObj((GByte)m_poPline->GetMapInfoType(), -1);
    7607                 : 
    7608                 :         // Update count of objects by type in header
    7609               0 :         if (!bCoordBlockDataOnly)
    7610               0 :             poMapFile->UpdateMapHeaderInfo((GByte)m_poPline->GetMapInfoType());
    7611                 : 
    7612                 :         // Write a placeholder for centroid/label point and MBR mini-header
    7613                 :         // and we'll come back later to write the real values.
    7614                 :         //
    7615                 :         // Note that the call to WriteGeometryToMAPFile() below will call 
    7616                 :         // StartNewFeature() as well, so we need to track the current 
    7617                 :         // value before calling it
    7618                 : 
    7619               0 :         poCoordBlock->StartNewFeature();
    7620               0 :         int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
    7621                 : 
    7622                 :         // In V800 the mini-header starts with a copy of num_parts
    7623               0 :         if (nVersion >= 800)
    7624                 :         {
    7625               0 :             poCoordBlock->WriteInt32(0);
    7626                 :         }
    7627                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7628               0 :                          0, 0, 0, 0, 0, 0);
    7629               0 :         nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
    7630                 : 
    7631               0 :         if (m_poPline->WriteGeometryToMAPFile(poMapFile, poPlineHdr,
    7632                 :                                               bCoordBlockDataOnly,
    7633               0 :                                               &poCoordBlock) != 0)
    7634                 :         {
    7635                 :             CPLError(CE_Failure, CPLE_FileIO,
    7636               0 :                      "Failed writing Region part in collection.");
    7637               0 :             delete poPlineHdr;
    7638               0 :             return -1;
    7639                 :         }
    7640                 : 
    7641               0 :         nTotalFeatureDataSize += poPlineHdr->m_nCoordDataSize;
    7642                 : 
    7643                 :         // Come back to write the real values in the mini-header
    7644               0 :         int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
    7645               0 :         poCoordBlock->StartNewFeature();
    7646                 : 
    7647               0 :         if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
    7648                 :         {
    7649               0 :             delete poPlineHdr;
    7650               0 :             return -1;
    7651                 :         }
    7652                 : 
    7653                 :         // In V800 the mini-header starts with a copy of num_parts
    7654               0 :         if (nVersion >= 800)
    7655                 :         {
    7656               0 :             poCoordBlock->WriteInt32(poPlineHdr->m_numLineSections);
    7657                 :         }
    7658                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7659                 :                          poPlineHdr->m_nMinX, poPlineHdr->m_nMinY, 
    7660                 :                          poPlineHdr->m_nMaxX, poPlineHdr->m_nMaxY,
    7661               0 :                          poPlineHdr->m_nLabelX, poPlineHdr->m_nLabelY);
    7662                 : 
    7663                 :         // And finally move the pointer back to the end of this component
    7664               0 :         if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
    7665                 :         {
    7666               0 :             delete poPlineHdr;
    7667               0 :             return -1;
    7668                 :         }
    7669                 : 
    7670                 :         // Copy other header members to the main collection header
    7671                 :         // TODO: Does m_nRegionDataSize need to include the centroid+mbr
    7672                 :         //       mini-header???
    7673               0 :         poCollHdr->m_nPolylineDataSize = poPlineHdr->m_nCoordDataSize;
    7674               0 :         poCollHdr->m_nNumPLineSections = poPlineHdr->m_numLineSections;
    7675               0 :         if (!bCoordBlockDataOnly)
    7676                 :         {
    7677               0 :             poCollHdr->m_nPolylinePenId    = poPlineHdr->m_nPenId;
    7678                 :             // TODO: Smooth flag           = poPlineHdr->m_bSmooth;
    7679                 :         }
    7680                 : 
    7681               0 :         delete poPlineHdr;        
    7682                 :     }
    7683                 :     else
    7684                 :     {
    7685                 :         // No Polyline component. Set corresponding header fields to 0
    7686                 : 
    7687               0 :         poCollHdr->m_nPolylineDataSize = 0;
    7688               0 :         poCollHdr->m_nNumPLineSections = 0;
    7689               0 :         poCollHdr->m_nPolylinePenId = 0;
    7690                 :     }
    7691                 : 
    7692                 : 
    7693                 :     /*-----------------------------------------------------------------
    7694                 :      * MultiPoint component
    7695                 :      *----------------------------------------------------------------*/
    7696               0 :     if (m_poMpoint && m_poMpoint->GetMapInfoType() != TAB_GEOM_NONE)
    7697                 :     {
    7698               0 :         CPLAssert(m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT ||
    7699                 :                   m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT_C ||
    7700                 :                   m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT ||
    7701               0 :                   m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT_C );
    7702                 : 
    7703                 :         TABMAPObjMultiPoint *poMpointHdr = (TABMAPObjMultiPoint *)
    7704               0 :             TABMAPObjHdr::NewObj((GByte)m_poMpoint->GetMapInfoType(), -1);
    7705                 : 
    7706                 :         // Update count of objects by type in header
    7707               0 :         if (!bCoordBlockDataOnly)
    7708               0 :             poMapFile->UpdateMapHeaderInfo((GByte)m_poMpoint->GetMapInfoType());
    7709                 : 
    7710                 :         // Write a placeholder for centroid/label point and MBR mini-header
    7711                 :         // and we'll come back later to write the real values.
    7712                 :         //
    7713                 :         // Note that the call to WriteGeometryToMAPFile() below will call 
    7714                 :         // StartNewFeature() as well, so we need to track the current 
    7715                 :         // value before calling it
    7716                 : 
    7717               0 :         poCoordBlock->StartNewFeature();
    7718               0 :         int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
    7719                 : 
    7720                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7721               0 :                          0, 0, 0, 0, 0, 0);
    7722               0 :         nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
    7723                 : 
    7724               0 :         if (m_poMpoint->WriteGeometryToMAPFile(poMapFile, poMpointHdr,
    7725                 :                                                bCoordBlockDataOnly,
    7726               0 :                                                &poCoordBlock) != 0)
    7727                 :         {
    7728                 :             CPLError(CE_Failure, CPLE_FileIO,
    7729               0 :                      "Failed writing Region part in collection.");
    7730               0 :             delete poMpointHdr;
    7731               0 :             return -1;
    7732                 :         }
    7733                 : 
    7734               0 :         nTotalFeatureDataSize += poMpointHdr->m_nCoordDataSize;
    7735                 : 
    7736                 :         // Come back to write the real values in the mini-header
    7737               0 :         int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
    7738               0 :         poCoordBlock->StartNewFeature();
    7739                 : 
    7740               0 :         if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
    7741                 :         {
    7742               0 :             delete poMpointHdr;
    7743               0 :             return -1;
    7744                 :         }
    7745                 : 
    7746                 :         WriteLabelAndMBR(poCoordBlock, bCompressed,
    7747                 :                          poMpointHdr->m_nMinX, poMpointHdr->m_nMinY, 
    7748                 :                          poMpointHdr->m_nMaxX, poMpointHdr->m_nMaxY,
    7749               0 :                          poMpointHdr->m_nLabelX, poMpointHdr->m_nLabelY);
    7750                 : 
    7751                 :         // And finally move the pointer back to the end of this component
    7752               0 :         if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
    7753                 :         {
    7754               0 :             delete poMpointHdr;
    7755               0 :             return -1;
    7756                 :         }
    7757                 : 
    7758                 :         // Copy other header members to the main collection header
    7759                 :         // TODO: Does m_nRegionDataSize need to include the centroid+mbr
    7760                 :         //       mini-header???
    7761               0 :         poCollHdr->m_nMPointDataSize     = poMpointHdr->m_nCoordDataSize;
    7762               0 :         poCollHdr->m_nNumMultiPoints     = poMpointHdr->m_nNumPoints;
    7763               0 :         if (!bCoordBlockDataOnly)
    7764                 :         {
    7765               0 :             poCollHdr->m_nMultiPointSymbolId = poMpointHdr->m_nSymbolId;
    7766                 :         }
    7767                 : 
    7768               0 :         delete poMpointHdr;        
    7769                 :     }
    7770                 :     else
    7771                 :     {
    7772                 :         // No Multipoint component. Set corresponding header fields to 0
    7773                 : 
    7774               0 :         poCollHdr->m_nMPointDataSize = 0;
    7775               0 :         poCollHdr->m_nNumMultiPoints = 0;
    7776               0 :         poCollHdr->m_nMultiPointSymbolId = 0;
    7777                 :     }
    7778                 : 
    7779                 : 
    7780                 :     /*-----------------------------------------------------------------
    7781                 :      * Copy object information
    7782                 :      *----------------------------------------------------------------*/
    7783                 : 
    7784                 :     // Compressed coordinate origin (useful only in compressed case!)
    7785               0 :     poCollHdr->m_nComprOrgX = m_nComprOrgX;
    7786               0 :     poCollHdr->m_nComprOrgY = m_nComprOrgY;
    7787                 : 
    7788               0 :     poCollHdr->m_nCoordDataSize = nTotalFeatureDataSize;
    7789                 : 
    7790               0 :     poCollHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
    7791                 : 
    7792                 : 
    7793               0 :     if (CPLGetLastErrorNo() != 0)
    7794               0 :         return -1;
    7795                 : 
    7796                 :     /* Return a ref to coord block so that caller can continue writing
    7797                 :      * after the end of this object (used by index splitting)
    7798                 :      */
    7799               0 :     if (ppoCoordBlock)
    7800               0 :         *ppoCoordBlock = poCoordBlock;
    7801                 : 
    7802               0 :     return 0;
    7803                 : }
    7804                 : 
    7805                 : 
    7806                 : /**********************************************************************
    7807                 :  *                   TABCollection::SyncOGRGeometryCollection()
    7808                 :  *
    7809                 :  * Copy the region/pline/multipoint's geometries to the OGRFeature's
    7810                 :  * geometry.
    7811                 :  **********************************************************************/
    7812               0 : int    TABCollection::SyncOGRGeometryCollection(GBool bSyncRegion,
    7813                 :                                                 GBool bSyncPline,
    7814                 :                                                 GBool bSyncMpoint)
    7815                 : {
    7816               0 :     OGRGeometry         *poThisGeom = GetGeometryRef();
    7817                 :     OGRGeometryCollection *poGeomColl;
    7818                 : 
    7819                 :     // poGeometry is defined in the OGRFeature class
    7820               0 :     if (poThisGeom == NULL)
    7821                 :     {
    7822               0 :         poThisGeom = poGeomColl = new OGRGeometryCollection();
    7823               0 :         SetGeometryDirectly(poGeomColl);
    7824                 :     }
    7825               0 :     else if (wkbFlatten(poThisGeom->getGeometryType())==wkbGeometryCollection)
    7826                 :     {
    7827               0 :          poGeomColl = (OGRGeometryCollection *)poThisGeom;
    7828                 :     }
    7829                 :     else
    7830                 :     {
    7831                 :         CPLError(CE_Failure, CPLE_AssertionFailed,
    7832               0 :                  "TABCollection: Invalid Geometry. Type must be OGRCollection.");
    7833               0 :         return -1;
    7834                 :     }
    7835                 : 
    7836                 :     /*-----------------------------------------------------------------
    7837                 :      * Start by removing geometries that need to be replaced
    7838                 :      * In theory there should be a single geometry of each type, but 
    7839                 :      * just in case, we'll loop over the whole collection and delete all
    7840                 :      * instances of each type if there are some.
    7841                 :      *----------------------------------------------------------------*/
    7842               0 :     int numGeometries = poGeomColl->getNumGeometries();
    7843               0 :     for (int i=0; i<numGeometries; i++)
    7844                 :     {
    7845               0 :         OGRGeometry *poGeom = poGeomColl->getGeometryRef(i);
    7846               0 :         if (!poGeom)
    7847               0 :             continue;
    7848                 : 
    7849               0 :         if ( (bSyncRegion && 
    7850               0 :               (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
    7851               0 :                wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) ) ||
    7852                 :              (bSyncPline && 
    7853               0 :               (wkbFlatten(poGeom->getGeometryType()) == wkbLineString ||
    7854               0 :                wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)) ||
    7855                 :              (bSyncMpoint && 
    7856               0 :               (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint) ) )
    7857                 :         {
    7858                 :             // Remove this geometry
    7859               0 :             poGeomColl->removeGeometry(i);
    7860                 : 
    7861                 :             // Unless this was the last geometry, we need to restart
    7862                 :             // scanning the collection since we modified it
    7863               0 :             if (i != numGeometries-1)
    7864                 :             {
    7865               0 :                 i=0;
    7866               0 :                 numGeometries = poGeomColl->getNumGeometries();
    7867                 :             }
    7868                 :         }
    7869                 :     }
    7870                 : 
    7871                 :     /*-----------------------------------------------------------------
    7872                 :      * Copy TAB Feature geometries to OGRGeometryCollection
    7873                 :      *----------------------------------------------------------------*/
    7874               0 :     if(bSyncRegion && m_poRegion && m_poRegion->GetGeometryRef() != NULL)
    7875               0 :         poGeomColl->addGeometry(m_poRegion->GetGeometryRef());
    7876                 :     
    7877               0 :     if(bSyncPline && m_poPline && m_poPline->GetGeometryRef() != NULL)
    7878               0 :         poGeomColl->addGeometry(m_poPline->GetGeometryRef());
    7879                 : 
    7880               0 :     if(bSyncMpoint && m_poMpoint && m_poMpoint->GetGeometryRef() != NULL)
    7881               0 :         poGeomColl->addGeometry(m_poMpoint->GetGeometryRef());
    7882                 : 
    7883               0 :     return 0;
    7884                 : }
    7885                 : 
    7886                 : 
    7887                 : /**********************************************************************
    7888                 :  *                   TABCollection::SetRegionDirectly()
    7889                 :  *
    7890                 :  * Set the region component of the collection, deleting the current
    7891                 :  * region component if there is one. The object is then owned by the
    7892                 :  * TABCollection object. Passing NULL just deletes it.
    7893                 :  *
    7894                 :  * Note that an intentional side-effect is that calling this method
    7895                 :  * with the same poRegion pointer that is already owned by this object
    7896                 :  * will force resync'ing the OGR Geometry member.
    7897                 :  **********************************************************************/
    7898               0 : int    TABCollection::SetRegionDirectly(TABRegion *poRegion)
    7899                 : {
    7900               0 :     if (m_poRegion && m_poRegion != poRegion)
    7901               0 :         delete m_poRegion;
    7902               0 :     m_poRegion = poRegion;
    7903                 : 
    7904                 :     // Update OGRGeometryCollection component as well
    7905               0 :     return SyncOGRGeometryCollection(TRUE, FALSE, FALSE);
    7906                 : }
    7907                 : 
    7908                 : /**********************************************************************
    7909                 :  *                   TABCollection::SetPolylineDirectly()
    7910                 :  *
    7911                 :  * Set the polyline component of the collection, deleting the current
    7912                 :  * polyline component if there is one. The object is then owned by the
    7913                 :  * TABCollection object. Passing NULL just deletes it.
    7914                 :  *
    7915                 :  * Note that an intentional side-effect is that calling this method
    7916                 :  * with the same poPline pointer that is already owned by this object
    7917                 :  * will force resync'ing the OGR Geometry member.
    7918                 :  **********************************************************************/
    7919               0 : int    TABCollection::SetPolylineDirectly(TABPolyline *poPline)
    7920                 : {
    7921               0 :     if (m_poPline && m_poPline != poPline)
    7922               0 :         delete m_poPline;
    7923               0 :     m_poPline = poPline;
    7924                 : 
    7925                 :     // Update OGRGeometryCollection component as well
    7926               0 :     return SyncOGRGeometryCollection(FALSE, TRUE, FALSE);
    7927                 : }
    7928                 : 
    7929                 : /**********************************************************************
    7930                 :  *                   TABCollection::SetMultiPointDirectly()
    7931                 :  *
    7932                 :  * Set the multipoint component of the collection, deleting the current
    7933                 :  * multipoint component if there is one. The object is then owned by the
    7934                 :  * TABCollection object. Passing NULL just deletes it.
    7935                 :  *
    7936                 :  * Note that an intentional side-effect is that calling this method
    7937                 :  * with the same poMpoint pointer that is already owned by this object
    7938                 :  * will force resync'ing the OGR Geometry member.
    7939                 :  **********************************************************************/
    7940               0 : int    TABCollection::SetMultiPointDirectly(TABMultiPoint *poMpoint)
    7941                 : {
    7942               0 :     if (m_poMpoint && m_poMpoint != poMpoint)
    7943               0 :         delete m_poMpoint;
    7944               0 :     m_poMpoint = poMpoint;
    7945                 : 
    7946                 :     // Update OGRGeometryCollection component as well
    7947               0 :     return SyncOGRGeometryCollection(FALSE, FALSE, TRUE);
    7948                 : }
    7949                 : 
    7950                 : 
    7951                 : /**********************************************************************
    7952                 :  *                   TABCollection::GetStyleString()
    7953                 :  *
    7954                 :  * Return style string for this feature.
    7955                 :  *
    7956                 :  * Style String is built only once during the first call to GetStyleString().
    7957                 :  **********************************************************************/
    7958               0 : const char *TABCollection::GetStyleString()
    7959                 : {
    7960               0 :     if (m_pszStyleString == NULL)
    7961                 :     {
    7962               0 :         m_pszStyleString = CPLStrdup(GetSymbolStyleString());
    7963                 :     }
    7964                 : 
    7965               0 :     return m_pszStyleString;
    7966                 : }
    7967                 : 
    7968                 : 
    7969                 : /**********************************************************************
    7970                 :  *                   TABCollection::DumpMIF()
    7971                 :  *
    7972                 :  * Dump feature geometry 
    7973                 :  **********************************************************************/
    7974               0 : void TABCollection::DumpMIF(FILE *fpOut /*=NULL*/)
    7975                 : {
    7976               0 :     if (fpOut == NULL)
    7977               0 :         fpOut = stdout;
    7978                 : 
    7979                 :     /*-----------------------------------------------------------------
    7980                 :      * Generate output
    7981                 :      *----------------------------------------------------------------*/
    7982               0 :     int numParts = 0;
    7983               0 :     if (m_poRegion)     numParts++;
    7984               0 :     if (m_poPline)      numParts++;
    7985               0 :     if (m_poMpoint)     numParts++;
    7986                 : 
    7987               0 :     fprintf(fpOut, "COLLECTION %d\n", numParts);
    7988                 : 
    7989               0 :     if (m_poRegion)
    7990               0 :         m_poRegion->DumpMIF(fpOut);
    7991                 : 
    7992               0 :     if (m_poPline)
    7993               0 :         m_poPline->DumpMIF(fpOut);
    7994                 : 
    7995               0 :     if (m_poMpoint)
    7996               0 :         m_poMpoint->DumpMIF(fpOut);
    7997                 : 
    7998                 : 
    7999               0 :     DumpSymbolDef(fpOut);
    8000                 : 
    8001               0 :     fflush(fpOut);
    8002               0 : }
    8003                 : 
    8004                 : /*=====================================================================
    8005                 :  *                      class TABDebugFeature
    8006                 :  *====================================================================*/
    8007                 : 
    8008                 : /**********************************************************************
    8009                 :  *                   TABDebugFeature::TABDebugFeature()
    8010                 :  *
    8011                 :  * Constructor.
    8012                 :  **********************************************************************/
    8013               0 : TABDebugFeature::TABDebugFeature(OGRFeatureDefn *poDefnIn):
    8014               0 :               TABFeature(poDefnIn)
    8015                 : {
    8016               0 : }
    8017                 : 
    8018                 : /**********************************************************************
    8019                 :  *                   TABDebugFeature::~TABDebugFeature()
    8020                 :  *
    8021                 :  * Destructor.
    8022                 :  **********************************************************************/
    8023               0 : TABDebugFeature::~TABDebugFeature()
    8024                 : {
    8025               0 : }
    8026                 : 
    8027                 : /**********************************************************************
    8028                 :  *                   TABDebugFeature::ReadGeometryFromMAPFile()
    8029                 :  *
    8030                 :  * Fill the geometry and representation (color, etc...) part of the
    8031                 :  * feature from the contents of the .MAP object pointed to by poMAPFile.
    8032                 :  *
    8033                 :  * It is assumed that poMAPFile currently points to the beginning of
    8034                 :  * a map object.
    8035                 :  *
    8036                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    8037                 :  * been called.
    8038                 :  **********************************************************************/
    8039               0 : int TABDebugFeature::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
    8040                 :                                              TABMAPObjHdr *poObjHdr,
    8041                 :                                              GBool /*bCoordBlockDataOnly=FALSE*/, 
    8042                 :                                              TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    8043                 : {
    8044                 :     TABMAPObjectBlock   *poObjBlock;
    8045                 :     TABMAPHeaderBlock   *poHeader;
    8046                 : 
    8047                 :     /*-----------------------------------------------------------------
    8048                 :      * Fetch geometry type
    8049                 :      *----------------------------------------------------------------*/
    8050               0 :     m_nMapInfoType = poObjHdr->m_nType;
    8051                 : 
    8052               0 :     poObjBlock = poMapFile->GetCurObjBlock();
    8053               0 :     poHeader = poMapFile->GetHeaderBlock();
    8054                 : 
    8055                 :     /*-----------------------------------------------------------------
    8056                 :      * If object type has coords in a type 3 block, then its position 
    8057                 :      * follows
    8058                 :      *----------------------------------------------------------------*/
    8059               0 :     if (poHeader->MapObjectUsesCoordBlock(m_nMapInfoType))
    8060                 :     {
    8061               0 :         m_nCoordDataPtr = poObjBlock->ReadInt32();
    8062               0 :         m_nCoordDataSize = poObjBlock->ReadInt32();
    8063                 :     }
    8064                 :     else
    8065                 :     {
    8066               0 :         m_nCoordDataPtr = -1;
    8067               0 :         m_nCoordDataSize = 0;
    8068                 :     }
    8069                 : 
    8070               0 :     m_nSize = poHeader->GetMapObjectSize(m_nMapInfoType);
    8071               0 :     if (m_nSize > 0)
    8072                 :     {
    8073               0 :         poObjBlock->GotoByteRel(-5);    // Go back to beginning of header
    8074               0 :         poObjBlock->ReadBytes(m_nSize, m_abyBuf);
    8075                 :     }
    8076                 : 
    8077               0 :     return 0;
    8078                 : }
    8079                 : 
    8080                 : /**********************************************************************
    8081                 :  *                   TABDebugFeature::WriteGeometryToMAPFile()
    8082                 :  *
    8083                 :  * Write the geometry and representation (color, etc...) part of the
    8084                 :  * feature to the .MAP object pointed to by poMAPFile.
    8085                 :  *
    8086                 :  * It is assumed that poMAPFile currently points to a valid map object.
    8087                 :  *
    8088                 :  * Returns 0 on success, -1 on error, in which case CPLError() will have
    8089                 :  * been called.
    8090                 :  **********************************************************************/
    8091               0 : int TABDebugFeature::WriteGeometryToMAPFile(TABMAPFile * /*poMapFile*/,
    8092                 :                                             TABMAPObjHdr * /*poObjHdr*/,
    8093                 :                                             GBool /*bCoordBlockDataOnly=FALSE*/, 
    8094                 :                                             TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
    8095                 : {
    8096                 :     // Nothing to do here!
    8097                 : 
    8098                 :     CPLError(CE_Failure, CPLE_NotSupported,
    8099               0 :              "TABDebugFeature::WriteGeometryToMAPFile() not implemented.\n");
    8100                 : 
    8101               0 :     return -1;
    8102                 : }
    8103                 : 
    8104                 : /**********************************************************************
    8105                 :  *                   TABDebugFeature::DumpMIF()
    8106                 :  *
    8107                 :  * Dump feature contents... available only in DEBUG mode.
    8108                 :  **********************************************************************/
    8109               0 : void TABDebugFeature::DumpMIF(FILE *fpOut /*=NULL*/)
    8110                 : {
    8111                 :     int i;
    8112                 : 
    8113               0 :     if (fpOut == NULL)
    8114               0 :         fpOut = stdout;
    8115                 : 
    8116                 :     fprintf(fpOut, "----- TABDebugFeature (type = 0x%2.2x) -----\n",
    8117               0 :             GetMapInfoType());
    8118               0 :     fprintf(fpOut, "  Object size: %d bytes\n", m_nSize);
    8119               0 :     fprintf(fpOut, "  m_nCoordDataPtr  = %d\n", m_nCoordDataPtr);
    8120               0 :     fprintf(fpOut, "  m_nCoordDataSize = %d\n", m_nCoordDataSize);
    8121               0 :     fprintf(fpOut, "  ");
    8122                 : 
    8123               0 :     for(i=0; i<m_nSize; i++)
    8124               0 :         fprintf(fpOut, " %2.2x", m_abyBuf[i]);
    8125                 : 
    8126               0 :     fprintf(fpOut, "  \n");
    8127                 : 
    8128                 : 
    8129               0 :     fflush(fpOut);
    8130               0 : }
    8131                 : 
    8132                 : 
    8133                 : /*=====================================================================
    8134                 :  *                      class ITABFeaturePen
    8135                 :  *====================================================================*/
    8136                 : 
    8137                 : /**********************************************************************
    8138                 :  *                   ITABFeaturePen::ITABFeaturePen()
    8139                 :  **********************************************************************/
    8140                 : 
    8141             102 : ITABFeaturePen::ITABFeaturePen()
    8142                 : {
    8143                 :     static const TABPenDef csDefaultPen = MITAB_PEN_DEFAULT;
    8144                 : 
    8145             102 :     m_nPenDefIndex=-1;
    8146                 : 
    8147                 :     /* MI default is PEN(1,2,0) */
    8148             102 :     m_sPenDef = csDefaultPen;
    8149             102 : }
    8150                 : 
    8151                 : 
    8152                 : /**********************************************************************
    8153                 :  *                   ITABFeaturePen::GetPenWidthPixel()
    8154                 :  *                   ITABFeaturePen::SetPenWidthPixel()
    8155                 :  *                   ITABFeaturePen::GetPenWidthPoint()
    8156                 :  *                   ITABFeaturePen::SetPenWidthPoint()
    8157                 :  *
    8158                 :  * Pen width can be expressed in pixels (value from 1 to 7 pixels) or 
    8159                 :  * in points (value from 0.1 to 203.7 points). The default pen width 
    8160                 :  * in MapInfo is 1 pixel.  Pen width in points exist only in file version 450.
    8161                 :  *
    8162                 :  * The following methods hide the way the pen width is stored in the files.
    8163                 :  *
    8164                 :  * In order to establish if a given pen def had its width specified in 
    8165                 :  * pixels or in points, one should first call GetPenWidthPoint(), and if
    8166                 :  * it returns 0 then the Pixel width should be used instead:
    8167                 :  *    if (GetPenWidthPoint() == 0)
    8168                 :  *       ... use pen width in points ...
    8169                 :  *    else
    8170                 :  *       ... use Pixel width from GetPenWidthPixel()
    8171                 :  *
    8172                 :  * Note that the reverse is not true: the default pixel width is always 1, 
    8173                 :  * even when the pen width was actually set in points.
    8174                 :  **********************************************************************/
    8175                 : 
    8176               7 : GByte ITABFeaturePen::GetPenWidthPixel()
    8177                 : {
    8178               7 :     return m_sPenDef.nPixelWidth;
    8179                 : }
    8180                 : 
    8181               0 : void  ITABFeaturePen::SetPenWidthPixel(GByte val) 
    8182                 : {
    8183               0 :     m_sPenDef.nPixelWidth = MIN(MAX(val, 1), 7);
    8184               0 :     m_sPenDef.nPointWidth = 0;
    8185               0 : }
    8186                 : 
    8187               0 : double ITABFeaturePen::GetPenWidthPoint()
    8188                 : {
    8189                 :     // We store point width internally as tenths of points
    8190               0 :     return m_sPenDef.nPointWidth/10.0;
    8191                 : }
    8192                 : 
    8193               0 : void  ITABFeaturePen::SetPenWidthPoint(double val) 
    8194                 : {
    8195               0 :     m_sPenDef.nPointWidth = MIN(MAX(((int)(val*10)), 1), 2037);
    8196               0 :     m_sPenDef.nPixelWidth = 1;
    8197               0 : }
    8198                 : 
    8199                 : /**********************************************************************
    8200                 :  *                   ITABFeaturePen::GetPenWidthMIF()
    8201                 :  *                   ITABFeaturePen::SetPenWidthMIF()
    8202                 :  *
    8203                 :  * The MIF representation for pen width is either a value from 1 to 7
    8204                 :  * for a pen width in pixels, or a value from 11 to 2047 for a pen
    8205                 :  * width in points = 10 + (point_width*10)
    8206                 :  **********************************************************************/
    8207              10 : int     ITABFeaturePen::GetPenWidthMIF()
    8208                 : {
    8209                 :     return ( m_sPenDef.nPointWidth > 0?
    8210              10 :              (m_sPenDef.nPointWidth+10): m_sPenDef.nPixelWidth );
    8211                 : }
    8212                 : 
    8213              28 : void  ITABFeaturePen::SetPenWidthMIF(int val) 
    8214                 : {
    8215              28 :     if (val > 10)
    8216                 :     {
    8217               0 :         m_sPenDef.nPointWidth = MIN((val-10), 2037);
    8218               0 :         m_sPenDef.nPixelWidth = 0;
    8219                 :     }
    8220                 :     else
    8221                 :     {
    8222              28 :         m_sPenDef.nPixelWidth = (GByte)MIN(MAX(val, 1), 7);
    8223              28 :         m_sPenDef.nPointWidth = 0;
    8224                 :     }
    8225              28 : }
    8226                 : 
    8227                 : /**********************************************************************
    8228                 :  *                   ITABFeaturePen::GetPenStyleString()
    8229                 :  *
    8230                 :  *  Return a PEN() string. All representations info for the pen are here.
    8231                 :  **********************************************************************/
    8232               7 : const char *ITABFeaturePen::GetPenStyleString()
    8233                 : {
    8234               7 :     const char *pszStyle = NULL;
    8235               7 :     int    nOGRStyle  = 0;
    8236                 :     char szPattern[20];
    8237                 :     
    8238               7 :     szPattern[0] = '\0';
    8239                 : 
    8240                 :     // For now, I only add the 25 first styles 
    8241               7 :     switch (GetPenPattern())
    8242                 :     {
    8243                 :       case 1:
    8244               0 :         nOGRStyle =1; 
    8245               0 :         break;
    8246                 :       case 2:
    8247               7 :         nOGRStyle = 0;
    8248               7 :         break;
    8249                 :       case 3:
    8250               0 :         nOGRStyle = 3; 
    8251               0 :         strcpy(szPattern,"1 1");
    8252               0 :         break;
    8253                 :       case 4:
    8254               0 :         nOGRStyle = 3;
    8255               0 :         strcpy(szPattern,"2 1");
    8256               0 :         break;
    8257                 :       case 5:
    8258               0 :         nOGRStyle = 3;
    8259               0 :         strcpy(szPattern,"3 1");
    8260               0 :         break;
    8261                 :       case 6:
    8262               0 :         nOGRStyle = 3;
    8263               0 :         strcpy(szPattern,"6 1");
    8264               0 :         break;
    8265                 :       case 7:
    8266               0 :         nOGRStyle = 4;
    8267               0 :         strcpy(szPattern,"12 2");
    8268               0 :         break;
    8269                 :       case 8:
    8270               0 :         nOGRStyle = 4;
    8271               0 :         strcpy(szPattern,"24 4");
    8272               0 :         break;
    8273                 :       case 9:
    8274               0 :         nOGRStyle = 3;
    8275               0 :         strcpy(szPattern,"4 3");
    8276               0 :         break;
    8277                 :       case 10:
    8278               0 :         nOGRStyle = 5;
    8279               0 :         strcpy(szPattern,"1 4");
    8280               0 :         break;
    8281                 :       case 11:
    8282               0 :         nOGRStyle = 3;
    8283               0 :         strcpy(szPattern,"4 6");
    8284               0 :         break;
    8285                 :       case 12:
    8286               0 :         nOGRStyle = 3;
    8287               0 :         strcpy(szPattern,"6 4");
    8288               0 :         break;
    8289                 :       case 13:
    8290               0 :         nOGRStyle = 4;
    8291               0 :         strcpy(szPattern,"12 12");
    8292               0 :         break;
    8293                 :       case 14:
    8294               0 :         nOGRStyle = 6;
    8295               0 :         strcpy(szPattern,"8 2 1 2");
    8296               0 :         break;
    8297                 :       case 15:
    8298               0 :         nOGRStyle = 6;
    8299               0 :         strcpy(szPattern,"12 1 1 1");
    8300               0 :         break;
    8301                 :       case 16:
    8302               0 :         nOGRStyle = 6;
    8303               0 :         strcpy(szPattern,"12 1 3 1");
    8304               0 :         break;
    8305                 :       case 17:
    8306               0 :         nOGRStyle = 6;
    8307               0 :         strcpy(szPattern,"24 6 4 6");
    8308               0 :         break;
    8309                 :       case 18:
    8310               0 :         nOGRStyle = 7;
    8311               0 :         strcpy(szPattern,"24 3 3 3 3 3");
    8312               0 :         break;
    8313                 :       case 19:
    8314               0 :         nOGRStyle = 7;
    8315               0 :         strcpy(szPattern,"24 3 3 3 3 3 3 3");
    8316               0 :         break;
    8317                 :       case 20:
    8318               0 :         nOGRStyle = 7;
    8319               0 :         strcpy(szPattern,"6 3 1 3 1 3");
    8320               0 :         break;
    8321                 :       case 21:
    8322               0 :         nOGRStyle = 7;
    8323               0 :         strcpy(szPattern,"12 2 1 2 1 2");
    8324               0 :         break;
    8325                 :       case 22:
    8326               0 :         nOGRStyle = 7;
    8327               0 :         strcpy(szPattern,"12 2 1 2 1 2 1 2");
    8328               0 :         break;
    8329                 :       case 23:
    8330               0 :         nOGRStyle = 6;
    8331               0 :         strcpy(szPattern,"4 1 1 1");
    8332               0 :         break;
    8333                 :       case 24:
    8334               0 :         nOGRStyle = 7;
    8335               0 :         strcpy(szPattern,"4 1 1 1 1");
    8336               0 :         break;
    8337                 :       case 25:
    8338               0 :         nOGRStyle = 6;
    8339               0 :         strcpy(szPattern,"4 1 1 1 2 1 1 1");
    8340               0 :         break;
    8341                 : 
    8342                 :         default:
    8343               0 :         nOGRStyle = 0;
    8344                 :         break;
    8345                 :     }
    8346                 : 
    8347               7 :     if (strlen(szPattern) != 0)
    8348                 :     {
    8349               0 :       if(m_sPenDef.nPointWidth > 0)
    8350                 :         pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\"mapinfo-pen-%d,"
    8351                 :                              "ogr-pen-%d\",p:\"%spx\")",
    8352                 :                              ((int)GetPenWidthPoint()),
    8353                 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
    8354               0 :                              szPattern);
    8355                 :       else
    8356                 :         pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\"mapinfo-pen-%d,"
    8357                 :                              "ogr-pen-%d\",p:\"%spx\")",
    8358                 :                              GetPenWidthPixel(),
    8359                 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
    8360               0 :                              szPattern);
    8361                 :     }
    8362                 :     else
    8363                 :     {
    8364               7 :       if(m_sPenDef.nPointWidth > 0)
    8365                 :         pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\""
    8366                 :                              "mapinfo-pen-%d,ogr-pen-%d\")",
    8367                 :                              ((int)GetPenWidthPoint()),
    8368               0 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
    8369                 :       else
    8370                 :         pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\""
    8371                 :                              "mapinfo-pen-%d,ogr-pen-%d\")",
    8372                 :                              GetPenWidthPixel(),
    8373               7 :                              m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
    8374                 :     }
    8375                 : 
    8376               7 :     return pszStyle;
    8377                 : }
    8378                 : 
    8379                 : /**********************************************************************
    8380                 :  *                   ITABFeaturePen::SetPenFromStyleString()
    8381                 :  *
    8382                 :  *  Init the Pen properties from a style string.
    8383                 :  **********************************************************************/
    8384               0 : void  ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
    8385                 : {
    8386                 :     int numParts, i;
    8387                 :     GBool bIsNull;
    8388                 : 
    8389                 :     const char *pszPenName, *pszPenPattern;
    8390                 : 
    8391                 :     double nPenWidth;
    8392                 : 
    8393                 :     GInt32 nPenColor;
    8394                 :     const char *pszPenColor;
    8395                 : 
    8396                 :     int   nPenId;
    8397                 :     char* pszPenId;
    8398                 : 
    8399                 :     // Use the Style Manager to retreive all the information we need.
    8400               0 :     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
    8401                 :     OGRStyleTool *poStylePart;
    8402                 : 
    8403                 :     // Init the StyleMgr with the StyleString.
    8404               0 :     poStyleMgr->InitStyleString(pszStyleString);
    8405                 : 
    8406                 :     // Retreive the Pen info.
    8407               0 :     numParts = poStyleMgr->GetPartCount();
    8408               0 :     for(i=0; i<numParts; i++)
    8409                 :     {
    8410               0 :         poStylePart = poStyleMgr->GetPart(i);
    8411                 : 
    8412               0 :         if(poStylePart->GetType() == OGRSTCPen)
    8413                 :         {
    8414               0 :             break;
    8415                 :         }
    8416                 :         else
    8417                 :         {
    8418               0 :             delete poStylePart;
    8419               0 :             poStylePart = NULL;
    8420                 :         }
    8421                 :     }
    8422                 : 
    8423                 :     // If the no Pen found, do nothing.
    8424               0 :     if(i >= numParts)
    8425                 :     {
    8426               0 :         delete poStyleMgr;
    8427               0 :         return;
    8428                 :     }
    8429                 : 
    8430               0 :     OGRStylePen *poPenStyle = (OGRStylePen*)poStylePart;
    8431                 : 
    8432                 :     // With Pen, we always want to output points or pixels (which are the same,
    8433                 :     // so just use points).
    8434                 :     //
    8435                 :     // It's very important to set the output unit of the feature.
    8436                 :     // The default value is meter. If we don't do it all numerical values 
    8437                 :     // will be assumed to be converted from the input unit to meter when we 
    8438                 :     // will get them via GetParam...() functions.
    8439                 :     // See OGRStyleTool::Parse() for more details.
    8440               0 :     poPenStyle->SetUnit(OGRSTUPoints, 1);
    8441                 : 
    8442                 :     // Get the Pen Id or pattern
    8443               0 :     pszPenName = poPenStyle->Id(bIsNull);
    8444               0 :     if (bIsNull) pszPenName = NULL;
    8445                 : 
    8446                 :     // Set the width
    8447               0 :     if(poPenStyle->Width(bIsNull))
    8448                 :     {
    8449               0 :         nPenWidth = poPenStyle->Width(bIsNull);
    8450                 :         // Width < 10 is a pixel
    8451               0 :         if(nPenWidth > 10)
    8452               0 :             SetPenWidthPoint(nPenWidth);
    8453                 :         else
    8454               0 :             SetPenWidthPixel((GByte)nPenWidth);
    8455                 :     }
    8456                 : 
    8457                 :     //Set the color
    8458               0 :     pszPenColor = poPenStyle->Color(bIsNull);
    8459               0 :     if(pszPenColor != NULL)
    8460                 :     {
    8461               0 :         if(pszPenColor[0] == '#')
    8462               0 :             pszPenColor++;
    8463                 :         // The Pen color is an Hexa string that need to be convert in a int
    8464               0 :         nPenColor = strtol(pszPenColor, NULL, 16);
    8465               0 :         SetPenColor(nPenColor);
    8466                 :     }
    8467                 : 
    8468                 :     // Set the Id of the Pen, use Pattern if necessary.
    8469               0 :     if(pszPenName && 
    8470                 :        (strstr(pszPenName, "mapinfo-pen-") || strstr(pszPenName, "ogr-pen-")) )
    8471                 :     {
    8472               0 :         if((pszPenId = (char *) strstr(pszPenName, "mapinfo-pen-")))
    8473                 :         {
    8474               0 :             nPenId = atoi(pszPenId+12);
    8475               0 :             SetPenPattern((GByte)nPenId);
    8476                 :         }
    8477               0 :         else if((pszPenId = (char *) strstr(pszPenName, "ogr-pen-")))
    8478                 :         {
    8479               0 :             nPenId = atoi(pszPenId+8);
    8480               0 :             if(nPenId == 0)
    8481               0 :                 nPenId = 2;
    8482               0 :             SetPenPattern((GByte)nPenId);
    8483                 :         }
    8484                 :     }
    8485                 :     else
    8486                 :     {
    8487                 :         // If no Pen Id, use the Pen Pattern to retreive the Id.
    8488               0 :         pszPenPattern = poPenStyle->Pattern(bIsNull);
    8489               0 :         if (bIsNull)
    8490               0 :             pszPenPattern = NULL;
    8491                 :         else
    8492                 :         {
    8493               0 :             if(strcmp(pszPenPattern, "1 1") == 0)
    8494               0 :                 SetPenPattern(3);
    8495               0 :             else if(strcmp(pszPenPattern, "2 1") == 0)
    8496               0 :                 SetPenPattern(4);
    8497               0 :             else if(strcmp(pszPenPattern, "3 1") == 0)
    8498               0 :                 SetPenPattern(5);
    8499               0 :             else if(strcmp(pszPenPattern, "6 1") == 0)
    8500               0 :                 SetPenPattern(6);
    8501               0 :             else if(strcmp(pszPenPattern, "12 2") == 0)
    8502               0 :                 SetPenPattern(7);
    8503               0 :             else if(strcmp(pszPenPattern, "24 4") == 0)
    8504               0 :                 SetPenPattern(8);
    8505               0 :             else if(strcmp(pszPenPattern, "4 3") == 0)
    8506               0 :                 SetPenPattern(9);
    8507               0 :             else if(strcmp(pszPenPattern, "1 4") == 0)
    8508               0 :                 SetPenPattern(10);
    8509               0 :             else if(strcmp(pszPenPattern, "4 6") == 0)
    8510               0 :                 SetPenPattern(11);
    8511               0 :             else if(strcmp(pszPenPattern, "6 4") == 0)
    8512               0 :                 SetPenPattern(12);
    8513               0 :             else if(strcmp(pszPenPattern, "12 12") == 0)
    8514               0 :                 SetPenPattern(13);
    8515               0 :             else if(strcmp(pszPenPattern, "8 2 1 2") == 0)
    8516               0 :                 SetPenPattern(14);
    8517               0 :             else if(strcmp(pszPenPattern, "12 1 1 1") == 0)
    8518               0 :                 SetPenPattern(15);
    8519               0 :             else if(strcmp(pszPenPattern, "12 1 3 1") == 0)
    8520               0 :                 SetPenPattern(16);
    8521               0 :             else if(strcmp(pszPenPattern, "24 6 4 6") == 0)
    8522               0 :                 SetPenPattern(17);
    8523               0 :             else if(strcmp(pszPenPattern, "24 3 3 3 3 3") == 0)
    8524               0 :                 SetPenPattern(18);
    8525               0 :             else if(strcmp(pszPenPattern, "24 3 3 3 3 3 3 3") == 0)
    8526               0 :                 SetPenPattern(19);
    8527               0 :             else if(strcmp(pszPenPattern, "6 3 1 3 1 3") == 0)
    8528               0 :                 SetPenPattern(20);
    8529               0 :             else if(strcmp(pszPenPattern, "12 2 1 2 1 2") == 0)
    8530               0 :                 SetPenPattern(21);
    8531               0 :             else if(strcmp(pszPenPattern, "12 2 1 2 1 2 1 2") == 0)
    8532               0 :                 SetPenPattern(22);
    8533               0 :             else if(strcmp(pszPenPattern, "4 1 1 1") == 0)
    8534               0 :                 SetPenPattern(23);
    8535               0 :             else if(strcmp(pszPenPattern, "4 1 1 1 1") == 0)
    8536               0 :                 SetPenPattern(24);
    8537               0 :             else if(strcmp(pszPenPattern, "4 1 1 1 2 1 1 1") == 0)
    8538               0 :                 SetPenPattern(25);
    8539                 :         }
    8540                 :     }
    8541                 : 
    8542               0 :     delete poStyleMgr;
    8543               0 :     delete poStylePart;
    8544                 : 
    8545               0 :     return;
    8546                 : }
    8547                 : 
    8548                 : /**********************************************************************
    8549                 :  *                   ITABFeaturePen::DumpPenDef()
    8550                 :  *
    8551                 :  * Dump pen definition information.
    8552                 :  **********************************************************************/
    8553               0 : void ITABFeaturePen::DumpPenDef(FILE *fpOut /*=NULL*/)
    8554                 : {
    8555               0 :     if (fpOut == NULL)
    8556               0 :         fpOut = stdout;
    8557                 : 
    8558               0 :     fprintf(fpOut, "  m_nPenDefIndex         = %d\n", m_nPenDefIndex);
    8559               0 :     fprintf(fpOut, "  m_sPenDef.nRefCount    = %d\n", m_sPenDef.nRefCount);
    8560               0 :     fprintf(fpOut, "  m_sPenDef.nPixelWidth  = %d\n", m_sPenDef.nPixelWidth);
    8561               0 :     fprintf(fpOut, "  m_sPenDef.nLinePattern = %d\n", m_sPenDef.nLinePattern);
    8562               0 :     fprintf(fpOut, "  m_sPenDef.nPointWidth  = %d\n", m_sPenDef.nPointWidth);
    8563                 :     fprintf(fpOut, "  m_sPenDef.rgbColor     = 0x%6.6x (%d)\n",
    8564               0 :                                      m_sPenDef.rgbColor, m_sPenDef.rgbColor);
    8565                 : 
    8566               0 :     fflush(fpOut);
    8567               0 : }
    8568                 : 
    8569                 : /*=====================================================================
    8570                 :  *                      class ITABFeatureBrush
    8571                 :  *====================================================================*/
    8572                 : 
    8573                 : /**********************************************************************
    8574                 :  *                   ITABFeatureBrush::ITABFeatureBrush()
    8575                 :  **********************************************************************/
    8576                 : 
    8577             100 : ITABFeatureBrush::ITABFeatureBrush()
    8578                 : {
    8579                 :     static const TABBrushDef csDefaultBrush = MITAB_BRUSH_DEFAULT;
    8580                 : 
    8581             100 :     m_nBrushDefIndex=-1;
    8582                 : 
    8583                 :     /* MI default is BRUSH(2,16777215,16777215) */
    8584             100 :     m_sBrushDef = csDefaultBrush;
    8585             100 : }
    8586                 : 
    8587                 : 
    8588                 : /**********************************************************************
    8589                 :  *                   ITABFeatureBrush::GetBrushStyleString()
    8590                 :  *
    8591                 :  *  Return a Brush() string. All representations info for the Brush are here.
    8592                 :  **********************************************************************/
    8593               7 : const char *ITABFeatureBrush::GetBrushStyleString()
    8594                 : {
    8595               7 :     const char *pszStyle = NULL;
    8596               7 :     int    nOGRStyle  = 0;
    8597                 :     char szPattern[20];
    8598                 :     
    8599               7 :     szPattern[0] = '\0';
    8600                 :     
    8601               7 :     if (m_sBrushDef.nFillPattern == 1)
    8602               7 :       nOGRStyle = 1;
    8603               0 :     else if (m_sBrushDef.nFillPattern == 3)
    8604               0 :       nOGRStyle = 2;
    8605               0 :     else if (m_sBrushDef.nFillPattern == 4)
    8606               0 :       nOGRStyle = 3;
    8607               0 :     else if (m_sBrushDef.nFillPattern == 5)
    8608               0 :       nOGRStyle = 5;
    8609               0 :     else if (m_sBrushDef.nFillPattern == 6)
    8610               0 :       nOGRStyle = 4;
    8611               0 :     else if (m_sBrushDef.nFillPattern == 7)
    8612               0 :       nOGRStyle = 6;
    8613               0 :     else if (m_sBrushDef.nFillPattern == 8)
    8614               0 :       nOGRStyle = 7;
    8615                 :           
    8616                 : 
    8617               7 :     if (GetBrushTransparent())
    8618                 :     {
    8619                 :         /* Omit BG Color for transparent brushes */
    8620                 :         pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
    8621                 :                              m_sBrushDef.rgbFGColor,
    8622               0 :                              m_sBrushDef.nFillPattern,nOGRStyle);
    8623                 :     }
    8624                 :     else
    8625                 :     {
    8626                 :         pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,bc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
    8627                 :                              m_sBrushDef.rgbFGColor,
    8628                 :                              m_sBrushDef.rgbBGColor,
    8629               7 :                              m_sBrushDef.nFillPattern,nOGRStyle);
    8630                 :     }
    8631                 : 
    8632               7 :      return pszStyle;
    8633                 :     
    8634                 : }  
    8635                 : 
    8636                 : 
    8637                 : /**********************************************************************
    8638                 :  *                   ITABFeatureBrush::SetBrushFromStyleString()
    8639                 :  *
    8640                 :  *  Set all Brush elements from a StyleString.
    8641                 :  *  Use StyleMgr to do so.
    8642                 :  **********************************************************************/
    8643               0 : void  ITABFeatureBrush::SetBrushFromStyleString(const char *pszStyleString)
    8644                 : {
    8645                 :     int numParts, i;
    8646                 :     GBool bIsNull;
    8647                 : 
    8648                 :     const char *pszBrushId;
    8649                 :     int nBrushId;
    8650                 : 
    8651                 :     const char *pszBrushColor;
    8652                 :     int nBrushColor;
    8653                 : 
    8654                 :     // Use the Style Manager to retreive all the information we need.
    8655               0 :     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
    8656                 :     OGRStyleTool *poStylePart;
    8657                 : 
    8658                 :     // Init the StyleMgr with the StyleString.
    8659               0 :     poStyleMgr->InitStyleString(pszStyleString);
    8660                 : 
    8661                 :     // Retreive the Brush info.
    8662               0 :     numParts = poStyleMgr->GetPartCount();
    8663               0 :     for(i=0; i<numParts; i++)
    8664                 :     {
    8665               0 :         poStylePart = poStyleMgr->GetPart(i);
    8666                 : 
    8667               0 :         if(poStylePart->GetType() == OGRSTCBrush)
    8668                 :         {
    8669               0 :             break;
    8670                 :         }
    8671                 :         else
    8672                 :         {
    8673               0 :             delete poStylePart;
    8674               0 :             poStylePart = NULL;
    8675                 :         }
    8676                 :     }
    8677                 : 
    8678                 :     // If the no Brush found, do nothing.
    8679               0 :     if(i >= numParts)
    8680                 :     {
    8681               0 :         delete poStyleMgr;
    8682               0 :         return;
    8683                 :     }
    8684                 : 
    8685               0 :     OGRStyleBrush *poBrushStyle = (OGRStyleBrush*)poStylePart;
    8686                 : 
    8687                 :     // Set the Brush Id (FillPattern)
    8688               0 :     pszBrushId = poBrushStyle->Id(bIsNull);
    8689               0 :     if(bIsNull) pszBrushId = NULL;
    8690                 : 
    8691               0 :     if(pszBrushId && 
    8692                 :        (strstr(pszBrushId, "mapinfo-brush-") || 
    8693                 :         strstr(pszBrushId, "ogr-brush-")) )
    8694                 :     {
    8695               0 :         if(strstr(pszBrushId, "mapinfo-brush-"))
    8696                 :         {
    8697               0 :             nBrushId = atoi(pszBrushId+14);
    8698               0 :             SetBrushPattern((GByte)nBrushId);
    8699                 :         }
    8700               0 :         else if(strstr(pszBrushId, "ogr-brush-"))
    8701                 :         {
    8702               0 :             nBrushId = atoi(pszBrushId+10);
    8703               0 :             if(nBrushId > 1)
    8704               0 :                 nBrushId++;
    8705               0 :             SetBrushPattern((GByte)nBrushId);
    8706                 :         }
    8707                 :     }
    8708                 : 
    8709                 :     // Set the BackColor, if not set, then it's transparent
    8710               0 :     pszBrushColor = poBrushStyle->BackColor(bIsNull);
    8711               0 :     if(bIsNull) pszBrushColor = NULL;
    8712                 : 
    8713               0 :     if(pszBrushColor)
    8714                 :     {
    8715               0 :         if(pszBrushColor[0] == '#')
    8716               0 :             pszBrushColor++;
    8717               0 :         nBrushColor = strtol(pszBrushColor, NULL, 16);
    8718               0 :         SetBrushBGColor((GInt32)nBrushColor);
    8719                 :     }
    8720                 :     else
    8721                 :     {
    8722               0 :         SetBrushTransparent(1);
    8723                 :     }
    8724                 : 
    8725                 :     // Set the ForeColor
    8726               0 :     pszBrushColor = poBrushStyle->ForeColor(bIsNull);
    8727               0 :     if(bIsNull) pszBrushColor = NULL;
    8728                 : 
    8729               0 :     if(pszBrushColor)
    8730                 :     {
    8731               0 :         if(pszBrushColor[0] == '#')
    8732               0 :             pszBrushColor++;
    8733               0 :         nBrushColor = strtol(pszBrushColor, NULL, 16);
    8734               0 :         SetBrushFGColor((GInt32)nBrushColor);
    8735                 :     }
    8736                 : 
    8737               0 :     delete poStyleMgr;
    8738               0 :     delete poStylePart;
    8739                 : 
    8740               0 :     return;
    8741                 : }  
    8742                 : 
    8743                 : /**********************************************************************
    8744                 :  *                   ITABFeatureBrush::DumpBrushDef()
    8745                 :  *
    8746                 :  * Dump Brush definition information.
    8747                 :  **********************************************************************/
    8748               0 : void ITABFeatureBrush::DumpBrushDef(FILE *fpOut /*=NULL*/)
    8749                 : {
    8750               0 :     if (fpOut == NULL)
    8751               0 :         fpOut = stdout;
    8752                 : 
    8753               0 :     fprintf(fpOut, "  m_nBrushDefIndex         = %d\n", m_nBrushDefIndex);
    8754               0 :     fprintf(fpOut, "  m_sBrushDef.nRefCount    = %d\n", m_sBrushDef.nRefCount);
    8755                 :     fprintf(fpOut, "  m_sBrushDef.nFillPattern = %d\n", 
    8756               0 :                                                 (int)m_sBrushDef.nFillPattern);
    8757                 :     fprintf(fpOut, "  m_sBrushDef.bTransparentFill = %d\n", 
    8758               0 :                                             (int)m_sBrushDef.bTransparentFill);
    8759                 :     fprintf(fpOut, "  m_sBrushDef.rgbFGColor   = 0x%6.6x (%d)\n",
    8760               0 :                                m_sBrushDef.rgbFGColor, m_sBrushDef.rgbFGColor);
    8761                 :     fprintf(fpOut, "  m_sBrushDef.rgbBGColor   = 0x%6.6x (%d)\n",
    8762               0 :                                m_sBrushDef.rgbBGColor, m_sBrushDef.rgbBGColor);
    8763                 : 
    8764               0 :     fflush(fpOut);
    8765               0 : }
    8766                 : 
    8767                 : /*=====================================================================
    8768                 :  *                      class ITABFeatureFont
    8769                 :  *====================================================================*/
    8770                 : 
    8771                 : /**********************************************************************
    8772                 :  *                   ITABFeatureFont::ITABFeatureFont()
    8773                 :  **********************************************************************/
    8774                 : 
    8775               0 : ITABFeatureFont::ITABFeatureFont()
    8776                 : {
    8777                 :     static const TABFontDef csDefaultFont = MITAB_FONT_DEFAULT;
    8778                 : 
    8779               0 :     m_nFontDefIndex=-1;
    8780                 : 
    8781                 :     /* MI default is Font("Arial",0,0,0) */
    8782               0 :     m_sFontDef = csDefaultFont;
    8783               0 : }
    8784                 : 
    8785                 : /**********************************************************************
    8786                 :  *                   ITABFeatureFont::SetFontName()
    8787                 :  **********************************************************************/
    8788               0 : void ITABFeatureFont::SetFontName(const char *pszName)
    8789                 : { 
    8790               0 :     strncpy( m_sFontDef.szFontName, pszName, 32);
    8791               0 :     m_sFontDef.szFontName[32] = '\0';  
    8792               0 : }
    8793                 : 
    8794                 : /**********************************************************************
    8795                 :  *                   ITABFeatureFont::DumpFontDef()
    8796                 :  *
    8797                 :  * Dump Font definition information.
    8798                 :  **********************************************************************/
    8799               0 : void ITABFeatureFont::DumpFontDef(FILE *fpOut /*=NULL*/)
    8800                 : {
    8801               0 :     if (fpOut == NULL)
    8802               0 :         fpOut = stdout;
    8803                 : 
    8804               0 :     fprintf(fpOut, "  m_nFontDefIndex       = %d\n", m_nFontDefIndex);
    8805               0 :     fprintf(fpOut, "  m_sFontDef.nRefCount  = %d\n", m_sFontDef.nRefCount);
    8806               0 :     fprintf(fpOut, "  m_sFontDef.szFontName = '%s'\n", m_sFontDef.szFontName);
    8807                 : 
    8808               0 :     fflush(fpOut);
    8809               0 : }
    8810                 : 
    8811                 : 
    8812                 : /*=====================================================================
    8813                 :  *                      class ITABFeatureSymbol
    8814                 :  *====================================================================*/
    8815                 : 
    8816                 : /**********************************************************************
    8817                 :  *                   ITABFeatureSymbol::ITABFeatureSymbol()
    8818                 :  **********************************************************************/
    8819                 : 
    8820               8 : ITABFeatureSymbol::ITABFeatureSymbol()
    8821                 : {
    8822                 :     static const TABSymbolDef csDefaultSymbol = MITAB_SYMBOL_DEFAULT;
    8823                 : 
    8824               8 :     m_nSymbolDefIndex=-1;
    8825                 : 
    8826                 :     /* MI default is Symbol(35,0,12) */
    8827               8 :     m_sSymbolDef = csDefaultSymbol;
    8828               8 : }
    8829                 : 
    8830                 : /**********************************************************************
    8831                 :  *                   ITABFeatureSymbol::GetSymbolStyleString()
    8832                 :  *
    8833                 :  *  Return a Symbol() string. All representations info for the Symbol are here.
    8834                 :  **********************************************************************/
    8835               0 : const char *ITABFeatureSymbol::GetSymbolStyleString(double dfAngle)
    8836                 : {
    8837               0 :     const char *pszStyle = NULL;
    8838               0 :     int    nOGRStyle  = 1;
    8839                 :     char szPattern[20];
    8840               0 :     int nAngle = 0;
    8841                 :     
    8842               0 :     szPattern[0] = '\0';
    8843                 :     
    8844               0 :     if (m_sSymbolDef.nSymbolNo == 31)
    8845               0 :       nOGRStyle = 0;
    8846               0 :     else if (m_sSymbolDef.nSymbolNo == 32)
    8847               0 :       nOGRStyle = 6;
    8848               0 :     else if (m_sSymbolDef.nSymbolNo == 33)
    8849                 :     {
    8850               0 :         nAngle = 45;
    8851               0 :         nOGRStyle = 6;
    8852                 :     }
    8853               0 :     else if (m_sSymbolDef.nSymbolNo == 34)
    8854               0 :       nOGRStyle = 4;
    8855               0 :     else if (m_sSymbolDef.nSymbolNo == 35)
    8856               0 :       nOGRStyle = 10;
    8857               0 :     else if (m_sSymbolDef.nSymbolNo == 36)
    8858               0 :       nOGRStyle = 8;
    8859               0 :     else if (m_sSymbolDef.nSymbolNo == 37)
    8860                 :     {
    8861               0 :         nAngle = 180;
    8862               0 :         nOGRStyle = 8;
    8863                 :     }
    8864               0 :     else if (m_sSymbolDef.nSymbolNo == 38)
    8865               0 :       nOGRStyle = 5;
    8866               0 :     else if (m_sSymbolDef.nSymbolNo == 39)
    8867                 :     {
    8868               0 :         nAngle = 45;
    8869               0 :         nOGRStyle = 5;
    8870                 :     }
    8871               0 :     else if (m_sSymbolDef.nSymbolNo == 40)
    8872               0 :       nOGRStyle = 3;
    8873               0 :     else if (m_sSymbolDef.nSymbolNo == 41)
    8874               0 :       nOGRStyle = 9;
    8875               0 :     else if (m_sSymbolDef.nSymbolNo == 42)
    8876               0 :       nOGRStyle = 7;
    8877               0 :     else if (m_sSymbolDef.nSymbolNo == 43)
    8878                 :     {
    8879               0 :         nAngle = 180;
    8880               0 :         nOGRStyle = 7;
    8881                 :     }
    8882               0 :     else if (m_sSymbolDef.nSymbolNo == 44)
    8883               0 :       nOGRStyle = 6;
    8884               0 :     else if (m_sSymbolDef.nSymbolNo == 45)
    8885               0 :       nOGRStyle = 8;
    8886               0 :     else if (m_sSymbolDef.nSymbolNo == 46)
    8887               0 :       nOGRStyle = 4;
    8888               0 :     else if (m_sSymbolDef.nSymbolNo == 49)
    8889               0 :       nOGRStyle = 1;
    8890               0 :     else if (m_sSymbolDef.nSymbolNo == 50)
    8891               0 :       nOGRStyle = 2;
    8892                 : 
    8893               0 :     nAngle += (int)dfAngle;
    8894                 :     
    8895                 :     pszStyle=CPLSPrintf("SYMBOL(a:%d,c:#%6.6x,s:%dpt,id:\"mapinfo-sym-%d,ogr-sym-%d\")",
    8896                 :                         nAngle,
    8897                 :                         m_sSymbolDef.rgbColor,
    8898                 :                         m_sSymbolDef.nPointSize,
    8899                 :                         m_sSymbolDef.nSymbolNo,
    8900               0 :                         nOGRStyle);
    8901                 :      
    8902               0 :     return pszStyle;
    8903                 :     
    8904                 : }  
    8905                 : 
    8906                 : /**********************************************************************
    8907                 :  *                   ITABFeatureSymbol::SetSymbolFromStyleString()
    8908                 :  *
    8909                 :  *  Set all Symbol var from a StyleString. Use StyleMgr to do so.
    8910                 :  **********************************************************************/
    8911               0 : void ITABFeatureSymbol::SetSymbolFromStyleString(const char *pszStyleString)
    8912                 : {
    8913                 :     int numParts, i;
    8914                 :     GBool bIsNull;
    8915                 : 
    8916                 :     const char *pszSymbolId;
    8917                 :     int nSymbolId;
    8918                 : 
    8919                 :     const char *pszSymbolColor;
    8920                 :     int nSymbolColor;
    8921                 : 
    8922                 :     double dSymbolSize;
    8923                 : 
    8924                 :     // Use the Style Manager to retreive all the information we need.
    8925               0 :     OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
    8926                 :     OGRStyleTool *poStylePart;
    8927                 : 
    8928                 :     // Init the StyleMgr with the StyleString.
    8929               0 :     poStyleMgr->InitStyleString(pszStyleString);
    8930                 : 
    8931                 :     // Retreive the Symbol info.
    8932               0 :     numParts = poStyleMgr->GetPartCount();
    8933               0 :     for(i=0; i<numParts; i++)
    8934                 :     {
    8935               0 :         poStylePart = poStyleMgr->GetPart(i);
    8936                 : 
    8937               0 :         if(poStylePart->GetType() == OGRSTCSymbol)
    8938                 :         {
    8939               0 :             break;
    8940                 :         }
    8941                 :         else
    8942                 :         {
    8943               0 :             delete poStylePart;
    8944               0 :             poStylePart = NULL;
    8945                 :         }
    8946                 :     }
    8947                 : 
    8948                 :     // If the no Symbol found, do nothing.
    8949               0 :     if(i >= numParts)
    8950                 :     {
    8951               0 :         delete poStyleMgr;
    8952               0 :         return;
    8953                 :     }
    8954                 : 
    8955               0 :     OGRStyleSymbol *poSymbolStyle = (OGRStyleSymbol*)poStylePart;
    8956                 : 
    8957                 :     // With Symbol, we always want to output points
    8958                 :     //
    8959                 :     // It's very important to set the output unit of the feature.
    8960                 :     // The default value is meter. If we don't do it all numerical values 
    8961                 :     // will be assumed to be converted from the input unit to meter when we 
    8962                 :     // will get them via GetParam...() functions.
    8963                 :     // See OGRStyleTool::Parse() for more details.
    8964               0 :     poSymbolStyle->SetUnit(OGRSTUPoints, (72.0 * 39.37));
    8965                 : 
    8966                 :     // Set the Symbol Id (SymbolNo)
    8967               0 :     pszSymbolId = poSymbolStyle->Id(bIsNull);
    8968               0 :     if(bIsNull) pszSymbolId = NULL;
    8969                 : 
    8970               0 :     if(pszSymbolId &&  
    8971                 :        (strstr(pszSymbolId, "mapinfo-sym-") || 
    8972                 :         strstr(pszSymbolId, "ogr-sym-")) )
    8973                 :     {
    8974               0 :         if(strstr(pszSymbolId, "mapinfo-sym-"))
    8975                 :         {
    8976               0 :             nSymbolId = atoi(pszSymbolId+12);
    8977               0 :             SetSymbolNo((GByte)nSymbolId);
    8978                 :         }
    8979               0 :         else if(strstr(pszSymbolId, "ogr-sym-"))
    8980                 :         {
    8981               0 :             nSymbolId = atoi(pszSymbolId+8);
    8982                 : 
    8983                 :             // The OGR symbol is not the MapInfo one
    8984                 :             // Here's some mapping
    8985               0 :             switch (nSymbolId)
    8986                 :             {
    8987                 :               case 0:
    8988               0 :                 SetSymbolNo(31);
    8989               0 :                 break;
    8990                 :               case 1:
    8991               0 :                 SetSymbolNo(49);
    8992               0 :                 break;
    8993                 :               case 2:
    8994               0 :                 SetSymbolNo(50);
    8995               0 :                 break;
    8996                 :               case 3:
    8997               0 :                 SetSymbolNo(40);
    8998               0 :                 break;
    8999                 :               case 4:
    9000               0 :                 SetSymbolNo(34);
    9001               0 :                 break;
    9002                 :               case 5:
    9003               0 :                 SetSymbolNo(38);
    9004               0 :                 break;
    9005                 :               case 6:
    9006               0 :                 SetSymbolNo(32);
    9007               0 :                 break;
    9008                 :               case 7:
    9009               0 :                 SetSymbolNo(42);
    9010               0 :                 break;
    9011                 :               case 8:
    9012               0 :                 SetSymbolNo(36);
    9013               0 :                 break;
    9014                 :               case 9:
    9015               0 :                 SetSymbolNo(41);
    9016               0 :                 break;
    9017                 :               case 10:
    9018               0 :                 SetSymbolNo(35);
    9019                 :                 break;
    9020                 :             }
    9021                 :         }
    9022                 :     }
    9023                 : 
    9024                 :     // Set SymbolSize
    9025               0 :     dSymbolSize = poSymbolStyle->Size(bIsNull);
    9026               0 :     if(dSymbolSize)
    9027                 :     {
    9028               0 :         SetSymbolSize((GInt16)dSymbolSize);
    9029                 :     }
    9030                 : 
    9031                 :     // Set Symbol Color
    9032               0 :     pszSymbolColor = poSymbolStyle->Color(bIsNull);
    9033               0 :     if(pszSymbolColor)
    9034                 :     {
    9035               0 :         if(pszSymbolColor[0] == '#')
    9036               0 :             pszSymbolColor++;
    9037               0 :         nSymbolColor = strtol(pszSymbolColor, NULL, 16);
    9038               0 :         SetSymbolColor((GInt32)nSymbolColor);
    9039                 :     }
    9040                 : 
    9041               0 :     delete poStyleMgr;
    9042               0 :     delete poStylePart;
    9043                 :     
    9044               0 :     return;
    9045                 : }  
    9046                 : 
    9047                 : /**********************************************************************
    9048                 :  *                   ITABFeatureSymbol::DumpSymbolDef()
    9049                 :  *
    9050                 :  * Dump Symbol definition information.
    9051                 :  **********************************************************************/
    9052               0 : void ITABFeatureSymbol::DumpSymbolDef(FILE *fpOut /*=NULL*/)
    9053                 : {
    9054               0 :     if (fpOut == NULL)
    9055               0 :         fpOut = stdout;
    9056                 : 
    9057               0 :     fprintf(fpOut, "  m_nSymbolDefIndex       = %d\n", m_nSymbolDefIndex);
    9058               0 :     fprintf(fpOut, "  m_sSymbolDef.nRefCount  = %d\n", m_sSymbolDef.nRefCount);
    9059               0 :     fprintf(fpOut, "  m_sSymbolDef.nSymbolNo  = %d\n", m_sSymbolDef.nSymbolNo);
    9060               0 :     fprintf(fpOut, "  m_sSymbolDef.nPointSize = %d\n",m_sSymbolDef.nPointSize);
    9061                 :     fprintf(fpOut, "  m_sSymbolDef._unknown_  = %d\n", 
    9062               0 :                                             (int)m_sSymbolDef._nUnknownValue_);
    9063                 :     fprintf(fpOut, "  m_sSymbolDef.rgbColor   = 0x%6.6x (%d)\n",
    9064               0 :                                 m_sSymbolDef.rgbColor, m_sSymbolDef.rgbColor);
    9065                 : 
    9066               0 :     fflush(fpOut);
    9067               0 : }

Generated by: LCOV version 1.7