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