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