1 /**********************************************************************
2  * $Id: mitab_feature_mif.cpp,v 1.39 2010-09-07 16:07:53 aboudreault Exp $
3  *
4  * Name:     mitab_feature.cpp
5  * Project:  MapInfo TAB Read/Write library
6  * Language: C++
7  * Purpose:  Implementation of R/W Fcts for (Mid/Mif) in feature classes
8  *           specific to MapInfo files.
9  * Author:   Stephane Villeneuve, stephane.v@videotron.ca
10  *
11  **********************************************************************
12  * Copyright (c) 1999-2002, Stephane Villeneuve
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  **********************************************************************
32  *
33  * $Log: mitab_feature_mif.cpp,v $
34  * Revision 1.39  2010-09-07 16:07:53  aboudreault
35  * Added the use of OGRGeometryFactory::organizePolygons for mif features
36  *
37  * Revision 1.38  2010-07-07 19:00:15  aboudreault
38  * Cleanup Win32 Compile Warnings (GDAL bug #2930)
39  *
40  * Revision 1.37  2008-12-17 14:55:20  aboudreault
41  * Fixed mitab mif/mid importer fails when a Text geometry have an empty
42  * text value (bug 1978)
43  *
44  * Revision 1.36  2008-11-27 20:50:22  aboudreault
45  * Improved support for OGR date/time types. New Read/Write methods (bug 1948)
46  * Added support of OGR date/time types for MIF features.
47  *
48  * Revision 1.35  2008/09/23 14:56:03  aboudreault
49  * Fixed an error related to the " character when converting mif to tab file.
50  *
51  * Revision 1.34  2008/09/23 13:45:03  aboudreault
52  * Fixed bug with the characters ",\n in the tab2tab application. (bug 1945)
53  *
54  * Revision 1.33  2008/02/01 20:30:59  dmorissette
55  * Use %.15g instead of %.16g as number precision in .MIF output
56  *
57  * Revision 1.32  2007/06/07 20:27:21  dmorissette
58  * Fixed memory leaks when reading multipoint objects from .MIF files
59  *
60  * Revision 1.31  2006/01/27 13:44:44  fwarmerdam
61  * fixed Mills.mif reading, crash at file end
62  *
63  * Revision 1.30  2006/01/26 21:26:36  fwarmerdam
64  * fixed bug with multi character delimeters in .mid file
65  *
66  * Revision 1.29  2005/10/04 19:36:10  dmorissette
67  * Added support for reading collections from MIF files (bug 1126)
68  *
69  * Revision 1.28  2005/10/04 15:44:31  dmorissette
70  * First round of support for Collection objects. Currently supports reading
71  * from .TAB/.MAP and writing to .MIF. Still lacks symbol support and write
72  * support. (Based in part on patch and docs from Jim Hope, bug 1126)
73  *
74  * Revision 1.27  2005/10/04 15:35:52  dmorissette
75  * Fixed an instance of hardcoded delimiter (",") in WriteRecordToMIDFile()
76  * (patch by KB Kieron, bug 1126)
77  *
78  * Revision 1.26  2005/07/14 16:15:05  jlacroix
79  * \n and \ are now unescaped internally.
80  *
81  * Revision 1.25  2003/12/19 07:52:34  fwarmerdam
82  * write 3d as 2d
83  *
84  * Revision 1.24  2002/11/27 22:51:52  daniel
85  * Bug 1631:Do not produce an error if .mid data records end with a stray ','
86  * Treat tabs (\t) as a blank space delimiter when reading .mif coordinates
87  *
88  * Revision 1.23  2002/10/29 21:09:20  warmerda
89  * Ensure that a blank line in a mid file is treated as one field containing
90  * an empty string.
91  *
92  * Revision 1.22  2002/04/26 14:16:49  julien
93  * Finishing the implementation of Multipoint (support for MIF)
94  *
95  * Revision 1.21  2002/03/26 01:48:40  daniel
96  * Added Multipoint object type (V650)
97  *
98  * Revision 1.20  2002/01/23 20:31:21  daniel
99  * Fixed warning produced by CPLAssert() in non-DEBUG mode.
100  *
101  * Revision 1.19  2001/06/25 01:50:42  daniel
102  * Fixed MIF Text object output: negative text angles were lost.  Also use
103  * TABText::SetTextAngle() when reading MIF instead of setting class members
104  * directly so that negative angles get converted to the [0..360] range.
105  *
106  * Revision 1.18  2001/02/28 07:15:09  daniel
107  * Added support for text label line end point
108  *
109  * Revision 1.17  2001/01/22 16:03:58  warmerda
110  * expanded tabs
111  *
112  * Revision 1.16  2000/10/03 19:29:51  daniel
113  * Include OGR StyleString stuff (implemented by Stephane)
114  *
115  * Revision 1.15  2000/09/28 16:39:44  warmerda
116  * avoid warnings for unused, and unitialized variables
117  *
118  * Revision 1.14  2000/09/19 17:23:53  daniel
119  * Maintain and/or compute valid region and polyline center/label point
120  *
121  * Revision 1.13  2000/03/27 03:33:45  daniel
122  * Treat SYMBOL line as optional when reading TABPoint
123  *
124  * Revision 1.12  2000/02/28 16:56:32  daniel
125  * Support pen width in points (width values 11 to 2047)
126  *
127  * Revision 1.11  2000/01/15 22:30:44  daniel
128  * Switch to MIT/X-Consortium OpenSource license
129  *
130  * Revision 1.10  2000/01/14 23:51:37  daniel
131  * Fixed handling of "\n" in TABText strings... now the external interface
132  * of the lib returns and expects escaped "\"+"n" as described in MIF specs
133  *
134  * Revision 1.9  1999/12/19 17:37:14  daniel
135  * Fixed memory leaks
136  *
137  * Revision 1.8  1999/12/19 01:02:50  stephane
138  * Add a test on the CENTER information
139  *
140  * Revision 1.7  1999/12/18 23:23:23  stephane
141  * Change the format of the output double from %g to %.16g
142  *
143  * Revision 1.6  1999/12/18 08:22:57  daniel
144  * Removed stray break statement in PLINE MULTIPLE write code
145  *
146  * Revision 1.5  1999/12/18 07:21:30  daniel
147  * Fixed test on geometry type when writing OGRMultiLineStrings
148  *
149  * Revision 1.4  1999/12/18 07:11:57  daniel
150  * Return regions as OGRMultiPolygons instead of multiple rings OGRPolygons
151  *
152  * Revision 1.3  1999/12/16 17:16:44  daniel
153  * Use addRing/GeometryDirectly() (prevents leak), and rounded rectangles
154  * always return real corner radius from file even if it is bigger than MBR
155  *
156  * Revision 1.2  1999/11/11 01:22:05  stephane
157  * Remove DebugFeature call, Point Reading error, add IsValidFeature() to
158  * test correctly if we are on a feature
159  *
160  * Revision 1.1  1999/11/08 19:20:30  stephane
161  * First version
162  *
163  * Revision 1.1  1999/11/08 04:16:07  stephane
164  * First Revision
165  *
166  *
167  **********************************************************************/
168 
169 #include "mitab.h"
170 #include "mitab_utils.h"
171 #include <ctype.h>
172 
173 /*=====================================================================
174  *                      class TABFeature
175  *====================================================================*/
176 
177 /************************************************************************/
178 /*                            MIDTokenize()                             */
179 /*                                                                      */
180 /*      We implement a special tokenize function so we can handle       */
181 /*      multibyte delimeters (ie. MITAB bug 1266).                      */
182 /*                                                                      */
183 /*      http://bugzilla.maptools.org/show_bug.cgi?id=1266               */
184 /************************************************************************/
MIDTokenize(const char * pszLine,const char * pszDelim)185 static char **MIDTokenize( const char *pszLine, const char *pszDelim )
186 
187 {
188     char **papszResult = NULL;
189     int iChar, iTokenChar = 0, bInQuotes = FALSE;
190     char *pszToken = (char *) CPLMalloc(strlen(pszLine)+1);
191     int nDelimLen = strlen(pszDelim);
192 
193     for( iChar = 0; pszLine[iChar] != '\0'; iChar++ )
194     {
195         if( bInQuotes && pszLine[iChar] == '"' && pszLine[iChar+1] == '"' )
196         {
197             pszToken[iTokenChar++] = '"';
198             iChar++;
199         }
200         else if( pszLine[iChar] == '"' )
201         {
202             bInQuotes = !bInQuotes;
203         }
204         else if( !bInQuotes && strncmp(pszLine+iChar,pszDelim,nDelimLen) == 0 )
205         {
206             pszToken[iTokenChar++] = '\0';
207             papszResult = CSLAddString( papszResult, pszToken );
208 
209             iChar += strlen(pszDelim) - 1;
210             iTokenChar = 0;
211         }
212         else
213         {
214             pszToken[iTokenChar++] = pszLine[iChar];
215         }
216     }
217 
218     pszToken[iTokenChar++] = '\0';
219     papszResult = CSLAddString( papszResult, pszToken );
220 
221     CPLFree( pszToken );
222 
223     return papszResult;
224 }
225 
226 /**********************************************************************
227  *                   TABFeature::ReadRecordFromMIDFile()
228  *
229  *  This method is used to read the Record (Attributs) for all type of
230  *  feature included in a mid/mif file.
231  *
232  * Returns 0 on success, -1 on error, in which case CPLError() will have
233  * been called.
234  **********************************************************************/
ReadRecordFromMIDFile(MIDDATAFile * fp)235 int TABFeature::ReadRecordFromMIDFile(MIDDATAFile *fp)
236 {
237     const char       *pszLine;
238     char            **papszToken;
239     int               nFields,i;
240     OGRFieldDefn        *poFDefn = NULL;
241 #ifdef MITAB_USE_OFTDATETIME
242     int nYear, nMonth, nDay, nHour, nMin, nSec, nMS, nTZFlag;
243     nYear = nMonth = nDay = nHour = nMin = nSec = nMS = nTZFlag = 0;
244 #endif
245 
246     nFields = GetFieldCount();
247 
248     pszLine = fp->GetLastLine();
249 
250     if (pszLine == NULL)
251     {
252         CPLError(CE_Failure, CPLE_FileIO,
253                "Unexpected EOF while reading attribute record from MID file.");
254         return -1;
255     }
256 
257     papszToken = MIDTokenize( pszLine, fp->GetDelimiter() );
258 
259     // Ensure that a blank line in a mid file is treated as one field
260     // containing an empty string.
261     if( nFields == 1 && CSLCount(papszToken) == 0 && pszLine[0] == '\0' )
262         papszToken = CSLAddString(papszToken,"");
263 
264     // Make sure we found at least the expected number of field values.
265     // Note that it is possible to have a stray delimiter at the end of
266     // the line (mif/mid files from Geomedia), so don't produce an error
267     // if we find more tokens than expected.
268     if (CSLCount(papszToken) < nFields)
269     {
270         CSLDestroy(papszToken);
271         return -1;
272     }
273 
274     for (i=0;i<nFields;i++)
275     {
276         poFDefn = GetFieldDefnRef(i);
277         switch(poFDefn->GetType())
278         {
279 #ifdef MITAB_USE_OFTDATETIME
280             case OFTTime:
281             {
282                 if (strlen(papszToken[i]) == 9)
283                 {
284                     sscanf(papszToken[i],"%2d%2d%2d%3d",&nHour, &nMin, &nSec, &nMS);
285                     SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec + nMS / 1000.0f,
286                              0);
287                 }
288                 break;
289             }
290             case OFTDate:
291             {
292                 if (strlen(papszToken[i]) == 8)
293                 {
294                     sscanf(papszToken[i], "%4d%2d%2d", &nYear, &nMonth, &nDay);
295                     SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
296                 }
297                 break;
298             }
299             case OFTDateTime:
300             {
301                 if (strlen(papszToken[i]) == 17)
302                 {
303                     sscanf(papszToken[i], "%4d%2d%2d%2d%2d%2d%3d",
304                            &nYear, &nMonth, &nDay, &nHour, &nMin, &nSec, &nMS);
305                     SetField(i, nYear, nMonth, nDay, nHour, nMin, nSec + nMS / 1000.0f,
306                              0);
307                 }
308                 break;
309             }
310 #endif
311 
312           default:
313              SetField(i,papszToken[i]);
314        }
315     }
316 
317     fp->GetLine();
318 
319     CSLDestroy(papszToken);
320 
321     return 0;
322 }
323 
324 /**********************************************************************
325  *                   TABFeature::WriteRecordToMIDFile()
326  *
327  *  This methode is used to write the Record (Attributs) for all type
328  *  of feature included in a mid file.
329  *
330  *  Return 0 on success, -1 on error
331  **********************************************************************/
WriteRecordToMIDFile(MIDDATAFile * fp)332 int TABFeature::WriteRecordToMIDFile(MIDDATAFile *fp)
333 {
334     int                  iField, numFields;
335     OGRFieldDefn        *poFDefn = NULL;
336 #ifdef MITAB_USE_OFTDATETIME
337     char szBuffer[20];
338     int nYear, nMonth, nDay, nHour, nMin, nMS, nTZFlag;
339     nYear = nMonth = nDay = nHour = nMin = nMS = nTZFlag = 0;
340     float fSec = 0.0f;
341 #endif
342 
343     CPLAssert(fp);
344 
345     const char *delimiter = fp->GetDelimiter();
346 
347     numFields = GetFieldCount();
348 
349     for(iField=0; iField<numFields; iField++)
350     {
351         if (iField != 0)
352           fp->WriteLine("%s", delimiter);
353         poFDefn = GetFieldDefnRef( iField );
354 
355         switch(poFDefn->GetType())
356         {
357           case OFTString:
358           {
359             int nStringLen = strlen(GetFieldAsString(iField));
360             char *pszString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
361             strcpy(pszString, GetFieldAsString(iField));
362             char *pszWorkString = (char*)CPLMalloc((2*(nStringLen)+1)*sizeof(char));
363             int j = 0;
364             for (int i =0; i < nStringLen; ++i)
365             {
366               if (pszString[i] == '"')
367               {
368                 pszWorkString[j] = pszString[i];
369                 ++j;
370                 pszWorkString[j] = pszString[i];
371               }
372               else if (pszString[i] == '\n')
373               {
374                 pszWorkString[j] = '\\';
375                 ++j;
376                 pszWorkString[j] = 'n';
377               }
378               else
379                 pszWorkString[j] = pszString[i];
380               ++j;
381             }
382 
383             pszWorkString[j] = '\0';
384             CPLFree(pszString);
385             pszString = (char*)CPLMalloc((strlen(pszWorkString)+1)*sizeof(char));
386             strcpy(pszString, pszWorkString);
387             CPLFree(pszWorkString);
388             fp->WriteLine("\"%s\"",pszString);
389             CPLFree(pszString);
390             break;
391           }
392 #ifdef MITAB_USE_OFTDATETIME
393           case OFTTime:
394           {
395               if (!IsFieldSet(iField))
396               {
397                  szBuffer[0] = '\0';
398               }
399               else
400               {
401                   GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
402                                      &nHour, &nMin, &fSec, &nTZFlag);
403                   sprintf(szBuffer, "%2.2d%2.2d%2.2d%3.3d", nHour, nMin,
404                           (int)fSec, OGR_GET_MS(fSec));
405               }
406               fp->WriteLine("%s",szBuffer);
407               break;
408           }
409           case OFTDate:
410           {
411               if (!IsFieldSet(iField))
412               {
413                  szBuffer[0] = '\0';
414               }
415               else
416               {
417                   GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
418                                      &nHour, &nMin, &fSec, &nTZFlag);
419                   sprintf(szBuffer, "%4.4d%2.2d%2.2d", nYear, nMonth, nDay);
420               }
421               fp->WriteLine("%s",szBuffer);
422               break;
423           }
424           case OFTDateTime:
425           {
426               if (!IsFieldSet(iField))
427               {
428                  szBuffer[0] = '\0';
429               }
430               else
431               {
432                   GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay,
433                                      &nHour, &nMin, &fSec, &nTZFlag);
434                   sprintf(szBuffer, "%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d%3.3d",
435                           nYear, nMonth, nDay, nHour, nMin,
436                           (int)fSec, OGR_GET_MS(fSec));
437               }
438               fp->WriteLine("%s",szBuffer);
439               break;
440           }
441 #endif
442           default:
443             fp->WriteLine("%s",GetFieldAsString(iField));
444         }
445     }
446 
447     fp->WriteLine("\n");
448 
449     return 0;
450 }
451 
452 /**********************************************************************
453  *                   TABFeature::ReadGeometryFromMIFFile()
454  *
455  * In derived classes, this method should be reimplemented to
456  * fill the geometry and representation (color, etc...) part of the
457  * feature from the contents of the .MAP object pointed to by poMAPFile.
458  *
459  * It is assumed that before calling ReadGeometryFromMAPFile(), poMAPFile
460  * currently points to the beginning of a map object.
461  *
462  * The current implementation does nothing since instances of TABFeature
463  * objects contain no geometry (i.e. TAB_GEOM_NONE).
464  *
465  * Returns 0 on success, -1 on error, in which case CPLError() will have
466  * been called.
467  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)468 int TABFeature::ReadGeometryFromMIFFile(MIDDATAFile *fp)
469 {
470     const char *pszLine;
471 
472     /* Go to the first line of the next feature */
473 
474     while (((pszLine = fp->GetLine()) != NULL) &&
475            fp->IsValidFeature(pszLine) == FALSE)
476       ;
477 
478     return 0;
479 }
480 
481 /**********************************************************************
482  *                   TABFeature::WriteGeometryToMIFFile()
483  *
484  *
485  * In derived classes, this method should be reimplemented to
486  * write the geometry and representation (color, etc...) part of the
487  * feature to the .MAP object pointed to by poMAPFile.
488  *
489  * It is assumed that before calling WriteGeometryToMAPFile(), poMAPFile
490  * currently points to a valid map object.
491  *
492  * The current implementation does nothing since instances of TABFeature
493  * objects contain no geometry.
494  *
495  * Returns 0 on success, -1 on error, in which case CPLError() will have
496  * been called.
497  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)498 int TABFeature::WriteGeometryToMIFFile(MIDDATAFile *fp)
499 {
500     fp->WriteLine("NONE\n");
501     return 0;
502 }
503 
504 /**********************************************************************
505  *
506  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)507 int TABPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
508 {
509     OGRGeometry         *poGeometry;
510 
511     char               **papszToken;
512     const char *pszLine;
513     double dfX,dfY;
514     papszToken = CSLTokenizeString2(fp->GetSavedLine(),
515                                     " \t", CSLT_HONOURSTRINGS);
516 
517     if (CSLCount(papszToken) !=3)
518     {
519         CSLDestroy(papszToken);
520         return -1;
521     }
522 
523     dfX = fp->GetXTrans(CPLAtof(papszToken[1]));
524     dfY = fp->GetYTrans(CPLAtof(papszToken[2]));
525 
526     CSLDestroy(papszToken);
527     papszToken = NULL;
528 
529     // Read optional SYMBOL line...
530     pszLine = fp->GetLastLine();
531     if( pszLine != NULL )
532         papszToken = CSLTokenizeStringComplex(pszLine," ,()\t",
533                                               TRUE,FALSE);
534     if (CSLCount(papszToken) == 4 && EQUAL(papszToken[0], "SYMBOL") )
535     {
536         SetSymbolNo((GInt16)atoi(papszToken[1]));
537         SetSymbolColor((GInt32)atoi(papszToken[2]));
538         SetSymbolSize((GInt16)atoi(papszToken[3]));
539     }
540 
541     CSLDestroy(papszToken);
542     papszToken = NULL;
543 
544     // scan until we reach 1st line of next feature
545     // Since SYMBOL is optional, we have to test IsValidFeature() on that
546     // line as well.
547     while (pszLine && fp->IsValidFeature(pszLine) == FALSE)
548     {
549         pszLine = fp->GetLine();
550     }
551 
552     poGeometry = new OGRPoint(dfX, dfY);
553 
554     SetGeometryDirectly(poGeometry);
555 
556     SetMBR(dfX, dfY, dfX, dfY);
557 
558 
559     return 0;
560 }
561 
562 /**********************************************************************
563  *
564  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)565 int TABPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
566 {
567     OGRGeometry         *poGeom;
568     OGRPoint            *poPoint;
569 
570     /*-----------------------------------------------------------------
571      * Fetch and validate geometry
572      *----------------------------------------------------------------*/
573     poGeom = GetGeometryRef();
574     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
575         poPoint = (OGRPoint*)poGeom;
576     else
577     {
578         CPLError(CE_Failure, CPLE_AssertionFailed,
579                  "TABPoint: Missing or Invalid Geometry!");
580         return -1;
581     }
582 
583     fp->WriteLine("Point %.15g %.15g\n",poPoint->getX(),poPoint->getY());
584     fp->WriteLine("    Symbol (%d,%d,%d)\n",GetSymbolNo(),GetSymbolColor(),
585                   GetSymbolSize());
586 
587     return 0;
588 }
589 
590 /**********************************************************************
591  *
592  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)593 int TABFontPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
594 {
595     OGRGeometry         *poGeometry;
596 
597     char               **papszToken;
598     const char *pszLine;
599     double dfX,dfY;
600     papszToken = CSLTokenizeString2(fp->GetSavedLine(),
601                                     " \t", CSLT_HONOURSTRINGS);
602 
603     if (CSLCount(papszToken) !=3)
604     {
605         CSLDestroy(papszToken);
606         return -1;
607     }
608 
609     dfX = fp->GetXTrans(CPLAtof(papszToken[1]));
610     dfY = fp->GetYTrans(CPLAtof(papszToken[2]));
611 
612     CSLDestroy(papszToken);
613 
614     papszToken = CSLTokenizeStringComplex(fp->GetLastLine()," ,()\t",
615                                           TRUE,FALSE);
616 
617     if (CSLCount(papszToken) !=7)
618     {
619         CSLDestroy(papszToken);
620         return -1;
621     }
622 
623     SetSymbolNo((GInt16)atoi(papszToken[1]));
624     SetSymbolColor((GInt32)atoi(papszToken[2]));
625     SetSymbolSize((GInt16)atoi(papszToken[3]));
626     SetFontName(papszToken[4]);
627     SetFontStyleMIFValue(atoi(papszToken[5]));
628     SetSymbolAngle(CPLAtof(papszToken[6]));
629 
630     CSLDestroy(papszToken);
631 
632     poGeometry = new OGRPoint(dfX, dfY);
633 
634     SetGeometryDirectly(poGeometry);
635 
636     SetMBR(dfX, dfY, dfX, dfY);
637 
638     /* Go to the first line of the next feature */
639 
640     while (((pszLine = fp->GetLine()) != NULL) &&
641            fp->IsValidFeature(pszLine) == FALSE)
642       ;
643     return 0;
644 }
645 
646 /**********************************************************************
647  *
648  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)649 int TABFontPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
650 {
651     OGRGeometry         *poGeom;
652     OGRPoint            *poPoint;
653 
654     /*-----------------------------------------------------------------
655      * Fetch and validate geometry
656      *----------------------------------------------------------------*/
657     poGeom = GetGeometryRef();
658     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
659         poPoint = (OGRPoint*)poGeom;
660     else
661     {
662         CPLError(CE_Failure, CPLE_AssertionFailed,
663                  "TABFontPoint: Missing or Invalid Geometry!");
664         return -1;
665     }
666 
667     fp->WriteLine("Point %.15g %.15g\n",poPoint->getX(),poPoint->getY());
668     fp->WriteLine("    Symbol (%d,%d,%d,\"%s\",%d,%.15g)\n",
669                   GetSymbolNo(),GetSymbolColor(),
670                   GetSymbolSize(),GetFontNameRef(),GetFontStyleMIFValue(),
671                   GetSymbolAngle());
672 
673     return 0;
674 }
675 
676 /**********************************************************************
677  *
678  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)679 int TABCustomPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
680 {
681     OGRGeometry         *poGeometry;
682 
683     char               **papszToken;
684     const char          *pszLine;
685     double               dfX,dfY;
686 
687     papszToken = CSLTokenizeString2(fp->GetSavedLine(),
688                                     " \t", CSLT_HONOURSTRINGS);
689 
690 
691     if (CSLCount(papszToken) !=3)
692     {
693         CSLDestroy(papszToken);
694         return -1;
695     }
696 
697     dfX = fp->GetXTrans(CPLAtof(papszToken[1]));
698     dfY = fp->GetYTrans(CPLAtof(papszToken[2]));
699 
700     CSLDestroy(papszToken);
701 
702     papszToken = CSLTokenizeStringComplex(fp->GetLastLine()," ,()\t",
703                                           TRUE,FALSE);
704     if (CSLCount(papszToken) !=5)
705     {
706 
707         CSLDestroy(papszToken);
708         return -1;
709     }
710 
711     SetFontName(papszToken[1]);
712     SetSymbolColor((GInt32)atoi(papszToken[2]));
713     SetSymbolSize((GInt16)atoi(papszToken[3]));
714     m_nCustomStyle = (GByte)atoi(papszToken[4]);
715 
716     CSLDestroy(papszToken);
717 
718     poGeometry = new OGRPoint(dfX, dfY);
719 
720     SetGeometryDirectly(poGeometry);
721 
722     SetMBR(dfX, dfY, dfX, dfY);
723 
724     /* Go to the first line of the next feature */
725 
726     while (((pszLine = fp->GetLine()) != NULL) &&
727            fp->IsValidFeature(pszLine) == FALSE)
728       ;
729 
730     return 0;
731 
732 }
733 
734 /**********************************************************************
735  *
736  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)737 int TABCustomPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
738 {
739     OGRGeometry         *poGeom;
740     OGRPoint            *poPoint;
741 
742     /*-----------------------------------------------------------------
743      * Fetch and validate geometry
744      *----------------------------------------------------------------*/
745     poGeom = GetGeometryRef();
746     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
747         poPoint = (OGRPoint*)poGeom;
748     else
749     {
750         CPLError(CE_Failure, CPLE_AssertionFailed,
751                  "TABCustomPoint: Missing or Invalid Geometry!");
752         return -1;
753     }
754 
755 
756     fp->WriteLine("Point %.15g %.15g\n",poPoint->getX(),poPoint->getY());
757     fp->WriteLine("    Symbol (\"%s\",%d,%d,%d)\n",GetFontNameRef(),
758                   GetSymbolColor(), GetSymbolSize(),m_nCustomStyle);
759 
760     return 0;
761 }
762 
763 /**********************************************************************
764  *
765  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)766 int TABPolyline::ReadGeometryFromMIFFile(MIDDATAFile *fp)
767 {
768     const char          *pszLine;
769     char               **papszToken;
770     OGRLineString       *poLine;
771     OGRMultiLineString  *poMultiLine;
772     GBool                bMultiple = FALSE;
773     int                  nNumPoints,nNumSec=0,i,j;
774     OGREnvelope          sEnvelope;
775 
776 
777     papszToken = CSLTokenizeString2(fp->GetLastLine(),
778                                     " \t", CSLT_HONOURSTRINGS);
779 
780     if (CSLCount(papszToken) < 1)
781     {
782         CSLDestroy(papszToken);
783         return -1;
784     }
785 
786     if (EQUALN(papszToken[0],"LINE",4))
787     {
788         if (CSLCount(papszToken) != 5)
789           return -1;
790 
791         poLine = new OGRLineString();
792         poLine->setNumPoints(2);
793         poLine->setPoint(0, fp->GetXTrans(CPLAtof(papszToken[1])),
794                          fp->GetYTrans(CPLAtof(papszToken[2])));
795         poLine->setPoint(1, fp->GetXTrans(CPLAtof(papszToken[3])),
796                          fp->GetYTrans(CPLAtof(papszToken[4])));
797         SetGeometryDirectly(poLine);
798         poLine->getEnvelope(&sEnvelope);
799         SetMBR(sEnvelope.MinX, sEnvelope.MinY,sEnvelope.MaxX,sEnvelope.MaxY);
800     }
801     else if (EQUALN(papszToken[0],"PLINE",5))
802     {
803         switch (CSLCount(papszToken))
804         {
805           case 1:
806             bMultiple = FALSE;
807             pszLine = fp->GetLine();
808             nNumPoints = atoi(pszLine);
809             break;
810           case 2:
811             bMultiple = FALSE;
812             nNumPoints = atoi(papszToken[1]);
813             break;
814           case 3:
815             if (EQUALN(papszToken[1],"MULTIPLE",8))
816             {
817                 bMultiple = TRUE;
818                 nNumSec = atoi(papszToken[2]);
819                 pszLine = fp->GetLine();
820                 nNumPoints = atoi(pszLine);
821                 break;
822             }
823             else
824             {
825               CSLDestroy(papszToken);
826               return -1;
827             }
828             break;
829           case 4:
830             if (EQUALN(papszToken[1],"MULTIPLE",8))
831             {
832                 bMultiple = TRUE;
833                 nNumSec = atoi(papszToken[2]);
834                 nNumPoints = atoi(papszToken[3]);
835                 break;
836             }
837             else
838             {
839                 CSLDestroy(papszToken);
840                 return -1;
841             }
842             break;
843           default:
844             CSLDestroy(papszToken);
845             return -1;
846             break;
847         }
848 
849         if (bMultiple)
850         {
851             poMultiLine = new OGRMultiLineString();
852             for (j=0;j<nNumSec;j++)
853             {
854                 poLine = new OGRLineString();
855                 if (j != 0)
856                     nNumPoints = atoi(fp->GetLine());
857                 if (nNumPoints < 2)
858                 {
859                     CPLError(CE_Failure, CPLE_FileIO,
860                              "Invalid number of vertices (%d) in PLINE "
861                              "MULTIPLE segment.", nNumPoints);
862                     return -1;
863                 }
864                 poLine->setNumPoints(nNumPoints);
865                 for (i=0;i<nNumPoints;i++)
866                 {
867                     CSLDestroy(papszToken);
868                     papszToken = CSLTokenizeString2(fp->GetLine(),
869                                                     " \t", CSLT_HONOURSTRINGS);
870                     poLine->setPoint(i,fp->GetXTrans(CPLAtof(papszToken[0])),
871                                      fp->GetYTrans(CPLAtof(papszToken[1])));
872                 }
873                 if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
874                 {
875                     CPLAssert(FALSE); // Just in case OGR is modified
876                 }
877             }
878             if (SetGeometryDirectly(poMultiLine) != OGRERR_NONE)
879             {
880                 CPLAssert(FALSE); // Just in case OGR is modified
881             }
882             poMultiLine->getEnvelope(&sEnvelope);
883             SetMBR(sEnvelope.MinX, sEnvelope.MinY,
884                    sEnvelope.MaxX,sEnvelope.MaxY);
885         }
886         else
887         {
888             poLine = new OGRLineString();
889             poLine->setNumPoints(nNumPoints);
890             for (i=0;i<nNumPoints;i++)
891             {
892                 CSLDestroy(papszToken);
893                 papszToken = CSLTokenizeString2(fp->GetLine(),
894                                                 " \t", CSLT_HONOURSTRINGS);
895 
896                 if (CSLCount(papszToken) != 2)
897                   return -1;
898                 poLine->setPoint(i,fp->GetXTrans(CPLAtof(papszToken[0])),
899                                  fp->GetYTrans(CPLAtof(papszToken[1])));
900             }
901             SetGeometryDirectly(poLine);
902             poLine->getEnvelope(&sEnvelope);
903             SetMBR(sEnvelope.MinX, sEnvelope.MinY,
904                    sEnvelope.MaxX,sEnvelope.MaxY);
905         }
906     }
907 
908     CSLDestroy(papszToken);
909     papszToken = NULL;
910 
911     while (((pszLine = fp->GetLine()) != NULL) &&
912            fp->IsValidFeature(pszLine) == FALSE)
913     {
914         papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
915                                               TRUE,FALSE);
916 
917         if (CSLCount(papszToken) >= 1)
918         {
919             if (EQUALN(papszToken[0],"PEN",3))
920             {
921 
922                 if (CSLCount(papszToken) == 4)
923                 {
924                     SetPenWidthMIF(atoi(papszToken[1]));
925                     SetPenPattern((GByte)atoi(papszToken[2]));
926                     SetPenColor((GInt32)atoi(papszToken[3]));
927                 }
928 
929             }
930             else if (EQUALN(papszToken[0],"SMOOTH",6))
931             {
932                 m_bSmooth = TRUE;
933             }
934         }
935         CSLDestroy(papszToken);
936     }
937     return 0;
938 }
939 
940 /**********************************************************************
941  *
942  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)943 int TABPolyline::WriteGeometryToMIFFile(MIDDATAFile *fp)
944 {
945     OGRGeometry   *poGeom;
946     OGRMultiLineString *poMultiLine = NULL;
947     OGRLineString *poLine = NULL;
948     int nNumPoints,i;
949 
950 
951     /*-----------------------------------------------------------------
952      * Fetch and validate geometry
953      *----------------------------------------------------------------*/
954     poGeom = GetGeometryRef();
955     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
956     {
957         /*-------------------------------------------------------------
958          * Simple polyline
959          *------------------------------------------------------------*/
960         poLine = (OGRLineString*)poGeom;
961         nNumPoints = poLine->getNumPoints();
962         if (nNumPoints == 2)
963         {
964             fp->WriteLine("Line %.15g %.15g %.15g %.15g\n",poLine->getX(0),poLine->getY(0),
965                           poLine->getX(1),poLine->getY(1));
966         }
967         else
968         {
969 
970             fp->WriteLine("Pline %d\n",nNumPoints);
971             for (i=0;i<nNumPoints;i++)
972             {
973                 fp->WriteLine("%.15g %.15g\n",poLine->getX(i),poLine->getY(i));
974             }
975         }
976     }
977     else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
978     {
979         /*-------------------------------------------------------------
980          * Multiple polyline... validate all components
981          *------------------------------------------------------------*/
982         int iLine, numLines;
983         poMultiLine = (OGRMultiLineString*)poGeom;
984         numLines = poMultiLine->getNumGeometries();
985 
986         fp->WriteLine("PLINE MULTIPLE %d\n", numLines);
987 
988         for(iLine=0; iLine < numLines; iLine++)
989         {
990             poGeom = poMultiLine->getGeometryRef(iLine);
991             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
992             {
993                 poLine = (OGRLineString*)poGeom;
994                 nNumPoints = poLine->getNumPoints();
995 
996                 fp->WriteLine("  %d\n",nNumPoints);
997                 for (i=0;i<nNumPoints;i++)
998                 {
999                     fp->WriteLine("%.15g %.15g\n",poLine->getX(i),poLine->getY(i));
1000                 }
1001             }
1002             else
1003             {
1004                 CPLError(CE_Failure, CPLE_AssertionFailed,
1005                          "TABPolyline: Object contains an invalid Geometry!");
1006             }
1007         }
1008     }
1009     else
1010     {
1011         CPLError(CE_Failure, CPLE_AssertionFailed,
1012                  "TABPolyline: Missing or Invalid Geometry!");
1013     }
1014 
1015     if (GetPenPattern())
1016       fp->WriteLine("    Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
1017                     GetPenColor());
1018     if (m_bSmooth)
1019       fp->WriteLine("    Smooth\n");
1020 
1021     return 0;
1022 
1023 }
1024 
1025 /**********************************************************************
1026  *                   TABRegion::ReadGeometryFromMIFFile()
1027  *
1028  * Fill the geometry and representation (color, etc...) part of the
1029  * feature from the contents of the .MIF file
1030  *
1031  * Returns 0 on success, -1 on error, in which case CPLError() will have
1032  * been called.
1033  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)1034 int TABRegion::ReadGeometryFromMIFFile(MIDDATAFile *fp)
1035 {
1036     double               dX, dY;
1037     OGRLinearRing       *poRing;
1038     OGRGeometry         *poGeometry = NULL;
1039     OGRPolygon          **tabPolygons = NULL;
1040     int                  i,iSection, numLineSections=0;
1041     char               **papszToken;
1042     const char          *pszLine;
1043     OGREnvelope          sEnvelope;
1044 
1045     m_bSmooth = FALSE;
1046     /*=============================================================
1047      * REGION (Similar to PLINE MULTIPLE)
1048      *============================================================*/
1049     papszToken = CSLTokenizeString2(fp->GetLastLine(),
1050                                     " \t", CSLT_HONOURSTRINGS);
1051 
1052     if (CSLCount(papszToken) ==2)
1053       numLineSections = atoi(papszToken[1]);
1054     CSLDestroy(papszToken);
1055     papszToken = NULL;
1056 
1057     if (numLineSections > 0)
1058         tabPolygons = new OGRPolygon*[numLineSections];
1059 
1060     for(iSection=0; iSection<numLineSections; iSection++)
1061     {
1062         int     numSectionVertices = 0;
1063 
1064         tabPolygons[iSection] = new OGRPolygon();
1065 
1066         if ((pszLine = fp->GetLine()) != NULL)
1067         {
1068             numSectionVertices = atoi(pszLine);
1069         }
1070 
1071         poRing = new OGRLinearRing();
1072         poRing->setNumPoints(numSectionVertices);
1073 
1074         for(i=0; i<numSectionVertices; i++)
1075         {
1076             pszLine = fp->GetLine();
1077             if (pszLine)
1078             {
1079                 papszToken = CSLTokenizeStringComplex(pszLine," ,\t",
1080                                                       TRUE,FALSE);
1081                 if (CSLCount(papszToken) == 2)
1082                 {
1083                     dX = fp->GetXTrans(CPLAtof(papszToken[0]));
1084                     dY = fp->GetYTrans(CPLAtof(papszToken[1]));
1085                     poRing->setPoint(i, dX, dY);
1086                 }
1087                 CSLDestroy(papszToken);
1088                 papszToken = NULL;
1089             }
1090         }
1091 
1092         poRing->closeRings();
1093 
1094         tabPolygons[iSection]->addRingDirectly(poRing);
1095 
1096         if (numLineSections == 1)
1097             poGeometry = tabPolygons[iSection];
1098 
1099         poRing = NULL;
1100     }
1101 
1102     if (numLineSections > 1)
1103     {
1104         int isValidGeometry;
1105         const char* papszOptions[] = { "METHOD=DEFAULT", NULL };
1106         poGeometry = OGRGeometryFactory::organizePolygons(
1107             (OGRGeometry**)tabPolygons, numLineSections, &isValidGeometry, papszOptions );
1108 
1109         if (!isValidGeometry)
1110         {
1111             CPLError(CE_Warning, CPLE_AppDefined,
1112                      "Geometry of polygon cannot be translated to Simple Geometry. "
1113                      "All polygons will be contained in a multipolygon.\n");
1114         }
1115     }
1116 
1117     if (tabPolygons)
1118         delete[] tabPolygons;
1119 
1120     SetGeometryDirectly(poGeometry);
1121     poGeometry->getEnvelope(&sEnvelope);
1122 
1123     SetMBR(sEnvelope.MinX, sEnvelope.MinY, sEnvelope.MaxX, sEnvelope.MaxY);
1124 
1125     while (((pszLine = fp->GetLine()) != NULL) &&
1126            fp->IsValidFeature(pszLine) == FALSE)
1127     {
1128         papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
1129                                               TRUE,FALSE);
1130 
1131         if (CSLCount(papszToken) > 1)
1132         {
1133             if (EQUALN(papszToken[0],"PEN",3))
1134             {
1135 
1136                 if (CSLCount(papszToken) == 4)
1137                 {
1138                     SetPenWidthMIF(atoi(papszToken[1]));
1139                     SetPenPattern((GByte)atoi(papszToken[2]));
1140                     SetPenColor((GInt32)atoi(papszToken[3]));
1141                 }
1142 
1143             }
1144             else if (EQUALN(papszToken[0],"BRUSH", 5))
1145             {
1146                 if (CSLCount(papszToken) >= 3)
1147                 {
1148                     SetBrushFGColor((GInt32)atoi(papszToken[2]));
1149                     SetBrushPattern((GByte)atoi(papszToken[1]));
1150 
1151                     if (CSLCount(papszToken) == 4)
1152                        SetBrushBGColor(atoi(papszToken[3]));
1153                     else
1154                       SetBrushTransparent(TRUE);
1155                 }
1156 
1157             }
1158             else if (EQUALN(papszToken[0],"CENTER",6))
1159             {
1160                 if (CSLCount(papszToken) == 3)
1161                 {
1162                     SetCenter(fp->GetXTrans(CPLAtof(papszToken[1])),
1163                               fp->GetYTrans(CPLAtof(papszToken[2])) );
1164                 }
1165             }
1166         }
1167         CSLDestroy(papszToken);
1168         papszToken = NULL;
1169     }
1170 
1171 
1172     return 0;
1173 }
1174 
1175 /**********************************************************************
1176  *                   TABRegion::WriteGeometryToMIFFile()
1177  *
1178  * Write the geometry and representation (color, etc...) part of the
1179  * feature to the .MIF file
1180  *
1181  * Returns 0 on success, -1 on error, in which case CPLError() will have
1182  * been called.
1183  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)1184 int TABRegion::WriteGeometryToMIFFile(MIDDATAFile *fp)
1185 {
1186     OGRGeometry         *poGeom;
1187 
1188     poGeom = GetGeometryRef();
1189 
1190     if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
1191                    wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon ) )
1192     {
1193         /*=============================================================
1194          * REGIONs are similar to PLINE MULTIPLE
1195          *
1196          * We accept both OGRPolygons (with one or multiple rings) and
1197          * OGRMultiPolygons as input.
1198          *============================================================*/
1199         int     i, iRing, numRingsTotal, numPoints;
1200 
1201         numRingsTotal = GetNumRings();
1202 
1203         fp->WriteLine("Region %d\n",numRingsTotal);
1204 
1205         for(iRing=0; iRing < numRingsTotal; iRing++)
1206         {
1207             OGRLinearRing       *poRing;
1208 
1209             poRing = GetRingRef(iRing);
1210             if (poRing == NULL)
1211             {
1212                 CPLError(CE_Failure, CPLE_AssertionFailed,
1213                          "TABRegion: Object Geometry contains NULL rings!");
1214                 return -1;
1215             }
1216 
1217             numPoints = poRing->getNumPoints();
1218 
1219             fp->WriteLine("  %d\n",numPoints);
1220             for(i=0; i<numPoints; i++)
1221             {
1222                 fp->WriteLine("%.15g %.15g\n",poRing->getX(i), poRing->getY(i));
1223             }
1224         }
1225 
1226         if (GetPenPattern())
1227           fp->WriteLine("    Pen (%d,%d,%d)\n",
1228                           GetPenWidthMIF(),GetPenPattern(),
1229                           GetPenColor());
1230 
1231 
1232         if (GetBrushPattern())
1233         {
1234             if (GetBrushTransparent() == 0)
1235               fp->WriteLine("    Brush (%d,%d,%d)\n",GetBrushPattern(),
1236                             GetBrushFGColor(),GetBrushBGColor());
1237             else
1238               fp->WriteLine("    Brush (%d,%d)\n",GetBrushPattern(),
1239                             GetBrushFGColor());
1240         }
1241 
1242         if (m_bCenterIsSet)
1243         {
1244             fp->WriteLine("    Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
1245         }
1246 
1247 
1248     }
1249     else
1250     {
1251         CPLError(CE_Failure, CPLE_AssertionFailed,
1252                  "TABRegion: Object contains an invalid Geometry!");
1253         return -1;
1254     }
1255 
1256     return 0;
1257 }
1258 
1259 /**********************************************************************
1260  *
1261  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)1262 int TABRectangle::ReadGeometryFromMIFFile(MIDDATAFile *fp)
1263 {
1264     const char          *pszLine;
1265     char               **papszToken;
1266     double               dXMin, dYMin, dXMax, dYMax;
1267     OGRPolygon          *poPolygon;
1268     OGRLinearRing       *poRing;
1269 
1270     papszToken = CSLTokenizeString2(fp->GetLastLine(),
1271                                     " \t", CSLT_HONOURSTRINGS);
1272 
1273     if (CSLCount(papszToken) <  5)
1274     {
1275         CSLDestroy(papszToken);
1276         return -1;
1277     }
1278 
1279     dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
1280     dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
1281     dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
1282     dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
1283 
1284     /*-----------------------------------------------------------------
1285      * Call SetMBR() and GetMBR() now to make sure that min values are
1286      * really smaller than max values.
1287      *----------------------------------------------------------------*/
1288     SetMBR(dXMin, dYMin, dXMax, dYMax);
1289     GetMBR(dXMin, dYMin, dXMax, dYMax);
1290 
1291     m_bRoundCorners = FALSE;
1292     m_dRoundXRadius  = 0.0;
1293     m_dRoundYRadius  = 0.0;
1294 
1295     if (EQUALN(papszToken[0],"ROUNDRECT",9))
1296     {
1297         m_bRoundCorners = TRUE;
1298         if (CSLCount(papszToken) == 6)
1299           m_dRoundXRadius = m_dRoundYRadius = CPLAtof(papszToken[5])/2.0;
1300         else
1301         {
1302             CSLDestroy(papszToken);
1303             papszToken = CSLTokenizeString2(fp->GetLine(),
1304                                             " \t", CSLT_HONOURSTRINGS);
1305             if (CSLCount(papszToken) !=1 )
1306               m_dRoundXRadius = m_dRoundYRadius = CPLAtof(papszToken[1])/2.0;
1307         }
1308     }
1309     CSLDestroy(papszToken);
1310     papszToken = NULL;
1311 
1312     /*-----------------------------------------------------------------
1313      * Create and fill geometry object
1314      *----------------------------------------------------------------*/
1315 
1316     poPolygon = new OGRPolygon;
1317     poRing = new OGRLinearRing();
1318     if (m_bRoundCorners && m_dRoundXRadius != 0.0 && m_dRoundYRadius != 0.0)
1319     {
1320         /*-------------------------------------------------------------
1321          * For rounded rectangles, we generate arcs with 45 line
1322          * segments for each corner.  We start with lower-left corner
1323          * and proceed counterclockwise
1324          * We also have to make sure that rounding radius is not too
1325          * large for the MBR however, we
1326          * always return the true X/Y radius (not adjusted) since this
1327          * is the way MapInfo seems to do it when a radius bigger than
1328          * the MBR is passed from TBA to MIF.
1329          *------------------------------------------------------------*/
1330         double dXRadius = MIN(m_dRoundXRadius, (dXMax-dXMin)/2.0);
1331         double dYRadius = MIN(m_dRoundYRadius, (dYMax-dYMin)/2.0);
1332         TABGenerateArc(poRing, 45,
1333                        dXMin + dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
1334                        PI, 3.0*PI/2.0);
1335         TABGenerateArc(poRing, 45,
1336                        dXMax - dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
1337                        3.0*PI/2.0, 2.0*PI);
1338         TABGenerateArc(poRing, 45,
1339                        dXMax - dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
1340                        0.0, PI/2.0);
1341         TABGenerateArc(poRing, 45,
1342                        dXMin + dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
1343                        PI/2.0, PI);
1344 
1345         TABCloseRing(poRing);
1346     }
1347     else
1348     {
1349         poRing->addPoint(dXMin, dYMin);
1350         poRing->addPoint(dXMax, dYMin);
1351         poRing->addPoint(dXMax, dYMax);
1352         poRing->addPoint(dXMin, dYMax);
1353         poRing->addPoint(dXMin, dYMin);
1354     }
1355 
1356     poPolygon->addRingDirectly(poRing);
1357     SetGeometryDirectly(poPolygon);
1358 
1359 
1360    while (((pszLine = fp->GetLine()) != NULL) &&
1361           fp->IsValidFeature(pszLine) == FALSE)
1362    {
1363        papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
1364                                              TRUE,FALSE);
1365 
1366        if (CSLCount(papszToken) > 1)
1367        {
1368            if (EQUALN(papszToken[0],"PEN",3))
1369            {
1370                if (CSLCount(papszToken) == 4)
1371                {
1372                    SetPenWidthMIF(atoi(papszToken[1]));
1373                    SetPenPattern((GByte)atoi(papszToken[2]));
1374                    SetPenColor((GInt32)atoi(papszToken[3]));
1375                }
1376 
1377            }
1378            else if (EQUALN(papszToken[0],"BRUSH", 5))
1379            {
1380                if (CSLCount(papszToken) >=3)
1381                {
1382                    SetBrushFGColor((GInt32)atoi(papszToken[2]));
1383                    SetBrushPattern((GByte)atoi(papszToken[1]));
1384 
1385                    if (CSLCount(papszToken) == 4)
1386                        SetBrushBGColor(atoi(papszToken[3]));
1387                    else
1388                       SetBrushTransparent(TRUE);
1389                }
1390 
1391            }
1392        }
1393        CSLDestroy(papszToken);
1394        papszToken = NULL;
1395    }
1396 
1397    return 0;
1398 
1399 }
1400 
1401 
1402 /**********************************************************************
1403  *
1404  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)1405 int TABRectangle::WriteGeometryToMIFFile(MIDDATAFile *fp)
1406 {
1407     OGRGeometry         *poGeom;
1408     OGRPolygon          *poPolygon;
1409     OGREnvelope         sEnvelope;
1410 
1411      /*-----------------------------------------------------------------
1412      * Fetch and validate geometry
1413      *----------------------------------------------------------------*/
1414     poGeom = GetGeometryRef();
1415     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
1416         poPolygon = (OGRPolygon*)poGeom;
1417     else
1418     {
1419         CPLError(CE_Failure, CPLE_AssertionFailed,
1420                  "TABRectangle: Missing or Invalid Geometry!");
1421         return -1;
1422     }
1423     /*-----------------------------------------------------------------
1424      * Note that we will simply use the rectangle's MBR and don't really
1425      * read the polygon geometry... this should be OK unless the
1426      * polygon geometry was not really a rectangle.
1427      *----------------------------------------------------------------*/
1428     poPolygon->getEnvelope(&sEnvelope);
1429 
1430     if (m_bRoundCorners == TRUE)
1431     {
1432         fp->WriteLine("Roundrect %.15g %.15g %.15g %.15g %.15g\n",
1433                       sEnvelope.MinX, sEnvelope.MinY,
1434                       sEnvelope.MaxX, sEnvelope.MaxY, m_dRoundXRadius*2.0);
1435     }
1436     else
1437     {
1438         fp->WriteLine("Rect %.15g %.15g %.15g %.15g\n",
1439                       sEnvelope.MinX, sEnvelope.MinY,
1440                       sEnvelope.MaxX, sEnvelope.MaxY);
1441     }
1442 
1443     if (GetPenPattern())
1444       fp->WriteLine("    Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
1445                     GetPenColor());
1446 
1447     if (GetBrushPattern())
1448     {
1449         if (GetBrushTransparent() == 0)
1450           fp->WriteLine("    Brush (%d,%d,%d)\n",GetBrushPattern(),
1451                         GetBrushFGColor(),GetBrushBGColor());
1452         else
1453           fp->WriteLine("    Brush (%d,%d)\n",GetBrushPattern(),
1454                         GetBrushFGColor());
1455     }
1456     return 0;
1457 }
1458 
1459 /**********************************************************************
1460  *
1461  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)1462 int TABEllipse::ReadGeometryFromMIFFile(MIDDATAFile *fp)
1463 {
1464     const char *pszLine;
1465     char **papszToken;
1466     double              dXMin, dYMin, dXMax, dYMax;
1467     OGRPolygon          *poPolygon;
1468     OGRLinearRing       *poRing;
1469 
1470     papszToken = CSLTokenizeString2(fp->GetLastLine(),
1471                                     " \t", CSLT_HONOURSTRINGS);
1472 
1473     if (CSLCount(papszToken) != 5)
1474     {
1475         CSLDestroy(papszToken);
1476         return -1;
1477     }
1478 
1479     dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
1480     dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
1481     dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
1482     dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
1483 
1484     CSLDestroy(papszToken);
1485     papszToken = NULL;
1486 
1487      /*-----------------------------------------------------------------
1488      * Save info about the ellipse def. inside class members
1489      *----------------------------------------------------------------*/
1490     m_dCenterX = (dXMin + dXMax) / 2.0;
1491     m_dCenterY = (dYMin + dYMax) / 2.0;
1492     m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
1493     m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
1494 
1495     SetMBR(dXMin, dYMin, dXMax, dYMax);
1496 
1497     /*-----------------------------------------------------------------
1498      * Create and fill geometry object
1499      *----------------------------------------------------------------*/
1500     poPolygon = new OGRPolygon;
1501     poRing = new OGRLinearRing();
1502 
1503     /*-----------------------------------------------------------------
1504      * For the OGR geometry, we generate an ellipse with 2 degrees line
1505      * segments.
1506      *----------------------------------------------------------------*/
1507     TABGenerateArc(poRing, 180,
1508                    m_dCenterX, m_dCenterY,
1509                    m_dXRadius, m_dYRadius,
1510                    0.0, 2.0*PI);
1511     TABCloseRing(poRing);
1512 
1513     poPolygon->addRingDirectly(poRing);
1514     SetGeometryDirectly(poPolygon);
1515 
1516     while (((pszLine = fp->GetLine()) != NULL) &&
1517            fp->IsValidFeature(pszLine) == FALSE)
1518     {
1519         papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
1520                                               TRUE,FALSE);
1521 
1522         if (CSLCount(papszToken) > 1)
1523         {
1524             if (EQUALN(papszToken[0],"PEN",3))
1525             {
1526                 if (CSLCount(papszToken) == 4)
1527                 {
1528                     SetPenWidthMIF(atoi(papszToken[1]));
1529                     SetPenPattern((GByte)atoi(papszToken[2]));
1530                     SetPenColor((GInt32)atoi(papszToken[3]));
1531                 }
1532 
1533             }
1534             else if (EQUALN(papszToken[0],"BRUSH", 5))
1535             {
1536                 if (CSLCount(papszToken) >= 3)
1537                 {
1538                     SetBrushFGColor((GInt32)atoi(papszToken[2]));
1539                     SetBrushPattern((GByte)atoi(papszToken[1]));
1540 
1541                     if (CSLCount(papszToken) == 4)
1542                       SetBrushBGColor(atoi(papszToken[3]));
1543                     else
1544                       SetBrushTransparent(TRUE);
1545 
1546                 }
1547 
1548             }
1549         }
1550         CSLDestroy(papszToken);
1551         papszToken = NULL;
1552     }
1553     return 0;
1554 }
1555 
1556 /**********************************************************************
1557  *
1558  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)1559 int TABEllipse::WriteGeometryToMIFFile(MIDDATAFile *fp)
1560 {
1561     OGRGeometry         *poGeom;
1562     OGREnvelope         sEnvelope;
1563 
1564     poGeom = GetGeometryRef();
1565     if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
1566          (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint )  )
1567         poGeom->getEnvelope(&sEnvelope);
1568     else
1569     {
1570         CPLError(CE_Failure, CPLE_AssertionFailed,
1571                  "TABEllipse: Missing or Invalid Geometry!");
1572         return -1;
1573     }
1574 
1575     fp->WriteLine("Ellipse %.15g %.15g %.15g %.15g\n",sEnvelope.MinX, sEnvelope.MinY,
1576                   sEnvelope.MaxX,sEnvelope.MaxY);
1577 
1578     if (GetPenPattern())
1579       fp->WriteLine("    Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
1580                     GetPenColor());
1581 
1582     if (GetBrushPattern())
1583     {
1584         if (GetBrushTransparent() == 0)
1585           fp->WriteLine("    Brush (%d,%d,%d)\n",GetBrushPattern(),
1586                         GetBrushFGColor(),GetBrushBGColor());
1587         else
1588           fp->WriteLine("    Brush (%d,%d)\n",GetBrushPattern(),
1589                         GetBrushFGColor());
1590     }
1591     return 0;
1592 }
1593 
1594 /**********************************************************************
1595  *
1596  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)1597 int TABArc::ReadGeometryFromMIFFile(MIDDATAFile *fp)
1598 {
1599     const char          *pszLine;
1600     OGRLineString       *poLine;
1601     char               **papszToken;
1602     double               dXMin,dXMax, dYMin,dYMax;
1603     int                  numPts;
1604 
1605     papszToken = CSLTokenizeString2(fp->GetLastLine(),
1606                                     " \t", CSLT_HONOURSTRINGS);
1607 
1608     if (CSLCount(papszToken) == 5)
1609     {
1610         dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
1611         dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
1612         dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
1613         dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
1614 
1615         CSLDestroy(papszToken);
1616         papszToken = CSLTokenizeString2(fp->GetLine(),
1617                                         " \t", CSLT_HONOURSTRINGS);
1618         if (CSLCount(papszToken) != 2)
1619         {
1620             CSLDestroy(papszToken);
1621             return -1;
1622         }
1623 
1624         m_dStartAngle = CPLAtof(papszToken[0]);
1625         m_dEndAngle = CPLAtof(papszToken[1]);
1626     }
1627     else if (CSLCount(papszToken) == 7)
1628     {
1629         dXMin = fp->GetXTrans(CPLAtof(papszToken[1]));
1630         dXMax = fp->GetXTrans(CPLAtof(papszToken[3]));
1631         dYMin = fp->GetYTrans(CPLAtof(papszToken[2]));
1632         dYMax = fp->GetYTrans(CPLAtof(papszToken[4]));
1633         m_dStartAngle = CPLAtof(papszToken[5]);
1634         m_dEndAngle = CPLAtof(papszToken[6]);
1635     }
1636     else
1637     {
1638         CSLDestroy(papszToken);
1639         return -1;
1640     }
1641 
1642     CSLDestroy(papszToken);
1643     papszToken = NULL;
1644 
1645     /*-------------------------------------------------------------
1646      * Start/End angles
1647      * Since the angles are specified for integer coordinates, and
1648      * that these coordinates can have the X axis reversed, we have to
1649      * adjust the angle values for the change in the X axis
1650      * direction.
1651      *
1652      * This should be necessary only when X axis is flipped.
1653      * __TODO__ Why is order of start/end values reversed as well???
1654      *------------------------------------------------------------*/
1655 
1656     if (fp->GetXMultiplier() <= 0.0)
1657     {
1658         m_dStartAngle = 360.0 - m_dStartAngle;
1659         m_dEndAngle = 360.0 - m_dEndAngle;
1660     }
1661 
1662     m_dCenterX = (dXMin + dXMax) / 2.0;
1663     m_dCenterY = (dYMin + dYMax) / 2.0;
1664     m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
1665     m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
1666 
1667     /*-----------------------------------------------------------------
1668      * Create and fill geometry object
1669      * For the OGR geometry, we generate an arc with 2 degrees line
1670      * segments.
1671      *----------------------------------------------------------------*/
1672     poLine = new OGRLineString;
1673 
1674     if (m_dEndAngle < m_dStartAngle)
1675         numPts = (int) ABS( ((m_dEndAngle+360.0)-m_dStartAngle)/2.0 ) + 1;
1676     else
1677         numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2.0 ) + 1;
1678     numPts = MAX(2, numPts);
1679 
1680     TABGenerateArc(poLine, numPts,
1681                    m_dCenterX, m_dCenterY,
1682                    m_dXRadius, m_dYRadius,
1683                    m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
1684 
1685     SetMBR(dXMin, dYMin, dXMax, dYMax);
1686     SetGeometryDirectly(poLine);
1687 
1688     while (((pszLine = fp->GetLine()) != NULL) &&
1689            fp->IsValidFeature(pszLine) == FALSE)
1690     {
1691         papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
1692                                               TRUE,FALSE);
1693 
1694         if (CSLCount(papszToken) > 1)
1695         {
1696             if (EQUALN(papszToken[0],"PEN",3))
1697             {
1698 
1699                 if (CSLCount(papszToken) == 4)
1700                 {
1701                     SetPenWidthMIF(atoi(papszToken[1]));
1702                     SetPenPattern((GByte)atoi(papszToken[2]));
1703                     SetPenColor((GInt32)atoi(papszToken[3]));
1704                 }
1705 
1706             }
1707         }
1708         CSLDestroy(papszToken);
1709         papszToken = NULL;
1710    }
1711    return 0;
1712 }
1713 
1714 /**********************************************************************
1715  *
1716  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)1717 int TABArc::WriteGeometryToMIFFile(MIDDATAFile *fp)
1718 {
1719     /*-------------------------------------------------------------
1720      * Start/End angles
1721      * Since we ALWAYS produce files in quadrant 1 then we can
1722      * ignore the special angle conversion required by flipped axis.
1723      *------------------------------------------------------------*/
1724 
1725 
1726     // Write the Arc's actual MBR
1727      fp->WriteLine("Arc %.15g %.15g %.15g %.15g\n", m_dCenterX-m_dXRadius,
1728                    m_dCenterY-m_dYRadius, m_dCenterX+m_dXRadius,
1729                    m_dCenterY+m_dYRadius);
1730 
1731      fp->WriteLine("  %.15g %.15g\n",m_dStartAngle,m_dEndAngle);
1732 
1733      if (GetPenPattern())
1734        fp->WriteLine("    Pen (%d,%d,%d)\n",GetPenWidthMIF(),GetPenPattern(),
1735                      GetPenColor());
1736 
1737 
1738     return 0;
1739 
1740 }
1741 
1742 /**********************************************************************
1743  *
1744  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)1745 int TABText::ReadGeometryFromMIFFile(MIDDATAFile *fp)
1746 {
1747     double               dXMin, dYMin, dXMax, dYMax;
1748     OGRGeometry         *poGeometry;
1749     const char          *pszLine;
1750     char               **papszToken;
1751     const char          *pszString;
1752     char                *pszTmpString;
1753     int                  bXYBoxRead = 0;
1754     int                  tokenLen;
1755 
1756     papszToken = CSLTokenizeString2(fp->GetLastLine(),
1757                                     " \t", CSLT_HONOURSTRINGS);
1758     if (CSLCount(papszToken) == 1)
1759     {
1760         CSLDestroy(papszToken);
1761         papszToken = CSLTokenizeString2(fp->GetLine(),
1762                                         " \t", CSLT_HONOURSTRINGS);
1763         tokenLen = CSLCount(papszToken);
1764         if (tokenLen == 4)
1765         {
1766            pszString = NULL;
1767            bXYBoxRead = 1;
1768         }
1769         else if (tokenLen == 0)
1770         {
1771             pszString = NULL;
1772         }
1773         else if (tokenLen != 1)
1774         {
1775             CSLDestroy(papszToken);
1776             return -1;
1777         }
1778         else
1779         {
1780           pszString = papszToken[0];
1781         }
1782     }
1783     else if (CSLCount(papszToken) == 2)
1784     {
1785         pszString = papszToken[1];
1786     }
1787     else
1788     {
1789         CSLDestroy(papszToken);
1790         return -1;
1791     }
1792 
1793     /*-------------------------------------------------------------
1794      * Note: The text string may contain escaped "\n" chars, and we
1795      * sstore them in memory in the UnEscaped form to be OGR
1796      * compliant. See Maptools bug 1107 for more details.
1797      *------------------------------------------------------------*/
1798     pszTmpString = CPLStrdup(pszString);
1799     m_pszString = TABUnEscapeString(pszTmpString, TRUE);
1800     if (pszTmpString != m_pszString)
1801         CPLFree(pszTmpString);
1802 
1803     if (!bXYBoxRead)
1804     {
1805         CSLDestroy(papszToken);
1806         papszToken = CSLTokenizeString2(fp->GetLine(),
1807                                         " \t", CSLT_HONOURSTRINGS);
1808     }
1809 
1810     if (CSLCount(papszToken) != 4)
1811     {
1812         CSLDestroy(papszToken);
1813         return -1;
1814     }
1815     else
1816     {
1817         dXMin = fp->GetXTrans(CPLAtof(papszToken[0]));
1818         dXMax = fp->GetXTrans(CPLAtof(papszToken[2]));
1819         dYMin = fp->GetYTrans(CPLAtof(papszToken[1]));
1820         dYMax = fp->GetYTrans(CPLAtof(papszToken[3]));
1821 
1822         m_dHeight = dYMax - dYMin;  //SetTextBoxHeight(dYMax - dYMin);
1823         m_dWidth  = dXMax - dXMin;  //SetTextBoxWidth(dXMax - dXMin);
1824 
1825         if (m_dHeight <0.0)
1826           m_dHeight*=-1.0;
1827         if (m_dWidth <0.0)
1828           m_dWidth*=-1.0;
1829     }
1830 
1831     CSLDestroy(papszToken);
1832     papszToken = NULL;
1833 
1834     /* Set/retrieve the MBR to make sure Mins are smaller than Maxs
1835      */
1836 
1837     SetMBR(dXMin, dYMin, dXMax, dYMax);
1838     GetMBR(dXMin, dYMin, dXMax, dYMax);
1839 
1840     while (((pszLine = fp->GetLine()) != NULL) &&
1841            fp->IsValidFeature(pszLine) == FALSE)
1842     {
1843         papszToken = CSLTokenizeStringComplex(pszLine,"() ,",
1844                                               TRUE,FALSE);
1845 
1846         if (CSLCount(papszToken) > 1)
1847         {
1848             if (EQUALN(papszToken[0],"FONT",4))
1849             {
1850                 if (CSLCount(papszToken) >= 5)
1851                 {
1852                     SetFontName(papszToken[1]);
1853                     SetFontFGColor(atoi(papszToken[4]));
1854                     if (CSLCount(papszToken) ==6)
1855                     {
1856                         SetFontBGColor(atoi(papszToken[5]));
1857                         SetFontStyleMIFValue(atoi(papszToken[2]),TRUE);
1858                     }
1859                     else
1860                       SetFontStyleMIFValue(atoi(papszToken[2]));
1861 
1862                     // papsztoken[3] = Size ???
1863                 }
1864 
1865             }
1866             else if (EQUALN(papszToken[0],"SPACING",7))
1867             {
1868                 if (CSLCount(papszToken) >= 2)
1869                 {
1870                     if (EQUALN(papszToken[1],"2",1))
1871                     {
1872                         SetTextSpacing(TABTSDouble);
1873                     }
1874                     else if (EQUALN(papszToken[1],"1.5",3))
1875                     {
1876                         SetTextSpacing(TABTS1_5);
1877                     }
1878                 }
1879 
1880                 if (CSLCount(papszToken) == 7)
1881                 {
1882                     if (EQUALN(papszToken[2],"LAbel",5))
1883                     {
1884                         if (EQUALN(papszToken[4],"simple",6))
1885                         {
1886                             SetTextLineType(TABTLSimple);
1887                             SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[5])),
1888                                                 fp->GetYTrans(CPLAtof(papszToken[6])));
1889                         }
1890                         else if (EQUALN(papszToken[4],"arrow", 5))
1891                         {
1892                             SetTextLineType(TABTLArrow);
1893                             SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[5])),
1894                                                 fp->GetYTrans(CPLAtof(papszToken[6])));
1895                         }
1896                     }
1897                 }
1898             }
1899             else if (EQUALN(papszToken[0],"Justify",7))
1900             {
1901                 if (CSLCount(papszToken) == 2)
1902                 {
1903                     if (EQUALN( papszToken[1],"Center",6))
1904                     {
1905                         SetTextJustification(TABTJCenter);
1906                     }
1907                     else  if (EQUALN( papszToken[1],"Right",5))
1908                     {
1909                         SetTextJustification(TABTJRight);
1910                     }
1911 
1912                 }
1913 
1914             }
1915             else if (EQUALN(papszToken[0],"Angle",5))
1916             {
1917                 if (CSLCount(papszToken) == 2)
1918                 {
1919                     SetTextAngle(CPLAtof(papszToken[1]));
1920                 }
1921 
1922             }
1923             else if (EQUALN(papszToken[0],"LAbel",5))
1924             {
1925                 if (CSLCount(papszToken) == 5)
1926                 {
1927                     if (EQUALN(papszToken[2],"simple",6))
1928                     {
1929                         SetTextLineType(TABTLSimple);
1930                         SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[3])),
1931                                            fp->GetYTrans(CPLAtof(papszToken[4])));
1932                     }
1933                     else if (EQUALN(papszToken[2],"arrow", 5))
1934                     {
1935                         SetTextLineType(TABTLArrow);
1936                         SetTextLineEndPoint(fp->GetXTrans(CPLAtof(papszToken[3])),
1937                                            fp->GetYTrans(CPLAtof(papszToken[4])));
1938                     }
1939                 }
1940 
1941 
1942                 // What I do with the XY coordonate
1943             }
1944         }
1945         CSLDestroy(papszToken);
1946         papszToken = NULL;
1947     }
1948     /*-----------------------------------------------------------------
1949      * Create an OGRPoint Geometry...
1950      * The point X,Y values will be the coords of the lower-left corner before
1951      * rotation is applied.  (Note that the rotation in MapInfo is done around
1952      * the upper-left corner)
1953      * We need to calculate the true lower left corner of the text based
1954      * on the MBR after rotation, the text height and the rotation angle.
1955      *---------------------------------------------------------------- */
1956     double dCos, dSin, dX, dY;
1957     dSin = sin(m_dAngle*PI/180.0);
1958     dCos = cos(m_dAngle*PI/180.0);
1959     if (dSin > 0.0  && dCos > 0.0)
1960     {
1961         dX = dXMin + m_dHeight * dSin;
1962         dY = dYMin;
1963     }
1964     else if (dSin > 0.0  && dCos < 0.0)
1965     {
1966         dX = dXMax;
1967         dY = dYMin - m_dHeight * dCos;
1968     }
1969     else if (dSin < 0.0  && dCos < 0.0)
1970     {
1971         dX = dXMax + m_dHeight * dSin;
1972         dY = dYMax;
1973     }
1974     else  // dSin < 0 && dCos > 0
1975     {
1976         dX = dXMin;
1977         dY = dYMax - m_dHeight * dCos;
1978     }
1979 
1980 
1981     poGeometry = new OGRPoint(dX, dY);
1982 
1983     SetGeometryDirectly(poGeometry);
1984 
1985     /*-----------------------------------------------------------------
1986      * Compute Text Width: the width of the Text MBR before rotation
1987      * in ground units... unfortunately this value is not stored in the
1988      * file, so we have to compute it with the MBR after rotation and
1989      * the height of the MBR before rotation:
1990      * With  W = Width of MBR before rotation
1991      *       H = Height of MBR before rotation
1992      *       dX = Width of MBR after rotation
1993      *       dY = Height of MBR after rotation
1994      *       teta = rotation angle
1995      *
1996      *  For [-PI/4..teta..+PI/4] or [3*PI/4..teta..5*PI/4], we'll use:
1997      *   W = H * (dX - H * sin(teta)) / (H * cos(teta))
1998      *
1999      * and for other teta values, use:
2000      *   W = H * (dY - H * cos(teta)) / (H * sin(teta))
2001      *---------------------------------------------------------------- */
2002     dSin = ABS(dSin);
2003     dCos = ABS(dCos);
2004     if (m_dHeight == 0.0)
2005         m_dWidth = 0.0;
2006     else if ( dCos > dSin )
2007         m_dWidth = m_dHeight * ((dXMax-dXMin) - m_dHeight*dSin) /
2008                                                         (m_dHeight*dCos);
2009     else
2010         m_dWidth = m_dHeight * ((dYMax-dYMin) - m_dHeight*dCos) /
2011                                                         (m_dHeight*dSin);
2012     m_dWidth = ABS(m_dWidth);
2013 
2014    return 0;
2015 }
2016 
2017 /**********************************************************************
2018  *
2019  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)2020 int TABText::WriteGeometryToMIFFile(MIDDATAFile *fp)
2021 {
2022     double dXMin,dYMin,dXMax,dYMax;
2023     char   *pszTmpString;
2024 
2025     /*-------------------------------------------------------------
2026      * Note: The text string may contain unescaped "\n" chars or
2027      * "\\" chars and we expect to receive them in an unescaped
2028      * form. Those characters are unescaped in memory to be like
2029      * other OGR drivers. See MapTools bug 1107 for more details.
2030      *------------------------------------------------------------*/
2031     pszTmpString = TABEscapeString(m_pszString);
2032     if(pszTmpString == NULL)
2033         fp->WriteLine("Text \"\"\n" );
2034     else
2035         fp->WriteLine("Text \"%s\"\n", pszTmpString );
2036     if (pszTmpString != m_pszString)
2037         CPLFree(pszTmpString);
2038 
2039     //    UpdateTextMBR();
2040     GetMBR(dXMin, dYMin, dXMax, dYMax);
2041     fp->WriteLine("    %.15g %.15g %.15g %.15g\n",dXMin, dYMin,dXMax, dYMax);
2042 
2043     if (IsFontBGColorUsed())
2044       fp->WriteLine("    Font (\"%s\",%d,%d,%d,%d)\n", GetFontNameRef(),
2045                     GetFontStyleMIFValue(),0,GetFontFGColor(),
2046                     GetFontBGColor());
2047     else
2048       fp->WriteLine("    Font (\"%s\",%d,%d,%d)\n", GetFontNameRef(),
2049                     GetFontStyleMIFValue(),0,GetFontFGColor());
2050 
2051     switch (GetTextSpacing())
2052     {
2053       case   TABTS1_5:
2054         fp->WriteLine("    Spacing 1.5\n");
2055         break;
2056       case TABTSDouble:
2057         fp->WriteLine("    Spacing 2.0\n");
2058         break;
2059       case TABTSSingle:
2060       default:
2061         break;
2062     }
2063 
2064     switch (GetTextJustification())
2065     {
2066       case TABTJCenter:
2067         fp->WriteLine("    Justify Center\n");
2068         break;
2069       case TABTJRight:
2070         fp->WriteLine("    Justify Right\n");
2071         break;
2072       case TABTJLeft:
2073       default:
2074         break;
2075     }
2076 
2077     if (ABS(GetTextAngle()) >  0.000001)
2078         fp->WriteLine("    Angle %.15g\n",GetTextAngle());
2079 
2080     switch (GetTextLineType())
2081     {
2082       case TABTLSimple:
2083         if (m_bLineEndSet)
2084             fp->WriteLine("    Label Line Simple %.15g %.15g \n",
2085                           m_dfLineEndX, m_dfLineEndY );
2086         break;
2087       case TABTLArrow:
2088         if (m_bLineEndSet)
2089             fp->WriteLine("    Label Line Arrow %.15g %.15g \n",
2090                           m_dfLineEndX, m_dfLineEndY );
2091         break;
2092       case TABTLNoLine:
2093       default:
2094         break;
2095     }
2096     return 0;
2097 
2098 }
2099 
2100 /**********************************************************************
2101  *
2102  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)2103 int TABMultiPoint::ReadGeometryFromMIFFile(MIDDATAFile *fp)
2104 {
2105     OGRPoint            *poPoint;
2106     OGRMultiPoint       *poMultiPoint;
2107     char                **papszToken;
2108     const char          *pszLine;
2109     int                 nNumPoint, i;
2110     double              dfX,dfY;
2111     OGREnvelope         sEnvelope;
2112 
2113     papszToken = CSLTokenizeString2(fp->GetLastLine(),
2114                                     " \t", CSLT_HONOURSTRINGS);
2115 
2116     if (CSLCount(papszToken) !=2)
2117     {
2118         CSLDestroy(papszToken);
2119         return -1;
2120     }
2121 
2122     nNumPoint = atoi(papszToken[1]);
2123     poMultiPoint = new OGRMultiPoint;
2124 
2125     CSLDestroy(papszToken);
2126     papszToken = NULL;
2127 
2128     // Get each point and add them to the multipoint feature
2129     for(i=0; i<nNumPoint; i++)
2130     {
2131         pszLine = fp->GetLine();
2132         papszToken = CSLTokenizeString2(fp->GetLastLine(),
2133                                         " \t", CSLT_HONOURSTRINGS);
2134         if (CSLCount(papszToken) !=2)
2135         {
2136             CSLDestroy(papszToken);
2137             return -1;
2138         }
2139 
2140         dfX = fp->GetXTrans(CPLAtof(papszToken[0]));
2141         dfY = fp->GetXTrans(CPLAtof(papszToken[1]));
2142         poPoint = new OGRPoint(dfX, dfY);
2143         if ( poMultiPoint->addGeometryDirectly( poPoint ) != OGRERR_NONE)
2144         {
2145             CPLAssert(FALSE); // Just in case OGR is modified
2146         }
2147 
2148         // Set center
2149         if(i == 0)
2150         {
2151             SetCenter( dfX, dfY );
2152         }
2153         CSLDestroy(papszToken);
2154     }
2155 
2156     if( SetGeometryDirectly( poMultiPoint ) != OGRERR_NONE)
2157     {
2158         CPLAssert(FALSE); // Just in case OGR is modified
2159     }
2160 
2161     poMultiPoint->getEnvelope(&sEnvelope);
2162     SetMBR(sEnvelope.MinX, sEnvelope.MinY,
2163            sEnvelope.MaxX,sEnvelope.MaxY);
2164 
2165     // Read optional SYMBOL line...
2166 
2167     while (((pszLine = fp->GetLine()) != NULL) &&
2168            fp->IsValidFeature(pszLine) == FALSE)
2169     {
2170         papszToken = CSLTokenizeStringComplex(pszLine," ,()\t",
2171                                               TRUE,FALSE);
2172         if (CSLCount(papszToken) == 4 && EQUAL(papszToken[0], "SYMBOL") )
2173         {
2174             SetSymbolNo((GInt16)atoi(papszToken[1]));
2175             SetSymbolColor((GInt32)atoi(papszToken[2]));
2176             SetSymbolSize((GInt16)atoi(papszToken[3]));
2177         }
2178         CSLDestroy(papszToken);
2179     }
2180 
2181     return 0;
2182 }
2183 
2184 /**********************************************************************
2185  *
2186  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)2187 int TABMultiPoint::WriteGeometryToMIFFile(MIDDATAFile *fp)
2188 {
2189     OGRGeometry         *poGeom;
2190     OGRPoint            *poPoint;
2191     OGRMultiPoint       *poMultiPoint;
2192     int                 nNumPoints, iPoint;
2193 
2194     /*-----------------------------------------------------------------
2195      * Fetch and validate geometry
2196      *----------------------------------------------------------------*/
2197     poGeom = GetGeometryRef();
2198     if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
2199     {
2200         poMultiPoint = (OGRMultiPoint*)poGeom;
2201         nNumPoints = poMultiPoint->getNumGeometries();
2202 
2203         fp->WriteLine("MultiPoint %d\n", nNumPoints);
2204 
2205         for(iPoint=0; iPoint < nNumPoints; iPoint++)
2206         {
2207             /*------------------------------------------------------------
2208              * Validate each point
2209              *-----------------------------------------------------------*/
2210             poGeom = poMultiPoint->getGeometryRef(iPoint);
2211             if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
2212             {
2213                 poPoint = (OGRPoint*)poGeom;
2214                 fp->WriteLine("%.15g %.15g\n",poPoint->getX(),poPoint->getY());
2215             }
2216             else
2217             {
2218                 CPLError(CE_Failure, CPLE_AssertionFailed,
2219                          "TABMultiPoint: Missing or Invalid Geometry!");
2220                 return -1;
2221             }
2222         }
2223         // Write symbol
2224         fp->WriteLine("    Symbol (%d,%d,%d)\n",GetSymbolNo(),GetSymbolColor(),
2225                       GetSymbolSize());
2226     }
2227 
2228     return 0;
2229 }
2230 
2231 
2232 /**********************************************************************
2233  *
2234  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)2235 int TABCollection::ReadGeometryFromMIFFile(MIDDATAFile *fp)
2236 {
2237     char                **papszToken;
2238     const char          *pszLine;
2239     int                 numParts, i;
2240     OGREnvelope         sEnvelope;
2241 
2242     /*-----------------------------------------------------------------
2243      * Fetch number of parts in "COLLECTION %d" line
2244      *----------------------------------------------------------------*/
2245     papszToken = CSLTokenizeString2(fp->GetLastLine(),
2246                                     " \t", CSLT_HONOURSTRINGS);
2247 
2248     if (CSLCount(papszToken) !=2)
2249     {
2250         CSLDestroy(papszToken);
2251         return -1;
2252     }
2253 
2254     numParts = atoi(papszToken[1]);
2255     CSLDestroy(papszToken);
2256     papszToken = NULL;
2257 
2258     // Make sure collection is empty
2259     EmptyCollection();
2260 
2261     pszLine = fp->GetLine();
2262 
2263     /*-----------------------------------------------------------------
2264      * Read each part and add them to the feature
2265      *----------------------------------------------------------------*/
2266     for (i=0; i < numParts; i++)
2267     {
2268         if (pszLine == NULL)
2269         {
2270             CPLError(CE_Failure, CPLE_FileIO,
2271                   "Unexpected EOF while reading TABCollection from MIF file.");
2272             return -1;
2273          }
2274 
2275         while(*pszLine == ' ' || *pszLine == '\t')
2276             pszLine++;  // skip leading spaces
2277 
2278         if (*pszLine == '\0')
2279             continue;  // Skip blank lines
2280 
2281         if (EQUALN(pszLine,"REGION",6))
2282         {
2283             m_poRegion = new TABRegion(GetDefnRef());
2284             if (m_poRegion->ReadGeometryFromMIFFile(fp) != 0)
2285             {
2286                 CPLError(CE_Failure, CPLE_NotSupported,
2287                          "TABCollection: Error reading REGION part.");
2288                 delete m_poRegion;
2289                 m_poRegion = NULL;
2290                 return -1;
2291             }
2292         }
2293         else if (EQUALN(pszLine,"LINE",4) ||
2294                  EQUALN(pszLine,"PLINE",5))
2295         {
2296             m_poPline = new TABPolyline(GetDefnRef());
2297             if (m_poPline->ReadGeometryFromMIFFile(fp) != 0)
2298             {
2299                 CPLError(CE_Failure, CPLE_NotSupported,
2300                          "TABCollection: Error reading PLINE part.");
2301                 delete m_poPline;
2302                 m_poPline = NULL;
2303                 return -1;
2304             }
2305         }
2306         else if (EQUALN(pszLine,"MULTIPOINT",10))
2307         {
2308             m_poMpoint = new TABMultiPoint(GetDefnRef());
2309             if (m_poMpoint->ReadGeometryFromMIFFile(fp) != 0)
2310             {
2311                 CPLError(CE_Failure, CPLE_NotSupported,
2312                          "TABCollection: Error reading MULTIPOINT part.");
2313                 delete m_poMpoint;
2314                 m_poMpoint = NULL;
2315                 return -1;
2316             }
2317         }
2318         else
2319         {
2320             CPLError(CE_Failure, CPLE_FileIO,
2321                      "Reading TABCollection from MIF failed, expecting one "
2322                      "of REGION, PLINE or MULTIPOINT, got: '%s'",
2323                      pszLine);
2324             return -1;
2325         }
2326 
2327         pszLine = fp->GetLastLine();
2328     }
2329 
2330     /*-----------------------------------------------------------------
2331      * Set the main OGRFeature Geometry
2332      * (this is actually duplicating geometries from each member)
2333      *----------------------------------------------------------------*/
2334     // use addGeometry() rather than addGeometryDirectly() as this clones
2335     // the added geometry so won't leave dangling ptrs when the above features
2336     // are deleted
2337 
2338     OGRGeometryCollection *poGeomColl = new OGRGeometryCollection();
2339     if(m_poRegion && m_poRegion->GetGeometryRef() != NULL)
2340         poGeomColl->addGeometry(m_poRegion->GetGeometryRef());
2341 
2342     if(m_poPline && m_poPline->GetGeometryRef() != NULL)
2343         poGeomColl->addGeometry(m_poPline->GetGeometryRef());
2344 
2345     if(m_poMpoint && m_poMpoint->GetGeometryRef() != NULL)
2346         poGeomColl->addGeometry(m_poMpoint->GetGeometryRef());
2347 
2348     this->SetGeometryDirectly(poGeomColl);
2349 
2350     poGeomColl->getEnvelope(&sEnvelope);
2351     SetMBR(sEnvelope.MinX, sEnvelope.MinY,
2352            sEnvelope.MaxX, sEnvelope.MaxY);
2353 
2354     return 0;
2355 }
2356 
2357 /**********************************************************************
2358  *
2359  **********************************************************************/
WriteGeometryToMIFFile(MIDDATAFile * fp)2360 int TABCollection::WriteGeometryToMIFFile(MIDDATAFile *fp)
2361 {
2362     int numParts = 0;
2363     if (m_poRegion)     numParts++;
2364     if (m_poPline)      numParts++;
2365     if (m_poMpoint)     numParts++;
2366 
2367     fp->WriteLine("COLLECTION %d\n", numParts);
2368 
2369     if (m_poRegion)
2370     {
2371         if (m_poRegion->WriteGeometryToMIFFile(fp) != 0)
2372             return -1;
2373     }
2374 
2375     if (m_poPline)
2376     {
2377         if (m_poPline->WriteGeometryToMIFFile(fp) != 0)
2378             return -1;
2379     }
2380 
2381     if (m_poMpoint)
2382     {
2383         if (m_poMpoint->WriteGeometryToMIFFile(fp) != 0)
2384             return -1;
2385     }
2386 
2387     return 0;
2388 }
2389 
2390 /**********************************************************************
2391  *
2392  **********************************************************************/
ReadGeometryFromMIFFile(MIDDATAFile * fp)2393 int TABDebugFeature::ReadGeometryFromMIFFile(MIDDATAFile *fp)
2394 {
2395    const char *pszLine;
2396 
2397 
2398   /* Go to the first line of the next feature */
2399    printf("%s\n", fp->GetLastLine());
2400 
2401    while (((pszLine = fp->GetLine()) != NULL) &&
2402           fp->IsValidFeature(pszLine) == FALSE)
2403      ;
2404 
2405    return 0;
2406 }
2407 
2408 
2409 /**********************************************************************
2410  *
2411  **********************************************************************/
WriteGeometryToMIFFile(CPL_UNUSED MIDDATAFile * fp)2412 int TABDebugFeature::WriteGeometryToMIFFile(CPL_UNUSED MIDDATAFile *fp){ return -1; }
2413