1 : /**********************************************************************
2 : * $Id: mitab_feature.cpp,v 1.100 2010-10-12 19:55:32 aboudreault Exp $
3 : *
4 : * Name: mitab_feature.cpp
5 : * Project: MapInfo TAB Read/Write library
6 : * Language: C++
7 : * Purpose: Implementation of the feature classes specific to MapInfo files.
8 : * Author: Daniel Morissette, dmorissette@dmsolutions.ca
9 : *
10 : **********************************************************************
11 : * Copyright (c) 1999-2002, Daniel Morissette
12 : *
13 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : **********************************************************************
31 : *
32 : * $Log: mitab_feature.cpp,v $
33 : * Revision 1.100 2010-10-12 19:55:32 aboudreault
34 : * Fixed style string ID parameter to use the proper delimiter as per OGR Feature Style Specification
35 : *
36 : * Revision 1.99 2010-10-08 19:36:44 aboudreault
37 : * Fixed memory leak (GDAL bug #3045)
38 : *
39 : * Revision 1.98 2010-07-07 19:00:15 aboudreault
40 : * Cleanup Win32 Compile Warnings (GDAL bug #2930)
41 : *
42 : * Revision 1.97 2010-07-06 13:56:26 aboudreault
43 : * Fixed TABText::GetLabelStyleString() doesn't escape the double quote character (bug 2236)
44 : *
45 : * Revision 1.96 2009-07-30 13:13:43 dmorissette
46 : * Fixed incorrect text justification returned by GetLabelStyleString()
47 : * for TABTJRight (bug 2085)
48 : *
49 : * Revision 1.95 2008-11-27 20:50:22 aboudreault
50 : * Improved support for OGR date/time types. New Read/Write methods (bug 1948)
51 : * Added support of OGR date/time types for MIF features.
52 : *
53 : * Revision 1.94 2008/11/18 16:47:44 dmorissette
54 : * Fixed compile warning when MITAB_USE_OFTDATETIME is set
55 : *
56 : * Revision 1.93 2008/11/17 22:06:21 aboudreault
57 : * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
58 : * OGR and fixed reading/writing support for these types.
59 : *
60 : * Revision 1.92 2008/07/29 13:06:17 aboudreault
61 : * Added Font Point styles support (halo, border) (bug 1925)
62 : *
63 : * Revision 1.91 2008/07/21 19:23:03 aboudreault
64 : * Fixed another small error with expanded text.
65 : *
66 : * Revision 1.90 2008/07/21 18:17:19 dmorissette
67 : * Fixed a few compile warnings
68 : *
69 : * Revision 1.89 2008/07/21 17:59:28 aboudreault
70 : * Fixed error in GetLabelStyleString() function: when text style expanded is
71 : * set, no space is needed after the last char.
72 : *
73 : * Revision 1.88 2008/07/21 14:09:41 aboudreault
74 : * Add font text styles support (bold, italic, etc.) (bug 1922)
75 : *
76 : * Revision 1.87 2008/07/17 14:09:30 aboudreault
77 : * Add text outline color support (halo background in MapInfo)
78 : *
79 : * Revision 1.86 2008/07/14 17:51:21 aboudreault
80 : * Fixed the text font size problem (bug 1918)
81 : *
82 : * Revision 1.85 2008/07/14 16:09:10 aboudreault
83 : * Fixed multi-line text height problem (bug 1919)
84 : *
85 : * Revision 1.84 2008/07/14 14:39:52 aboudreault
86 : * Fixed multi-line text rendering by adding support of the end of line char
87 : * "\n" as well as the "\\n".
88 : *
89 : * Revision 1.83 2008/07/01 14:33:17 aboudreault
90 : * * Fixed deprecated warnings generated by mitab.h by moving SetFontName to
91 : * mitab_feature.cpp.
92 : *
93 : * Revision 1.82 2008/02/22 20:20:44 dmorissette
94 : * Fixed the internal compressed coordinate range detection test to prevent
95 : * possible overflow of the compressed integer coordinate values leading
96 : * to some coord. errors in very rare cases while writing to TAB (bug 1854)
97 : *
98 : * Revision 1.81 2008/02/20 21:35:30 dmorissette
99 : * Added support for V800 COLLECTION of large objects (bug 1496)
100 : *
101 : * Revision 1.80 2008/02/05 22:22:48 dmorissette
102 : * Added support for TAB_GEOM_V800_MULTIPOINT (bug 1496)
103 : *
104 : * Revision 1.79 2008/02/01 19:36:31 dmorissette
105 : * Initial support for V800 REGION and MULTIPLINE (bug 1496)
106 : *
107 : * Revision 1.78 2008/01/29 20:46:32 dmorissette
108 : * Added support for v9 Time and DateTime fields (byg 1754)
109 : *
110 : * Revision 1.77 2007/12/11 04:21:54 dmorissette
111 : * Fixed leaks in ITABFeature???::Set???FromStyleString() (GDAL ticket 1696)
112 : *
113 : * Revision 1.76 2007/09/18 17:43:56 dmorissette
114 : * Fixed another index splitting issue: compr coordinates origin was not
115 : * stored in the TABFeature in ReadGeometry... (bug 1732)
116 : *
117 : * Revision 1.75 2007/09/14 19:29:24 dmorissette
118 : * Completed handling of bCoordBlockDataOnly arg to Read/WriteGeometry()
119 : * functions to avoid screwing up pen/brush ref counters (bug 1732)
120 : *
121 : * Revision 1.74 2007/09/14 18:30:19 dmorissette
122 : * Fixed the splitting of object blocks with the optimized spatial
123 : * index mode that was producing files with misaligned bytes that
124 : * confused MapInfo (bug 1732)
125 : *
126 : * Revision 1.73 2007/09/12 20:22:31 dmorissette
127 : * Added TABFeature::CreateFromMapInfoType()
128 : *
129 : * Revision 1.72 2007/06/12 14:17:16 dmorissette
130 : * Added TABFile::TwoPointLineAsPolyline() to allow writing two point lines
131 : * as polylines (bug 1735)
132 : *
133 : * Revision 1.71 2007/06/11 17:57:06 dmorissette
134 : * Removed stray calls to poMapFile->GetCurObjBlock()
135 : *
136 : * Revision 1.70 2007/06/11 14:52:30 dmorissette
137 : * Return a valid m_nCoordDatasize value for Collection objects to prevent
138 : * trashing of collection data during object splitting (bug 1728)
139 : *
140 : * Revision 1.69 2007/02/28 20:41:40 dmorissette
141 : * Added missing NULL pointer checks in SetPenFromStyleString(),
142 : * SetBrushFromStyleString() and SetSymbolFromStyleString() (bug 1670)
143 : *
144 : * Revision 1.68 2007/02/22 18:35:53 dmorissette
145 : * Fixed problem writing collections where MITAB was sometimes trying to
146 : * read past EOF in write mode (bug 1657).
147 : *
148 : * Revision 1.67 2006/11/28 18:49:07 dmorissette
149 : * Completed changes to split TABMAPObjectBlocks properly and produce an
150 : * optimal spatial index (bug 1585)
151 : *
152 : * Revision 1.66 2006/10/17 14:34:31 dmorissette
153 : * Fixed problem with null brush bg color (bug 1603)
154 : *
155 : * Revision 1.65 2006/07/25 13:22:58 dmorissette
156 : * Fixed initialization of MBR of TABCollection members (bug 1520)
157 : *
158 : * Revision 1.64 2006/06/29 19:49:35 dmorissette
159 : * Fixed problem writing PLINE MULTIPLE to TAB format introduced in
160 : * MITAB 1.5.0 (bug 1466).
161 : *
162 : * Revision 1.63 2006/02/08 05:02:57 dmorissette
163 : * Fixed crash when attempting to write TABPolyline object with an invalid
164 : * geometry (GDAL bug 1059)
165 : *
166 : * ...
167 : *
168 : * Revision 1.1 1999/07/12 04:18:24 daniel
169 : * Initial checkin
170 : *
171 : **********************************************************************/
172 :
173 : #include "mitab.h"
174 : #include "mitab_utils.h"
175 : #include "mitab_geometry.h"
176 :
177 : /*=====================================================================
178 : * class TABFeature
179 : *====================================================================*/
180 :
181 :
182 : /**********************************************************************
183 : * TABFeature::TABFeature()
184 : *
185 : * Constructor.
186 : **********************************************************************/
187 132 : TABFeature::TABFeature(OGRFeatureDefn *poDefnIn):
188 132 : OGRFeature(poDefnIn)
189 : {
190 132 : m_nMapInfoType = TAB_GEOM_NONE;
191 132 : m_bDeletedFlag = FALSE;
192 :
193 132 : SetMBR(0.0, 0.0, 0.0, 0.0);
194 132 : }
195 :
196 : /**********************************************************************
197 : * TABFeature::~TABFeature()
198 : *
199 : * Destructor.
200 : **********************************************************************/
201 132 : TABFeature::~TABFeature()
202 : {
203 132 : }
204 :
205 :
206 : /**********************************************************************
207 : * TABFeature::CreateFromMapInfoType()
208 : *
209 : * Factory that creates a TABFeature of the right class for the specified
210 : * MapInfo Type
211 : *
212 : **********************************************************************/
213 53 : TABFeature *TABFeature::CreateFromMapInfoType(int nMapInfoType,
214 : OGRFeatureDefn *poDefn)
215 : {
216 53 : TABFeature *poFeature = NULL;
217 :
218 : /*-----------------------------------------------------------------
219 : * Create new feature object of the right type
220 : *----------------------------------------------------------------*/
221 53 : switch(nMapInfoType)
222 : {
223 : case TAB_GEOM_NONE:
224 1 : poFeature = new TABFeature(poDefn);
225 1 : break;
226 : case TAB_GEOM_SYMBOL_C:
227 : case TAB_GEOM_SYMBOL:
228 0 : poFeature = new TABPoint(poDefn);
229 0 : break;
230 : case TAB_GEOM_FONTSYMBOL_C:
231 : case TAB_GEOM_FONTSYMBOL:
232 0 : poFeature = new TABFontPoint(poDefn);
233 0 : break;
234 : case TAB_GEOM_CUSTOMSYMBOL_C:
235 : case TAB_GEOM_CUSTOMSYMBOL:
236 0 : poFeature = new TABCustomPoint(poDefn);
237 0 : break;
238 : case TAB_GEOM_LINE_C:
239 : case TAB_GEOM_LINE:
240 : case TAB_GEOM_PLINE_C:
241 : case TAB_GEOM_PLINE:
242 : case TAB_GEOM_MULTIPLINE_C:
243 : case TAB_GEOM_MULTIPLINE:
244 : case TAB_GEOM_V450_MULTIPLINE_C:
245 : case TAB_GEOM_V450_MULTIPLINE:
246 : case TAB_GEOM_V800_MULTIPLINE_C:
247 : case TAB_GEOM_V800_MULTIPLINE:
248 1 : poFeature = new TABPolyline(poDefn);
249 1 : break;
250 : case TAB_GEOM_ARC_C:
251 : case TAB_GEOM_ARC:
252 0 : poFeature = new TABArc(poDefn);
253 0 : break;
254 :
255 : case TAB_GEOM_REGION_C:
256 : case TAB_GEOM_REGION:
257 : case TAB_GEOM_V450_REGION_C:
258 : case TAB_GEOM_V450_REGION:
259 : case TAB_GEOM_V800_REGION_C:
260 : case TAB_GEOM_V800_REGION:
261 51 : poFeature = new TABRegion(poDefn);
262 51 : break;
263 : case TAB_GEOM_RECT_C:
264 : case TAB_GEOM_RECT:
265 : case TAB_GEOM_ROUNDRECT_C:
266 : case TAB_GEOM_ROUNDRECT:
267 0 : poFeature = new TABRectangle(poDefn);
268 0 : break;
269 : case TAB_GEOM_ELLIPSE_C:
270 : case TAB_GEOM_ELLIPSE:
271 0 : poFeature = new TABEllipse(poDefn);
272 0 : break;
273 : case TAB_GEOM_TEXT_C:
274 : case TAB_GEOM_TEXT:
275 0 : poFeature = new TABText(poDefn);
276 0 : break;
277 : case TAB_GEOM_MULTIPOINT_C:
278 : case TAB_GEOM_MULTIPOINT:
279 : case TAB_GEOM_V800_MULTIPOINT_C:
280 : case TAB_GEOM_V800_MULTIPOINT:
281 0 : poFeature = new TABMultiPoint(poDefn);
282 0 : break;
283 : case TAB_GEOM_COLLECTION_C:
284 : case TAB_GEOM_COLLECTION:
285 : case TAB_GEOM_V800_COLLECTION_C:
286 : case TAB_GEOM_V800_COLLECTION:
287 0 : poFeature = new TABCollection(poDefn);
288 0 : break;
289 : default:
290 : /*-------------------------------------------------------------
291 : * Unsupported feature type... we still return a valid feature
292 : * with NONE geometry after producing a Warning.
293 : * Callers can trap that case by checking CPLGetLastErrorNo()
294 : * against TAB_WarningFeatureTypeNotSupported
295 : *------------------------------------------------------------*/
296 : // poFeature = new TABDebugFeature(poDefn);
297 0 : poFeature = new TABFeature(poDefn);
298 :
299 : CPLError(CE_Warning, TAB_WarningFeatureTypeNotSupported,
300 : "Unsupported object type %d (0x%2.2x). Feature will be "
301 : "returned with NONE geometry.",
302 0 : nMapInfoType, nMapInfoType);
303 : }
304 :
305 53 : return poFeature;
306 : }
307 :
308 :
309 : /**********************************************************************
310 : * TABFeature::CopyTABFeatureBase()
311 : *
312 : * Used by CloneTABFeature() to copy the basic (fields, geometry, etc.)
313 : * TABFeature members.
314 : *
315 : * The newly created feature is owned by the caller, and will have it's own
316 : * reference to the OGRFeatureDefn.
317 : *
318 : * It is possible to create the clone with a different OGRFeatureDefn,
319 : * in this case, the fields won't be copied of course.
320 : *
321 : **********************************************************************/
322 0 : void TABFeature::CopyTABFeatureBase(TABFeature *poDestFeature)
323 : {
324 : /*-----------------------------------------------------------------
325 : * Copy fields only if OGRFeatureDefn is the same
326 : *----------------------------------------------------------------*/
327 0 : OGRFeatureDefn *poThisDefnRef = GetDefnRef();
328 :
329 0 : if (poThisDefnRef == poDestFeature->GetDefnRef())
330 : {
331 0 : for( int i = 0; i < poThisDefnRef->GetFieldCount(); i++ )
332 : {
333 0 : poDestFeature->SetField( i, GetRawFieldRef( i ) );
334 : }
335 : }
336 :
337 : /*-----------------------------------------------------------------
338 : * Copy the geometry
339 : *----------------------------------------------------------------*/
340 0 : poDestFeature->SetGeometry( GetGeometryRef() );
341 :
342 : double dXMin, dYMin, dXMax, dYMax;
343 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
344 0 : poDestFeature->SetMBR(dXMin, dYMin, dXMax, dYMax);
345 :
346 : GInt32 nXMin, nYMin, nXMax, nYMax;
347 0 : GetIntMBR(nXMin, nYMin, nXMax, nYMax);
348 0 : poDestFeature->SetIntMBR(nXMin, nYMin, nXMax, nYMax);
349 :
350 : // m_nMapInfoType is not carried but it is not required anyways.
351 : // it will default to TAB_GEOM_NONE
352 0 : }
353 :
354 :
355 : /**********************************************************************
356 : * TABFeature::CloneTABFeature()
357 : *
358 : * Duplicate feature, including stuff specific to each TABFeature type.
359 : *
360 : * The newly created feature is owned by the caller, and will have it's own
361 : * reference to the OGRFeatureDefn.
362 : *
363 : * It is possible to create the clone with a different OGRFeatureDefn,
364 : * in this case, the fields won't be copied of course.
365 : *
366 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
367 : * then copies any members specific to its own type.
368 : **********************************************************************/
369 0 : TABFeature *TABFeature::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
370 : {
371 : /*-----------------------------------------------------------------
372 : * Alloc new feature and copy the base stuff
373 : *----------------------------------------------------------------*/
374 0 : TABFeature *poNew = new TABFeature(poNewDefn ? poNewDefn : GetDefnRef());
375 :
376 0 : CopyTABFeatureBase(poNew);
377 :
378 : /*-----------------------------------------------------------------
379 : * And members specific to this class
380 : *----------------------------------------------------------------*/
381 : // Nothing to do for this class
382 :
383 0 : return poNew;
384 : }
385 :
386 : /**********************************************************************
387 : * TABFeature::SetMBR()
388 : *
389 : * Set the values for the MBR corners for this feature.
390 : **********************************************************************/
391 216 : void TABFeature::SetMBR(double dXMin, double dYMin,
392 : double dXMax, double dYMax)
393 : {
394 216 : m_dXMin = MIN(dXMin, dXMax);
395 216 : m_dYMin = MIN(dYMin, dYMax);
396 216 : m_dXMax = MAX(dXMin, dXMax);
397 216 : m_dYMax = MAX(dYMin, dYMax);
398 216 : }
399 :
400 : /**********************************************************************
401 : * TABFeature::GetMBR()
402 : *
403 : * Return the values for the MBR corners for this feature.
404 : **********************************************************************/
405 0 : void TABFeature::GetMBR(double &dXMin, double &dYMin,
406 : double &dXMax, double &dYMax)
407 : {
408 0 : dXMin = m_dXMin;
409 0 : dYMin = m_dYMin;
410 0 : dXMax = m_dXMax;
411 0 : dYMax = m_dYMax;
412 0 : }
413 :
414 : /**********************************************************************
415 : * TABFeature::SetIntMBR()
416 : *
417 : * Set the integer coordinates values of the MBR of this feature.
418 : **********************************************************************/
419 52 : void TABFeature::SetIntMBR(GInt32 nXMin, GInt32 nYMin,
420 : GInt32 nXMax, GInt32 nYMax)
421 : {
422 52 : m_nXMin = nXMin;
423 52 : m_nYMin = nYMin;
424 52 : m_nXMax = nXMax;
425 52 : m_nYMax = nYMax;
426 52 : }
427 :
428 : /**********************************************************************
429 : * TABFeature::GetIntMBR()
430 : *
431 : * Return the integer coordinates values of the MBR of this feature.
432 : **********************************************************************/
433 12 : void TABFeature::GetIntMBR(GInt32 &nXMin, GInt32 &nYMin,
434 : GInt32 &nXMax, GInt32 &nYMax)
435 : {
436 12 : nXMin = m_nXMin;
437 12 : nYMin = m_nYMin;
438 12 : nXMax = m_nXMax;
439 12 : nYMax = m_nYMax;
440 12 : }
441 :
442 : /**********************************************************************
443 : * TABFeature::ReadRecordFromDATFile()
444 : *
445 : * Fill the fields part of the feature from the contents of the
446 : * table record pointed to by poDATFile.
447 : *
448 : * It is assumed that poDATFile currently points to the beginning of
449 : * the table record and that this feature's OGRFeatureDefn has been
450 : * properly initialized for this table.
451 : **********************************************************************/
452 53 : int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
453 : {
454 : int iField, numFields, nValue;
455 : double dValue;
456 : const char *pszValue;
457 : #ifdef MITAB_USE_OFTDATETIME
458 : int nYear, nMonth, nDay, nHour, nMin, nSec, nMS, status;
459 53 : nYear = nMonth = nDay = nHour = nMin = nSec = nMS = 0;
460 : #endif
461 :
462 53 : CPLAssert(poDATFile);
463 :
464 53 : numFields = poDATFile->GetNumFields();
465 :
466 206 : for(iField=0; iField<numFields; iField++)
467 : {
468 153 : switch(poDATFile->GetFieldType(iField))
469 : {
470 : case TABFChar:
471 : pszValue = poDATFile->ReadCharField(poDATFile->
472 53 : GetFieldWidth(iField));
473 53 : SetField(iField, pszValue);
474 53 : break;
475 : case TABFDecimal:
476 : dValue = poDATFile->ReadDecimalField(poDATFile->
477 0 : GetFieldWidth(iField));
478 0 : SetField(iField, dValue);
479 0 : break;
480 : case TABFInteger:
481 : nValue = poDATFile->ReadIntegerField(poDATFile->
482 50 : GetFieldWidth(iField));
483 50 : SetField(iField, nValue);
484 50 : break;
485 : case TABFSmallInt:
486 : nValue = poDATFile->ReadSmallIntField(poDATFile->
487 0 : GetFieldWidth(iField));
488 0 : SetField(iField, nValue);
489 0 : break;
490 : case TABFFloat:
491 : dValue = poDATFile->ReadFloatField(poDATFile->
492 50 : GetFieldWidth(iField));
493 50 : SetField(iField, dValue);
494 50 : break;
495 : case TABFLogical:
496 : pszValue = poDATFile->ReadLogicalField(poDATFile->
497 0 : GetFieldWidth(iField));
498 0 : SetField(iField, pszValue);
499 0 : break;
500 : case TABFDate:
501 : #ifdef MITAB_USE_OFTDATETIME
502 0 : if ((status = poDATFile->ReadDateField(poDATFile->GetFieldWidth(iField),
503 : &nYear, &nMonth, &nDay)) == 0)
504 : {
505 0 : SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
506 : }
507 : #else
508 : pszValue = poDATFile->ReadDateField(poDATFile->
509 : GetFieldWidth(iField));
510 : SetField(iField, pszValue);
511 : #endif
512 0 : break;
513 : case TABFTime:
514 : #ifdef MITAB_USE_OFTDATETIME
515 0 : if ((status = poDATFile->ReadTimeField(poDATFile->GetFieldWidth(iField),
516 : &nHour, &nMin, &nSec, &nMS)) == 0)
517 : {
518 0 : SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
519 : }
520 : #else
521 : pszValue = poDATFile->ReadTimeField(poDATFile->
522 : GetFieldWidth(iField));
523 : SetField(iField, pszValue);
524 : #endif
525 0 : break;
526 : case TABFDateTime:
527 : #ifdef MITAB_USE_OFTDATETIME
528 0 : if ((status = poDATFile->ReadDateTimeField(poDATFile->GetFieldWidth(iField),
529 : &nYear, &nMonth, &nDay,
530 : &nHour, &nMin, &nSec, &nMS)) == 0)
531 : {
532 0 : SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
533 : }
534 : #else
535 : pszValue = poDATFile->ReadDateTimeField(poDATFile->
536 : GetFieldWidth(iField));
537 : SetField(iField, pszValue);
538 : #endif
539 0 : break;
540 : default:
541 : // Other type??? Impossible!
542 : CPLError(CE_Failure, CPLE_AssertionFailed,
543 0 : "Unsupported field type!");
544 : }
545 :
546 : }
547 :
548 53 : return 0;
549 : }
550 :
551 : /**********************************************************************
552 : * TABFeature::WriteRecordToDATFile()
553 : *
554 : * Write the attribute part of the feature to the .DAT file.
555 : *
556 : * It is assumed that poDATFile currently points to the beginning of
557 : * the table record and that this feature's OGRFeatureDefn has been
558 : * properly initialized for this table.
559 : *
560 : * Returns 0 on success, -1 on error.
561 : **********************************************************************/
562 14 : int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
563 : TABINDFile *poINDFile, int *panIndexNo)
564 : {
565 14 : int iField, numFields, nStatus=0;
566 : #ifdef MITAB_USE_OFTDATETIME
567 : int nYear, nMon, nDay, nHour, nMin, nSec, nTZFlag;
568 14 : nYear = nMon = nDay = nHour = nMin = nSec = nTZFlag = 0;
569 : #endif
570 :
571 14 : CPLAssert(poDATFile);
572 14 : CPLAssert(panIndexNo || GetDefnRef()->GetFieldCount() == 0);
573 :
574 14 : numFields = poDATFile->GetNumFields();
575 :
576 51 : for(iField=0; nStatus == 0 && iField<numFields; iField++)
577 : {
578 : // Hack for "extra" introduced field.
579 37 : if( iField >= GetDefnRef()->GetFieldCount() )
580 : {
581 : CPLAssert( poDATFile->GetFieldType(iField) == TABFInteger
582 0 : && iField == 0 );
583 0 : nStatus = poDATFile->WriteIntegerField( GetFID(), poINDFile, 0 );
584 0 : continue;
585 : }
586 :
587 37 : switch(poDATFile->GetFieldType(iField))
588 : {
589 : case TABFChar:
590 : nStatus = poDATFile->WriteCharField(GetFieldAsString(iField),
591 : poDATFile->GetFieldWidth(iField),
592 13 : poINDFile, panIndexNo[iField]);
593 13 : break;
594 : case TABFDecimal:
595 : nStatus = poDATFile->WriteDecimalField(GetFieldAsDouble(iField),
596 : poDATFile->GetFieldWidth(iField),
597 : poDATFile->GetFieldPrecision(iField),
598 1 : poINDFile, panIndexNo[iField]);
599 1 : break;
600 : case TABFInteger:
601 : nStatus = poDATFile->WriteIntegerField(GetFieldAsInteger(iField),
602 12 : poINDFile, panIndexNo[iField]);
603 12 : break;
604 : case TABFSmallInt:
605 : nStatus = poDATFile->WriteSmallIntField((GInt16)GetFieldAsInteger(iField),
606 0 : poINDFile, panIndexNo[iField]);
607 0 : break;
608 : case TABFFloat:
609 : nStatus = poDATFile->WriteFloatField(GetFieldAsDouble(iField),
610 11 : poINDFile, panIndexNo[iField]);
611 11 : break;
612 : case TABFLogical:
613 : nStatus = poDATFile->WriteLogicalField(GetFieldAsString(iField),
614 0 : poINDFile, panIndexNo[iField]);
615 0 : break;
616 : case TABFDate:
617 : #ifdef MITAB_USE_OFTDATETIME
618 0 : if (IsFieldSet(iField))
619 : {
620 : GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
621 0 : &nHour, &nMin, &nSec, &nTZFlag);
622 : }
623 : else
624 0 : nYear = nMon = nDay = 0;
625 :
626 : nStatus = poDATFile->WriteDateField(nYear, nMon, nDay,
627 0 : poINDFile, panIndexNo[iField]);
628 : #else
629 : nStatus = poDATFile->WriteDateField(GetFieldAsString(iField),
630 : poINDFile, panIndexNo[iField]);
631 : #endif
632 0 : break;
633 : case TABFTime:
634 : #ifdef MITAB_USE_OFTDATETIME
635 0 : if (IsFieldSet(iField))
636 : {
637 : GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
638 0 : &nHour, &nMin, &nSec, &nTZFlag);
639 : }
640 : else
641 : {
642 0 : nHour = nMin = nSec = -1;
643 : }
644 : nStatus = poDATFile->WriteTimeField(nHour, nMin, nSec, 0,
645 0 : poINDFile, panIndexNo[iField]);
646 :
647 : #else
648 : nStatus = poDATFile->WriteTimeField(GetFieldAsString(iField),
649 : poINDFile, panIndexNo[iField]);
650 : #endif
651 0 : break;
652 : case TABFDateTime:
653 : #ifdef MITAB_USE_OFTDATETIME
654 0 : if (IsFieldSet(iField))
655 : {
656 : GetFieldAsDateTime(iField, &nYear, &nMon, &nDay,
657 0 : &nHour, &nMin, &nSec, &nTZFlag);
658 : }
659 : else
660 0 : nYear = nMon = nDay = nHour = nMin = nSec = 0;
661 :
662 : nStatus = poDATFile->WriteDateTimeField(nYear, nMon, nDay,
663 : nHour, nMin, nSec, 0,
664 0 : poINDFile, panIndexNo[iField]);
665 : #else
666 : nStatus = poDATFile->WriteDateTimeField(GetFieldAsString(iField),
667 : poINDFile, panIndexNo[iField]);
668 : #endif
669 0 : break;
670 : default:
671 : // Other type??? Impossible!
672 : CPLError(CE_Failure, CPLE_AssertionFailed,
673 0 : "Unsupported field type!");
674 : }
675 :
676 : }
677 :
678 14 : if (poDATFile->CommitRecordToFile() != 0)
679 0 : return -1;
680 :
681 14 : return 0;
682 : }
683 :
684 : /**********************************************************************
685 : * TABFeature::ReadGeometryFromMAPFile()
686 : *
687 : * In derived classes, this method should be reimplemented to
688 : * fill the geometry and representation (color, etc...) part of the
689 : * feature from the contents of the .MAP object pointed to by poMAPFile.
690 : *
691 : * It is assumed that before calling ReadGeometryFromMAPFile(), poMAPFile
692 : * currently points to the beginning of a map object.
693 : *
694 : * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
695 : * the CoordBlock data during splitting of object blocks. In this case we
696 : * need to process only the information related to the CoordBlock. One
697 : * important thing to avoid is reading/writing pen/brush/symbol definitions
698 : * as that would screw up their ref counters.
699 : *
700 : * ppoCoordBlock is used by TABCollection and by index splitting code
701 : * to provide a CoordBlock to use instead of the one from the poMAPFile and
702 : * return the current pointer at the end of the call.
703 : *
704 : * The current implementation does nothing since instances of TABFeature
705 : * objects contain no geometry (i.e. TAB_GEOM_NONE).
706 : *
707 : * Returns 0 on success, -1 on error, in which case CPLError() will have
708 : * been called.
709 : **********************************************************************/
710 1 : int TABFeature::ReadGeometryFromMAPFile(TABMAPFile * /*poMapFile*/,
711 : TABMAPObjHdr * /*poObjHdr*/,
712 : GBool /*bCoordBlockDataOnly=FALSE*/,
713 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
714 : {
715 : /*-----------------------------------------------------------------
716 : * Nothing to do... instances of TABFeature objects contain no geometry.
717 : *----------------------------------------------------------------*/
718 :
719 1 : return 0;
720 : }
721 :
722 :
723 : /**********************************************************************
724 : * TABFeature::UpdateMBR()
725 : *
726 : * Fetch envelope of poGeom and update MBR.
727 : * Integer coord MBR is updated only if poMapFile is not NULL.
728 : *
729 : * Returns 0 on success, or -1 if there is no geometry in object
730 : **********************************************************************/
731 12 : int TABFeature::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
732 : {
733 : OGRGeometry *poGeom;
734 :
735 12 : poGeom = GetGeometryRef();
736 :
737 12 : if (poGeom)
738 : {
739 12 : OGREnvelope oEnv;
740 12 : poGeom->getEnvelope(&oEnv);
741 :
742 12 : m_dXMin = oEnv.MinX;
743 12 : m_dYMin = oEnv.MinY;
744 12 : m_dXMax = oEnv.MaxX;
745 12 : m_dYMax = oEnv.MaxY;
746 :
747 12 : if (poMapFile)
748 : {
749 12 : poMapFile->Coordsys2Int(oEnv.MinX, oEnv.MinY, m_nXMin, m_nYMin);
750 12 : poMapFile->Coordsys2Int(oEnv.MaxX, oEnv.MaxY, m_nXMax, m_nYMax);
751 : }
752 :
753 12 : return 0;
754 : }
755 :
756 0 : return -1;
757 : }
758 :
759 : /**********************************************************************
760 : * TABFeature::ValidateCoordType()
761 : *
762 : * Checks the feature envelope to establish if the feature should be
763 : * written using Compressed coordinates or not and adjust m_nMapInfoType
764 : * accordingly. Calling this method also sets (initializes) m_nXMin, m_nYMin,
765 : * m_nXMax, m_nYMax
766 : *
767 : * This function should be used only by the ValidateMapInfoType()
768 : * implementations.
769 : *
770 : * Returns TRUE if coord. should be compressed, FALSE otherwise
771 : **********************************************************************/
772 11 : GBool TABFeature::ValidateCoordType(TABMAPFile * poMapFile)
773 : {
774 11 : GBool bCompr = FALSE;
775 :
776 : /*-------------------------------------------------------------
777 : * Decide if coordinates should be compressed or not.
778 : *------------------------------------------------------------*/
779 11 : if (UpdateMBR(poMapFile) == 0)
780 : {
781 : /* Test for max range < 65535 here instead of < 65536 to avoid
782 : * compressed coordinate overflows in some boundary situations
783 : */
784 11 : if ((m_nXMax - m_nXMin) < 65535 && (m_nYMax-m_nYMin) < 65535)
785 : {
786 10 : bCompr = TRUE;
787 : }
788 11 : m_nComprOrgX = (m_nXMin + m_nXMax) / 2;
789 11 : m_nComprOrgY = (m_nYMin + m_nYMax) / 2;
790 : }
791 :
792 : /*-------------------------------------------------------------
793 : * Adjust native type
794 : *------------------------------------------------------------*/
795 21 : if (bCompr && ((m_nMapInfoType%3) == 2))
796 10 : m_nMapInfoType--; // compr = 1, 4, 7, ...
797 1 : else if (!bCompr && ((m_nMapInfoType%3) == 1))
798 0 : m_nMapInfoType++; // non-compr = 2, 5, 8, ...
799 :
800 11 : return bCompr;
801 : }
802 :
803 : /**********************************************************************
804 : * TABFeature::ForceCoordTypeAndOrigin()
805 : *
806 : * This function is used by TABCollection::ValidateMapInfoType() to force
807 : * the coord type and compressed origin of all members of a collection
808 : * to be the same. (A replacement for ValidateCoordType() for this
809 : * specific case)
810 : **********************************************************************/
811 0 : void TABFeature::ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
812 : GInt32 nComprOrgX, GInt32 nComprOrgY,
813 : GInt32 nXMin, GInt32 nYMin,
814 : GInt32 nXMax, GInt32 nYMax)
815 : {
816 : /*-------------------------------------------------------------
817 : * Set Compressed Origin and adjust native type
818 : *------------------------------------------------------------*/
819 0 : m_nComprOrgX = nComprOrgX;
820 0 : m_nComprOrgY = nComprOrgY;
821 :
822 0 : m_nMapInfoType = nMapInfoType;
823 :
824 0 : if (bCompr && ((m_nMapInfoType%3) == 2))
825 0 : m_nMapInfoType--; // compr = 1, 4, 7, ...
826 0 : else if (!bCompr && ((m_nMapInfoType%3) == 1))
827 0 : m_nMapInfoType++; // non-compr = 2, 5, 8, ...
828 :
829 0 : m_nXMin = nXMin;
830 0 : m_nYMin = nYMin;
831 0 : m_nXMax = nXMax;
832 0 : m_nYMax = nYMax;
833 0 : }
834 :
835 : /**********************************************************************
836 : * TABFeature::WriteGeometryToMAPFile()
837 : *
838 : *
839 : * In derived classes, this method should be reimplemented to
840 : * write the geometry and representation (color, etc...) part of the
841 : * feature to the .MAP object pointed to by poMAPFile.
842 : *
843 : * It is assumed that before calling WriteGeometryToMAPFile(), poMAPFile
844 : * currently points to a valid map object.
845 : *
846 : * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
847 : * the CoordBlock data during splitting of object blocks. In this case we
848 : * need to process only the information related to the CoordBlock. One
849 : * important thing to avoid is reading/writing pen/brush/symbol definitions
850 : * as that would screw up their ref counters.
851 : *
852 : * ppoCoordBlock is used by TABCollection and by index splitting code
853 : * to provide a CoordBlock to use instead of the one from the poMAPFile and
854 : * return the current pointer at the end of the call.
855 : *
856 : * The current implementation does nothing since instances of TABFeature
857 : * objects contain no geometry (i.e. TAB_GEOM_NONE).
858 : *
859 : * Returns 0 on success, -1 on error, in which case CPLError() will have
860 : * been called.
861 : **********************************************************************/
862 2 : int TABFeature::WriteGeometryToMAPFile(TABMAPFile * /* poMapFile*/,
863 : TABMAPObjHdr * /*poObjHdr*/,
864 : GBool /*bCoordBlockDataOnly=FALSE*/,
865 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
866 : {
867 : /*-----------------------------------------------------------------
868 : * Nothing to do... instances of TABFeature objects contain no geometry.
869 : *----------------------------------------------------------------*/
870 :
871 2 : return 0;
872 : }
873 :
874 : /**********************************************************************
875 : * TABFeature::DumpMID()
876 : *
877 : * Dump feature attributes in a format similar to .MID data records.
878 : **********************************************************************/
879 0 : void TABFeature::DumpMID(FILE *fpOut /*=NULL*/)
880 : {
881 0 : OGRFeatureDefn *poDefn = GetDefnRef();
882 :
883 0 : if (fpOut == NULL)
884 0 : fpOut = stdout;
885 :
886 0 : for( int iField = 0; iField < GetFieldCount(); iField++ )
887 : {
888 0 : OGRFieldDefn *poFDefn = poDefn->GetFieldDefn(iField);
889 :
890 : fprintf( fpOut, " %s (%s) = %s\n",
891 : poFDefn->GetNameRef(),
892 : OGRFieldDefn::GetFieldTypeName(poFDefn->GetType()),
893 0 : GetFieldAsString( iField ) );
894 : }
895 :
896 0 : fflush(fpOut);
897 0 : }
898 :
899 : /**********************************************************************
900 : * TABFeature::DumpMIF()
901 : *
902 : * Dump feature geometry in a format similar to .MIF files.
903 : **********************************************************************/
904 0 : void TABFeature::DumpMIF(FILE *fpOut /*=NULL*/)
905 : {
906 0 : if (fpOut == NULL)
907 0 : fpOut = stdout;
908 :
909 : /*-----------------------------------------------------------------
910 : * Generate output... not much to do, feature contains no geometry.
911 : *----------------------------------------------------------------*/
912 0 : fprintf(fpOut, "NONE\n" );
913 :
914 0 : fflush(fpOut);
915 0 : }
916 :
917 :
918 : /*=====================================================================
919 : * class TABPoint
920 : *====================================================================*/
921 :
922 :
923 : /**********************************************************************
924 : * TABPoint::TABPoint()
925 : *
926 : * Constructor.
927 : **********************************************************************/
928 8 : TABPoint::TABPoint(OGRFeatureDefn *poDefnIn):
929 8 : TABFeature(poDefnIn)
930 : {
931 8 : }
932 :
933 : /**********************************************************************
934 : * TABPoint::~TABPoint()
935 : *
936 : * Destructor.
937 : **********************************************************************/
938 8 : TABPoint::~TABPoint()
939 : {
940 8 : }
941 :
942 : /**********************************************************************
943 : * TABPoint::CloneTABFeature()
944 : *
945 : * Duplicate feature, including stuff specific to each TABFeature type.
946 : *
947 : * This method calls the generic TABFeature::CloneTABFeature() and
948 : * then copies any members specific to its own type.
949 : **********************************************************************/
950 0 : TABFeature *TABPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
951 : {
952 : /*-----------------------------------------------------------------
953 : * Alloc new feature and copy the base stuff
954 : *----------------------------------------------------------------*/
955 0 : TABPoint *poNew = new TABPoint(poNewDefn ? poNewDefn : GetDefnRef());
956 :
957 0 : CopyTABFeatureBase(poNew);
958 :
959 : /*-----------------------------------------------------------------
960 : * And members specific to this class
961 : *----------------------------------------------------------------*/
962 : // ITABFeatureSymbol
963 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
964 :
965 0 : return poNew;
966 : }
967 :
968 :
969 : /**********************************************************************
970 : * TABPoint::ValidateMapInfoType()
971 : *
972 : * Check the feature's geometry part and return the corresponding
973 : * mapinfo object type code. The m_nMapInfoType member will also
974 : * be updated for further calls to GetMapInfoType();
975 : *
976 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
977 : * is expected for this object class.
978 : **********************************************************************/
979 0 : int TABPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
980 : {
981 : OGRGeometry *poGeom;
982 :
983 : /*-----------------------------------------------------------------
984 : * Fetch and validate geometry
985 : * __TODO__ For now we always write in uncompressed format (until we
986 : * find that this is not correct... note that at this point the
987 : * decision to use compressed/uncompressed will likely be based on
988 : * the distance between the point and the object block center in
989 : * integer coordinates being > 32767 or not... remains to be verified)
990 : *----------------------------------------------------------------*/
991 0 : poGeom = GetGeometryRef();
992 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
993 : {
994 0 : switch(GetFeatureClass())
995 : {
996 : case TABFCFontPoint:
997 0 : m_nMapInfoType = TAB_GEOM_FONTSYMBOL;
998 0 : break;
999 : case TABFCCustomPoint:
1000 0 : m_nMapInfoType = TAB_GEOM_CUSTOMSYMBOL;
1001 0 : break;
1002 : case TABFCPoint:
1003 : default:
1004 0 : m_nMapInfoType = TAB_GEOM_SYMBOL;
1005 : break;
1006 : }
1007 : }
1008 : else
1009 : {
1010 : CPLError(CE_Failure, CPLE_AssertionFailed,
1011 0 : "TABPoint: Missing or Invalid Geometry!");
1012 0 : m_nMapInfoType = TAB_GEOM_NONE;
1013 : }
1014 :
1015 0 : UpdateMBR(poMapFile);
1016 :
1017 0 : return m_nMapInfoType;
1018 : }
1019 :
1020 : /**********************************************************************
1021 : * TABPoint::ReadGeometryFromMAPFile()
1022 : *
1023 : * Fill the geometry and representation (color, etc...) part of the
1024 : * feature from the contents of the .MAP object pointed to by poMAPFile.
1025 : *
1026 : * It is assumed that poMAPFile currently points to the beginning of
1027 : * a map object.
1028 : *
1029 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1030 : * been called.
1031 : **********************************************************************/
1032 0 : int TABPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
1033 : TABMAPObjHdr *poObjHdr,
1034 : GBool bCoordBlockDataOnly /*=FALSE*/,
1035 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1036 : {
1037 : double dX, dY;
1038 : OGRGeometry *poGeometry;
1039 :
1040 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1041 0 : if (bCoordBlockDataOnly)
1042 0 : return 0;
1043 :
1044 : /*-----------------------------------------------------------------
1045 : * Fetch and validate geometry type
1046 : *----------------------------------------------------------------*/
1047 0 : m_nMapInfoType = poObjHdr->m_nType;
1048 :
1049 0 : if (m_nMapInfoType != TAB_GEOM_SYMBOL &&
1050 : m_nMapInfoType != TAB_GEOM_SYMBOL_C )
1051 : {
1052 : CPLError(CE_Failure, CPLE_AssertionFailed,
1053 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
1054 0 : m_nMapInfoType, m_nMapInfoType);
1055 0 : return -1;
1056 : }
1057 :
1058 : /*-----------------------------------------------------------------
1059 : * Read object information
1060 : *----------------------------------------------------------------*/
1061 0 : TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
1062 :
1063 0 : m_nSymbolDefIndex = poPointHdr->m_nSymbolId; // Symbol index
1064 :
1065 0 : poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
1066 :
1067 : /*-----------------------------------------------------------------
1068 : * Create and fill geometry object
1069 : *----------------------------------------------------------------*/
1070 0 : poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
1071 0 : poGeometry = new OGRPoint(dX, dY);
1072 :
1073 0 : SetGeometryDirectly(poGeometry);
1074 :
1075 0 : SetMBR(dX, dY, dX, dY);
1076 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
1077 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
1078 :
1079 0 : return 0;
1080 : }
1081 :
1082 : /**********************************************************************
1083 : * TABPoint::WriteGeometryToMAPFile()
1084 : *
1085 : * Write the geometry and representation (color, etc...) part of the
1086 : * feature to the .MAP object pointed to by poMAPFile.
1087 : *
1088 : * It is assumed that poMAPFile currently points to a valid map object.
1089 : *
1090 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1091 : * been called.
1092 : **********************************************************************/
1093 0 : int TABPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
1094 : TABMAPObjHdr *poObjHdr,
1095 : GBool bCoordBlockDataOnly /*=FALSE*/,
1096 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1097 : {
1098 : GInt32 nX, nY;
1099 : OGRGeometry *poGeom;
1100 : OGRPoint *poPoint;
1101 :
1102 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1103 0 : if (bCoordBlockDataOnly)
1104 0 : return 0;
1105 :
1106 : /*-----------------------------------------------------------------
1107 : * We assume that ValidateMapInfoType() was called already and that
1108 : * the type in poObjHdr->m_nType is valid.
1109 : *----------------------------------------------------------------*/
1110 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
1111 :
1112 : /*-----------------------------------------------------------------
1113 : * Fetch and validate geometry
1114 : *----------------------------------------------------------------*/
1115 0 : poGeom = GetGeometryRef();
1116 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1117 0 : poPoint = (OGRPoint*)poGeom;
1118 : else
1119 : {
1120 : CPLError(CE_Failure, CPLE_AssertionFailed,
1121 0 : "TABPoint: Missing or Invalid Geometry!");
1122 0 : return -1;
1123 : }
1124 :
1125 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
1126 :
1127 : /*-----------------------------------------------------------------
1128 : * Copy object information
1129 : *----------------------------------------------------------------*/
1130 0 : TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
1131 :
1132 0 : poPointHdr->m_nX = nX;
1133 0 : poPointHdr->m_nY = nY;
1134 0 : poPointHdr->SetMBR(nX, nY, nX, nY);
1135 :
1136 0 : m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
1137 0 : poPointHdr->m_nSymbolId = (GByte)m_nSymbolDefIndex; // Symbol index
1138 :
1139 0 : if (CPLGetLastErrorNo() != 0)
1140 0 : return -1;
1141 :
1142 0 : return 0;
1143 : }
1144 :
1145 :
1146 : /**********************************************************************
1147 : * TABPoint::GetX()
1148 : *
1149 : * Return this point's X coordinate.
1150 : **********************************************************************/
1151 0 : double TABPoint::GetX()
1152 : {
1153 : OGRGeometry *poGeom;
1154 0 : OGRPoint *poPoint=NULL;
1155 :
1156 : /*-----------------------------------------------------------------
1157 : * Fetch and validate geometry
1158 : *----------------------------------------------------------------*/
1159 0 : poGeom = GetGeometryRef();
1160 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1161 0 : poPoint = (OGRPoint*)poGeom;
1162 : else
1163 : {
1164 : CPLError(CE_Failure, CPLE_AssertionFailed,
1165 0 : "TABPoint: Missing or Invalid Geometry!");
1166 0 : return 0.0;
1167 : }
1168 :
1169 0 : return poPoint->getX();
1170 : }
1171 :
1172 : /**********************************************************************
1173 : * TABPoint::GetY()
1174 : *
1175 : * Return this point's Y coordinate.
1176 : **********************************************************************/
1177 0 : double TABPoint::GetY()
1178 : {
1179 : OGRGeometry *poGeom;
1180 0 : OGRPoint *poPoint=NULL;
1181 :
1182 : /*-----------------------------------------------------------------
1183 : * Fetch and validate geometry
1184 : *----------------------------------------------------------------*/
1185 0 : poGeom = GetGeometryRef();
1186 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1187 0 : poPoint = (OGRPoint*)poGeom;
1188 : else
1189 : {
1190 : CPLError(CE_Failure, CPLE_AssertionFailed,
1191 0 : "TABPoint: Missing or Invalid Geometry!");
1192 0 : return 0.0;
1193 : }
1194 :
1195 0 : return poPoint->getY();
1196 : }
1197 :
1198 :
1199 : /**********************************************************************
1200 : * TABPoint::GetStyleString()
1201 : *
1202 : * Return style string for this feature.
1203 : *
1204 : * Style String is built only once during the first call to GetStyleString().
1205 : **********************************************************************/
1206 0 : const char *TABPoint::GetStyleString()
1207 : {
1208 0 : if (m_pszStyleString == NULL)
1209 : {
1210 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
1211 : }
1212 :
1213 0 : return m_pszStyleString;
1214 : }
1215 :
1216 :
1217 : /**********************************************************************
1218 : * TABPoint::DumpMIF()
1219 : *
1220 : * Dump feature geometry in a format similar to .MIF POINTs.
1221 : **********************************************************************/
1222 0 : void TABPoint::DumpMIF(FILE *fpOut /*=NULL*/)
1223 : {
1224 : OGRGeometry *poGeom;
1225 : OGRPoint *poPoint;
1226 :
1227 0 : if (fpOut == NULL)
1228 0 : fpOut = stdout;
1229 :
1230 : /*-----------------------------------------------------------------
1231 : * Fetch and validate geometry
1232 : *----------------------------------------------------------------*/
1233 0 : poGeom = GetGeometryRef();
1234 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1235 0 : poPoint = (OGRPoint*)poGeom;
1236 : else
1237 : {
1238 : CPLError(CE_Failure, CPLE_AssertionFailed,
1239 0 : "TABPoint: Missing or Invalid Geometry!");
1240 0 : return;
1241 : }
1242 :
1243 : /*-----------------------------------------------------------------
1244 : * Generate output
1245 : *----------------------------------------------------------------*/
1246 0 : fprintf(fpOut, "POINT %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
1247 :
1248 0 : DumpSymbolDef(fpOut);
1249 :
1250 : /*-----------------------------------------------------------------
1251 : * Handle stuff specific to derived classes
1252 : *----------------------------------------------------------------*/
1253 0 : if (GetFeatureClass() == TABFCFontPoint)
1254 : {
1255 0 : TABFontPoint *poFeature = (TABFontPoint *)this;
1256 : fprintf(fpOut, " m_nFontStyle = 0x%2.2x (%d)\n",
1257 : poFeature->GetFontStyleTABValue(),
1258 0 : poFeature->GetFontStyleTABValue());
1259 :
1260 0 : poFeature->DumpFontDef(fpOut);
1261 : }
1262 0 : if (GetFeatureClass() == TABFCCustomPoint)
1263 : {
1264 0 : TABCustomPoint *poFeature = (TABCustomPoint *)this;
1265 :
1266 : fprintf(fpOut, " m_nUnknown_ = 0x%2.2x (%d)\n",
1267 0 : poFeature->m_nUnknown_, poFeature->m_nUnknown_);
1268 : fprintf(fpOut, " m_nCustomStyle = 0x%2.2x (%d)\n",
1269 : poFeature->GetCustomSymbolStyle(),
1270 0 : poFeature->GetCustomSymbolStyle());
1271 :
1272 0 : poFeature->DumpFontDef(fpOut);
1273 : }
1274 :
1275 0 : fflush(fpOut);
1276 : }
1277 :
1278 : /*=====================================================================
1279 : * class TABFontPoint
1280 : *====================================================================*/
1281 :
1282 :
1283 : /**********************************************************************
1284 : * TABFontPoint::TABFontPoint()
1285 : *
1286 : * Constructor.
1287 : **********************************************************************/
1288 0 : TABFontPoint::TABFontPoint(OGRFeatureDefn *poDefnIn):
1289 0 : TABPoint(poDefnIn)
1290 : {
1291 0 : m_nFontStyle = 0;
1292 0 : m_dAngle = 0.0;
1293 0 : }
1294 :
1295 : /**********************************************************************
1296 : * TABFontPoint::~TABFontPoint()
1297 : *
1298 : * Destructor.
1299 : **********************************************************************/
1300 0 : TABFontPoint::~TABFontPoint()
1301 : {
1302 0 : }
1303 :
1304 : /**********************************************************************
1305 : * TABFontPoint::CloneTABFeature()
1306 : *
1307 : * Duplicate feature, including stuff specific to each TABFeature type.
1308 : *
1309 : * This method calls the generic TABFeature::CloneTABFeature() and
1310 : * then copies any members specific to its own type.
1311 : **********************************************************************/
1312 0 : TABFeature *TABFontPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
1313 : {
1314 : /*-----------------------------------------------------------------
1315 : * Alloc new feature and copy the base stuff
1316 : *----------------------------------------------------------------*/
1317 : TABFontPoint *poNew = new TABFontPoint(poNewDefn ? poNewDefn :
1318 0 : GetDefnRef());
1319 :
1320 0 : CopyTABFeatureBase(poNew);
1321 :
1322 : /*-----------------------------------------------------------------
1323 : * And members specific to this class
1324 : *----------------------------------------------------------------*/
1325 : // ITABFeatureSymbol
1326 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
1327 :
1328 : // ITABFeatureFont
1329 0 : *(poNew->GetFontDefRef()) = *GetFontDefRef();
1330 :
1331 0 : poNew->SetSymbolAngle( GetSymbolAngle() );
1332 0 : poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
1333 :
1334 0 : return poNew;
1335 : }
1336 :
1337 : /**********************************************************************
1338 : * TABFontPoint::ReadGeometryFromMAPFile()
1339 : *
1340 : * Fill the geometry and representation (color, etc...) part of the
1341 : * feature from the contents of the .MAP object pointed to by poMAPFile.
1342 : *
1343 : * It is assumed that poMAPFile currently points to the beginning of
1344 : * a map object.
1345 : *
1346 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1347 : * been called.
1348 : **********************************************************************/
1349 0 : int TABFontPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
1350 : TABMAPObjHdr *poObjHdr,
1351 : GBool bCoordBlockDataOnly /*=FALSE*/,
1352 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1353 : {
1354 : double dX, dY;
1355 : OGRGeometry *poGeometry;
1356 :
1357 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1358 0 : if (bCoordBlockDataOnly)
1359 0 : return 0;
1360 :
1361 : /*-----------------------------------------------------------------
1362 : * Fetch and validate geometry type
1363 : *----------------------------------------------------------------*/
1364 0 : m_nMapInfoType = poObjHdr->m_nType;
1365 :
1366 0 : if (m_nMapInfoType != TAB_GEOM_FONTSYMBOL &&
1367 : m_nMapInfoType != TAB_GEOM_FONTSYMBOL_C )
1368 : {
1369 : CPLError(CE_Failure, CPLE_AssertionFailed,
1370 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
1371 0 : m_nMapInfoType, m_nMapInfoType);
1372 0 : return -1;
1373 : }
1374 :
1375 : /*-----------------------------------------------------------------
1376 : * Read object information
1377 : * NOTE: This symbol type does not contain a reference to a
1378 : * SymbolDef block in the file, but we still use the m_sSymbolDef
1379 : * structure to store the information inside the class so that the
1380 : * ITABFeatureSymbol methods work properly for the class user.
1381 : *----------------------------------------------------------------*/
1382 0 : TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
1383 :
1384 0 : m_nSymbolDefIndex = -1;
1385 0 : m_sSymbolDef.nRefCount = 0;
1386 :
1387 0 : m_sSymbolDef.nSymbolNo = poPointHdr->m_nSymbolId; // shape
1388 0 : m_sSymbolDef.nPointSize = poPointHdr->m_nPointSize; // point size
1389 :
1390 0 : m_nFontStyle = poPointHdr->m_nFontStyle; // font style
1391 :
1392 : m_sSymbolDef.rgbColor = (poPointHdr->m_nR*256*256 +
1393 : poPointHdr->m_nG*256 +
1394 0 : poPointHdr->m_nB);
1395 :
1396 : /*-------------------------------------------------------------
1397 : * Symbol Angle, in thenths of degree.
1398 : * Contrary to arc start/end angles, no conversion based on
1399 : * origin quadrant is required here
1400 : *------------------------------------------------------------*/
1401 0 : m_dAngle = poPointHdr->m_nAngle/10.0;
1402 :
1403 0 : m_nFontDefIndex = poPointHdr->m_nFontId; // Font name index
1404 :
1405 0 : poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
1406 :
1407 : /*-----------------------------------------------------------------
1408 : * Create and fill geometry object
1409 : *----------------------------------------------------------------*/
1410 0 : poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
1411 0 : poGeometry = new OGRPoint(dX, dY);
1412 :
1413 0 : SetGeometryDirectly(poGeometry);
1414 :
1415 0 : SetMBR(dX, dY, dX, dY);
1416 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
1417 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
1418 :
1419 0 : return 0;
1420 : }
1421 :
1422 : /**********************************************************************
1423 : * TABFontPoint::WriteGeometryToMAPFile()
1424 : *
1425 : * Write the geometry and representation (color, etc...) part of the
1426 : * feature to the .MAP object pointed to by poMAPFile.
1427 : *
1428 : * It is assumed that poMAPFile currently points to a valid map object.
1429 : *
1430 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1431 : * been called.
1432 : **********************************************************************/
1433 0 : int TABFontPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
1434 : TABMAPObjHdr *poObjHdr,
1435 : GBool bCoordBlockDataOnly /*=FALSE*/,
1436 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1437 : {
1438 : GInt32 nX, nY;
1439 : OGRGeometry *poGeom;
1440 : OGRPoint *poPoint;
1441 :
1442 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1443 0 : if (bCoordBlockDataOnly)
1444 0 : return 0;
1445 :
1446 : /*-----------------------------------------------------------------
1447 : * We assume that ValidateMapInfoType() was called already and that
1448 : * the type in poObjHdr->m_nType is valid.
1449 : *----------------------------------------------------------------*/
1450 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
1451 :
1452 : /*-----------------------------------------------------------------
1453 : * Fetch and validate geometry
1454 : *----------------------------------------------------------------*/
1455 0 : poGeom = GetGeometryRef();
1456 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1457 0 : poPoint = (OGRPoint*)poGeom;
1458 : else
1459 : {
1460 : CPLError(CE_Failure, CPLE_AssertionFailed,
1461 0 : "TABFontPoint: Missing or Invalid Geometry!");
1462 0 : return -1;
1463 : }
1464 :
1465 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
1466 :
1467 : /*-----------------------------------------------------------------
1468 : * Copy object information
1469 : * NOTE: This symbol type does not contain a reference to a
1470 : * SymbolDef block in the file, but we still use the m_sSymbolDef
1471 : * structure to store the information inside the class so that the
1472 : * ITABFeatureSymbol methods work properly for the class user.
1473 : *----------------------------------------------------------------*/
1474 0 : TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
1475 :
1476 0 : poPointHdr->m_nX = nX;
1477 0 : poPointHdr->m_nY = nY;
1478 0 : poPointHdr->SetMBR(nX, nY, nX, nY);
1479 :
1480 0 : poPointHdr->m_nSymbolId = (GByte)m_sSymbolDef.nSymbolNo; // shape
1481 0 : poPointHdr->m_nPointSize = (GByte)m_sSymbolDef.nPointSize; // point size
1482 0 : poPointHdr->m_nFontStyle = m_nFontStyle; // font style
1483 :
1484 0 : poPointHdr->m_nR = (GByte)COLOR_R(m_sSymbolDef.rgbColor);
1485 0 : poPointHdr->m_nG = (GByte)COLOR_G(m_sSymbolDef.rgbColor);
1486 0 : poPointHdr->m_nB = (GByte)COLOR_B(m_sSymbolDef.rgbColor);
1487 :
1488 : /*-------------------------------------------------------------
1489 : * Symbol Angle, in thenths of degree.
1490 : * Contrary to arc start/end angles, no conversion based on
1491 : * origin quadrant is required here
1492 : *------------------------------------------------------------*/
1493 0 : poPointHdr->m_nAngle = (GInt16)ROUND_INT(m_dAngle * 10.0);
1494 :
1495 : // Write Font Def
1496 0 : m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
1497 0 : poPointHdr->m_nFontId = (GByte)m_nFontDefIndex; // Font name index
1498 :
1499 0 : if (CPLGetLastErrorNo() != 0)
1500 0 : return -1;
1501 :
1502 0 : return 0;
1503 : }
1504 :
1505 : /**********************************************************************
1506 : * TABFontPoint::QueryFontStyle()
1507 : *
1508 : * Return TRUE if the specified font style attribute is turned ON,
1509 : * or FALSE otherwise. See enum TABFontStyle for the list of styles
1510 : * that can be queried on.
1511 : **********************************************************************/
1512 0 : GBool TABFontPoint::QueryFontStyle(TABFontStyle eStyleToQuery)
1513 : {
1514 0 : return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
1515 : }
1516 :
1517 0 : void TABFontPoint::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
1518 : {
1519 0 : if (bStyleOn)
1520 0 : m_nFontStyle |= (int)eStyleToToggle;
1521 : else
1522 0 : m_nFontStyle &= ~(int)eStyleToToggle;
1523 0 : }
1524 :
1525 : /**********************************************************************
1526 : * TABFontPoint::GetFontStyleMIFValue()
1527 : *
1528 : * Return the Font Style value for this object using the style values
1529 : * that are used in a MIF FONT() clause. See MIF specs (appendix A).
1530 : *
1531 : * The reason why we have to differentiate between the TAB and the MIF font
1532 : * style values is that in TAB, TABFSBox is included in the style value
1533 : * as code 0x100, but in MIF it is not included, instead it is implied by
1534 : * the presence of the BG color in the FONT() clause (the BG color is
1535 : * present only when TABFSBox or TABFSHalo is set).
1536 : * This also has the effect of shifting all the other style values > 0x100
1537 : * by 1 byte.
1538 : *
1539 : * NOTE: Even if there is no BG color for font symbols, we inherit this
1540 : * problem because Font Point styles use the same codes as Text Font styles.
1541 : **********************************************************************/
1542 0 : int TABFontPoint::GetFontStyleMIFValue()
1543 : {
1544 : // The conversion is simply to remove bit 0x100 from the value and shift
1545 : // down all values past this bit.
1546 0 : return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
1547 : }
1548 :
1549 0 : void TABFontPoint:: SetFontStyleMIFValue(int nStyle)
1550 : {
1551 0 : m_nFontStyle = (GByte)((nStyle & 0xff) + (nStyle & 0x7f00)*2);
1552 0 : }
1553 :
1554 : /**********************************************************************
1555 : * TABFontPoint::SetSymbolAngle()
1556 : *
1557 : * Set the symbol angle value in degrees, making sure the value is
1558 : * always in the range [0..360]
1559 : **********************************************************************/
1560 0 : void TABFontPoint::SetSymbolAngle(double dAngle)
1561 : {
1562 0 : while(dAngle < 0.0) dAngle += 360.0;
1563 0 : while(dAngle > 360.0) dAngle -= 360.0;
1564 :
1565 0 : m_dAngle = dAngle;
1566 0 : }
1567 :
1568 :
1569 : /**********************************************************************
1570 : * TABFontPoint::GetStyleString()
1571 : *
1572 : * Return style string for this feature.
1573 : *
1574 : * Style String is built only once during the first call to GetStyleString().
1575 : **********************************************************************/
1576 0 : const char *TABFontPoint::GetStyleString()
1577 : {
1578 0 : if (m_pszStyleString == NULL)
1579 : {
1580 : /* Get the SymbolStyleString, and add the outline Color
1581 : (halo/border in MapInfo Symbol terminology) */
1582 0 : char *pszSymbolStyleString = CPLStrdup(GetSymbolStyleString(GetSymbolAngle()));
1583 0 : int nStyleStringlen = strlen(pszSymbolStyleString);
1584 0 : pszSymbolStyleString[nStyleStringlen-1] = '\0';
1585 :
1586 : const char *outlineColor;
1587 0 : if (m_nFontStyle & 16)
1588 0 : outlineColor = ",o:#000000";
1589 0 : else if (m_nFontStyle & 512)
1590 0 : outlineColor = ",o:#ffffff";
1591 : else
1592 0 : outlineColor = "";
1593 :
1594 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s%s)",
1595 : pszSymbolStyleString,
1596 0 : outlineColor));
1597 0 : CPLFree(pszSymbolStyleString);
1598 : }
1599 :
1600 0 : return m_pszStyleString;
1601 : }
1602 :
1603 :
1604 : /*=====================================================================
1605 : * class TABCustomPoint
1606 : *====================================================================*/
1607 :
1608 :
1609 : /**********************************************************************
1610 : * TABCustomPoint::TABCustomPoint()
1611 : *
1612 : * Constructor.
1613 : **********************************************************************/
1614 0 : TABCustomPoint::TABCustomPoint(OGRFeatureDefn *poDefnIn):
1615 0 : TABPoint(poDefnIn)
1616 : {
1617 0 : m_nUnknown_ = m_nCustomStyle = 0;
1618 0 : }
1619 :
1620 : /**********************************************************************
1621 : * TABCustomPoint::~TABCustomPoint()
1622 : *
1623 : * Destructor.
1624 : **********************************************************************/
1625 0 : TABCustomPoint::~TABCustomPoint()
1626 : {
1627 0 : }
1628 :
1629 : /**********************************************************************
1630 : * TABCustomPoint::CloneTABFeature()
1631 : *
1632 : * Duplicate feature, including stuff specific to each TABFeature type.
1633 : *
1634 : * This method calls the generic TABFeature::CloneTABFeature() and
1635 : * then copies any members specific to its own type.
1636 : **********************************************************************/
1637 0 : TABFeature *TABCustomPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
1638 : {
1639 : /*-----------------------------------------------------------------
1640 : * Alloc new feature and copy the base stuff
1641 : *----------------------------------------------------------------*/
1642 : TABCustomPoint *poNew = new TABCustomPoint(poNewDefn ? poNewDefn :
1643 0 : GetDefnRef());
1644 :
1645 0 : CopyTABFeatureBase(poNew);
1646 :
1647 : /*-----------------------------------------------------------------
1648 : * And members specific to this class
1649 : *----------------------------------------------------------------*/
1650 : // ITABFeatureSymbol
1651 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
1652 :
1653 : // ITABFeatureFont
1654 0 : *(poNew->GetFontDefRef()) = *GetFontDefRef();
1655 :
1656 0 : poNew->SetCustomSymbolStyle( GetCustomSymbolStyle() );
1657 :
1658 0 : return poNew;
1659 : }
1660 :
1661 : /**********************************************************************
1662 : * TABCustomPoint::ReadGeometryFromMAPFile()
1663 : *
1664 : * Fill the geometry and representation (color, etc...) part of the
1665 : * feature from the contents of the .MAP object pointed to by poMAPFile.
1666 : *
1667 : * It is assumed that poMAPFile currently points to the beginning of
1668 : * a map object.
1669 : *
1670 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1671 : * been called.
1672 : **********************************************************************/
1673 0 : int TABCustomPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
1674 : TABMAPObjHdr *poObjHdr,
1675 : GBool bCoordBlockDataOnly /*=FALSE*/,
1676 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1677 : {
1678 : double dX, dY;
1679 : OGRGeometry *poGeometry;
1680 :
1681 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1682 0 : if (bCoordBlockDataOnly)
1683 0 : return 0;
1684 :
1685 : /*-----------------------------------------------------------------
1686 : * Fetch and validate geometry type
1687 : *----------------------------------------------------------------*/
1688 0 : m_nMapInfoType = poObjHdr->m_nType;
1689 :
1690 0 : if (m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL &&
1691 : m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL_C )
1692 : {
1693 : CPLError(CE_Failure, CPLE_AssertionFailed,
1694 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
1695 0 : m_nMapInfoType, m_nMapInfoType);
1696 0 : return -1;
1697 : }
1698 :
1699 : /*-----------------------------------------------------------------
1700 : * Read object information
1701 : *----------------------------------------------------------------*/
1702 0 : TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
1703 :
1704 0 : m_nUnknown_ = poPointHdr->m_nUnknown_; // ???
1705 0 : m_nCustomStyle = poPointHdr->m_nCustomStyle;// 0x01=Show BG,
1706 : // 0x02=Apply Color
1707 :
1708 0 : m_nSymbolDefIndex = poPointHdr->m_nSymbolId; // Symbol index
1709 0 : poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
1710 :
1711 0 : m_nFontDefIndex = poPointHdr->m_nFontId; // Font index
1712 0 : poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
1713 :
1714 : /*-----------------------------------------------------------------
1715 : * Create and fill geometry object
1716 : *----------------------------------------------------------------*/
1717 0 : poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
1718 0 : poGeometry = new OGRPoint(dX, dY);
1719 :
1720 0 : SetGeometryDirectly(poGeometry);
1721 :
1722 0 : SetMBR(dX, dY, dX, dY);
1723 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
1724 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
1725 :
1726 0 : return 0;
1727 : }
1728 :
1729 : /**********************************************************************
1730 : * TABCustomPoint::WriteGeometryToMAPFile()
1731 : *
1732 : * Write the geometry and representation (color, etc...) part of the
1733 : * feature to the .MAP object pointed to by poMAPFile.
1734 : *
1735 : * It is assumed that poMAPFile currently points to a valid map object.
1736 : *
1737 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1738 : * been called.
1739 : **********************************************************************/
1740 0 : int TABCustomPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
1741 : TABMAPObjHdr *poObjHdr,
1742 : GBool bCoordBlockDataOnly /*=FALSE*/,
1743 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1744 : {
1745 : GInt32 nX, nY;
1746 : OGRGeometry *poGeom;
1747 : OGRPoint *poPoint;
1748 :
1749 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1750 0 : if (bCoordBlockDataOnly)
1751 0 : return 0;
1752 :
1753 : /*-----------------------------------------------------------------
1754 : * We assume that ValidateMapInfoType() was called already and that
1755 : * the type in poObjHdr->m_nType is valid.
1756 : *----------------------------------------------------------------*/
1757 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
1758 :
1759 : /*-----------------------------------------------------------------
1760 : * Fetch and validate geometry
1761 : *----------------------------------------------------------------*/
1762 0 : poGeom = GetGeometryRef();
1763 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1764 0 : poPoint = (OGRPoint*)poGeom;
1765 : else
1766 : {
1767 : CPLError(CE_Failure, CPLE_AssertionFailed,
1768 0 : "TABCustomPoint: Missing or Invalid Geometry!");
1769 0 : return -1;
1770 : }
1771 :
1772 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
1773 :
1774 : /*-----------------------------------------------------------------
1775 : * Copy object information
1776 : *----------------------------------------------------------------*/
1777 0 : TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
1778 :
1779 0 : poPointHdr->m_nX = nX;
1780 0 : poPointHdr->m_nY = nY;
1781 0 : poPointHdr->SetMBR(nX, nY, nX, nY);
1782 0 : poPointHdr->m_nUnknown_ = m_nUnknown_;
1783 0 : poPointHdr->m_nCustomStyle = m_nCustomStyle;// 0x01=Show BG,
1784 : // 0x02=Apply Color
1785 :
1786 0 : m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
1787 0 : poPointHdr->m_nSymbolId = (GByte)m_nSymbolDefIndex; // Symbol index
1788 :
1789 0 : m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
1790 0 : poPointHdr->m_nFontId = (GByte)m_nFontDefIndex; // Font index
1791 :
1792 0 : if (CPLGetLastErrorNo() != 0)
1793 0 : return -1;
1794 :
1795 0 : return 0;
1796 : }
1797 :
1798 :
1799 : /**********************************************************************
1800 : * TABCustomPoint::GetStyleString()
1801 : *
1802 : * Return style string for this feature.
1803 : *
1804 : * Style String is built only once during the first call to GetStyleString().
1805 : **********************************************************************/
1806 0 : const char *TABCustomPoint::GetStyleString()
1807 : {
1808 0 : if (m_pszStyleString == NULL)
1809 : {
1810 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
1811 : }
1812 :
1813 0 : return m_pszStyleString;
1814 : }
1815 :
1816 : /*=====================================================================
1817 : * class TABPolyline
1818 : *====================================================================*/
1819 :
1820 :
1821 : /**********************************************************************
1822 : * TABPolyline::TABPolyline()
1823 : *
1824 : * Constructor.
1825 : **********************************************************************/
1826 2 : TABPolyline::TABPolyline(OGRFeatureDefn *poDefnIn):
1827 2 : TABFeature(poDefnIn)
1828 : {
1829 2 : m_bCenterIsSet = FALSE;
1830 2 : m_bSmooth = FALSE;
1831 2 : m_bWriteTwoPointLineAsPolyline = FALSE;
1832 2 : }
1833 :
1834 : /**********************************************************************
1835 : * TABPolyline::~TABPolyline()
1836 : *
1837 : * Destructor.
1838 : **********************************************************************/
1839 2 : TABPolyline::~TABPolyline()
1840 : {
1841 2 : }
1842 :
1843 : /**********************************************************************
1844 : * TABPolyline::CloneTABFeature()
1845 : *
1846 : * Duplicate feature, including stuff specific to each TABFeature type.
1847 : *
1848 : * This method calls the generic TABFeature::CloneTABFeature() and
1849 : * then copies any members specific to its own type.
1850 : **********************************************************************/
1851 0 : TABFeature *TABPolyline::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
1852 : {
1853 : /*-----------------------------------------------------------------
1854 : * Alloc new feature and copy the base stuff
1855 : *----------------------------------------------------------------*/
1856 0 : TABPolyline *poNew = new TABPolyline(poNewDefn ? poNewDefn : GetDefnRef());
1857 :
1858 0 : CopyTABFeatureBase(poNew);
1859 :
1860 : /*-----------------------------------------------------------------
1861 : * And members specific to this class
1862 : *----------------------------------------------------------------*/
1863 : // ITABFeaturePen
1864 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
1865 :
1866 0 : poNew->m_bSmooth = m_bSmooth;
1867 0 : poNew->m_bCenterIsSet = m_bCenterIsSet;
1868 0 : poNew->m_dCenterX = m_dCenterX;
1869 0 : poNew->m_dCenterY = m_dCenterY;
1870 :
1871 0 : return poNew;
1872 : }
1873 :
1874 : /**********************************************************************
1875 : * TABPolyline::GetNumParts()
1876 : *
1877 : * Return the total number of parts in this object.
1878 : *
1879 : * Returns 0 if the geometry contained in the object is invalid or missing.
1880 : **********************************************************************/
1881 0 : int TABPolyline::GetNumParts()
1882 : {
1883 : OGRGeometry *poGeom;
1884 0 : int numParts = 0;
1885 :
1886 0 : poGeom = GetGeometryRef();
1887 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
1888 : {
1889 : /*-------------------------------------------------------------
1890 : * Simple polyline
1891 : *------------------------------------------------------------*/
1892 0 : numParts = 1;
1893 : }
1894 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
1895 : {
1896 : /*-------------------------------------------------------------
1897 : * Multiple polyline
1898 : *------------------------------------------------------------*/
1899 0 : OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
1900 0 : numParts = poMultiLine->getNumGeometries();
1901 : }
1902 :
1903 0 : return numParts;
1904 : }
1905 :
1906 : /**********************************************************************
1907 : * TABPolyline::GetPartRef()
1908 : *
1909 : * Returns a reference to the specified OGRLineString number, hiding the
1910 : * complexity of dealing with OGRMultiLineString vs OGRLineString cases.
1911 : *
1912 : * Returns NULL if the geometry contained in the object is invalid or
1913 : * missing or if the specified part index is invalid.
1914 : **********************************************************************/
1915 0 : OGRLineString *TABPolyline::GetPartRef(int nPartIndex)
1916 : {
1917 : OGRGeometry *poGeom;
1918 :
1919 0 : poGeom = GetGeometryRef();
1920 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString && nPartIndex==0)
1921 : {
1922 : /*-------------------------------------------------------------
1923 : * Simple polyline
1924 : *------------------------------------------------------------*/
1925 0 : return (OGRLineString *)poGeom;
1926 : }
1927 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
1928 : {
1929 : /*-------------------------------------------------------------
1930 : * Multiple polyline
1931 : *------------------------------------------------------------*/
1932 0 : OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
1933 0 : if (nPartIndex >= 0 &&
1934 : nPartIndex < poMultiLine->getNumGeometries())
1935 : {
1936 0 : return (OGRLineString*)poMultiLine->getGeometryRef(nPartIndex);
1937 : }
1938 : else
1939 0 : return NULL;
1940 : }
1941 :
1942 0 : return NULL;
1943 : }
1944 :
1945 : /**********************************************************************
1946 : * TABPolyline::ValidateMapInfoType()
1947 : *
1948 : * Check the feature's geometry part and return the corresponding
1949 : * mapinfo object type code. The m_nMapInfoType member will also
1950 : * be updated for further calls to GetMapInfoType();
1951 : *
1952 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
1953 : * is expected for this object class.
1954 : **********************************************************************/
1955 1 : int TABPolyline::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
1956 : {
1957 : OGRGeometry *poGeom;
1958 1 : OGRMultiLineString *poMultiLine = NULL;
1959 :
1960 : /*-----------------------------------------------------------------
1961 : * Fetch and validate geometry
1962 : *----------------------------------------------------------------*/
1963 1 : poGeom = GetGeometryRef();
1964 1 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
1965 : {
1966 : /*-------------------------------------------------------------
1967 : * Simple polyline
1968 : *------------------------------------------------------------*/
1969 1 : OGRLineString *poLine = (OGRLineString*)poGeom;
1970 1 : if ( TAB_REGION_PLINE_REQUIRES_V800(1, poLine->getNumPoints()) )
1971 : {
1972 0 : m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
1973 : }
1974 1 : else if ( poLine->getNumPoints() > TAB_REGION_PLINE_300_MAX_VERTICES)
1975 : {
1976 0 : m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
1977 : }
1978 1 : else if ( poLine->getNumPoints() > 2 )
1979 : {
1980 0 : m_nMapInfoType = TAB_GEOM_PLINE;
1981 : }
1982 1 : else if ( (poLine->getNumPoints() == 2) &&
1983 : (m_bWriteTwoPointLineAsPolyline == TRUE) )
1984 : {
1985 0 : m_nMapInfoType = TAB_GEOM_PLINE;
1986 : }
1987 1 : else if ( (poLine->getNumPoints() == 2) &&
1988 : (m_bWriteTwoPointLineAsPolyline == FALSE) )
1989 : {
1990 1 : m_nMapInfoType = TAB_GEOM_LINE;
1991 : }
1992 : else
1993 : {
1994 : CPLError(CE_Failure, CPLE_AssertionFailed,
1995 0 : "TABPolyline: Geometry must contain at least 2 points.");
1996 0 : m_nMapInfoType = TAB_GEOM_NONE;
1997 : }
1998 : }
1999 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2000 : {
2001 : /*-------------------------------------------------------------
2002 : * Multiple polyline... validate all components
2003 : *------------------------------------------------------------*/
2004 : int iLine, numLines;
2005 0 : GInt32 numPointsTotal = 0;
2006 0 : poMultiLine = (OGRMultiLineString*)poGeom;
2007 0 : numLines = poMultiLine->getNumGeometries();
2008 :
2009 0 : m_nMapInfoType = TAB_GEOM_MULTIPLINE;
2010 :
2011 0 : for(iLine=0; iLine < numLines; iLine++)
2012 : {
2013 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2014 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) != wkbLineString)
2015 : {
2016 : CPLError(CE_Failure, CPLE_AssertionFailed,
2017 0 : "TABPolyline: Object contains an invalid Geometry!");
2018 0 : m_nMapInfoType = TAB_GEOM_NONE;
2019 0 : numPointsTotal = 0;
2020 0 : break;
2021 : }
2022 0 : OGRLineString *poLine = (OGRLineString*)poGeom;
2023 0 : numPointsTotal += poLine->getNumPoints();
2024 : }
2025 :
2026 0 : if ( TAB_REGION_PLINE_REQUIRES_V800(numLines, numPointsTotal) )
2027 0 : m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
2028 0 : else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
2029 0 : m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
2030 : }
2031 : else
2032 : {
2033 : CPLError(CE_Failure, CPLE_AssertionFailed,
2034 0 : "TABPolyline: Missing or Invalid Geometry!");
2035 0 : m_nMapInfoType = TAB_GEOM_NONE;
2036 : }
2037 :
2038 : /*-----------------------------------------------------------------
2039 : * Decide if coordinates should be compressed or not.
2040 : *
2041 : * __TODO__ We never write type LINE (2 points line) as compressed
2042 : * for the moment. If we ever do it, then the decision to write
2043 : * a 2 point line in compressed coordinates or not should take into
2044 : * account the location of the object block MBR, so this would be
2045 : * better handled directly by TABMAPObjLine::WriteObject() since the
2046 : * object block center is not known until it is written to disk.
2047 : *----------------------------------------------------------------*/
2048 1 : if (m_nMapInfoType != TAB_GEOM_LINE)
2049 : {
2050 0 : ValidateCoordType(poMapFile);
2051 : }
2052 : else
2053 : {
2054 1 : UpdateMBR(poMapFile);
2055 : }
2056 :
2057 1 : return m_nMapInfoType;
2058 : }
2059 :
2060 :
2061 : /**********************************************************************
2062 : * TABPolyline::ReadGeometryFromMAPFile()
2063 : *
2064 : * Fill the geometry and representation (color, etc...) part of the
2065 : * feature from the contents of the .MAP object pointed to by poMAPFile.
2066 : *
2067 : * It is assumed that poMAPFile currently points to the beginning of
2068 : * a map object.
2069 : *
2070 : * Returns 0 on success, -1 on error, in which case CPLError() will have
2071 : * been called.
2072 : **********************************************************************/
2073 1 : int TABPolyline::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
2074 : TABMAPObjHdr *poObjHdr,
2075 : GBool bCoordBlockDataOnly /*=FALSE*/,
2076 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
2077 : {
2078 : GInt32 nX, nY;
2079 : double dX, dY, dXMin, dYMin, dXMax, dYMax;
2080 : OGRGeometry *poGeometry;
2081 : OGRLineString *poLine;
2082 1 : GBool bComprCoord = poObjHdr->IsCompressedType();
2083 1 : TABMAPCoordBlock *poCoordBlock = NULL;
2084 :
2085 : /*-----------------------------------------------------------------
2086 : * Fetch and validate geometry type
2087 : *----------------------------------------------------------------*/
2088 1 : m_nMapInfoType = poObjHdr->m_nType;
2089 :
2090 2 : if (m_nMapInfoType == TAB_GEOM_LINE ||
2091 : m_nMapInfoType == TAB_GEOM_LINE_C )
2092 : {
2093 : /*=============================================================
2094 : * LINE (2 vertices)
2095 : *============================================================*/
2096 1 : TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
2097 :
2098 1 : m_bSmooth = FALSE;
2099 :
2100 1 : poGeometry = poLine = new OGRLineString();
2101 1 : poLine->setNumPoints(2);
2102 :
2103 : poMapFile->Int2Coordsys(poLineHdr->m_nX1, poLineHdr->m_nY1,
2104 1 : dXMin, dYMin);
2105 1 : poLine->setPoint(0, dXMin, dYMin);
2106 :
2107 : poMapFile->Int2Coordsys(poLineHdr->m_nX2, poLineHdr->m_nY2,
2108 1 : dXMax, dYMax);
2109 1 : poLine->setPoint(1, dXMax, dYMax);
2110 :
2111 1 : if (!bCoordBlockDataOnly)
2112 : {
2113 1 : m_nPenDefIndex = poLineHdr->m_nPenId; // Pen index
2114 1 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
2115 : }
2116 : }
2117 0 : else if (m_nMapInfoType == TAB_GEOM_PLINE ||
2118 : m_nMapInfoType == TAB_GEOM_PLINE_C )
2119 : {
2120 : /*=============================================================
2121 : * PLINE ( > 2 vertices)
2122 : *============================================================*/
2123 : int i, numPoints, nStatus;
2124 : GUInt32 nCoordDataSize;
2125 : GInt32 nCoordBlockPtr;
2126 :
2127 : /*-------------------------------------------------------------
2128 : * Copy data from poObjHdr
2129 : *------------------------------------------------------------*/
2130 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2131 :
2132 0 : nCoordBlockPtr = poPLineHdr->m_nCoordBlockPtr;
2133 0 : nCoordDataSize = poPLineHdr->m_nCoordDataSize;
2134 : //numLineSections = poPLineHdr->m_numLineSections; // Always 1
2135 0 : m_bSmooth = poPLineHdr->m_bSmooth;
2136 :
2137 : // Centroid/label point
2138 : poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY,
2139 0 : dX, dY);
2140 0 : SetCenter(dX, dY);
2141 :
2142 : // Compressed coordinate origin (useful only in compressed case!)
2143 0 : m_nComprOrgX = poPLineHdr->m_nComprOrgX;
2144 0 : m_nComprOrgY = poPLineHdr->m_nComprOrgY;
2145 :
2146 : // MBR
2147 : poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY,
2148 0 : dXMin, dYMin);
2149 : poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY,
2150 0 : dXMax, dYMax);
2151 :
2152 0 : if (!bCoordBlockDataOnly)
2153 : {
2154 0 : m_nPenDefIndex = poPLineHdr->m_nPenId; // Pen index
2155 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
2156 : }
2157 :
2158 : /*-------------------------------------------------------------
2159 : * Create Geometry and read coordinates
2160 : *------------------------------------------------------------*/
2161 0 : numPoints = nCoordDataSize/(bComprCoord?4:8);
2162 :
2163 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2164 0 : poCoordBlock = *ppoCoordBlock;
2165 : else
2166 0 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
2167 0 : if (poCoordBlock == NULL)
2168 : {
2169 : CPLError(CE_Failure, CPLE_FileIO,
2170 : "Can't access coordinate block at offset %d",
2171 0 : nCoordBlockPtr);
2172 0 : return -1;
2173 : }
2174 :
2175 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2176 :
2177 0 : poGeometry = poLine = new OGRLineString();
2178 0 : poLine->setNumPoints(numPoints);
2179 :
2180 0 : nStatus = 0;
2181 0 : for(i=0; nStatus == 0 && i<numPoints; i++)
2182 : {
2183 0 : nStatus = poCoordBlock->ReadIntCoord(bComprCoord, nX, nY);
2184 0 : if (nStatus != 0)
2185 0 : break;
2186 0 : poMapFile->Int2Coordsys(nX, nY, dX, dY);
2187 0 : poLine->setPoint(i, dX, dY);
2188 : }
2189 :
2190 0 : if (nStatus != 0)
2191 : {
2192 : // Failed ... error message has already been produced
2193 0 : delete poGeometry;
2194 0 : return nStatus;
2195 : }
2196 :
2197 : }
2198 0 : else if (m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
2199 : m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
2200 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
2201 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
2202 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
2203 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C )
2204 : {
2205 : /*=============================================================
2206 : * PLINE MULTIPLE
2207 : *============================================================*/
2208 : int i, iSection;
2209 : GInt32 nCoordBlockPtr, numLineSections;
2210 : GInt32 nCoordDataSize, numPointsTotal, *panXY;
2211 : OGRMultiLineString *poMultiLine;
2212 : TABMAPCoordSecHdr *pasSecHdrs;
2213 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
2214 :
2215 : /*-------------------------------------------------------------
2216 : * Copy data from poObjHdr
2217 : *------------------------------------------------------------*/
2218 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2219 :
2220 0 : nCoordBlockPtr = poPLineHdr->m_nCoordBlockPtr;
2221 0 : nCoordDataSize = poPLineHdr->m_nCoordDataSize;
2222 0 : numLineSections = poPLineHdr->m_numLineSections;
2223 0 : m_bSmooth = poPLineHdr->m_bSmooth;
2224 :
2225 : // Centroid/label point
2226 : poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY,
2227 0 : dX, dY);
2228 0 : SetCenter(dX, dY);
2229 :
2230 : // Compressed coordinate origin (useful only in compressed case!)
2231 0 : m_nComprOrgX = poPLineHdr->m_nComprOrgX;
2232 0 : m_nComprOrgY = poPLineHdr->m_nComprOrgY;
2233 :
2234 : // MBR
2235 : poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY,
2236 0 : dXMin, dYMin);
2237 : poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY,
2238 0 : dXMax, dYMax);
2239 :
2240 0 : if (!bCoordBlockDataOnly)
2241 : {
2242 0 : m_nPenDefIndex = poPLineHdr->m_nPenId; // Pen index
2243 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
2244 : }
2245 :
2246 : /*-------------------------------------------------------------
2247 : * Read data from the coord. block
2248 : *------------------------------------------------------------*/
2249 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
2250 0 : sizeof(TABMAPCoordSecHdr));
2251 :
2252 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2253 0 : poCoordBlock = *ppoCoordBlock;
2254 : else
2255 0 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
2256 :
2257 0 : if (poCoordBlock == NULL ||
2258 : poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion,
2259 : numLineSections,
2260 : pasSecHdrs, numPointsTotal) != 0)
2261 : {
2262 : CPLError(CE_Failure, CPLE_FileIO,
2263 : "Failed reading coordinate data at offset %d",
2264 0 : nCoordBlockPtr);
2265 0 : CPLFree(pasSecHdrs);
2266 0 : return -1;
2267 : }
2268 :
2269 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2270 :
2271 0 : panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
2272 :
2273 0 : if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
2274 : {
2275 : CPLError(CE_Failure, CPLE_FileIO,
2276 : "Failed reading coordinate data at offset %d",
2277 0 : nCoordBlockPtr);
2278 0 : CPLFree(pasSecHdrs);
2279 0 : CPLFree(panXY);
2280 0 : return -1;
2281 : }
2282 :
2283 : /*-------------------------------------------------------------
2284 : * Create a Geometry collection with one line geometry for
2285 : * each coordinates section
2286 : * If object contains only one section, then return a simple LineString
2287 : *------------------------------------------------------------*/
2288 0 : if (numLineSections > 1)
2289 0 : poGeometry = poMultiLine = new OGRMultiLineString();
2290 : else
2291 0 : poGeometry = poMultiLine = NULL;
2292 :
2293 0 : for(iSection=0; iSection<numLineSections; iSection++)
2294 : {
2295 : GInt32 *pnXYPtr;
2296 : int numSectionVertices;
2297 :
2298 0 : numSectionVertices = pasSecHdrs[iSection].numVertices;
2299 0 : pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
2300 :
2301 0 : poLine = new OGRLineString();
2302 0 : poLine->setNumPoints(numSectionVertices);
2303 :
2304 0 : for(i=0; i<numSectionVertices; i++)
2305 : {
2306 0 : poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
2307 0 : poLine->setPoint(i, dX, dY);
2308 0 : pnXYPtr += 2;
2309 : }
2310 :
2311 0 : if (poGeometry==NULL)
2312 0 : poGeometry = poLine;
2313 0 : else if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
2314 : {
2315 0 : CPLAssert(FALSE); // Just in case lower-level lib is modified
2316 : }
2317 0 : poLine = NULL;
2318 : }
2319 :
2320 0 : CPLFree(pasSecHdrs);
2321 0 : CPLFree(panXY);
2322 : }
2323 : else
2324 : {
2325 : CPLError(CE_Failure, CPLE_AssertionFailed,
2326 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
2327 0 : m_nMapInfoType, m_nMapInfoType);
2328 0 : return -1;
2329 : }
2330 :
2331 1 : SetGeometryDirectly(poGeometry);
2332 :
2333 1 : SetMBR(dXMin, dYMin, dXMax, dYMax);
2334 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
2335 1 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
2336 :
2337 : /* Return a ref to coord block so that caller can continue reading
2338 : * after the end of this object (used by TABCollection and index splitting)
2339 : */
2340 1 : if (ppoCoordBlock)
2341 0 : *ppoCoordBlock = poCoordBlock;
2342 :
2343 1 : return 0;
2344 : }
2345 :
2346 : /**********************************************************************
2347 : * TABPolyline::WriteGeometryToMAPFile()
2348 : *
2349 : * Write the geometry and representation (color, etc...) part of the
2350 : * feature to the .MAP object pointed to by poMAPFile.
2351 : *
2352 : * It is assumed that poMAPFile currently points to a valid map object.
2353 : *
2354 : * Returns 0 on success, -1 on error, in which case CPLError() will have
2355 : * been called.
2356 : **********************************************************************/
2357 1 : int TABPolyline::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
2358 : TABMAPObjHdr *poObjHdr,
2359 : GBool bCoordBlockDataOnly /*=FALSE*/,
2360 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
2361 : {
2362 : GInt32 nX, nY;
2363 : OGRGeometry *poGeom;
2364 1 : OGRLineString *poLine=NULL;
2365 1 : TABMAPCoordBlock *poCoordBlock = NULL;
2366 :
2367 : /*-----------------------------------------------------------------
2368 : * We assume that ValidateMapInfoType() was called already and that
2369 : * the type in poObjHdr->m_nType is valid.
2370 : *----------------------------------------------------------------*/
2371 1 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
2372 1 : CPLErrorReset();
2373 :
2374 : /*-----------------------------------------------------------------
2375 : * Fetch and validate geometry
2376 : *----------------------------------------------------------------*/
2377 1 : poGeom = GetGeometryRef();
2378 :
2379 2 : if ((m_nMapInfoType == TAB_GEOM_LINE ||
2380 : m_nMapInfoType == TAB_GEOM_LINE_C ) &&
2381 1 : poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString &&
2382 : (poLine = (OGRLineString*)poGeom)->getNumPoints() == 2)
2383 : {
2384 : /*=============================================================
2385 : * LINE (2 vertices)
2386 : *============================================================*/
2387 1 : TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
2388 :
2389 : poMapFile->Coordsys2Int(poLine->getX(0), poLine->getY(0),
2390 1 : poLineHdr->m_nX1, poLineHdr->m_nY1);
2391 : poMapFile->Coordsys2Int(poLine->getX(1), poLine->getY(1),
2392 1 : poLineHdr->m_nX2, poLineHdr->m_nY2);
2393 : poLineHdr->SetMBR(poLineHdr->m_nX1, poLineHdr->m_nY1,
2394 1 : poLineHdr->m_nX2, poLineHdr->m_nY2 );
2395 :
2396 1 : if (!bCoordBlockDataOnly)
2397 : {
2398 1 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
2399 1 : poLineHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
2400 : }
2401 :
2402 : }
2403 0 : else if ((m_nMapInfoType == TAB_GEOM_PLINE ||
2404 : m_nMapInfoType == TAB_GEOM_PLINE_C ) &&
2405 0 : poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
2406 : {
2407 : /*=============================================================
2408 : * PLINE ( > 2 vertices and less than 32767 vertices)
2409 : *============================================================*/
2410 : int i, numPoints, nStatus;
2411 : GUInt32 nCoordDataSize;
2412 : GInt32 nCoordBlockPtr;
2413 0 : GBool bCompressed = poObjHdr->IsCompressedType();
2414 :
2415 : /*-------------------------------------------------------------
2416 : * Process geometry first...
2417 : *------------------------------------------------------------*/
2418 0 : poLine = (OGRLineString*)poGeom;
2419 0 : numPoints = poLine->getNumPoints();
2420 0 : CPLAssert(numPoints <= TAB_REGION_PLINE_300_MAX_VERTICES);
2421 :
2422 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2423 0 : poCoordBlock = *ppoCoordBlock;
2424 : else
2425 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
2426 0 : poCoordBlock->StartNewFeature();
2427 0 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
2428 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2429 :
2430 0 : nStatus = 0;
2431 0 : for(i=0; nStatus == 0 && i<numPoints; i++)
2432 : {
2433 0 : poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i), nX, nY);
2434 0 : if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY,
2435 : bCompressed)) != 0)
2436 : {
2437 : // Failed ... error message has already been produced
2438 0 : return nStatus;
2439 : }
2440 : }
2441 :
2442 0 : nCoordDataSize = poCoordBlock->GetFeatureDataSize();
2443 :
2444 : /*-------------------------------------------------------------
2445 : * Copy info to poObjHdr
2446 : *------------------------------------------------------------*/
2447 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2448 :
2449 0 : poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
2450 0 : poPLineHdr->m_nCoordDataSize = nCoordDataSize;
2451 0 : poPLineHdr->m_numLineSections = 1;
2452 :
2453 0 : poPLineHdr->m_bSmooth = m_bSmooth;
2454 :
2455 : // MBR
2456 0 : poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
2457 :
2458 : // Polyline center/label point
2459 : double dX, dY;
2460 0 : if (GetCenter(dX, dY) != -1)
2461 : {
2462 : poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX,
2463 0 : poPLineHdr->m_nLabelY);
2464 : }
2465 : else
2466 : {
2467 0 : poPLineHdr->m_nLabelX = m_nComprOrgX;
2468 0 : poPLineHdr->m_nLabelY = m_nComprOrgY;
2469 : }
2470 :
2471 : // Compressed coordinate origin (useful only in compressed case!)
2472 0 : poPLineHdr->m_nComprOrgX = m_nComprOrgX;
2473 0 : poPLineHdr->m_nComprOrgY = m_nComprOrgY;
2474 :
2475 0 : if (!bCoordBlockDataOnly)
2476 : {
2477 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
2478 0 : poPLineHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
2479 : }
2480 :
2481 : }
2482 0 : else if ((m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
2483 : m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
2484 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
2485 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
2486 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
2487 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C) &&
2488 0 : poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
2489 0 : wkbFlatten(poGeom->getGeometryType()) == wkbLineString) )
2490 : {
2491 : /*=============================================================
2492 : * PLINE MULTIPLE (or single PLINE with more than 32767 vertices)
2493 : *============================================================*/
2494 0 : int nStatus=0, i, iLine;
2495 : GInt32 numPointsTotal, numPoints;
2496 : GUInt32 nCoordDataSize;
2497 : GInt32 nCoordBlockPtr, numLines;
2498 0 : OGRMultiLineString *poMultiLine=NULL;
2499 : TABMAPCoordSecHdr *pasSecHdrs;
2500 0 : OGREnvelope sEnvelope;
2501 0 : GBool bCompressed = poObjHdr->IsCompressedType();
2502 :
2503 : CPLAssert(m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
2504 : m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
2505 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
2506 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
2507 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
2508 0 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C);
2509 : /*-------------------------------------------------------------
2510 : * Process geometry first...
2511 : *------------------------------------------------------------*/
2512 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2513 0 : poCoordBlock = *ppoCoordBlock;
2514 : else
2515 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
2516 0 : poCoordBlock->StartNewFeature();
2517 0 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
2518 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2519 :
2520 0 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2521 : {
2522 0 : poMultiLine = (OGRMultiLineString*)poGeom;
2523 0 : numLines = poMultiLine->getNumGeometries();
2524 : }
2525 : else
2526 : {
2527 0 : poMultiLine = NULL;
2528 0 : numLines = 1;
2529 : }
2530 :
2531 : /*-------------------------------------------------------------
2532 : * Build and write array of coord sections headers
2533 : *------------------------------------------------------------*/
2534 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLCalloc(numLines,
2535 0 : sizeof(TABMAPCoordSecHdr));
2536 :
2537 : /*-------------------------------------------------------------
2538 : * In calculation of nDataOffset, we have to take into account that
2539 : * V450 header section uses int32 instead of int16 for numVertices
2540 : * and we add another 2 bytes to align with a 4 bytes boundary.
2541 : *------------------------------------------------------------*/
2542 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
2543 :
2544 : int nTotalHdrSizeUncompressed;
2545 0 : if (nVersion >= 450)
2546 0 : nTotalHdrSizeUncompressed = 28 * numLines;
2547 : else
2548 0 : nTotalHdrSizeUncompressed = 24 * numLines;
2549 :
2550 0 : numPointsTotal = 0;
2551 0 : for(iLine=0; iLine < numLines; iLine++)
2552 : {
2553 0 : if (poMultiLine)
2554 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2555 :
2556 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2557 : {
2558 0 : poLine = (OGRLineString*)poGeom;
2559 0 : numPoints = poLine->getNumPoints();
2560 0 : poLine->getEnvelope(&sEnvelope);
2561 :
2562 0 : pasSecHdrs[iLine].numVertices = poLine->getNumPoints();
2563 0 : pasSecHdrs[iLine].numHoles = 0; // It's a line!
2564 :
2565 : poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
2566 0 : pasSecHdrs[iLine].nXMin,
2567 0 : pasSecHdrs[iLine].nYMin);
2568 : poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
2569 0 : pasSecHdrs[iLine].nXMax,
2570 0 : pasSecHdrs[iLine].nYMax);
2571 0 : pasSecHdrs[iLine].nDataOffset = nTotalHdrSizeUncompressed +
2572 0 : numPointsTotal*4*2;
2573 0 : pasSecHdrs[iLine].nVertexOffset = numPointsTotal;
2574 :
2575 0 : numPointsTotal += numPoints;
2576 : }
2577 : else
2578 : {
2579 : CPLError(CE_Failure, CPLE_AssertionFailed,
2580 0 : "TABPolyline: Object contains an invalid Geometry!");
2581 0 : nStatus = -1;
2582 : }
2583 :
2584 : }
2585 :
2586 0 : if (nStatus == 0)
2587 : nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numLines,
2588 0 : pasSecHdrs, bCompressed);
2589 :
2590 0 : CPLFree(pasSecHdrs);
2591 0 : pasSecHdrs = NULL;
2592 :
2593 0 : if (nStatus != 0)
2594 0 : return nStatus; // Error has already been reported.
2595 :
2596 : /*-------------------------------------------------------------
2597 : * Then write the coordinates themselves...
2598 : *------------------------------------------------------------*/
2599 0 : for(iLine=0; nStatus == 0 && iLine < numLines; iLine++)
2600 : {
2601 0 : if (poMultiLine)
2602 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2603 :
2604 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2605 : {
2606 0 : poLine = (OGRLineString*)poGeom;
2607 0 : numPoints = poLine->getNumPoints();
2608 :
2609 0 : for(i=0; nStatus == 0 && i<numPoints; i++)
2610 : {
2611 : poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i),
2612 0 : nX, nY);
2613 0 : if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
2614 : bCompressed)) != 0)
2615 : {
2616 : // Failed ... error message has already been produced
2617 0 : return nStatus;
2618 : }
2619 : }
2620 : }
2621 : else
2622 : {
2623 : CPLError(CE_Failure, CPLE_AssertionFailed,
2624 0 : "TABPolyline: Object contains an invalid Geometry!");
2625 0 : return -1;
2626 : }
2627 :
2628 : }
2629 :
2630 0 : nCoordDataSize = poCoordBlock->GetFeatureDataSize();
2631 :
2632 : /*-------------------------------------------------------------
2633 : * ... and finally copy info to poObjHdr
2634 : *------------------------------------------------------------*/
2635 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2636 :
2637 0 : poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
2638 0 : poPLineHdr->m_nCoordDataSize = nCoordDataSize;
2639 0 : poPLineHdr->m_numLineSections = numLines;
2640 :
2641 0 : poPLineHdr->m_bSmooth = m_bSmooth;
2642 :
2643 : // MBR
2644 0 : poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
2645 :
2646 : // Polyline center/label point
2647 : double dX, dY;
2648 0 : if (GetCenter(dX, dY) != -1)
2649 : {
2650 : poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX,
2651 0 : poPLineHdr->m_nLabelY);
2652 : }
2653 : else
2654 : {
2655 0 : poPLineHdr->m_nLabelX = m_nComprOrgX;
2656 0 : poPLineHdr->m_nLabelY = m_nComprOrgY;
2657 : }
2658 :
2659 : // Compressed coordinate origin (useful only in compressed case!)
2660 0 : poPLineHdr->m_nComprOrgX = m_nComprOrgX;
2661 0 : poPLineHdr->m_nComprOrgY = m_nComprOrgY;
2662 :
2663 0 : if (!bCoordBlockDataOnly)
2664 : {
2665 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
2666 0 : poPLineHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
2667 : }
2668 :
2669 : }
2670 : else
2671 : {
2672 : CPLError(CE_Failure, CPLE_AssertionFailed,
2673 0 : "TABPolyline: Object contains an invalid Geometry!");
2674 0 : return -1;
2675 : }
2676 :
2677 1 : if (CPLGetLastErrorType() == CE_Failure )
2678 0 : return -1;
2679 :
2680 : /* Return a ref to coord block so that caller can continue writing
2681 : * after the end of this object (used by index splitting)
2682 : */
2683 1 : if (ppoCoordBlock)
2684 0 : *ppoCoordBlock = poCoordBlock;
2685 :
2686 1 : return 0;
2687 : }
2688 :
2689 : /**********************************************************************
2690 : * TABPolyline::GetStyleString()
2691 : *
2692 : * Return style string for this feature.
2693 : *
2694 : * Style String is built only once during the first call to GetStyleString().
2695 : **********************************************************************/
2696 0 : const char *TABPolyline::GetStyleString()
2697 : {
2698 0 : if (m_pszStyleString == NULL)
2699 : {
2700 0 : m_pszStyleString = CPLStrdup(GetPenStyleString());
2701 : }
2702 :
2703 0 : return m_pszStyleString;
2704 : }
2705 :
2706 :
2707 : /**********************************************************************
2708 : * TABPolyline::DumpMIF()
2709 : *
2710 : * Dump feature geometry in a format similar to .MIF PLINEs.
2711 : **********************************************************************/
2712 0 : void TABPolyline::DumpMIF(FILE *fpOut /*=NULL*/)
2713 : {
2714 : OGRGeometry *poGeom;
2715 0 : OGRMultiLineString *poMultiLine = NULL;
2716 0 : OGRLineString *poLine = NULL;
2717 : int i, numPoints;
2718 :
2719 0 : if (fpOut == NULL)
2720 0 : fpOut = stdout;
2721 :
2722 : /*-----------------------------------------------------------------
2723 : * Fetch and validate geometry
2724 : *----------------------------------------------------------------*/
2725 0 : poGeom = GetGeometryRef();
2726 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2727 : {
2728 : /*-------------------------------------------------------------
2729 : * Generate output for simple polyline
2730 : *------------------------------------------------------------*/
2731 0 : poLine = (OGRLineString*)poGeom;
2732 0 : numPoints = poLine->getNumPoints();
2733 0 : fprintf(fpOut, "PLINE %d\n", numPoints);
2734 0 : for(i=0; i<numPoints; i++)
2735 0 : fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
2736 : }
2737 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2738 : {
2739 : /*-------------------------------------------------------------
2740 : * Generate output for multiple polyline
2741 : *------------------------------------------------------------*/
2742 : int iLine, numLines;
2743 0 : poMultiLine = (OGRMultiLineString*)poGeom;
2744 0 : numLines = poMultiLine->getNumGeometries();
2745 0 : fprintf(fpOut, "PLINE MULTIPLE %d\n", numLines);
2746 0 : for(iLine=0; iLine < numLines; iLine++)
2747 : {
2748 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2749 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2750 : {
2751 0 : poLine = (OGRLineString*)poGeom;
2752 0 : numPoints = poLine->getNumPoints();
2753 0 : fprintf(fpOut, " %d\n", numPoints);
2754 0 : for(i=0; i<numPoints; i++)
2755 0 : fprintf(fpOut, "%.15g %.15g\n",poLine->getX(i),poLine->getY(i));
2756 : }
2757 : else
2758 : {
2759 : CPLError(CE_Failure, CPLE_AssertionFailed,
2760 0 : "TABPolyline: Object contains an invalid Geometry!");
2761 0 : return;
2762 : }
2763 :
2764 : }
2765 : }
2766 : else
2767 : {
2768 : CPLError(CE_Failure, CPLE_AssertionFailed,
2769 0 : "TABPolyline: Missing or Invalid Geometry!");
2770 0 : return;
2771 : }
2772 :
2773 0 : if (m_bCenterIsSet)
2774 0 : fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
2775 :
2776 : // Finish with PEN/BRUSH/etc. clauses
2777 0 : DumpPenDef();
2778 :
2779 0 : fflush(fpOut);
2780 : }
2781 :
2782 : /**********************************************************************
2783 : * TABPolyline::GetCenter()
2784 : *
2785 : * Returns the center point of the line. Compute one if it was not
2786 : * explicitly set:
2787 : *
2788 : * In MapInfo, for a simple or multiple polyline (pline), the center point
2789 : * in the object definition is supposed to be either the center point of
2790 : * the pline or the first section of a multiple pline (if an odd number of
2791 : * points in the pline or first section), or the midway point between the
2792 : * two central points (if an even number of points involved).
2793 : *
2794 : * Returns 0 on success, -1 on error.
2795 : **********************************************************************/
2796 0 : int TABPolyline::GetCenter(double &dX, double &dY)
2797 : {
2798 0 : if (!m_bCenterIsSet)
2799 : {
2800 : OGRGeometry *poGeom;
2801 0 : OGRLineString *poLine = NULL;
2802 :
2803 0 : poGeom = GetGeometryRef();
2804 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2805 : {
2806 0 : poLine = (OGRLineString *)poGeom;
2807 : }
2808 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2809 : {
2810 0 : OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
2811 0 : if (poMultiLine->getNumGeometries() > 0)
2812 0 : poLine = (OGRLineString *)poMultiLine->getGeometryRef(0);
2813 : }
2814 :
2815 0 : if (poLine && poLine->getNumPoints() > 0)
2816 : {
2817 0 : int i = poLine->getNumPoints()/2;
2818 0 : if (poLine->getNumPoints() % 2 == 0)
2819 : {
2820 : // Return the midway between the 2 center points
2821 0 : m_dCenterX = (poLine->getX(i-1) + poLine->getX(i))/2.0;
2822 0 : m_dCenterY = (poLine->getY(i-1) + poLine->getY(i))/2.0;
2823 : }
2824 : else
2825 : {
2826 : // Return the center point
2827 0 : m_dCenterX = poLine->getX(i);
2828 0 : m_dCenterY = poLine->getY(i);
2829 : }
2830 0 : m_bCenterIsSet = TRUE;
2831 : }
2832 : }
2833 :
2834 0 : if (!m_bCenterIsSet)
2835 0 : return -1;
2836 :
2837 0 : dX = m_dCenterX;
2838 0 : dY = m_dCenterY;
2839 0 : return 0;
2840 : }
2841 :
2842 : /**********************************************************************
2843 : * TABPolyline::SetCenter()
2844 : *
2845 : * Set the X,Y coordinates to use as center point for the line.
2846 : **********************************************************************/
2847 0 : void TABPolyline::SetCenter(double dX, double dY)
2848 : {
2849 0 : m_dCenterX = dX;
2850 0 : m_dCenterY = dY;
2851 0 : m_bCenterIsSet = TRUE;
2852 0 : }
2853 :
2854 : /**********************************************************************
2855 : * TABPolyline::TwoPointLineAsPolyline()
2856 : *
2857 : * Returns the value of m_bWriteTwoPointLineAsPolyline
2858 : **********************************************************************/
2859 0 : GBool TABPolyline::TwoPointLineAsPolyline()
2860 : {
2861 0 : return m_bWriteTwoPointLineAsPolyline;
2862 : }
2863 :
2864 : /**********************************************************************
2865 : * TABPolyline::TwoPointLineAsPolyline()
2866 : *
2867 : * Sets the value of m_bWriteTwoPointLineAsPolyline
2868 : **********************************************************************/
2869 0 : void TABPolyline::TwoPointLineAsPolyline(GBool bTwoPointLineAsPolyline)
2870 : {
2871 0 : m_bWriteTwoPointLineAsPolyline = bTwoPointLineAsPolyline;
2872 0 : }
2873 :
2874 :
2875 : /*=====================================================================
2876 : * class TABRegion
2877 : *====================================================================*/
2878 :
2879 : /**********************************************************************
2880 : * TABRegion::TABRegion()
2881 : *
2882 : * Constructor.
2883 : **********************************************************************/
2884 100 : TABRegion::TABRegion(OGRFeatureDefn *poDefnIn):
2885 100 : TABFeature(poDefnIn)
2886 : {
2887 100 : m_bCenterIsSet = FALSE;
2888 100 : m_bSmooth = FALSE;
2889 100 : }
2890 :
2891 : /**********************************************************************
2892 : * TABRegion::~TABRegion()
2893 : *
2894 : * Destructor.
2895 : **********************************************************************/
2896 100 : TABRegion::~TABRegion()
2897 : {
2898 100 : }
2899 :
2900 : /**********************************************************************
2901 : * TABRegion::CloneTABFeature()
2902 : *
2903 : * Duplicate feature, including stuff specific to each TABFeature type.
2904 : *
2905 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
2906 : * then copies any members specific to its own type.
2907 : **********************************************************************/
2908 0 : TABFeature *TABRegion::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
2909 : {
2910 : /*-----------------------------------------------------------------
2911 : * Alloc new feature and copy the base stuff
2912 : *----------------------------------------------------------------*/
2913 0 : TABRegion *poNew = new TABRegion(poNewDefn ? poNewDefn : GetDefnRef());
2914 :
2915 0 : CopyTABFeatureBase(poNew);
2916 :
2917 : /*-----------------------------------------------------------------
2918 : * And members specific to this class
2919 : *----------------------------------------------------------------*/
2920 : // ITABFeaturePen
2921 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
2922 :
2923 : // ITABFeatureBrush
2924 0 : *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
2925 :
2926 0 : poNew->m_bSmooth = m_bSmooth;
2927 0 : poNew->m_bCenterIsSet = m_bCenterIsSet;
2928 0 : poNew->m_dCenterX = m_dCenterX;
2929 0 : poNew->m_dCenterY = m_dCenterY;
2930 :
2931 0 : return poNew;
2932 : }
2933 :
2934 : /**********************************************************************
2935 : * TABRegion::ValidateMapInfoType()
2936 : *
2937 : * Check the feature's geometry part and return the corresponding
2938 : * mapinfo object type code. The m_nMapInfoType member will also
2939 : * be updated for further calls to GetMapInfoType();
2940 : *
2941 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
2942 : * is expected for this object class.
2943 : **********************************************************************/
2944 11 : int TABRegion::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
2945 : {
2946 : OGRGeometry *poGeom;
2947 :
2948 : /*-----------------------------------------------------------------
2949 : * Fetch and validate geometry
2950 : *----------------------------------------------------------------*/
2951 11 : poGeom = GetGeometryRef();
2952 11 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
2953 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
2954 : {
2955 11 : GInt32 numPointsTotal=0, numRings=GetNumRings();
2956 22 : for(int i=0; i<numRings; i++)
2957 : {
2958 11 : OGRLinearRing *poRing = GetRingRef(i);
2959 11 : if (poRing)
2960 11 : numPointsTotal += poRing->getNumPoints();
2961 : }
2962 11 : if ( TAB_REGION_PLINE_REQUIRES_V800(numRings, numPointsTotal) )
2963 0 : m_nMapInfoType = TAB_GEOM_V800_REGION;
2964 11 : else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
2965 0 : m_nMapInfoType = TAB_GEOM_V450_REGION;
2966 : else
2967 11 : m_nMapInfoType = TAB_GEOM_REGION;
2968 :
2969 : }
2970 : else
2971 : {
2972 : CPLError(CE_Failure, CPLE_AssertionFailed,
2973 0 : "TABRegion: Missing or Invalid Geometry!");
2974 0 : m_nMapInfoType = TAB_GEOM_NONE;
2975 : }
2976 :
2977 : /*-----------------------------------------------------------------
2978 : * Decide if coordinates should be compressed or not.
2979 : *----------------------------------------------------------------*/
2980 11 : ValidateCoordType(poMapFile);
2981 :
2982 11 : return m_nMapInfoType;
2983 : }
2984 :
2985 : /**********************************************************************
2986 : * TABRegion::ReadGeometryFromMAPFile()
2987 : *
2988 : * Fill the geometry and representation (color, etc...) part of the
2989 : * feature from the contents of the .MAP object pointed to by poMAPFile.
2990 : *
2991 : * It is assumed that poMAPFile currently points to the beginning of
2992 : * a map object.
2993 : *
2994 : * Returns 0 on success, -1 on error, in which case CPLError() will have
2995 : * been called.
2996 : **********************************************************************/
2997 51 : int TABRegion::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
2998 : TABMAPObjHdr *poObjHdr,
2999 : GBool bCoordBlockDataOnly /*=FALSE*/,
3000 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
3001 : {
3002 : double dX, dY, dXMin, dYMin, dXMax, dYMax;
3003 : OGRGeometry *poGeometry;
3004 : OGRLinearRing *poRing;
3005 51 : TABMAPCoordBlock *poCoordBlock = NULL;
3006 :
3007 : /*-----------------------------------------------------------------
3008 : * Fetch and validate geometry type
3009 : *----------------------------------------------------------------*/
3010 51 : m_nMapInfoType = poObjHdr->m_nType;
3011 :
3012 51 : if (m_nMapInfoType == TAB_GEOM_REGION ||
3013 : m_nMapInfoType == TAB_GEOM_REGION_C ||
3014 : m_nMapInfoType == TAB_GEOM_V450_REGION ||
3015 : m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
3016 : m_nMapInfoType == TAB_GEOM_V800_REGION ||
3017 : m_nMapInfoType == TAB_GEOM_V800_REGION_C )
3018 : {
3019 : /*=============================================================
3020 : * REGION (Similar to PLINE MULTIPLE)
3021 : *============================================================*/
3022 : int i, iSection;
3023 : GInt32 nCoordBlockPtr, numLineSections;
3024 : GInt32 nCoordDataSize, numPointsTotal, *panXY;
3025 51 : OGRMultiPolygon *poMultiPolygon = NULL;
3026 51 : OGRPolygon *poPolygon = NULL;
3027 : TABMAPCoordSecHdr *pasSecHdrs;
3028 51 : GBool bComprCoord = poObjHdr->IsCompressedType();
3029 51 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
3030 :
3031 : /*-------------------------------------------------------------
3032 : * Copy data from poObjHdr
3033 : *------------------------------------------------------------*/
3034 51 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
3035 :
3036 51 : nCoordBlockPtr = poPLineHdr->m_nCoordBlockPtr;
3037 51 : nCoordDataSize = poPLineHdr->m_nCoordDataSize;
3038 51 : numLineSections = poPLineHdr->m_numLineSections;
3039 51 : m_bSmooth = poPLineHdr->m_bSmooth;
3040 :
3041 : // Centroid/label point
3042 : poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY,
3043 51 : dX, dY);
3044 51 : SetCenter(dX, dY);
3045 :
3046 : // Compressed coordinate origin (useful only in compressed case!)
3047 51 : m_nComprOrgX = poPLineHdr->m_nComprOrgX;
3048 51 : m_nComprOrgY = poPLineHdr->m_nComprOrgY;
3049 :
3050 : // MBR
3051 : poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY,
3052 51 : dXMin, dYMin);
3053 : poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY,
3054 51 : dXMax, dYMax);
3055 :
3056 51 : if (!bCoordBlockDataOnly)
3057 : {
3058 51 : m_nPenDefIndex = poPLineHdr->m_nPenId; // Pen index
3059 51 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
3060 51 : m_nBrushDefIndex = poPLineHdr->m_nBrushId; // Brush index
3061 51 : poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
3062 : }
3063 :
3064 : /*-------------------------------------------------------------
3065 : * Read data from the coord. block
3066 : *------------------------------------------------------------*/
3067 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
3068 51 : sizeof(TABMAPCoordSecHdr));
3069 :
3070 51 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
3071 0 : poCoordBlock = *ppoCoordBlock;
3072 : else
3073 51 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
3074 :
3075 51 : if (poCoordBlock)
3076 51 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
3077 :
3078 51 : if (poCoordBlock == NULL ||
3079 : poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion,
3080 : numLineSections,
3081 : pasSecHdrs, numPointsTotal) != 0)
3082 : {
3083 : CPLError(CE_Failure, CPLE_FileIO,
3084 : "Failed reading coordinate data at offset %d",
3085 0 : nCoordBlockPtr);
3086 0 : CPLFree(pasSecHdrs);
3087 0 : return -1;
3088 : }
3089 :
3090 51 : panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
3091 :
3092 51 : if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
3093 : {
3094 : CPLError(CE_Failure, CPLE_FileIO,
3095 : "Failed reading coordinate data at offset %d",
3096 0 : nCoordBlockPtr);
3097 0 : CPLFree(pasSecHdrs);
3098 0 : CPLFree(panXY);
3099 0 : return -1;
3100 : }
3101 :
3102 : /*-------------------------------------------------------------
3103 : * Decide if we should return an OGRPolygon or an OGRMultiPolygon
3104 : * depending on the number of outer rings found in CoordSecHdr blocks.
3105 : * The CoodSecHdr block for each outer ring in the region has a flag
3106 : * indicating the number of inner rings that follow.
3107 : * In older versions of the format, the count of inner rings was
3108 : * always zero, so in this case we would always return MultiPolygons.
3109 : *
3110 : * Note: The current implementation assumes that there cannot be
3111 : * holes inside holes (i.e. multiple levels of inner rings)... if
3112 : * that case was encountered then we would return an OGRMultiPolygon
3113 : * in which the topological relationship between the rings would
3114 : * be lost.
3115 : *------------------------------------------------------------*/
3116 51 : int numOuterRings = 0;
3117 102 : for(iSection=0; iSection<numLineSections; iSection++)
3118 : {
3119 : // Count this as an outer ring.
3120 51 : numOuterRings++;
3121 : // Skip inner rings... so loop continues on an outer ring.
3122 51 : iSection += pasSecHdrs[iSection].numHoles;
3123 : }
3124 :
3125 51 : if (numOuterRings > 1)
3126 0 : poGeometry = poMultiPolygon = new OGRMultiPolygon;
3127 : else
3128 51 : poGeometry = NULL; // Will be set later
3129 :
3130 : /*-------------------------------------------------------------
3131 : * OK, build the OGRGeometry object.
3132 : *------------------------------------------------------------*/
3133 51 : int numHolesToRead = 0;
3134 51 : poPolygon = NULL;
3135 102 : for(iSection=0; iSection<numLineSections; iSection++)
3136 : {
3137 : GInt32 *pnXYPtr;
3138 : int numSectionVertices;
3139 :
3140 51 : if (poPolygon == NULL)
3141 51 : poPolygon = new OGRPolygon();
3142 :
3143 51 : if (numHolesToRead < 1)
3144 51 : numHolesToRead = pasSecHdrs[iSection].numHoles;
3145 : else
3146 0 : numHolesToRead--;
3147 :
3148 51 : numSectionVertices = pasSecHdrs[iSection].numVertices;
3149 51 : pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
3150 :
3151 51 : poRing = new OGRLinearRing();
3152 51 : poRing->setNumPoints(numSectionVertices);
3153 :
3154 1281 : for(i=0; i<numSectionVertices; i++)
3155 : {
3156 1230 : poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
3157 1230 : poRing->setPoint(i, dX, dY);
3158 1230 : pnXYPtr += 2;
3159 : }
3160 :
3161 51 : poPolygon->addRingDirectly(poRing);
3162 51 : poRing = NULL;
3163 :
3164 51 : if (numHolesToRead < 1)
3165 : {
3166 51 : if (numOuterRings > 1)
3167 : {
3168 0 : poMultiPolygon->addGeometryDirectly(poPolygon);
3169 : }
3170 : else
3171 : {
3172 51 : poGeometry = poPolygon;
3173 51 : CPLAssert(iSection == numLineSections-1);
3174 : }
3175 :
3176 51 : poPolygon = NULL; // We'll alloc a new polygon next loop.
3177 : }
3178 :
3179 : }
3180 :
3181 51 : CPLFree(pasSecHdrs);
3182 51 : CPLFree(panXY);
3183 : }
3184 : else
3185 : {
3186 : CPLError(CE_Failure, CPLE_AssertionFailed,
3187 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
3188 0 : m_nMapInfoType, m_nMapInfoType);
3189 0 : return -1;
3190 : }
3191 :
3192 51 : SetGeometryDirectly(poGeometry);
3193 :
3194 51 : SetMBR(dXMin, dYMin, dXMax, dYMax);
3195 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
3196 51 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
3197 :
3198 : /* Return a ref to coord block so that caller can continue reading
3199 : * after the end of this object (used by TABCollection and index splitting)
3200 : */
3201 51 : if (ppoCoordBlock)
3202 0 : *ppoCoordBlock = poCoordBlock;
3203 :
3204 51 : return 0;
3205 : }
3206 :
3207 : /**********************************************************************
3208 : * TABRegion::WriteGeometryToMAPFile()
3209 : *
3210 : * Write the geometry and representation (color, etc...) part of the
3211 : * feature to the .MAP object pointed to by poMAPFile.
3212 : *
3213 : * It is assumed that poMAPFile currently points to a valid map object.
3214 : *
3215 : * Returns 0 on success, -1 on error, in which case CPLError() will have
3216 : * been called.
3217 : **********************************************************************/
3218 11 : int TABRegion::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
3219 : TABMAPObjHdr *poObjHdr,
3220 : GBool bCoordBlockDataOnly /*=FALSE*/,
3221 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
3222 : {
3223 : GInt32 nX, nY;
3224 : OGRGeometry *poGeom;
3225 11 : TABMAPCoordBlock *poCoordBlock=NULL;
3226 :
3227 : /*-----------------------------------------------------------------
3228 : * We assume that ValidateMapInfoType() was called already and that
3229 : * the type in poObjHdr->m_nType is valid.
3230 : *----------------------------------------------------------------*/
3231 11 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
3232 :
3233 : /*-----------------------------------------------------------------
3234 : * Fetch and validate geometry
3235 : *----------------------------------------------------------------*/
3236 11 : poGeom = GetGeometryRef();
3237 :
3238 22 : if ((m_nMapInfoType == TAB_GEOM_REGION ||
3239 : m_nMapInfoType == TAB_GEOM_REGION_C ||
3240 : m_nMapInfoType == TAB_GEOM_V450_REGION ||
3241 : m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
3242 : m_nMapInfoType == TAB_GEOM_V800_REGION ||
3243 : m_nMapInfoType == TAB_GEOM_V800_REGION_C) &&
3244 11 : poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3245 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3246 : {
3247 : /*=============================================================
3248 : * REGIONs are similar to PLINE MULTIPLE
3249 : *
3250 : * We accept both OGRPolygons (with one or multiple rings) and
3251 : * OGRMultiPolygons as input.
3252 : *============================================================*/
3253 11 : int nStatus=0, i, iRing;
3254 : int numRingsTotal;
3255 : GUInt32 nCoordDataSize;
3256 : GInt32 nCoordBlockPtr;
3257 11 : TABMAPCoordSecHdr *pasSecHdrs = NULL;
3258 11 : GBool bCompressed = poObjHdr->IsCompressedType();
3259 :
3260 : /*-------------------------------------------------------------
3261 : * Process geometry first...
3262 : *------------------------------------------------------------*/
3263 11 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
3264 0 : poCoordBlock = *ppoCoordBlock;
3265 : else
3266 11 : poCoordBlock = poMapFile->GetCurCoordBlock();
3267 11 : poCoordBlock->StartNewFeature();
3268 11 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
3269 11 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
3270 :
3271 : #ifdef TABDUMP
3272 : printf("TABRegion::WriteGeometryToMAPFile(): ComprOrgX,Y= (%d,%d)\n",
3273 : m_nComprOrgX, m_nComprOrgY);
3274 : #endif
3275 : /*-------------------------------------------------------------
3276 : * Fetch total number of rings and build array of coord
3277 : * sections headers.
3278 : *------------------------------------------------------------*/
3279 11 : numRingsTotal = ComputeNumRings(&pasSecHdrs, poMapFile);
3280 11 : if (numRingsTotal == 0)
3281 0 : nStatus = -1;
3282 :
3283 : /*-------------------------------------------------------------
3284 : * Write the Coord. Section Header
3285 : *------------------------------------------------------------*/
3286 11 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
3287 :
3288 11 : if (nStatus == 0)
3289 : nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numRingsTotal,
3290 11 : pasSecHdrs, bCompressed);
3291 :
3292 11 : CPLFree(pasSecHdrs);
3293 11 : pasSecHdrs = NULL;
3294 :
3295 11 : if (nStatus != 0)
3296 0 : return nStatus; // Error has already been reported.
3297 :
3298 : /*-------------------------------------------------------------
3299 : * Go through all the rings in our OGRMultiPolygon or OGRPolygon
3300 : * to write the coordinates themselves...
3301 : *------------------------------------------------------------*/
3302 :
3303 22 : for(iRing=0; iRing < numRingsTotal; iRing++)
3304 : {
3305 : OGRLinearRing *poRing;
3306 :
3307 11 : poRing = GetRingRef(iRing);
3308 11 : if (poRing == NULL)
3309 : {
3310 : CPLError(CE_Failure, CPLE_AssertionFailed,
3311 0 : "TABRegion: Object Geometry contains NULL rings!");
3312 0 : return -1;
3313 : }
3314 :
3315 11 : int numPoints = poRing->getNumPoints();
3316 :
3317 261 : for(i=0; nStatus == 0 && i<numPoints; i++)
3318 : {
3319 : poMapFile->Coordsys2Int(poRing->getX(i), poRing->getY(i),
3320 250 : nX, nY);
3321 250 : if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
3322 : bCompressed)) != 0)
3323 : {
3324 : // Failed ... error message has already been produced
3325 0 : return nStatus;
3326 : }
3327 : }
3328 : }/* for iRing*/
3329 :
3330 11 : nCoordDataSize = poCoordBlock->GetFeatureDataSize();
3331 :
3332 : /*-------------------------------------------------------------
3333 : * ... and finally copy info to poObjHdr
3334 : *------------------------------------------------------------*/
3335 11 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
3336 :
3337 11 : poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
3338 11 : poPLineHdr->m_nCoordDataSize = nCoordDataSize;
3339 11 : poPLineHdr->m_numLineSections = numRingsTotal;
3340 :
3341 11 : poPLineHdr->m_bSmooth = m_bSmooth;
3342 :
3343 : // MBR
3344 11 : poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
3345 :
3346 : // Region center/label point
3347 : double dX, dY;
3348 11 : if (GetCenter(dX, dY) != -1)
3349 : {
3350 : poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX,
3351 11 : poPLineHdr->m_nLabelY);
3352 : }
3353 : else
3354 : {
3355 0 : poPLineHdr->m_nLabelX = m_nComprOrgX;
3356 0 : poPLineHdr->m_nLabelY = m_nComprOrgY;
3357 : }
3358 :
3359 : // Compressed coordinate origin (useful only in compressed case!)
3360 11 : poPLineHdr->m_nComprOrgX = m_nComprOrgX;
3361 11 : poPLineHdr->m_nComprOrgY = m_nComprOrgY;
3362 :
3363 11 : if (!bCoordBlockDataOnly)
3364 : {
3365 11 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
3366 11 : poPLineHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
3367 :
3368 11 : m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
3369 11 : poPLineHdr->m_nBrushId = (GByte)m_nBrushDefIndex; // Brush index
3370 : }
3371 : }
3372 : else
3373 : {
3374 : CPLError(CE_Failure, CPLE_AssertionFailed,
3375 0 : "TABRegion: Object contains an invalid Geometry!");
3376 0 : return -1;
3377 : }
3378 :
3379 11 : if (CPLGetLastErrorNo() != 0)
3380 0 : return -1;
3381 :
3382 : /* Return a ref to coord block so that caller can continue writing
3383 : * after the end of this object (used by index splitting)
3384 : */
3385 11 : if (ppoCoordBlock)
3386 0 : *ppoCoordBlock = poCoordBlock;
3387 :
3388 11 : return 0;
3389 : }
3390 :
3391 :
3392 : /**********************************************************************
3393 : * TABRegion::GetNumRings()
3394 : *
3395 : * Return the total number of rings in this object making it look like
3396 : * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
3397 : * of rings... hides the complexity of handling OGRMultiPolygons vs
3398 : * OGRPolygons, etc.
3399 : *
3400 : * Returns 0 if the geometry contained in the object is invalid or missing.
3401 : **********************************************************************/
3402 21 : int TABRegion::GetNumRings()
3403 : {
3404 21 : return ComputeNumRings(NULL, NULL);
3405 : }
3406 :
3407 32 : int TABRegion::ComputeNumRings(TABMAPCoordSecHdr **ppasSecHdrs,
3408 : TABMAPFile *poMapFile)
3409 : {
3410 : OGRGeometry *poGeom;
3411 32 : int numRingsTotal = 0, iLastSect = 0;
3412 :
3413 32 : if (ppasSecHdrs)
3414 11 : *ppasSecHdrs = NULL;
3415 32 : poGeom = GetGeometryRef();
3416 :
3417 32 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3418 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3419 : {
3420 : /*-------------------------------------------------------------
3421 : * Calculate total number of rings...
3422 : *------------------------------------------------------------*/
3423 32 : OGRPolygon *poPolygon=NULL;
3424 32 : OGRMultiPolygon *poMultiPolygon = NULL;
3425 :
3426 32 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3427 : {
3428 0 : poMultiPolygon = (OGRMultiPolygon *)poGeom;
3429 0 : for(int iPoly=0; iPoly<poMultiPolygon->getNumGeometries(); iPoly++)
3430 : {
3431 : // We are guaranteed that all parts are OGRPolygons
3432 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
3433 0 : if (poPolygon == NULL)
3434 0 : continue;
3435 :
3436 0 : numRingsTotal += poPolygon->getNumInteriorRings()+1;
3437 :
3438 0 : if (ppasSecHdrs)
3439 : {
3440 0 : if (AppendSecHdrs(poPolygon, *ppasSecHdrs,
3441 : poMapFile, iLastSect) != 0)
3442 0 : return 0; // An error happened, return count=0
3443 : }
3444 :
3445 : }/*for*/
3446 : }
3447 : else
3448 : {
3449 32 : poPolygon = (OGRPolygon*)poGeom;
3450 32 : numRingsTotal = poPolygon->getNumInteriorRings()+1;
3451 :
3452 32 : if (ppasSecHdrs)
3453 : {
3454 11 : if (AppendSecHdrs(poPolygon, *ppasSecHdrs,
3455 : poMapFile, iLastSect) != 0)
3456 0 : return 0; // An error happened, return count=0
3457 : }
3458 : }
3459 : }
3460 :
3461 : /*-----------------------------------------------------------------
3462 : * If we're generating section header blocks, then init the
3463 : * coordinate offset values.
3464 : *
3465 : * In calculation of nDataOffset, we have to take into account that
3466 : * V450 header section uses int32 instead of int16 for numVertices
3467 : * and we add another 2 bytes to align with a 4 bytes boundary.
3468 : *------------------------------------------------------------*/
3469 : int nTotalHdrSizeUncompressed;
3470 32 : if (m_nMapInfoType == TAB_GEOM_V450_REGION ||
3471 : m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
3472 : m_nMapInfoType == TAB_GEOM_V800_REGION ||
3473 : m_nMapInfoType == TAB_GEOM_V800_REGION_C)
3474 0 : nTotalHdrSizeUncompressed = 28 * numRingsTotal;
3475 : else
3476 32 : nTotalHdrSizeUncompressed = 24 * numRingsTotal;
3477 :
3478 32 : if (ppasSecHdrs)
3479 : {
3480 11 : int numPointsTotal = 0;
3481 11 : CPLAssert(iLastSect == numRingsTotal);
3482 22 : for (int iRing=0; iRing<numRingsTotal; iRing++)
3483 : {
3484 11 : (*ppasSecHdrs)[iRing].nDataOffset = nTotalHdrSizeUncompressed +
3485 11 : numPointsTotal*4*2;
3486 11 : (*ppasSecHdrs)[iRing].nVertexOffset = numPointsTotal;
3487 :
3488 11 : numPointsTotal += (*ppasSecHdrs)[iRing].numVertices;
3489 : }
3490 : }
3491 :
3492 32 : return numRingsTotal;
3493 : }
3494 :
3495 :
3496 : /**********************************************************************
3497 : * TABRegion::AppendSecHdrs()
3498 : *
3499 : * (Private method)
3500 : *
3501 : * Add a TABMAPCoordSecHdr for each ring in the specified polygon.
3502 : **********************************************************************/
3503 11 : int TABRegion::AppendSecHdrs(OGRPolygon *poPolygon,
3504 : TABMAPCoordSecHdr * &pasSecHdrs,
3505 : TABMAPFile *poMapFile,
3506 : int &iLastRing)
3507 : {
3508 : int iRing, numRingsInPolygon;
3509 : /*-------------------------------------------------------------
3510 : * Add a pasSecHdrs[] entry for each ring in this polygon.
3511 : * Note that the structs won't be fully initialized.
3512 : *------------------------------------------------------------*/
3513 11 : numRingsInPolygon = poPolygon->getNumInteriorRings()+1;
3514 :
3515 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLRealloc(pasSecHdrs,
3516 : (iLastRing+numRingsInPolygon)*
3517 11 : sizeof(TABMAPCoordSecHdr));
3518 :
3519 22 : for(iRing=0; iRing < numRingsInPolygon; iRing++)
3520 : {
3521 : OGRLinearRing *poRing;
3522 11 : OGREnvelope sEnvelope;
3523 :
3524 11 : if (iRing == 0)
3525 11 : poRing = poPolygon->getExteriorRing();
3526 : else
3527 0 : poRing = poPolygon->getInteriorRing(iRing-1);
3528 :
3529 11 : if (poRing == NULL)
3530 : {
3531 : CPLError(CE_Failure, CPLE_AssertionFailed,
3532 0 : "Assertion Failed: Encountered NULL ring in OGRPolygon");
3533 0 : return -1;
3534 : }
3535 :
3536 11 : poRing->getEnvelope(&sEnvelope);
3537 :
3538 11 : pasSecHdrs[iLastRing].numVertices = poRing->getNumPoints();
3539 :
3540 11 : if (iRing == 0)
3541 11 : pasSecHdrs[iLastRing].numHoles = numRingsInPolygon-1;
3542 : else
3543 0 : pasSecHdrs[iLastRing].numHoles = 0;
3544 :
3545 : poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
3546 11 : pasSecHdrs[iLastRing].nXMin,
3547 22 : pasSecHdrs[iLastRing].nYMin);
3548 : poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
3549 11 : pasSecHdrs[iLastRing].nXMax,
3550 22 : pasSecHdrs[iLastRing].nYMax);
3551 :
3552 11 : iLastRing++;
3553 : }/* for iRing*/
3554 :
3555 11 : return 0;
3556 : }
3557 :
3558 : /**********************************************************************
3559 : * TABRegion::GetRingRef()
3560 : *
3561 : * Returns a reference to the specified ring number making it look like
3562 : * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
3563 : * of rings... hides the complexity of handling OGRMultiPolygons vs
3564 : * OGRPolygons, etc.
3565 : *
3566 : * Returns NULL if the geometry contained in the object is invalid or
3567 : * missing or if the specified ring index is invalid.
3568 : **********************************************************************/
3569 32 : OGRLinearRing *TABRegion::GetRingRef(int nRequestedRingIndex)
3570 : {
3571 : OGRGeometry *poGeom;
3572 32 : OGRLinearRing *poRing = NULL;
3573 :
3574 32 : poGeom = GetGeometryRef();
3575 :
3576 32 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3577 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3578 : {
3579 : /*-------------------------------------------------------------
3580 : * Establish number of polygons based on geometry type
3581 : *------------------------------------------------------------*/
3582 32 : OGRPolygon *poPolygon=NULL;
3583 32 : OGRMultiPolygon *poMultiPolygon = NULL;
3584 32 : int iCurRing = 0;
3585 32 : int numOGRPolygons = 0;
3586 :
3587 32 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3588 : {
3589 0 : poMultiPolygon = (OGRMultiPolygon *)poGeom;
3590 0 : numOGRPolygons = poMultiPolygon->getNumGeometries();
3591 : }
3592 : else
3593 : {
3594 32 : poPolygon = (OGRPolygon*)poGeom;
3595 32 : numOGRPolygons = 1;
3596 : }
3597 :
3598 : /*-------------------------------------------------------------
3599 : * Loop through polygons until we find the requested ring.
3600 : *------------------------------------------------------------*/
3601 32 : iCurRing = 0;
3602 64 : for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
3603 : {
3604 32 : if (poMultiPolygon)
3605 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
3606 : else
3607 32 : poPolygon = (OGRPolygon*)poGeom;
3608 :
3609 32 : int numIntRings = poPolygon->getNumInteriorRings();
3610 :
3611 32 : if (iCurRing == nRequestedRingIndex)
3612 : {
3613 32 : poRing = poPolygon->getExteriorRing();
3614 : }
3615 0 : else if (nRequestedRingIndex > iCurRing &&
3616 : nRequestedRingIndex-(iCurRing+1) < numIntRings)
3617 : {
3618 : poRing = poPolygon->getInteriorRing(nRequestedRingIndex-
3619 0 : (iCurRing+1) );
3620 : }
3621 32 : iCurRing += numIntRings+1;
3622 : }
3623 : }
3624 :
3625 32 : return poRing;
3626 : }
3627 :
3628 : /**********************************************************************
3629 : * TABRegion::RingIsHole()
3630 : *
3631 : * Return false if the requested ring index is the first of a polygon
3632 : **********************************************************************/
3633 0 : GBool TABRegion::IsInteriorRing(int nRequestedRingIndex)
3634 : {
3635 : OGRGeometry *poGeom;
3636 0 : OGRLinearRing *poRing = NULL;
3637 :
3638 0 : poGeom = GetGeometryRef();
3639 :
3640 0 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3641 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3642 : {
3643 : /*-------------------------------------------------------------
3644 : * Establish number of polygons based on geometry type
3645 : *------------------------------------------------------------*/
3646 0 : OGRPolygon *poPolygon=NULL;
3647 0 : OGRMultiPolygon *poMultiPolygon = NULL;
3648 0 : int iCurRing = 0;
3649 0 : int numOGRPolygons = 0;
3650 :
3651 0 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3652 : {
3653 0 : poMultiPolygon = (OGRMultiPolygon *)poGeom;
3654 0 : numOGRPolygons = poMultiPolygon->getNumGeometries();
3655 : }
3656 : else
3657 : {
3658 0 : poPolygon = (OGRPolygon*)poGeom;
3659 0 : numOGRPolygons = 1;
3660 : }
3661 :
3662 : /*-------------------------------------------------------------
3663 : * Loop through polygons until we find the requested ring.
3664 : *------------------------------------------------------------*/
3665 0 : iCurRing = 0;
3666 0 : for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
3667 : {
3668 0 : if (poMultiPolygon)
3669 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
3670 : else
3671 0 : poPolygon = (OGRPolygon*)poGeom;
3672 :
3673 0 : int numIntRings = poPolygon->getNumInteriorRings();
3674 :
3675 0 : if (iCurRing == nRequestedRingIndex)
3676 : {
3677 0 : return FALSE;
3678 : }
3679 0 : else if (nRequestedRingIndex > iCurRing &&
3680 : nRequestedRingIndex-(iCurRing+1) < numIntRings)
3681 : {
3682 0 : return TRUE;
3683 : }
3684 0 : iCurRing += numIntRings+1;
3685 : }
3686 : }
3687 :
3688 0 : return FALSE;
3689 : }
3690 :
3691 : /**********************************************************************
3692 : * TABRegion::GetStyleString()
3693 : *
3694 : * Return style string for this feature.
3695 : *
3696 : * Style String is built only once during the first call to GetStyleString().
3697 : **********************************************************************/
3698 11 : const char *TABRegion::GetStyleString()
3699 : {
3700 11 : if (m_pszStyleString == NULL)
3701 : {
3702 : // Since GetPen/BrushStyleString() use CPLSPrintf(), we need
3703 : // to use temporary buffers
3704 7 : char *pszPen = CPLStrdup(GetPenStyleString());
3705 7 : char *pszBrush = CPLStrdup(GetBrushStyleString());
3706 :
3707 7 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
3708 :
3709 7 : CPLFree(pszPen);
3710 7 : CPLFree(pszBrush);
3711 : }
3712 :
3713 11 : return m_pszStyleString;
3714 : }
3715 :
3716 :
3717 :
3718 : /**********************************************************************
3719 : * TABRegion::DumpMIF()
3720 : *
3721 : * Dump feature geometry in a format similar to .MIF REGIONs.
3722 : **********************************************************************/
3723 0 : void TABRegion::DumpMIF(FILE *fpOut /*=NULL*/)
3724 : {
3725 : OGRGeometry *poGeom;
3726 : int i, numPoints;
3727 :
3728 0 : if (fpOut == NULL)
3729 0 : fpOut = stdout;
3730 :
3731 : /*-----------------------------------------------------------------
3732 : * Fetch and validate geometry
3733 : *----------------------------------------------------------------*/
3734 0 : poGeom = GetGeometryRef();
3735 0 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3736 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3737 : {
3738 : /*-------------------------------------------------------------
3739 : * Generate output for region
3740 : *
3741 : * Note that we want to handle both OGRPolygons and OGRMultiPolygons
3742 : * that's why we use the GetNumRings()/GetRingRef() interface.
3743 : *------------------------------------------------------------*/
3744 0 : int iRing, numRingsTotal = GetNumRings();
3745 :
3746 0 : fprintf(fpOut, "REGION %d\n", numRingsTotal);
3747 :
3748 0 : for(iRing=0; iRing < numRingsTotal; iRing++)
3749 : {
3750 : OGRLinearRing *poRing;
3751 :
3752 0 : poRing = GetRingRef(iRing);
3753 :
3754 0 : if (poRing == NULL)
3755 : {
3756 : CPLError(CE_Failure, CPLE_AssertionFailed,
3757 0 : "TABRegion: Object Geometry contains NULL rings!");
3758 0 : return;
3759 : }
3760 :
3761 0 : numPoints = poRing->getNumPoints();
3762 0 : fprintf(fpOut, " %d\n", numPoints);
3763 0 : for(i=0; i<numPoints; i++)
3764 0 : fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
3765 : }
3766 : }
3767 : else
3768 : {
3769 : CPLError(CE_Failure, CPLE_AssertionFailed,
3770 0 : "TABRegion: Missing or Invalid Geometry!");
3771 0 : return;
3772 : }
3773 :
3774 0 : if (m_bCenterIsSet)
3775 0 : fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
3776 :
3777 : // Finish with PEN/BRUSH/etc. clauses
3778 0 : DumpPenDef();
3779 0 : DumpBrushDef();
3780 :
3781 0 : fflush(fpOut);
3782 : }
3783 :
3784 : /**********************************************************************
3785 : * TABRegion::GetCenter()
3786 : *
3787 : * Returns the center/label point of the region.
3788 : * Compute one using OGRPolygonLabelPoint() if it was not explicitly set
3789 : * before.
3790 : *
3791 : * Returns 0 on success, -1 on error.
3792 : **********************************************************************/
3793 11 : int TABRegion::GetCenter(double &dX, double &dY)
3794 : {
3795 11 : if (!m_bCenterIsSet)
3796 : {
3797 : /*-------------------------------------------------------------
3798 : * Calculate label point. If we have a multipolygon then we use
3799 : * the first OGRPolygon in the feature to calculate the point.
3800 : *------------------------------------------------------------*/
3801 11 : OGRPoint oLabelPoint;
3802 11 : OGRPolygon *poPolygon=NULL;
3803 : OGRGeometry *poGeom;
3804 :
3805 11 : poGeom = GetGeometryRef();
3806 11 : if (poGeom == NULL)
3807 0 : return -1;
3808 :
3809 11 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3810 : {
3811 0 : OGRMultiPolygon *poMultiPolygon = (OGRMultiPolygon *)poGeom;
3812 0 : if (poMultiPolygon->getNumGeometries() > 0)
3813 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(0);
3814 : }
3815 11 : else if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
3816 : {
3817 11 : poPolygon = (OGRPolygon*)poGeom;
3818 : }
3819 :
3820 11 : if (poPolygon != NULL &&
3821 : OGRPolygonLabelPoint(poPolygon, &oLabelPoint) == OGRERR_NONE)
3822 : {
3823 11 : m_dCenterX = oLabelPoint.getX();
3824 11 : m_dCenterY = oLabelPoint.getY();
3825 : }
3826 : else
3827 : {
3828 0 : OGREnvelope oEnv;
3829 0 : poGeom->getEnvelope(&oEnv);
3830 0 : m_dCenterX = (oEnv.MaxX + oEnv.MinX)/2.0;
3831 0 : m_dCenterY = (oEnv.MaxY + oEnv.MinY)/2.0;
3832 : }
3833 :
3834 11 : m_bCenterIsSet = TRUE;
3835 : }
3836 :
3837 11 : if (!m_bCenterIsSet)
3838 0 : return -1;
3839 :
3840 11 : dX = m_dCenterX;
3841 11 : dY = m_dCenterY;
3842 11 : return 0;
3843 : }
3844 :
3845 : /**********************************************************************
3846 : * TABRegion::SetCenter()
3847 : *
3848 : * Set the X,Y coordinates to use as center/label point for the region.
3849 : **********************************************************************/
3850 51 : void TABRegion::SetCenter(double dX, double dY)
3851 : {
3852 51 : m_dCenterX = dX;
3853 51 : m_dCenterY = dY;
3854 51 : m_bCenterIsSet = TRUE;
3855 51 : }
3856 :
3857 :
3858 : /*=====================================================================
3859 : * class TABRectangle
3860 : *====================================================================*/
3861 :
3862 : /**********************************************************************
3863 : * TABRectangle::TABRectangle()
3864 : *
3865 : * Constructor.
3866 : **********************************************************************/
3867 0 : TABRectangle::TABRectangle(OGRFeatureDefn *poDefnIn):
3868 0 : TABFeature(poDefnIn)
3869 : {
3870 0 : m_bRoundCorners = FALSE;
3871 0 : m_dRoundXRadius = m_dRoundYRadius = 0.0;
3872 0 : }
3873 :
3874 : /**********************************************************************
3875 : * TABRectangle::~TABRectangle()
3876 : *
3877 : * Destructor.
3878 : **********************************************************************/
3879 0 : TABRectangle::~TABRectangle()
3880 : {
3881 0 : }
3882 :
3883 : /**********************************************************************
3884 : * TABRectangle::CloneTABFeature()
3885 : *
3886 : * Duplicate feature, including stuff specific to each TABFeature type.
3887 : *
3888 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
3889 : * then copies any members specific to its own type.
3890 : **********************************************************************/
3891 0 : TABFeature *TABRectangle::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
3892 : {
3893 : /*-----------------------------------------------------------------
3894 : * Alloc new feature and copy the base stuff
3895 : *----------------------------------------------------------------*/
3896 : TABRectangle *poNew = new TABRectangle(poNewDefn ? poNewDefn :
3897 0 : GetDefnRef());
3898 :
3899 0 : CopyTABFeatureBase(poNew);
3900 :
3901 : /*-----------------------------------------------------------------
3902 : * And members specific to this class
3903 : *----------------------------------------------------------------*/
3904 : // ITABFeaturePen
3905 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
3906 :
3907 : // ITABFeatureBrush
3908 0 : *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
3909 :
3910 0 : poNew->m_bRoundCorners = m_bRoundCorners;
3911 0 : poNew->m_dRoundXRadius = m_dRoundXRadius;
3912 0 : poNew->m_dRoundYRadius = m_dRoundYRadius;
3913 :
3914 0 : return poNew;
3915 : }
3916 :
3917 : /**********************************************************************
3918 : * TABRectangle::ValidateMapInfoType()
3919 : *
3920 : * Check the feature's geometry part and return the corresponding
3921 : * mapinfo object type code. The m_nMapInfoType member will also
3922 : * be updated for further calls to GetMapInfoType();
3923 : *
3924 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
3925 : * is expected for this object class.
3926 : **********************************************************************/
3927 0 : int TABRectangle::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
3928 : {
3929 : OGRGeometry *poGeom;
3930 :
3931 : /*-----------------------------------------------------------------
3932 : * Fetch and validate geometry
3933 : *----------------------------------------------------------------*/
3934 0 : poGeom = GetGeometryRef();
3935 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
3936 : {
3937 0 : if (m_bRoundCorners && m_dRoundXRadius!=0.0 && m_dRoundYRadius!=0.0)
3938 0 : m_nMapInfoType = TAB_GEOM_ROUNDRECT;
3939 : else
3940 0 : m_nMapInfoType = TAB_GEOM_RECT;
3941 : }
3942 : else
3943 : {
3944 : CPLError(CE_Failure, CPLE_AssertionFailed,
3945 0 : "TABRectangle: Missing or Invalid Geometry!");
3946 0 : m_nMapInfoType = TAB_GEOM_NONE;
3947 : }
3948 :
3949 : /*-----------------------------------------------------------------
3950 : * Decide if coordinates should be compressed or not.
3951 : *----------------------------------------------------------------*/
3952 : // __TODO__ For now we always write uncompressed for this class...
3953 : // ValidateCoordType(poMapFile);
3954 0 : UpdateMBR(poMapFile);
3955 :
3956 0 : return m_nMapInfoType;
3957 : }
3958 :
3959 : /**********************************************************************
3960 : * TABRectangle::UpdateMBR()
3961 : *
3962 : * Update the feature MBR members using the geometry
3963 : *
3964 : * Returns 0 on success, or -1 if there is no geometry in object
3965 : **********************************************************************/
3966 0 : int TABRectangle::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
3967 : {
3968 : OGRGeometry *poGeom;
3969 0 : OGREnvelope sEnvelope;
3970 :
3971 : /*-----------------------------------------------------------------
3972 : * Fetch and validate geometry
3973 : *----------------------------------------------------------------*/
3974 0 : poGeom = GetGeometryRef();
3975 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
3976 0 : poGeom->getEnvelope(&sEnvelope);
3977 : else
3978 : {
3979 : CPLError(CE_Failure, CPLE_AssertionFailed,
3980 0 : "TABRectangle: Missing or Invalid Geometry!");
3981 0 : return -1;
3982 : }
3983 :
3984 : /*-----------------------------------------------------------------
3985 : * Note that we will simply use the rectangle's MBR and don't really
3986 : * read the polygon geometry... this should be OK unless the
3987 : * polygon geometry was not really a rectangle.
3988 : *----------------------------------------------------------------*/
3989 0 : m_dXMin = sEnvelope.MinX;
3990 0 : m_dYMin = sEnvelope.MinY;
3991 0 : m_dXMax = sEnvelope.MaxX;
3992 0 : m_dYMax = sEnvelope.MaxY;
3993 :
3994 0 : if (poMapFile)
3995 : {
3996 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
3997 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
3998 : }
3999 :
4000 0 : return 0;
4001 : }
4002 :
4003 : /**********************************************************************
4004 : * TABRectangle::ReadGeometryFromMAPFile()
4005 : *
4006 : * Fill the geometry and representation (color, etc...) part of the
4007 : * feature from the contents of the .MAP object pointed to by poMAPFile.
4008 : *
4009 : * It is assumed that poMAPFile currently points to the beginning of
4010 : * a map object.
4011 : *
4012 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4013 : * been called.
4014 : **********************************************************************/
4015 0 : int TABRectangle::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
4016 : TABMAPObjHdr *poObjHdr,
4017 : GBool bCoordBlockDataOnly /*=FALSE*/,
4018 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4019 : {
4020 : double dXMin, dYMin, dXMax, dYMax;
4021 : OGRPolygon *poPolygon;
4022 : OGRLinearRing *poRing;
4023 :
4024 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4025 0 : if (bCoordBlockDataOnly)
4026 0 : return 0;
4027 :
4028 : /*-----------------------------------------------------------------
4029 : * Fetch and validate geometry type
4030 : *----------------------------------------------------------------*/
4031 0 : m_nMapInfoType = poObjHdr->m_nType;
4032 :
4033 0 : if (m_nMapInfoType != TAB_GEOM_RECT &&
4034 : m_nMapInfoType != TAB_GEOM_RECT_C &&
4035 : m_nMapInfoType != TAB_GEOM_ROUNDRECT &&
4036 : m_nMapInfoType != TAB_GEOM_ROUNDRECT_C)
4037 : {
4038 : CPLError(CE_Failure, CPLE_AssertionFailed,
4039 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
4040 0 : m_nMapInfoType, m_nMapInfoType);
4041 0 : return -1;
4042 : }
4043 :
4044 : /*-----------------------------------------------------------------
4045 : * Read object information
4046 : *----------------------------------------------------------------*/
4047 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4048 :
4049 : // Read the corners radius
4050 :
4051 0 : if (m_nMapInfoType == TAB_GEOM_ROUNDRECT ||
4052 : m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
4053 : {
4054 : // Read the corner's diameters
4055 : poMapFile->Int2CoordsysDist(poRectHdr->m_nCornerWidth,
4056 : poRectHdr->m_nCornerHeight,
4057 0 : m_dRoundXRadius, m_dRoundYRadius);
4058 :
4059 : // Divide by 2 since we store the corner's radius
4060 0 : m_dRoundXRadius /= 2.0;
4061 0 : m_dRoundYRadius /= 2.0;
4062 :
4063 0 : m_bRoundCorners = TRUE;
4064 : }
4065 : else
4066 : {
4067 0 : m_bRoundCorners = FALSE;
4068 0 : m_dRoundXRadius = m_dRoundYRadius = 0.0;
4069 : }
4070 :
4071 : // A rectangle is defined by its MBR
4072 :
4073 : poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY,
4074 0 : dXMin, dYMin);
4075 : poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY,
4076 0 : dXMax, dYMax);
4077 :
4078 0 : m_nPenDefIndex = poRectHdr->m_nPenId; // Pen index
4079 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
4080 :
4081 0 : m_nBrushDefIndex = poRectHdr->m_nBrushId; // Brush index
4082 0 : poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
4083 :
4084 : /*-----------------------------------------------------------------
4085 : * Call SetMBR() and GetMBR() now to make sure that min values are
4086 : * really smaller than max values.
4087 : *----------------------------------------------------------------*/
4088 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
4089 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
4090 :
4091 : /* Copy int MBR to feature class members */
4092 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
4093 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
4094 :
4095 : /*-----------------------------------------------------------------
4096 : * Create and fill geometry object
4097 : *----------------------------------------------------------------*/
4098 0 : poPolygon = new OGRPolygon;
4099 0 : poRing = new OGRLinearRing();
4100 0 : if (m_bRoundCorners && m_dRoundXRadius != 0.0 && m_dRoundYRadius != 0.0)
4101 : {
4102 : /*-------------------------------------------------------------
4103 : * For rounded rectangles, we generate arcs with 45 line
4104 : * segments for each corner. We start with lower-left corner
4105 : * and proceed counterclockwise
4106 : * We also have to make sure that rounding radius is not too
4107 : * large for the MBR in the generated polygon... however, we
4108 : * always return the true X/Y radius (not adjusted) since this
4109 : * is the way MapInfo seems to do it when a radius bigger than
4110 : * the MBR is passed from TBA to MIF.
4111 : *------------------------------------------------------------*/
4112 0 : double dXRadius = MIN(m_dRoundXRadius, (dXMax-dXMin)/2.0);
4113 0 : double dYRadius = MIN(m_dRoundYRadius, (dYMax-dYMin)/2.0);
4114 : TABGenerateArc(poRing, 45,
4115 : dXMin + dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
4116 0 : PI, 3.0*PI/2.0);
4117 : TABGenerateArc(poRing, 45,
4118 : dXMax - dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
4119 0 : 3.0*PI/2.0, 2.0*PI);
4120 : TABGenerateArc(poRing, 45,
4121 : dXMax - dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
4122 0 : 0.0, PI/2.0);
4123 : TABGenerateArc(poRing, 45,
4124 : dXMin + dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
4125 0 : PI/2.0, PI);
4126 :
4127 0 : TABCloseRing(poRing);
4128 : }
4129 : else
4130 : {
4131 0 : poRing->addPoint(dXMin, dYMin);
4132 0 : poRing->addPoint(dXMax, dYMin);
4133 0 : poRing->addPoint(dXMax, dYMax);
4134 0 : poRing->addPoint(dXMin, dYMax);
4135 0 : poRing->addPoint(dXMin, dYMin);
4136 : }
4137 :
4138 0 : poPolygon->addRingDirectly(poRing);
4139 0 : SetGeometryDirectly(poPolygon);
4140 :
4141 0 : return 0;
4142 : }
4143 :
4144 : /**********************************************************************
4145 : * TABRectangle::WriteGeometryToMAPFile()
4146 : *
4147 : * Write the geometry and representation (color, etc...) part of the
4148 : * feature to the .MAP object pointed to by poMAPFile.
4149 : *
4150 : * It is assumed that poMAPFile currently points to a valid map object.
4151 : *
4152 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4153 : * been called.
4154 : **********************************************************************/
4155 0 : int TABRectangle::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
4156 : TABMAPObjHdr *poObjHdr,
4157 : GBool bCoordBlockDataOnly /*=FALSE*/,
4158 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4159 : {
4160 :
4161 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4162 0 : if (bCoordBlockDataOnly)
4163 0 : return 0;
4164 :
4165 : /*-----------------------------------------------------------------
4166 : * We assume that ValidateMapInfoType() was called already and that
4167 : * the type in poObjHdr->m_nType is valid.
4168 : *----------------------------------------------------------------*/
4169 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
4170 :
4171 : /*-----------------------------------------------------------------
4172 : * Fetch and validate geometry and update MBR
4173 : * Note that we will simply use the geometry's MBR and don't really
4174 : * read the polygon geometry... this should be OK unless the
4175 : * polygon geometry was not really a rectangle.
4176 : *----------------------------------------------------------------*/
4177 0 : if (UpdateMBR(poMapFile) != 0)
4178 0 : return -1; /* Error already reported */
4179 :
4180 : /*-----------------------------------------------------------------
4181 : * Copy object information
4182 : *----------------------------------------------------------------*/
4183 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4184 :
4185 0 : if (m_nMapInfoType == TAB_GEOM_ROUNDRECT ||
4186 : m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
4187 : {
4188 : poMapFile->Coordsys2IntDist(m_dRoundXRadius*2.0, m_dRoundYRadius*2.0,
4189 : poRectHdr->m_nCornerWidth,
4190 0 : poRectHdr->m_nCornerHeight);
4191 : }
4192 : else
4193 : {
4194 0 : poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
4195 : }
4196 :
4197 : // A rectangle is defined by its MBR (values were set in UpdateMBR())
4198 0 : poRectHdr->m_nMinX = m_nXMin;
4199 0 : poRectHdr->m_nMinY = m_nYMin;
4200 0 : poRectHdr->m_nMaxX = m_nXMax;
4201 0 : poRectHdr->m_nMaxY = m_nYMax;
4202 :
4203 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
4204 0 : poRectHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
4205 :
4206 0 : m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
4207 0 : poRectHdr->m_nBrushId = (GByte)m_nBrushDefIndex; // Brush index
4208 :
4209 0 : if (CPLGetLastErrorNo() != 0)
4210 0 : return -1;
4211 :
4212 0 : return 0;
4213 : }
4214 :
4215 : /**********************************************************************
4216 : * TABRectangle::GetStyleString()
4217 : *
4218 : * Return style string for this feature.
4219 : *
4220 : * Style String is built only once during the first call to GetStyleString().
4221 : **********************************************************************/
4222 0 : const char *TABRectangle::GetStyleString()
4223 : {
4224 0 : if (m_pszStyleString == NULL)
4225 : {
4226 : // Since GetPen/BrushStyleString() use CPLSPrintf(), we need
4227 : // to use temporary buffers
4228 0 : char *pszPen = CPLStrdup(GetPenStyleString());
4229 0 : char *pszBrush = CPLStrdup(GetBrushStyleString());
4230 :
4231 0 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
4232 :
4233 0 : CPLFree(pszPen);
4234 0 : CPLFree(pszBrush);
4235 : }
4236 :
4237 0 : return m_pszStyleString;
4238 : }
4239 :
4240 : /**********************************************************************
4241 : * TABRectangle::DumpMIF()
4242 : *
4243 : * Dump feature geometry in a format similar to .MIF REGIONs.
4244 : **********************************************************************/
4245 0 : void TABRectangle::DumpMIF(FILE *fpOut /*=NULL*/)
4246 : {
4247 : OGRGeometry *poGeom;
4248 0 : OGRPolygon *poPolygon = NULL;
4249 : int i, numPoints;
4250 :
4251 0 : if (fpOut == NULL)
4252 0 : fpOut = stdout;
4253 :
4254 : /*-----------------------------------------------------------------
4255 : * Output RECT or ROUNDRECT parameters
4256 : *----------------------------------------------------------------*/
4257 : double dXMin, dYMin, dXMax, dYMax;
4258 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
4259 0 : if (m_bRoundCorners)
4260 : fprintf(fpOut, "(ROUNDRECT %.15g %.15g %.15g %.15g %.15g %.15g)\n",
4261 : dXMin, dYMin, dXMax, dYMax,
4262 0 : m_dRoundXRadius, m_dRoundYRadius);
4263 : else
4264 0 : fprintf(fpOut, "(RECT %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
4265 :
4266 : /*-----------------------------------------------------------------
4267 : * Fetch and validate geometry
4268 : *----------------------------------------------------------------*/
4269 0 : poGeom = GetGeometryRef();
4270 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
4271 : {
4272 : /*-------------------------------------------------------------
4273 : * Generate rectangle output as a region
4274 : * We could also output as a RECT or ROUNDRECT in a real MIF generator
4275 : *------------------------------------------------------------*/
4276 : int iRing, numIntRings;
4277 0 : poPolygon = (OGRPolygon*)poGeom;
4278 0 : numIntRings = poPolygon->getNumInteriorRings();
4279 0 : fprintf(fpOut, "REGION %d\n", numIntRings+1);
4280 : // In this loop, iRing=-1 for the outer ring.
4281 0 : for(iRing=-1; iRing < numIntRings; iRing++)
4282 : {
4283 : OGRLinearRing *poRing;
4284 :
4285 0 : if (iRing == -1)
4286 0 : poRing = poPolygon->getExteriorRing();
4287 : else
4288 0 : poRing = poPolygon->getInteriorRing(iRing);
4289 :
4290 0 : if (poRing == NULL)
4291 : {
4292 : CPLError(CE_Failure, CPLE_AssertionFailed,
4293 0 : "TABRectangle: Object Geometry contains NULL rings!");
4294 0 : return;
4295 : }
4296 :
4297 0 : numPoints = poRing->getNumPoints();
4298 0 : fprintf(fpOut, " %d\n", numPoints);
4299 0 : for(i=0; i<numPoints; i++)
4300 0 : fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
4301 : }
4302 : }
4303 : else
4304 : {
4305 : CPLError(CE_Failure, CPLE_AssertionFailed,
4306 0 : "TABRectangle: Missing or Invalid Geometry!");
4307 0 : return;
4308 : }
4309 :
4310 : // Finish with PEN/BRUSH/etc. clauses
4311 0 : DumpPenDef();
4312 0 : DumpBrushDef();
4313 :
4314 0 : fflush(fpOut);
4315 : }
4316 :
4317 :
4318 : /*=====================================================================
4319 : * class TABEllipse
4320 : *====================================================================*/
4321 :
4322 : /**********************************************************************
4323 : * TABEllipse::TABEllipse()
4324 : *
4325 : * Constructor.
4326 : **********************************************************************/
4327 0 : TABEllipse::TABEllipse(OGRFeatureDefn *poDefnIn):
4328 0 : TABFeature(poDefnIn)
4329 : {
4330 0 : }
4331 :
4332 : /**********************************************************************
4333 : * TABEllipse::~TABEllipse()
4334 : *
4335 : * Destructor.
4336 : **********************************************************************/
4337 0 : TABEllipse::~TABEllipse()
4338 : {
4339 0 : }
4340 :
4341 : /**********************************************************************
4342 : * TABEllipse::CloneTABFeature()
4343 : *
4344 : * Duplicate feature, including stuff specific to each TABFeature type.
4345 : *
4346 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
4347 : * then copies any members specific to its own type.
4348 : **********************************************************************/
4349 0 : TABFeature *TABEllipse::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
4350 : {
4351 : /*-----------------------------------------------------------------
4352 : * Alloc new feature and copy the base stuff
4353 : *----------------------------------------------------------------*/
4354 : TABEllipse *poNew = new TABEllipse(poNewDefn ? poNewDefn :
4355 0 : GetDefnRef());
4356 :
4357 0 : CopyTABFeatureBase(poNew);
4358 :
4359 : /*-----------------------------------------------------------------
4360 : * And members specific to this class
4361 : *----------------------------------------------------------------*/
4362 : // ITABFeaturePen
4363 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
4364 :
4365 : // ITABFeatureBrush
4366 0 : *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
4367 :
4368 0 : poNew->m_dCenterX = m_dCenterX;
4369 0 : poNew->m_dCenterY = m_dCenterY;
4370 0 : poNew->m_dXRadius = m_dXRadius;
4371 0 : poNew->m_dYRadius = m_dYRadius;
4372 :
4373 0 : return poNew;
4374 : }
4375 :
4376 : /**********************************************************************
4377 : * TABEllipse::ValidateMapInfoType()
4378 : *
4379 : * Check the feature's geometry part and return the corresponding
4380 : * mapinfo object type code. The m_nMapInfoType member will also
4381 : * be updated for further calls to GetMapInfoType();
4382 : *
4383 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
4384 : * is expected for this object class.
4385 : **********************************************************************/
4386 0 : int TABEllipse::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
4387 : {
4388 : OGRGeometry *poGeom;
4389 :
4390 : /*-----------------------------------------------------------------
4391 : * Fetch and validate geometry
4392 : *----------------------------------------------------------------*/
4393 0 : poGeom = GetGeometryRef();
4394 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
4395 0 : (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4396 : {
4397 0 : m_nMapInfoType = TAB_GEOM_ELLIPSE;
4398 : }
4399 : else
4400 : {
4401 : CPLError(CE_Failure, CPLE_AssertionFailed,
4402 0 : "TABEllipse: Missing or Invalid Geometry!");
4403 0 : m_nMapInfoType = TAB_GEOM_NONE;
4404 : }
4405 :
4406 : /*-----------------------------------------------------------------
4407 : * Decide if coordinates should be compressed or not.
4408 : *----------------------------------------------------------------*/
4409 : // __TODO__ For now we always write uncompressed for this class...
4410 : // ValidateCoordType(poMapFile);
4411 0 : UpdateMBR(poMapFile);
4412 :
4413 0 : return m_nMapInfoType;
4414 : }
4415 :
4416 : /**********************************************************************
4417 : * TABEllipse::UpdateMBR()
4418 : *
4419 : * Update the feature MBR members using the geometry
4420 : *
4421 : * Returns 0 on success, or -1 if there is no geometry in object
4422 : **********************************************************************/
4423 0 : int TABEllipse::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
4424 : {
4425 : OGRGeometry *poGeom;
4426 0 : OGREnvelope sEnvelope;
4427 :
4428 : /*-----------------------------------------------------------------
4429 : * Fetch and validate geometry... Polygon and point are accepted.
4430 : * Note that we will simply use the ellipse's MBR and don't really
4431 : * read the polygon geometry... this should be OK unless the
4432 : * polygon geometry was not really an ellipse.
4433 : *----------------------------------------------------------------*/
4434 0 : poGeom = GetGeometryRef();
4435 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
4436 0 : (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4437 0 : poGeom->getEnvelope(&sEnvelope);
4438 : else
4439 : {
4440 : CPLError(CE_Failure, CPLE_AssertionFailed,
4441 0 : "TABEllipse: Missing or Invalid Geometry!");
4442 0 : return -1;
4443 : }
4444 :
4445 : /*-----------------------------------------------------------------
4446 : * We use the center of the MBR as the ellipse center, and the
4447 : * X/Y radius to define the MBR size. If X/Y radius are null then
4448 : * we'll try to use the MBR to recompute them.
4449 : *----------------------------------------------------------------*/
4450 : double dXCenter, dYCenter;
4451 0 : dXCenter = (sEnvelope.MaxX + sEnvelope.MinX)/2.0;
4452 0 : dYCenter = (sEnvelope.MaxY + sEnvelope.MinY)/2.0;
4453 0 : if (m_dXRadius == 0.0 && m_dYRadius == 0.0)
4454 : {
4455 0 : m_dXRadius = ABS(sEnvelope.MaxX - sEnvelope.MinX) / 2.0;
4456 0 : m_dYRadius = ABS(sEnvelope.MaxY - sEnvelope.MinY) / 2.0;
4457 : }
4458 :
4459 0 : m_dXMin = dXCenter - m_dXRadius;
4460 0 : m_dYMin = dYCenter - m_dYRadius;
4461 0 : m_dXMax = dXCenter + m_dXRadius;
4462 0 : m_dYMax = dYCenter + m_dYRadius;
4463 :
4464 0 : if (poMapFile)
4465 : {
4466 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
4467 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
4468 : }
4469 :
4470 0 : return 0;
4471 : }
4472 :
4473 : /**********************************************************************
4474 : * TABEllipse::ReadGeometryFromMAPFile()
4475 : *
4476 : * Fill the geometry and representation (color, etc...) part of the
4477 : * feature from the contents of the .MAP object pointed to by poMAPFile.
4478 : *
4479 : * It is assumed that poMAPFile currently points to the beginning of
4480 : * a map object.
4481 : *
4482 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4483 : * been called.
4484 : **********************************************************************/
4485 0 : int TABEllipse::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
4486 : TABMAPObjHdr *poObjHdr,
4487 : GBool bCoordBlockDataOnly /*=FALSE*/,
4488 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4489 : {
4490 : double dXMin, dYMin, dXMax, dYMax;
4491 : OGRPolygon *poPolygon;
4492 : OGRLinearRing *poRing;
4493 :
4494 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4495 0 : if (bCoordBlockDataOnly)
4496 0 : return 0;
4497 :
4498 : /*-----------------------------------------------------------------
4499 : * Fetch and validate geometry type
4500 : *----------------------------------------------------------------*/
4501 0 : m_nMapInfoType = poObjHdr->m_nType;
4502 :
4503 0 : if (m_nMapInfoType != TAB_GEOM_ELLIPSE &&
4504 : m_nMapInfoType != TAB_GEOM_ELLIPSE_C )
4505 : {
4506 : CPLError(CE_Failure, CPLE_AssertionFailed,
4507 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
4508 0 : m_nMapInfoType, m_nMapInfoType);
4509 0 : return -1;
4510 : }
4511 :
4512 : /*-----------------------------------------------------------------
4513 : * Read object information
4514 : *----------------------------------------------------------------*/
4515 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4516 :
4517 : // An ellipse is defined by its MBR
4518 :
4519 : poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY,
4520 0 : dXMin, dYMin);
4521 : poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY,
4522 0 : dXMax, dYMax);
4523 :
4524 0 : m_nPenDefIndex = poRectHdr->m_nPenId; // Pen index
4525 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
4526 :
4527 0 : m_nBrushDefIndex = poRectHdr->m_nBrushId; // Brush index
4528 0 : poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
4529 :
4530 : /*-----------------------------------------------------------------
4531 : * Save info about the ellipse def. inside class members
4532 : *----------------------------------------------------------------*/
4533 0 : m_dCenterX = (dXMin + dXMax) / 2.0;
4534 0 : m_dCenterY = (dYMin + dYMax) / 2.0;
4535 0 : m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
4536 0 : m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
4537 :
4538 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
4539 :
4540 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
4541 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
4542 :
4543 : /*-----------------------------------------------------------------
4544 : * Create and fill geometry object
4545 : *----------------------------------------------------------------*/
4546 0 : poPolygon = new OGRPolygon;
4547 0 : poRing = new OGRLinearRing();
4548 :
4549 :
4550 : /*-----------------------------------------------------------------
4551 : * For the OGR geometry, we generate an ellipse with 2 degrees line
4552 : * segments.
4553 : *----------------------------------------------------------------*/
4554 : TABGenerateArc(poRing, 180,
4555 : m_dCenterX, m_dCenterY,
4556 : m_dXRadius, m_dYRadius,
4557 0 : 0.0, 2.0*PI);
4558 0 : TABCloseRing(poRing);
4559 :
4560 0 : poPolygon->addRingDirectly(poRing);
4561 0 : SetGeometryDirectly(poPolygon);
4562 :
4563 0 : return 0;
4564 : }
4565 :
4566 : /**********************************************************************
4567 : * TABEllipse::WriteGeometryToMAPFile()
4568 : *
4569 : * Write the geometry and representation (color, etc...) part of the
4570 : * feature to the .MAP object pointed to by poMAPFile.
4571 : *
4572 : * It is assumed that poMAPFile currently points to a valid map object.
4573 : *
4574 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4575 : * been called.
4576 : **********************************************************************/
4577 0 : int TABEllipse::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
4578 : TABMAPObjHdr *poObjHdr,
4579 : GBool bCoordBlockDataOnly /*=FALSE*/,
4580 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4581 : {
4582 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4583 0 : if (bCoordBlockDataOnly)
4584 0 : return 0;
4585 :
4586 : /*-----------------------------------------------------------------
4587 : * We assume that ValidateMapInfoType() was called already and that
4588 : * the type in poObjHdr->m_nType is valid.
4589 : *----------------------------------------------------------------*/
4590 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
4591 :
4592 : /*-----------------------------------------------------------------
4593 : * Fetch and validate geometry... Polygon and point are accepted.
4594 : * Note that we will simply use the ellipse's MBR and don't really
4595 : * read the polygon geometry... this should be OK unless the
4596 : * polygon geometry was not really an ellipse.
4597 : *
4598 : * We use the center of the MBR as the ellipse center, and the
4599 : * X/Y radius to define the MBR size. If X/Y radius are null then
4600 : * we'll try to use the MBR to recompute them.
4601 : *----------------------------------------------------------------*/
4602 0 : if (UpdateMBR(poMapFile) != 0)
4603 0 : return -1; /* Error already reported */
4604 :
4605 : /*-----------------------------------------------------------------
4606 : * Copy object information
4607 : *----------------------------------------------------------------*/
4608 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4609 :
4610 : // Reset RoundRect Corner members... just in case (unused for ellipse)
4611 0 : poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
4612 :
4613 : // An ellipse is defined by its MBR (values were set in UpdateMBR())
4614 0 : poRectHdr->m_nMinX = m_nXMin;
4615 0 : poRectHdr->m_nMinY = m_nYMin;
4616 0 : poRectHdr->m_nMaxX = m_nXMax;
4617 0 : poRectHdr->m_nMaxY = m_nYMax;
4618 :
4619 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
4620 0 : poRectHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
4621 :
4622 0 : m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
4623 0 : poRectHdr->m_nBrushId = (GByte)m_nBrushDefIndex; // Brush index
4624 :
4625 0 : if (CPLGetLastErrorNo() != 0)
4626 0 : return -1;
4627 :
4628 0 : return 0;
4629 : }
4630 :
4631 : /**********************************************************************
4632 : * TABEllipse::GetStyleString()
4633 : *
4634 : * Return style string for this feature.
4635 : *
4636 : * Style String is built only once during the first call to GetStyleString().
4637 : **********************************************************************/
4638 0 : const char *TABEllipse::GetStyleString()
4639 : {
4640 0 : if (m_pszStyleString == NULL)
4641 : {
4642 : // Since GetPen/BrushStyleString() use CPLSPrintf(), we need
4643 : // to use temporary buffers
4644 0 : char *pszPen = CPLStrdup(GetPenStyleString());
4645 0 : char *pszBrush = CPLStrdup(GetBrushStyleString());
4646 :
4647 0 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
4648 :
4649 0 : CPLFree(pszPen);
4650 0 : CPLFree(pszBrush);
4651 : }
4652 :
4653 0 : return m_pszStyleString;
4654 : }
4655 :
4656 :
4657 : /**********************************************************************
4658 : * TABEllipse::DumpMIF()
4659 : *
4660 : * Dump feature geometry in a format similar to .MIF REGIONs.
4661 : **********************************************************************/
4662 0 : void TABEllipse::DumpMIF(FILE *fpOut /*=NULL*/)
4663 : {
4664 : OGRGeometry *poGeom;
4665 0 : OGRPolygon *poPolygon = NULL;
4666 : int i, numPoints;
4667 :
4668 0 : if (fpOut == NULL)
4669 0 : fpOut = stdout;
4670 :
4671 : /*-----------------------------------------------------------------
4672 : * Output ELLIPSE parameters
4673 : *----------------------------------------------------------------*/
4674 : double dXMin, dYMin, dXMax, dYMax;
4675 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
4676 0 : fprintf(fpOut, "(ELLIPSE %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
4677 :
4678 : /*-----------------------------------------------------------------
4679 : * Fetch and validate geometry
4680 : *----------------------------------------------------------------*/
4681 0 : poGeom = GetGeometryRef();
4682 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
4683 : {
4684 : /*-------------------------------------------------------------
4685 : * Generate ellipse output as a region
4686 : * We could also output as an ELLIPSE in a real MIF generator
4687 : *------------------------------------------------------------*/
4688 : int iRing, numIntRings;
4689 0 : poPolygon = (OGRPolygon*)poGeom;
4690 0 : numIntRings = poPolygon->getNumInteriorRings();
4691 0 : fprintf(fpOut, "REGION %d\n", numIntRings+1);
4692 : // In this loop, iRing=-1 for the outer ring.
4693 0 : for(iRing=-1; iRing < numIntRings; iRing++)
4694 : {
4695 : OGRLinearRing *poRing;
4696 :
4697 0 : if (iRing == -1)
4698 0 : poRing = poPolygon->getExteriorRing();
4699 : else
4700 0 : poRing = poPolygon->getInteriorRing(iRing);
4701 :
4702 0 : if (poRing == NULL)
4703 : {
4704 : CPLError(CE_Failure, CPLE_AssertionFailed,
4705 0 : "TABEllipse: Object Geometry contains NULL rings!");
4706 0 : return;
4707 : }
4708 :
4709 0 : numPoints = poRing->getNumPoints();
4710 0 : fprintf(fpOut, " %d\n", numPoints);
4711 0 : for(i=0; i<numPoints; i++)
4712 0 : fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
4713 : }
4714 : }
4715 : else
4716 : {
4717 : CPLError(CE_Failure, CPLE_AssertionFailed,
4718 0 : "TABEllipse: Missing or Invalid Geometry!");
4719 0 : return;
4720 : }
4721 :
4722 : // Finish with PEN/BRUSH/etc. clauses
4723 0 : DumpPenDef();
4724 0 : DumpBrushDef();
4725 :
4726 0 : fflush(fpOut);
4727 : }
4728 :
4729 :
4730 : /*=====================================================================
4731 : * class TABArc
4732 : *====================================================================*/
4733 :
4734 : /**********************************************************************
4735 : * TABArc::TABArc()
4736 : *
4737 : * Constructor.
4738 : **********************************************************************/
4739 0 : TABArc::TABArc(OGRFeatureDefn *poDefnIn):
4740 0 : TABFeature(poDefnIn)
4741 : {
4742 0 : m_dStartAngle = m_dEndAngle = 0.0;
4743 0 : m_dCenterX = m_dCenterY = m_dXRadius = m_dYRadius = 0.0;
4744 :
4745 0 : }
4746 :
4747 : /**********************************************************************
4748 : * TABArc::~TABArc()
4749 : *
4750 : * Destructor.
4751 : **********************************************************************/
4752 0 : TABArc::~TABArc()
4753 : {
4754 0 : }
4755 :
4756 : /**********************************************************************
4757 : * TABArc::CloneTABFeature()
4758 : *
4759 : * Duplicate feature, including stuff specific to each TABFeature type.
4760 : *
4761 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
4762 : * then copies any members specific to its own type.
4763 : **********************************************************************/
4764 0 : TABFeature *TABArc::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
4765 : {
4766 : /*-----------------------------------------------------------------
4767 : * Alloc new feature and copy the base stuff
4768 : *----------------------------------------------------------------*/
4769 0 : TABArc *poNew = new TABArc(poNewDefn ? poNewDefn : GetDefnRef());
4770 :
4771 0 : CopyTABFeatureBase(poNew);
4772 :
4773 : /*-----------------------------------------------------------------
4774 : * And members specific to this class
4775 : *----------------------------------------------------------------*/
4776 : // ITABFeaturePen
4777 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
4778 :
4779 0 : poNew->SetStartAngle( GetStartAngle() );
4780 0 : poNew->SetEndAngle( GetEndAngle() );
4781 :
4782 0 : poNew->m_dCenterX = m_dCenterX;
4783 0 : poNew->m_dCenterY = m_dCenterY;
4784 0 : poNew->m_dXRadius = m_dXRadius;
4785 0 : poNew->m_dYRadius = m_dYRadius;
4786 :
4787 0 : return poNew;
4788 : }
4789 :
4790 : /**********************************************************************
4791 : * TABArc::ValidateMapInfoType()
4792 : *
4793 : * Check the feature's geometry part and return the corresponding
4794 : * mapinfo object type code. The m_nMapInfoType member will also
4795 : * be updated for further calls to GetMapInfoType();
4796 : *
4797 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
4798 : * is expected for this object class.
4799 : **********************************************************************/
4800 0 : int TABArc::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
4801 : {
4802 : OGRGeometry *poGeom;
4803 :
4804 : /*-----------------------------------------------------------------
4805 : * Fetch and validate geometry
4806 : *----------------------------------------------------------------*/
4807 0 : poGeom = GetGeometryRef();
4808 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) ||
4809 0 : (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4810 : {
4811 0 : m_nMapInfoType = TAB_GEOM_ARC;
4812 : }
4813 : else
4814 : {
4815 : CPLError(CE_Failure, CPLE_AssertionFailed,
4816 0 : "TABArc: Missing or Invalid Geometry!");
4817 0 : m_nMapInfoType = TAB_GEOM_NONE;
4818 : }
4819 :
4820 : /*-----------------------------------------------------------------
4821 : * Decide if coordinates should be compressed or not.
4822 : *----------------------------------------------------------------*/
4823 : // __TODO__ For now we always write uncompressed for this class...
4824 : // ValidateCoordType(poMapFile);
4825 0 : UpdateMBR(poMapFile);
4826 :
4827 0 : return m_nMapInfoType;
4828 : }
4829 :
4830 : /**********************************************************************
4831 : * TABArc::UpdateMBR()
4832 : *
4833 : * Update the feature MBR members using the geometry
4834 : *
4835 : * Returns 0 on success, or -1 if there is no geometry in object
4836 : **********************************************************************/
4837 0 : int TABArc::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
4838 : {
4839 : OGRGeometry *poGeom;
4840 0 : OGREnvelope sEnvelope;
4841 :
4842 0 : poGeom = GetGeometryRef();
4843 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) )
4844 : {
4845 : /*-------------------------------------------------------------
4846 : * POLYGON geometry:
4847 : * Note that we will simply use the ellipse's MBR and don't really
4848 : * read the polygon geometry... this should be OK unless the
4849 : * polygon geometry was not really an ellipse.
4850 : * In the case of a polygon geometry. the m_dCenterX/Y values MUST
4851 : * have been set by the caller.
4852 : *------------------------------------------------------------*/
4853 0 : poGeom->getEnvelope(&sEnvelope);
4854 : }
4855 0 : else if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4856 : {
4857 : /*-------------------------------------------------------------
4858 : * In the case of a POINT GEOMETRY, we will make sure the the
4859 : * feature's m_dCenterX/Y are in sync with the point's X,Y coords.
4860 : *
4861 : * In this case we have to reconstruct the arc inside a temporary
4862 : * geometry object in order to find its real MBR.
4863 : *------------------------------------------------------------*/
4864 0 : OGRPoint *poPoint = (OGRPoint *)poGeom;
4865 0 : m_dCenterX = poPoint->getX();
4866 0 : m_dCenterY = poPoint->getY();
4867 :
4868 0 : OGRLineString oTmpLine;
4869 0 : int numPts=0;
4870 0 : if (m_dEndAngle < m_dStartAngle)
4871 0 : numPts = (int) ABS( ((m_dEndAngle+360)-m_dStartAngle)/2 ) + 1;
4872 : else
4873 0 : numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2 ) + 1;
4874 0 : numPts = MAX(2, numPts);
4875 :
4876 : TABGenerateArc(&oTmpLine, numPts,
4877 : m_dCenterX, m_dCenterY,
4878 : m_dXRadius, m_dYRadius,
4879 0 : m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
4880 :
4881 0 : oTmpLine.getEnvelope(&sEnvelope);
4882 : }
4883 : else
4884 : {
4885 : CPLError(CE_Failure, CPLE_AssertionFailed,
4886 0 : "TABArc: Missing or Invalid Geometry!");
4887 0 : return -1;
4888 : }
4889 :
4890 : // Update the Arc's MBR
4891 0 : m_dXMin = sEnvelope.MinX;
4892 0 : m_dYMin = sEnvelope.MinY;
4893 0 : m_dXMax = sEnvelope.MaxX;
4894 0 : m_dYMax = sEnvelope.MaxY;
4895 :
4896 0 : if (poMapFile)
4897 : {
4898 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
4899 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
4900 : }
4901 :
4902 0 : return 0;
4903 : }
4904 :
4905 : /**********************************************************************
4906 : * TABArc::ReadGeometryFromMAPFile()
4907 : *
4908 : * Fill the geometry and representation (color, etc...) part of the
4909 : * feature from the contents of the .MAP object pointed to by poMAPFile.
4910 : *
4911 : * It is assumed that poMAPFile currently points to the beginning of
4912 : * a map object.
4913 : *
4914 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4915 : * been called.
4916 : **********************************************************************/
4917 0 : int TABArc::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
4918 : TABMAPObjHdr *poObjHdr,
4919 : GBool bCoordBlockDataOnly /*=FALSE*/,
4920 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4921 : {
4922 : double dXMin, dYMin, dXMax, dYMax;
4923 : OGRLineString *poLine;
4924 : int numPts;
4925 :
4926 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4927 0 : if (bCoordBlockDataOnly)
4928 0 : return 0;
4929 :
4930 : /*-----------------------------------------------------------------
4931 : * Fetch and validate geometry type
4932 : *----------------------------------------------------------------*/
4933 0 : m_nMapInfoType = poObjHdr->m_nType;
4934 :
4935 0 : if (m_nMapInfoType != TAB_GEOM_ARC &&
4936 : m_nMapInfoType != TAB_GEOM_ARC_C )
4937 : {
4938 : CPLError(CE_Failure, CPLE_AssertionFailed,
4939 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
4940 0 : m_nMapInfoType, m_nMapInfoType);
4941 0 : return -1;
4942 : }
4943 :
4944 :
4945 : /*-----------------------------------------------------------------
4946 : * Read object information
4947 : *----------------------------------------------------------------*/
4948 0 : TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
4949 :
4950 : /*-------------------------------------------------------------
4951 : * Start/End angles
4952 : * Since the angles are specified for integer coordinates, and
4953 : * that these coordinates can have the X axis reversed, we have to
4954 : * adjust the angle values for the change in the X axis
4955 : * direction.
4956 : *
4957 : * This should be necessary only when X axis is flipped.
4958 : * __TODO__ Why is order of start/end values reversed as well???
4959 : *------------------------------------------------------------*/
4960 :
4961 : /*-------------------------------------------------------------
4962 : * OK, Arc angles again!!!!!!!!!!!!
4963 : * After some tests in 1999-11, it appeared that the angle values
4964 : * ALWAYS had to be flipped (read order= end angle followed by
4965 : * start angle), no matter which quadrant the file is in.
4966 : * This does not make any sense, so I suspect that there is something
4967 : * that we are missing here!
4968 : *
4969 : * 2000-01-14.... Again!!! Based on some sample data files:
4970 : * File Ver Quadr ReflXAxis Read_Order Adjust_Angle
4971 : * test_symb.tab 300 2 1 end,start X=yes Y=no
4972 : * alltypes.tab: 300 1 0 start,end X=no Y=no
4973 : * arcs.tab: 300 2 0 end,start X=yes Y=no
4974 : *
4975 : * Until we prove it wrong, the rule would be:
4976 : * -> Quadrant 1 and 3, angles order = start, end
4977 : * -> Quadrant 2 and 4, angles order = end, start
4978 : * + Always adjust angles for x and y axis based on quadrant.
4979 : *
4980 : * This was confirmed using some more files in which the quadrant was
4981 : * manually changed, but whether these are valid results is
4982 : * discutable.
4983 : *
4984 : * The ReflectXAxis flag seems to have no effect here...
4985 : *------------------------------------------------------------*/
4986 :
4987 : /*-------------------------------------------------------------
4988 : * In version 100 .tab files (version 400 .map), it is possible
4989 : * to have a quadrant value of 0 and it should be treated the
4990 : * same way as quadrant 3
4991 : *------------------------------------------------------------*/
4992 0 : if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==1 ||
4993 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
4994 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
4995 : {
4996 : // Quadrants 1 and 3 ... read order = start, end
4997 0 : m_dStartAngle = poArcHdr->m_nStartAngle/10.0;
4998 0 : m_dEndAngle = poArcHdr->m_nEndAngle/10.0;
4999 : }
5000 : else
5001 : {
5002 : // Quadrants 2 and 4 ... read order = end, start
5003 0 : m_dStartAngle = poArcHdr->m_nEndAngle/10.0;
5004 0 : m_dEndAngle = poArcHdr->m_nStartAngle/10.0;
5005 : }
5006 :
5007 0 : if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==2 ||
5008 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
5009 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
5010 : {
5011 : // X axis direction is flipped... adjust angle
5012 : m_dStartAngle = (m_dStartAngle<=180.0) ? (180.0-m_dStartAngle):
5013 0 : (540.0-m_dStartAngle);
5014 : m_dEndAngle = (m_dEndAngle<=180.0) ? (180.0-m_dEndAngle):
5015 0 : (540.0-m_dEndAngle);
5016 : }
5017 :
5018 0 : if (poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
5019 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==4 ||
5020 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
5021 : {
5022 : // Y axis direction is flipped... this reverses angle direction
5023 : // Unfortunately we never found any file that contains this case,
5024 : // but this should be the behavior to expect!!!
5025 : //
5026 : // 2000-01-14: some files in which quadrant was set to 3 and 4
5027 : // manually seemed to confirm that this is the right thing to do.
5028 0 : m_dStartAngle = 360.0 - m_dStartAngle;
5029 0 : m_dEndAngle = 360.0 - m_dEndAngle;
5030 : }
5031 :
5032 : // An arc is defined by its defining ellipse's MBR:
5033 :
5034 : poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMinX,
5035 0 : poArcHdr->m_nArcEllipseMinY , dXMin, dYMin);
5036 : poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMaxX,
5037 0 : poArcHdr->m_nArcEllipseMaxY , dXMax, dYMax);
5038 :
5039 0 : m_dCenterX = (dXMin + dXMax) / 2.0;
5040 0 : m_dCenterY = (dYMin + dYMax) / 2.0;
5041 0 : m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
5042 0 : m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
5043 :
5044 : // Read the Arc's MBR and use that as this feature's MBR
5045 : poMapFile->Int2Coordsys(poArcHdr->m_nMinX, poArcHdr->m_nMinY,
5046 0 : dXMin, dYMin);
5047 : poMapFile->Int2Coordsys(poArcHdr->m_nMaxX, poArcHdr->m_nMaxY,
5048 0 : dXMax, dYMax);
5049 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
5050 :
5051 0 : m_nPenDefIndex = poArcHdr->m_nPenId; // Pen index
5052 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
5053 :
5054 :
5055 : /*-----------------------------------------------------------------
5056 : * Create and fill geometry object
5057 : * For the OGR geometry, we generate an arc with 2 degrees line
5058 : * segments.
5059 : *----------------------------------------------------------------*/
5060 0 : poLine = new OGRLineString;
5061 :
5062 0 : if (m_dEndAngle < m_dStartAngle)
5063 0 : numPts = (int) ABS( ((m_dEndAngle+360.0)-m_dStartAngle)/2.0 ) + 1;
5064 : else
5065 0 : numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2.0 ) + 1;
5066 0 : numPts = MAX(2, numPts);
5067 :
5068 : TABGenerateArc(poLine, numPts,
5069 : m_dCenterX, m_dCenterY,
5070 : m_dXRadius, m_dYRadius,
5071 0 : m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
5072 :
5073 0 : SetGeometryDirectly(poLine);
5074 :
5075 0 : return 0;
5076 : }
5077 :
5078 : /**********************************************************************
5079 : * TABArc::WriteGeometryToMAPFile()
5080 : *
5081 : * Write the geometry and representation (color, etc...) part of the
5082 : * feature to the .MAP object pointed to by poMAPFile.
5083 : *
5084 : * It is assumed that poMAPFile currently points to a valid map object.
5085 : *
5086 : * Returns 0 on success, -1 on error, in which case CPLError() will have
5087 : * been called.
5088 : **********************************************************************/
5089 0 : int TABArc::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
5090 : TABMAPObjHdr *poObjHdr,
5091 : GBool bCoordBlockDataOnly /*=FALSE*/,
5092 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
5093 : {
5094 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
5095 0 : if (bCoordBlockDataOnly)
5096 0 : return 0;
5097 :
5098 : /*-----------------------------------------------------------------
5099 : * We assume that ValidateMapInfoType() was called already and that
5100 : * the type in poObjHdr->m_nType is valid.
5101 : *----------------------------------------------------------------*/
5102 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
5103 :
5104 : /*-----------------------------------------------------------------
5105 : * Fetch and validate geometry
5106 : * In the case of ARCs, this is all done inside UpdateMBR()
5107 : *----------------------------------------------------------------*/
5108 0 : if (UpdateMBR(poMapFile) != 0)
5109 0 : return -1; /* Error already reported */
5110 :
5111 : /*-----------------------------------------------------------------
5112 : * Copy object information
5113 : *----------------------------------------------------------------*/
5114 0 : TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
5115 :
5116 : /*-------------------------------------------------------------
5117 : * Start/End angles
5118 : * Since we ALWAYS produce files in quadrant 1 then we can
5119 : * ignore the special angle conversion required by flipped axis.
5120 : *
5121 : * See the notes about Arc angles in TABArc::ReadGeometryFromMAPFile()
5122 : *------------------------------------------------------------*/
5123 0 : CPLAssert(poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant == 1);
5124 :
5125 0 : poArcHdr->m_nStartAngle = ROUND_INT(m_dStartAngle*10.0);
5126 0 : poArcHdr->m_nEndAngle = ROUND_INT(m_dEndAngle*10.0);
5127 :
5128 : // An arc is defined by its defining ellipse's MBR:
5129 : poMapFile->Coordsys2Int(m_dCenterX-m_dXRadius, m_dCenterY-m_dYRadius,
5130 : poArcHdr->m_nArcEllipseMinX,
5131 0 : poArcHdr->m_nArcEllipseMinY);
5132 : poMapFile->Coordsys2Int(m_dCenterX+m_dXRadius, m_dCenterY+m_dYRadius,
5133 : poArcHdr->m_nArcEllipseMaxX,
5134 0 : poArcHdr->m_nArcEllipseMaxY);
5135 :
5136 : // Pass the Arc's actual MBR (values were set in UpdateMBR())
5137 0 : poArcHdr->m_nMinX = m_nXMin;
5138 0 : poArcHdr->m_nMinY = m_nYMin;
5139 0 : poArcHdr->m_nMaxX = m_nXMax;
5140 0 : poArcHdr->m_nMaxY = m_nYMax;
5141 :
5142 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
5143 0 : poArcHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index
5144 :
5145 0 : if (CPLGetLastErrorNo() != 0)
5146 0 : return -1;
5147 :
5148 0 : return 0;
5149 : }
5150 :
5151 : /**********************************************************************
5152 : * TABArc::SetStart/EndAngle()
5153 : *
5154 : * Set the start/end angle values in degrees, making sure the values are
5155 : * always in the range [0..360]
5156 : **********************************************************************/
5157 0 : void TABArc::SetStartAngle(double dAngle)
5158 : {
5159 0 : while(dAngle < 0.0) dAngle += 360.0;
5160 0 : while(dAngle > 360.0) dAngle -= 360.0;
5161 :
5162 0 : m_dStartAngle = dAngle;
5163 0 : }
5164 :
5165 0 : void TABArc::SetEndAngle(double dAngle)
5166 : {
5167 0 : while(dAngle < 0.0) dAngle += 360.0;
5168 0 : while(dAngle > 360.0) dAngle -= 360.0;
5169 :
5170 0 : m_dEndAngle = dAngle;
5171 0 : }
5172 :
5173 :
5174 : /**********************************************************************
5175 : * TABArc::GetStyleString()
5176 : *
5177 : * Return style string for this feature.
5178 : *
5179 : * Style String is built only once during the first call to GetStyleString().
5180 : **********************************************************************/
5181 0 : const char *TABArc::GetStyleString()
5182 : {
5183 0 : if (m_pszStyleString == NULL)
5184 : {
5185 0 : m_pszStyleString = CPLStrdup(GetPenStyleString());
5186 : }
5187 :
5188 0 : return m_pszStyleString;
5189 : }
5190 :
5191 : /**********************************************************************
5192 : * TABArc::DumpMIF()
5193 : *
5194 : * Dump feature geometry in a format similar to .MIF REGIONs.
5195 : **********************************************************************/
5196 0 : void TABArc::DumpMIF(FILE *fpOut /*=NULL*/)
5197 : {
5198 : OGRGeometry *poGeom;
5199 0 : OGRLineString *poLine = NULL;
5200 : int i, numPoints;
5201 :
5202 0 : if (fpOut == NULL)
5203 0 : fpOut = stdout;
5204 :
5205 : /*-----------------------------------------------------------------
5206 : * Output ARC parameters
5207 : *----------------------------------------------------------------*/
5208 : fprintf(fpOut, "(ARC %.15g %.15g %.15g %.15g %d %d)\n",
5209 : m_dCenterX - m_dXRadius, m_dCenterY - m_dYRadius,
5210 : m_dCenterX + m_dXRadius, m_dCenterY + m_dYRadius,
5211 0 : (int)m_dStartAngle, (int)m_dEndAngle);
5212 :
5213 : /*-----------------------------------------------------------------
5214 : * Fetch and validate geometry
5215 : *----------------------------------------------------------------*/
5216 0 : poGeom = GetGeometryRef();
5217 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
5218 : {
5219 : /*-------------------------------------------------------------
5220 : * Generate arc output as a simple polyline
5221 : * We could also output as an ELLIPSE in a real MIF generator
5222 : *------------------------------------------------------------*/
5223 0 : poLine = (OGRLineString*)poGeom;
5224 0 : numPoints = poLine->getNumPoints();
5225 0 : fprintf(fpOut, "PLINE %d\n", numPoints);
5226 0 : for(i=0; i<numPoints; i++)
5227 0 : fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
5228 : }
5229 : else
5230 : {
5231 : CPLError(CE_Failure, CPLE_AssertionFailed,
5232 0 : "TABArc: Missing or Invalid Geometry!");
5233 0 : return;
5234 : }
5235 :
5236 : // Finish with PEN/BRUSH/etc. clauses
5237 0 : DumpPenDef();
5238 :
5239 0 : fflush(fpOut);
5240 : }
5241 :
5242 :
5243 :
5244 : /*=====================================================================
5245 : * class TABText
5246 : *====================================================================*/
5247 :
5248 : /**********************************************************************
5249 : * TABText::TABText()
5250 : *
5251 : * Constructor.
5252 : **********************************************************************/
5253 0 : TABText::TABText(OGRFeatureDefn *poDefnIn):
5254 0 : TABFeature(poDefnIn)
5255 : {
5256 0 : m_pszString = NULL;
5257 :
5258 0 : m_dAngle = m_dHeight = 0.0;
5259 0 : m_dfLineEndX = m_dfLineEndY = 0.0;
5260 0 : m_bLineEndSet = FALSE;
5261 :
5262 0 : m_rgbForeground = 0x000000;
5263 0 : m_rgbBackground = 0xffffff;
5264 0 : m_rgbOutline = 0xffffff;
5265 0 : m_rgbShadow = 0x808080;
5266 :
5267 0 : m_nTextAlignment = 0;
5268 0 : m_nFontStyle = 0;
5269 0 : m_dWidth = 0;
5270 0 : }
5271 :
5272 : /**********************************************************************
5273 : * TABText::~TABText()
5274 : *
5275 : * Destructor.
5276 : **********************************************************************/
5277 0 : TABText::~TABText()
5278 : {
5279 0 : CPLFree(m_pszString);
5280 0 : }
5281 :
5282 : /**********************************************************************
5283 : * TABText::CloneTABFeature()
5284 : *
5285 : * Duplicate feature, including stuff specific to each TABFeature type.
5286 : *
5287 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
5288 : * then copies any members specific to its own type.
5289 : **********************************************************************/
5290 0 : TABFeature *TABText::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
5291 : {
5292 : /*-----------------------------------------------------------------
5293 : * Alloc new feature and copy the base stuff
5294 : *----------------------------------------------------------------*/
5295 0 : TABText *poNew = new TABText(poNewDefn ? poNewDefn : GetDefnRef());
5296 :
5297 0 : CopyTABFeatureBase(poNew);
5298 :
5299 : /*-----------------------------------------------------------------
5300 : * And members specific to this class
5301 : *----------------------------------------------------------------*/
5302 : // ITABFeaturePen
5303 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
5304 :
5305 : // ITABFeatureFont
5306 0 : *(poNew->GetFontDefRef()) = *GetFontDefRef();
5307 :
5308 :
5309 0 : poNew->SetTextString( GetTextString() );
5310 0 : poNew->SetTextAngle( GetTextAngle() );
5311 0 : poNew->SetTextBoxHeight( GetTextBoxHeight() );
5312 0 : poNew->SetTextBoxWidth( GetTextBoxWidth() );
5313 0 : poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
5314 0 : poNew->SetFontBGColor( GetFontBGColor() );
5315 0 : poNew->SetFontFGColor( GetFontFGColor() );
5316 0 : poNew->SetFontOColor( GetFontOColor() );
5317 0 : poNew->SetFontSColor( GetFontSColor() );
5318 :
5319 0 : poNew->SetTextJustification( GetTextJustification() );
5320 0 : poNew->SetTextSpacing( GetTextSpacing() );
5321 : // Note: Text arrow/line coordinates are not transported... but
5322 : // we ignore them most of the time anyways.
5323 0 : poNew->SetTextLineType( TABTLNoLine );
5324 :
5325 0 : return poNew;
5326 : }
5327 :
5328 : /**********************************************************************
5329 : * TABText::ValidateMapInfoType()
5330 : *
5331 : * Check the feature's geometry part and return the corresponding
5332 : * mapinfo object type code. The m_nMapInfoType member will also
5333 : * be updated for further calls to GetMapInfoType();
5334 : *
5335 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
5336 : * is expected for this object class.
5337 : **********************************************************************/
5338 0 : int TABText::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
5339 : {
5340 : OGRGeometry *poGeom;
5341 :
5342 : /*-----------------------------------------------------------------
5343 : * Fetch and validate geometry
5344 : *----------------------------------------------------------------*/
5345 0 : poGeom = GetGeometryRef();
5346 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
5347 : {
5348 0 : m_nMapInfoType = TAB_GEOM_TEXT;
5349 : }
5350 : else
5351 : {
5352 : CPLError(CE_Failure, CPLE_AssertionFailed,
5353 0 : "TABText: Missing or Invalid Geometry!");
5354 0 : m_nMapInfoType = TAB_GEOM_NONE;
5355 : }
5356 :
5357 : /*-----------------------------------------------------------------
5358 : * Decide if coordinates should be compressed or not.
5359 : *----------------------------------------------------------------*/
5360 : // __TODO__ For now we always write uncompressed for this class...
5361 : // ValidateCoordType(poMapFile);
5362 0 : UpdateMBR(poMapFile);
5363 :
5364 0 : return m_nMapInfoType;
5365 : }
5366 :
5367 : /**********************************************************************
5368 : * TABText::ReadGeometryFromMAPFile()
5369 : *
5370 : * Fill the geometry and representation (color, etc...) part of the
5371 : * feature from the contents of the .MAP object pointed to by poMAPFile.
5372 : *
5373 : * It is assumed that poMAPFile currently points to the beginning of
5374 : * a map object.
5375 : *
5376 : * Returns 0 on success, -1 on error, in which case CPLError() will have
5377 : * been called.
5378 : **********************************************************************/
5379 0 : int TABText::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
5380 : TABMAPObjHdr *poObjHdr,
5381 : GBool bCoordBlockDataOnly /*=FALSE*/,
5382 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
5383 : {
5384 : double dXMin, dYMin, dXMax, dYMax;
5385 : OGRGeometry *poGeometry;
5386 :
5387 : /*-----------------------------------------------------------------
5388 : * Fetch and validate geometry type
5389 : *----------------------------------------------------------------*/
5390 0 : m_nMapInfoType = poObjHdr->m_nType;
5391 :
5392 0 : if (m_nMapInfoType != TAB_GEOM_TEXT &&
5393 : m_nMapInfoType != TAB_GEOM_TEXT_C )
5394 : {
5395 : CPLError(CE_Failure, CPLE_AssertionFailed,
5396 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
5397 0 : m_nMapInfoType, m_nMapInfoType);
5398 0 : return -1;
5399 : }
5400 :
5401 : /*=============================================================
5402 : * TEXT
5403 : *============================================================*/
5404 : int nStringLen;
5405 : GInt32 nCoordBlockPtr;
5406 : double dJunk;
5407 :
5408 : /*-----------------------------------------------------------------
5409 : * Read object information
5410 : *----------------------------------------------------------------*/
5411 0 : TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
5412 :
5413 0 : nCoordBlockPtr = poTextHdr->m_nCoordBlockPtr; // String position
5414 0 : nStringLen = poTextHdr->m_nCoordDataSize; // String length
5415 0 : m_nTextAlignment = poTextHdr->m_nTextAlignment; // just./spacing/arrow
5416 :
5417 : /*-------------------------------------------------------------
5418 : * Text Angle, in thenths of degree.
5419 : * Contrary to arc start/end angles, no conversion based on
5420 : * origin quadrant is required here
5421 : *------------------------------------------------------------*/
5422 0 : m_dAngle = poTextHdr->m_nAngle/10.0;
5423 :
5424 0 : m_nFontStyle = poTextHdr->m_nFontStyle; // Font style
5425 :
5426 : m_rgbForeground = (poTextHdr->m_nFGColorR*256*256 +
5427 : poTextHdr->m_nFGColorG*256 +
5428 0 : poTextHdr->m_nFGColorB);
5429 : m_rgbBackground = (poTextHdr->m_nBGColorR*256*256 +
5430 : poTextHdr->m_nBGColorG*256 +
5431 0 : poTextHdr->m_nBGColorB);
5432 0 : m_rgbOutline = m_rgbBackground;
5433 : // In MapInfo, the shadow color is always gray (128,128,128)
5434 0 : m_rgbShadow = 0x808080;
5435 :
5436 : // arrow endpoint
5437 : poMapFile->Int2Coordsys(poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY,
5438 0 : m_dfLineEndX, m_dfLineEndY);
5439 0 : m_bLineEndSet = TRUE;
5440 :
5441 : // Text Height
5442 0 : poMapFile->Int2CoordsysDist(0, poTextHdr->m_nHeight, dJunk, m_dHeight);
5443 :
5444 0 : if (!bCoordBlockDataOnly)
5445 : {
5446 0 : m_nFontDefIndex = poTextHdr->m_nFontId; // Font name index
5447 0 : poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
5448 : }
5449 :
5450 : // MBR after rotation
5451 : poMapFile->Int2Coordsys(poTextHdr->m_nMinX, poTextHdr->m_nMinY,
5452 0 : dXMin, dYMin);
5453 : poMapFile->Int2Coordsys(poTextHdr->m_nMaxX, poTextHdr->m_nMaxY,
5454 0 : dXMax, dYMax);
5455 :
5456 0 : if (!bCoordBlockDataOnly)
5457 : {
5458 0 : m_nPenDefIndex = poTextHdr->m_nPenId; // Pen index for line
5459 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
5460 : }
5461 :
5462 : /*-------------------------------------------------------------
5463 : * Read text string from the coord. block
5464 : * Note that the string may contain binary '\n' and '\\' chars
5465 : * that we keep to an unescaped form internally. This is to
5466 : * be like OGR drivers. See bug 1107 for details.
5467 : *------------------------------------------------------------*/
5468 0 : char *pszTmpString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
5469 :
5470 0 : if (nStringLen > 0)
5471 : {
5472 : TABMAPCoordBlock *poCoordBlock;
5473 0 : CPLAssert(nCoordBlockPtr > 0);
5474 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
5475 0 : poCoordBlock = *ppoCoordBlock;
5476 : else
5477 0 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
5478 0 : if (poCoordBlock == NULL ||
5479 0 : poCoordBlock->ReadBytes(nStringLen,(GByte*)pszTmpString) != 0)
5480 : {
5481 : CPLError(CE_Failure, CPLE_FileIO,
5482 : "Failed reading text string at offset %d",
5483 0 : nCoordBlockPtr);
5484 0 : CPLFree(pszTmpString);
5485 0 : return -1;
5486 : }
5487 :
5488 : /* Return a ref to coord block so that caller can continue reading
5489 : * after the end of this object (used by index splitting)
5490 : */
5491 0 : if (ppoCoordBlock)
5492 0 : *ppoCoordBlock = poCoordBlock;
5493 : }
5494 :
5495 0 : pszTmpString[nStringLen] = '\0';
5496 :
5497 0 : CPLFree(m_pszString);
5498 0 : m_pszString = pszTmpString; // This string was Escaped before 20050714
5499 :
5500 :
5501 : /* Set/retrieve the MBR to make sure Mins are smaller than Maxs
5502 : */
5503 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
5504 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
5505 :
5506 : /* Copy int MBR to feature class members */
5507 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
5508 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
5509 :
5510 : /*-----------------------------------------------------------------
5511 : * Create an OGRPoint Geometry...
5512 : * The point X,Y values will be the coords of the lower-left corner before
5513 : * rotation is applied. (Note that the rotation in MapInfo is done around
5514 : * the upper-left corner)
5515 : * We need to calculate the true lower left corner of the text based
5516 : * on the MBR after rotation, the text height and the rotation angle.
5517 : *----------------------------------------------------------------*/
5518 : double dCos, dSin, dX, dY;
5519 0 : dSin = sin(m_dAngle*PI/180.0);
5520 0 : dCos = cos(m_dAngle*PI/180.0);
5521 0 : if (dSin > 0.0 && dCos > 0.0)
5522 : {
5523 0 : dX = dXMin + m_dHeight * dSin;
5524 0 : dY = dYMin;
5525 : }
5526 0 : else if (dSin > 0.0 && dCos < 0.0)
5527 : {
5528 0 : dX = dXMax;
5529 0 : dY = dYMin - m_dHeight * dCos;
5530 : }
5531 0 : else if (dSin < 0.0 && dCos < 0.0)
5532 : {
5533 0 : dX = dXMax + m_dHeight * dSin;
5534 0 : dY = dYMax;
5535 : }
5536 : else // dSin < 0 && dCos > 0
5537 : {
5538 0 : dX = dXMin;
5539 0 : dY = dYMax - m_dHeight * dCos;
5540 : }
5541 :
5542 0 : poGeometry = new OGRPoint(dX, dY);
5543 :
5544 0 : SetGeometryDirectly(poGeometry);
5545 :
5546 : /*-----------------------------------------------------------------
5547 : * Compute Text Width: the width of the Text MBR before rotation
5548 : * in ground units... unfortunately this value is not stored in the
5549 : * file, so we have to compute it with the MBR after rotation and
5550 : * the height of the MBR before rotation:
5551 : * With W = Width of MBR before rotation
5552 : * H = Height of MBR before rotation
5553 : * dX = Width of MBR after rotation
5554 : * dY = Height of MBR after rotation
5555 : * teta = rotation angle
5556 : *
5557 : * For [-PI/4..teta..+PI/4] or [3*PI/4..teta..5*PI/4], we'll use:
5558 : * W = H * (dX - H * sin(teta)) / (H * cos(teta))
5559 : *
5560 : * and for other teta values, use:
5561 : * W = H * (dY - H * cos(teta)) / (H * sin(teta))
5562 : *----------------------------------------------------------------*/
5563 0 : dSin = ABS(dSin);
5564 0 : dCos = ABS(dCos);
5565 0 : if (m_dHeight == 0.0)
5566 0 : m_dWidth = 0.0;
5567 0 : else if ( dCos > dSin )
5568 : m_dWidth = m_dHeight * ((dXMax-dXMin) - m_dHeight*dSin) /
5569 0 : (m_dHeight*dCos);
5570 : else
5571 : m_dWidth = m_dHeight * ((dYMax-dYMin) - m_dHeight*dCos) /
5572 0 : (m_dHeight*dSin);
5573 0 : m_dWidth = ABS(m_dWidth);
5574 :
5575 0 : return 0;
5576 : }
5577 :
5578 : /**********************************************************************
5579 : * TABText::WriteGeometryToMAPFile()
5580 : *
5581 : * Write the geometry and representation (color, etc...) part of the
5582 : * feature to the .MAP object pointed to by poMAPFile.
5583 : *
5584 : * It is assumed that poMAPFile currently points to a valid map object.
5585 : *
5586 : * Returns 0 on success, -1 on error, in which case CPLError() will have
5587 : * been called.
5588 : **********************************************************************/
5589 0 : int TABText::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
5590 : TABMAPObjHdr *poObjHdr,
5591 : GBool bCoordBlockDataOnly /*=FALSE*/,
5592 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
5593 : {
5594 : GInt32 nX, nY, nXMin, nYMin, nXMax, nYMax;
5595 : OGRGeometry *poGeom;
5596 : OGRPoint *poPoint;
5597 : GInt32 nCoordBlockPtr;
5598 : TABMAPCoordBlock *poCoordBlock;
5599 : int nStringLen;
5600 :
5601 : /*-----------------------------------------------------------------
5602 : * We assume that ValidateMapInfoType() was called already and that
5603 : * the type in poObjHdr->m_nType is valid.
5604 : *----------------------------------------------------------------*/
5605 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
5606 :
5607 : /*-----------------------------------------------------------------
5608 : * Fetch and validate geometry
5609 : *----------------------------------------------------------------*/
5610 0 : poGeom = GetGeometryRef();
5611 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
5612 0 : poPoint = (OGRPoint*)poGeom;
5613 : else
5614 : {
5615 : CPLError(CE_Failure, CPLE_AssertionFailed,
5616 0 : "TABText: Missing or Invalid Geometry!");
5617 0 : return -1;
5618 : }
5619 :
5620 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
5621 :
5622 : /*-----------------------------------------------------------------
5623 : * Write string to a coord block first...
5624 : * Note that the string may contain unescaped '\n' and '\\'
5625 : * that we have to keep like that for the MAP file.
5626 : * See MapTools bug 1107 for more details.
5627 : *----------------------------------------------------------------*/
5628 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
5629 0 : poCoordBlock = *ppoCoordBlock;
5630 : else
5631 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
5632 0 : poCoordBlock->StartNewFeature();
5633 0 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
5634 :
5635 : // This string was escaped before 20050714
5636 0 : char *pszTmpString = m_pszString;
5637 :
5638 0 : nStringLen = strlen(pszTmpString);
5639 :
5640 0 : if (nStringLen > 0)
5641 : {
5642 0 : poCoordBlock->WriteBytes(nStringLen, (GByte *)pszTmpString);
5643 : }
5644 : else
5645 : {
5646 0 : nCoordBlockPtr = 0;
5647 : }
5648 :
5649 0 : pszTmpString = NULL;
5650 :
5651 : /*-----------------------------------------------------------------
5652 : * Copy object information
5653 : *----------------------------------------------------------------*/
5654 0 : TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
5655 :
5656 0 : poTextHdr->m_nCoordBlockPtr = nCoordBlockPtr; // String position
5657 0 : poTextHdr->m_nCoordDataSize = nStringLen; // String length
5658 0 : poTextHdr->m_nTextAlignment = m_nTextAlignment; // just./spacing/arrow
5659 :
5660 : /*-----------------------------------------------------------------
5661 : * Text Angle, (written in thenths of degrees)
5662 : * Contrary to arc start/end angles, no conversion based on
5663 : * origin quadrant is required here
5664 : *----------------------------------------------------------------*/
5665 0 : poTextHdr->m_nAngle = ROUND_INT(m_dAngle*10.0);
5666 :
5667 0 : poTextHdr->m_nFontStyle = m_nFontStyle; // Font style/effect
5668 :
5669 0 : poTextHdr->m_nFGColorR = (GByte)COLOR_R(m_rgbForeground);
5670 0 : poTextHdr->m_nFGColorG = (GByte)COLOR_G(m_rgbForeground);
5671 0 : poTextHdr->m_nFGColorB = (GByte)COLOR_B(m_rgbForeground);
5672 :
5673 0 : poTextHdr->m_nBGColorR = (GByte)COLOR_R(m_rgbBackground);
5674 0 : poTextHdr->m_nBGColorG = (GByte)COLOR_G(m_rgbBackground);
5675 0 : poTextHdr->m_nBGColorB = (GByte)COLOR_B(m_rgbBackground);
5676 :
5677 : /*-----------------------------------------------------------------
5678 : * The OGRPoint's X,Y values were the coords of the lower-left corner
5679 : * before rotation was applied. (Note that the rotation in MapInfo is
5680 : * done around the upper-left corner)
5681 : * The Feature's MBR is the MBR of the text after rotation... that's
5682 : * what MapInfo uses to define the text location.
5683 : *----------------------------------------------------------------*/
5684 : double dXMin, dYMin, dXMax, dYMax;
5685 : // Make sure Feature MBR is in sync with other params
5686 :
5687 0 : UpdateMBR();
5688 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
5689 :
5690 0 : poMapFile->Coordsys2Int(dXMin, dYMin, nXMin, nYMin);
5691 0 : poMapFile->Coordsys2Int(dXMax, dYMax, nXMax, nYMax);
5692 :
5693 : // Label line end point
5694 : double dX, dY;
5695 0 : GetTextLineEndPoint(dX, dY); // Make sure a default line end point is set
5696 : poMapFile->Coordsys2Int(m_dfLineEndX, m_dfLineEndY,
5697 0 : poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY);
5698 :
5699 : // Text Height
5700 0 : poMapFile->Coordsys2IntDist(0.0, m_dHeight, nX, nY);
5701 0 : poTextHdr->m_nHeight = nY;
5702 :
5703 0 : if (!bCoordBlockDataOnly)
5704 : {
5705 : // Font name
5706 0 : m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
5707 0 : poTextHdr->m_nFontId = (GByte)m_nFontDefIndex; // Font name index
5708 : }
5709 :
5710 : // MBR after rotation
5711 0 : poTextHdr->SetMBR(nXMin, nYMin, nXMax, nYMax);
5712 :
5713 0 : if (!bCoordBlockDataOnly)
5714 : {
5715 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
5716 0 : poTextHdr->m_nPenId = (GByte)m_nPenDefIndex; // Pen index for line/arrow
5717 : }
5718 :
5719 0 : if (CPLGetLastErrorNo() != 0)
5720 0 : return -1;
5721 :
5722 : /* Return a ref to coord block so that caller can continue writing
5723 : * after the end of this object (used by index splitting)
5724 : */
5725 0 : if (ppoCoordBlock)
5726 0 : *ppoCoordBlock = poCoordBlock;
5727 :
5728 0 : return 0;
5729 : }
5730 :
5731 :
5732 : /**********************************************************************
5733 : * TABText::GetTextString()
5734 : *
5735 : * Return ref to text string value.
5736 : *
5737 : * Returned string is a reference to the internal string buffer and should
5738 : * not be modified or freed by the caller.
5739 : **********************************************************************/
5740 0 : const char *TABText::GetTextString()
5741 : {
5742 0 : if (m_pszString == NULL)
5743 0 : return "";
5744 :
5745 0 : return m_pszString;
5746 : }
5747 :
5748 : /**********************************************************************
5749 : * TABText::SetTextString()
5750 : *
5751 : * Set new text string value.
5752 : *
5753 : * Note: The text string may contain "\n" chars or "\\" chars
5754 : * and we expect to receive them in a 2 chars escaped form as
5755 : * described in the MIF format specs.
5756 : **********************************************************************/
5757 0 : void TABText::SetTextString(const char *pszNewStr)
5758 : {
5759 0 : CPLFree(m_pszString);
5760 0 : m_pszString = CPLStrdup(pszNewStr);
5761 0 : }
5762 :
5763 : /**********************************************************************
5764 : * TABText::GetTextAngle()
5765 : *
5766 : * Return text angle in degrees.
5767 : **********************************************************************/
5768 0 : double TABText::GetTextAngle()
5769 : {
5770 0 : return m_dAngle;
5771 : }
5772 :
5773 0 : void TABText::SetTextAngle(double dAngle)
5774 : {
5775 : // Make sure angle is in the range [0..360]
5776 0 : while(dAngle < 0.0) dAngle += 360.0;
5777 0 : while(dAngle > 360.0) dAngle -= 360.0;
5778 0 : m_dAngle = dAngle;
5779 0 : UpdateMBR();
5780 0 : }
5781 :
5782 : /**********************************************************************
5783 : * TABText::GetTextBoxHeight()
5784 : *
5785 : * Return text height in Y axis coord. units of the text box before rotation.
5786 : **********************************************************************/
5787 0 : double TABText::GetTextBoxHeight()
5788 : {
5789 0 : return m_dHeight;
5790 : }
5791 :
5792 0 : void TABText::SetTextBoxHeight(double dHeight)
5793 : {
5794 0 : m_dHeight = dHeight;
5795 0 : UpdateMBR();
5796 0 : }
5797 :
5798 : /**********************************************************************
5799 : * TABText::GetTextBoxWidth()
5800 : *
5801 : * Return text width in X axis coord. units. of the text box before rotation.
5802 : *
5803 : * If value has not been set, then we force a default value that assumes
5804 : * that one char's box width is 60% of its height... and we ignore
5805 : * the multiline case. This should not matter when the user PROPERLY sets
5806 : * the value.
5807 : **********************************************************************/
5808 0 : double TABText::GetTextBoxWidth()
5809 : {
5810 0 : if (m_dWidth == 0.0 && m_pszString)
5811 : {
5812 0 : m_dWidth = 0.6 * m_dHeight * strlen(m_pszString);
5813 : }
5814 0 : return m_dWidth;
5815 : }
5816 :
5817 0 : void TABText::SetTextBoxWidth(double dWidth)
5818 : {
5819 0 : m_dWidth = dWidth;
5820 0 : UpdateMBR();
5821 0 : }
5822 :
5823 : /**********************************************************************
5824 : * TABText::GetTextLineEndPoint()
5825 : *
5826 : * Return X,Y coordinates of the text label line end point.
5827 : * Default is the center of the text MBR.
5828 : **********************************************************************/
5829 0 : void TABText::GetTextLineEndPoint(double &dX, double &dY)
5830 : {
5831 0 : if (!m_bLineEndSet)
5832 : {
5833 : // Set default location at center of text MBR
5834 : double dXMin, dYMin, dXMax, dYMax;
5835 0 : UpdateMBR();
5836 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
5837 0 : m_dfLineEndX = (dXMin + dXMax) /2.0;
5838 0 : m_dfLineEndY = (dYMin + dYMax) /2.0;
5839 0 : m_bLineEndSet = TRUE;
5840 : }
5841 :
5842 : // Return values
5843 0 : dX = m_dfLineEndX;
5844 0 : dY = m_dfLineEndY;
5845 0 : }
5846 :
5847 0 : void TABText::SetTextLineEndPoint(double dX, double dY)
5848 : {
5849 0 : m_dfLineEndX = dX;
5850 0 : m_dfLineEndY = dY;
5851 0 : m_bLineEndSet = TRUE;
5852 0 : }
5853 :
5854 : /**********************************************************************
5855 : * TABText::UpdateMBR()
5856 : *
5857 : * Update the feature MBR using the text origin (OGRPoint geometry), the
5858 : * rotation angle, and the Width/height before rotation.
5859 : *
5860 : * This function cannot perform properly unless all the above have been set.
5861 : *
5862 : * Returns 0 on success, or -1 if there is no geometry in object
5863 : **********************************************************************/
5864 0 : int TABText::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
5865 : {
5866 : OGRGeometry *poGeom;
5867 0 : OGRPoint *poPoint=NULL;
5868 :
5869 0 : poGeom = GetGeometryRef();
5870 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
5871 : {
5872 : double dSin, dCos, dX0, dY0, dX1, dY1;
5873 : double dX[4], dY[4];
5874 0 : poPoint = (OGRPoint *)poGeom;
5875 :
5876 0 : dX0 = poPoint->getX();
5877 0 : dY0 = poPoint->getY();
5878 :
5879 0 : dSin = sin(m_dAngle*PI/180.0);
5880 0 : dCos = cos(m_dAngle*PI/180.0);
5881 :
5882 0 : GetTextBoxWidth(); // Force default width value if necessary.
5883 :
5884 0 : dX[0] = dX0;
5885 0 : dY[0] = dY0;
5886 0 : dX[1] = dX0 + m_dWidth;
5887 0 : dY[1] = dY0;
5888 0 : dX[2] = dX0 + m_dWidth;
5889 0 : dY[2] = dY0 + m_dHeight;
5890 0 : dX[3] = dX0;
5891 0 : dY[3] = dY0 + m_dHeight;
5892 :
5893 0 : SetMBR(dX0, dY0, dX0, dY0);
5894 0 : for(int i=0; i<4; i++)
5895 : {
5896 : // Rotate one of the box corners
5897 0 : dX1 = dX0 + (dX[i]-dX0)*dCos - (dY[i]-dY0)*dSin;
5898 0 : dY1 = dY0 + (dX[i]-dX0)*dSin + (dY[i]-dY0)*dCos;
5899 :
5900 : // And update feature MBR with rotated coordinate
5901 0 : if (dX1 < m_dXMin) m_dXMin = dX1;
5902 0 : if (dX1 > m_dXMax) m_dXMax = dX1;
5903 0 : if (dY1 < m_dYMin) m_dYMin = dY1;
5904 0 : if (dY1 > m_dYMax) m_dYMax = dY1;
5905 : }
5906 :
5907 0 : if (poMapFile)
5908 : {
5909 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
5910 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
5911 : }
5912 :
5913 0 : return 0;
5914 : }
5915 :
5916 0 : return -1;
5917 : }
5918 :
5919 : /**********************************************************************
5920 : * TABText::GetFontBGColor()
5921 : *
5922 : * Return background color.
5923 : **********************************************************************/
5924 0 : GInt32 TABText::GetFontBGColor()
5925 : {
5926 0 : return m_rgbBackground;
5927 : }
5928 :
5929 0 : void TABText::SetFontBGColor(GInt32 rgbColor)
5930 : {
5931 0 : m_rgbBackground = rgbColor;
5932 0 : }
5933 :
5934 : /**********************************************************************
5935 : * TABText::GetFontOColor()
5936 : *
5937 : * Return outline color.
5938 : **********************************************************************/
5939 0 : GInt32 TABText::GetFontOColor()
5940 : {
5941 0 : return m_rgbOutline;
5942 : }
5943 :
5944 0 : void TABText::SetFontOColor(GInt32 rgbColor)
5945 : {
5946 0 : m_rgbOutline = rgbColor;
5947 0 : }
5948 :
5949 : /**********************************************************************
5950 : * TABText::GetFontSColor()
5951 : *
5952 : * Return shadow color.
5953 : **********************************************************************/
5954 0 : GInt32 TABText::GetFontSColor()
5955 : {
5956 0 : return m_rgbShadow;
5957 : }
5958 :
5959 0 : void TABText::SetFontSColor(GInt32 rgbColor)
5960 : {
5961 0 : m_rgbShadow = rgbColor;
5962 0 : }
5963 :
5964 : /**********************************************************************
5965 : * TABText::GetFontFGColor()
5966 : *
5967 : * Return foreground color.
5968 : **********************************************************************/
5969 0 : GInt32 TABText::GetFontFGColor()
5970 : {
5971 0 : return m_rgbForeground;
5972 : }
5973 :
5974 0 : void TABText::SetFontFGColor(GInt32 rgbColor)
5975 : {
5976 0 : m_rgbForeground = rgbColor;
5977 0 : }
5978 :
5979 : /**********************************************************************
5980 : * TABText::GetTextJustification()
5981 : *
5982 : * Return text justification. Default is TABTJLeft
5983 : **********************************************************************/
5984 0 : TABTextJust TABText::GetTextJustification()
5985 : {
5986 0 : TABTextJust eJust = TABTJLeft;
5987 :
5988 0 : if (m_nTextAlignment & 0x0200)
5989 0 : eJust = TABTJCenter;
5990 0 : else if (m_nTextAlignment & 0x0400)
5991 0 : eJust = TABTJRight;
5992 :
5993 0 : return eJust;
5994 : }
5995 :
5996 0 : void TABText::SetTextJustification(TABTextJust eJustification)
5997 : {
5998 : // Flush current value... default is TABTJLeft
5999 0 : m_nTextAlignment &= ~ 0x0600;
6000 : // ... and set new one.
6001 0 : if (eJustification == TABTJCenter)
6002 0 : m_nTextAlignment |= 0x0200;
6003 0 : else if (eJustification == TABTJRight)
6004 0 : m_nTextAlignment |= 0x0400;
6005 0 : }
6006 :
6007 : /**********************************************************************
6008 : * TABText::GetTextSpacing()
6009 : *
6010 : * Return text vertical spacing factor. Default is TABTSSingle
6011 : **********************************************************************/
6012 0 : TABTextSpacing TABText::GetTextSpacing()
6013 : {
6014 0 : TABTextSpacing eSpacing = TABTSSingle;
6015 :
6016 0 : if (m_nTextAlignment & 0x0800)
6017 0 : eSpacing = TABTS1_5;
6018 0 : else if (m_nTextAlignment & 0x1000)
6019 0 : eSpacing = TABTSDouble;
6020 :
6021 0 : return eSpacing;
6022 : }
6023 :
6024 0 : void TABText::SetTextSpacing(TABTextSpacing eSpacing)
6025 : {
6026 : // Flush current value... default is TABTSSingle
6027 0 : m_nTextAlignment &= ~ 0x1800;
6028 : // ... and set new one.
6029 0 : if (eSpacing == TABTS1_5)
6030 0 : m_nTextAlignment |= 0x0800;
6031 0 : else if (eSpacing == TABTSDouble)
6032 0 : m_nTextAlignment |= 0x1000;
6033 0 : }
6034 :
6035 : /**********************************************************************
6036 : * TABText::GetTextLineType()
6037 : *
6038 : * Return text line (arrow) type. Default is TABTLNoLine
6039 : **********************************************************************/
6040 0 : TABTextLineType TABText::GetTextLineType()
6041 : {
6042 0 : TABTextLineType eLine = TABTLNoLine;
6043 :
6044 0 : if (m_nTextAlignment & 0x2000)
6045 0 : eLine = TABTLSimple;
6046 0 : else if (m_nTextAlignment & 0x4000)
6047 0 : eLine = TABTLArrow;
6048 :
6049 0 : return eLine;
6050 : }
6051 :
6052 0 : void TABText::SetTextLineType(TABTextLineType eLineType)
6053 : {
6054 : // Flush current value... default is TABTLNoLine
6055 0 : m_nTextAlignment &= ~ 0x6000;
6056 : // ... and set new one.
6057 0 : if (eLineType == TABTLSimple)
6058 0 : m_nTextAlignment |= 0x2000;
6059 0 : else if (eLineType == TABTLArrow)
6060 0 : m_nTextAlignment |= 0x4000;
6061 0 : }
6062 :
6063 : /**********************************************************************
6064 : * TABText::QueryFontStyle()
6065 : *
6066 : * Return TRUE if the specified font style attribute is turned ON,
6067 : * or FALSE otherwise. See enum TABFontStyle for the list of styles
6068 : * that can be queried on.
6069 : **********************************************************************/
6070 0 : GBool TABText::QueryFontStyle(TABFontStyle eStyleToQuery)
6071 : {
6072 0 : return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
6073 : }
6074 :
6075 0 : void TABText::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
6076 : {
6077 0 : if (bStyleOn)
6078 0 : m_nFontStyle |= (int)eStyleToToggle;
6079 : else
6080 0 : m_nFontStyle &= ~ (int)eStyleToToggle;
6081 0 : }
6082 :
6083 :
6084 : /**********************************************************************
6085 : * TABText::GetFontStyleMIFValue()
6086 : *
6087 : * Return the Font Style value for this object using the style values
6088 : * that are used in a MIF FONT() clause. See MIF specs (appendix A).
6089 : *
6090 : * The reason why we have to differentiate between the TAB and the MIF font
6091 : * style values is that in TAB, TABFSBox is included in the style value
6092 : * as code 0x100, but in MIF it is not included, instead it is implied by
6093 : * the presence of the BG color in the FONT() clause (the BG color is
6094 : * present only when TABFSBox or TABFSHalo is set).
6095 : * This also has the effect of shifting all the other style values > 0x100
6096 : * by 1 byte.
6097 : **********************************************************************/
6098 0 : int TABText::GetFontStyleMIFValue()
6099 : {
6100 : // The conversion is simply to remove bit 0x100 from the value and shift
6101 : // down all values past this bit.
6102 0 : return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
6103 : }
6104 :
6105 0 : void TABText:: SetFontStyleMIFValue(int nStyle, GBool bBGColorSet)
6106 : {
6107 0 : m_nFontStyle = (GInt16)((nStyle & 0xff) + (nStyle & 0x7f00)*2);
6108 : // When BG color is set, then either BOX or HALO should be set.
6109 0 : if (bBGColorSet && !QueryFontStyle(TABFSHalo))
6110 0 : ToggleFontStyle(TABFSBox, TRUE);
6111 0 : }
6112 :
6113 0 : int TABText::IsFontBGColorUsed()
6114 : {
6115 : // Font BG color is used only when BOX is set.
6116 0 : return (QueryFontStyle(TABFSBox));
6117 : }
6118 :
6119 0 : int TABText::IsFontOColorUsed()
6120 : {
6121 : // Font outline color is used only when HALO is set.
6122 0 : return (QueryFontStyle(TABFSHalo));
6123 : }
6124 :
6125 0 : int TABText::IsFontSColorUsed()
6126 : {
6127 : // Font shadow color is used only when Shadow is set.
6128 0 : return (QueryFontStyle(TABFSShadow));
6129 : }
6130 :
6131 0 : int TABText::IsFontBold()
6132 : {
6133 : // Font bold is used only when Bold is set.
6134 0 : return (QueryFontStyle(TABFSBold));
6135 : }
6136 :
6137 0 : int TABText::IsFontItalic()
6138 : {
6139 : // Font italic is used only when Italic is set.
6140 0 : return (QueryFontStyle(TABFSItalic));
6141 : }
6142 :
6143 0 : int TABText::IsFontUnderline()
6144 : {
6145 : // Font underline is used only when Underline is set.
6146 0 : return (QueryFontStyle(TABFSUnderline));
6147 : }
6148 :
6149 : /**********************************************************************
6150 : * TABText::GetLabelStyleString()
6151 : *
6152 : * This is not the correct location, it should be in ITABFeatureFont,
6153 : * but it's really more easy to put it here. This fct return a complete
6154 : * string for the representation with the string to display
6155 : **********************************************************************/
6156 0 : const char *TABText::GetLabelStyleString()
6157 : {
6158 0 : const char *pszStyle = NULL;
6159 0 : int nStringLen = strlen(GetTextString());
6160 : // ALL Caps, Extpanded need to modify the string value
6161 0 : char *pszTextString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
6162 : char szPattern[20];
6163 0 : int nJustification = 1;
6164 :
6165 0 : strcpy(pszTextString, GetTextString());
6166 0 : szPattern[0] = '\0';
6167 :
6168 :
6169 0 : switch(GetTextJustification())
6170 : {
6171 : case TABTJCenter:
6172 0 : nJustification = 2;
6173 0 : break;
6174 : case TABTJRight:
6175 0 : nJustification = 3;
6176 0 : break;
6177 : case TABTJLeft:
6178 : default:
6179 0 : nJustification = 1;
6180 : break;
6181 : }
6182 :
6183 : // Compute real font size, taking number of lines ("\\n", "\n") and line
6184 : // spacing into account.
6185 0 : int numLines = 1;
6186 0 : for (int i=0; pszTextString[i];
6187 0 : numLines += ((pszTextString[i]=='\n' ||
6188 0 : (pszTextString[i]=='\\' && pszTextString[i+1]=='n')) &&
6189 0 : pszTextString[i+1] != '\0' ),++i);
6190 :
6191 0 : double dHeight = GetTextBoxHeight()/numLines;
6192 :
6193 : // In all cases, take out 20% of font height to account for line spacing
6194 0 : if (numLines > 1)
6195 : {
6196 0 : switch(GetTextSpacing())
6197 : {
6198 : case TABTS1_5:
6199 0 : dHeight *= (0.80 * 0.69);
6200 0 : break;
6201 : case TABTSDouble:
6202 0 : dHeight *= (0.66 * 0.69);
6203 0 : break;
6204 : default:
6205 0 : dHeight *= 0.69;
6206 : }
6207 : }
6208 : else
6209 : {
6210 0 : dHeight *= 0.69;
6211 : }
6212 :
6213 0 : if (QueryFontStyle(TABFSAllCaps))
6214 0 : for (int i=0; pszTextString[i];++i)
6215 0 : if (isalpha(pszTextString[i]))
6216 0 : pszTextString[i] = (char)toupper(pszTextString[i]);
6217 :
6218 : /* Escape the double quote chars and expand the text */
6219 : char *pszTmpTextString;
6220 0 : int j = 0;
6221 :
6222 0 : if (QueryFontStyle(TABFSExpanded))
6223 0 : pszTmpTextString = (char*)CPLMalloc(((nStringLen*4)+1)*sizeof(char));
6224 : else
6225 0 : pszTmpTextString = (char*)CPLMalloc(((nStringLen*2)+1)*sizeof(char));
6226 :
6227 0 : for (int i =0; i < nStringLen; ++i,++j)
6228 : {
6229 0 : if (pszTextString[i] == '"')
6230 : {
6231 0 : pszTmpTextString[j] = '\\';
6232 0 : pszTmpTextString[j+1] = pszTextString[i];
6233 0 : ++j;
6234 : }
6235 : else
6236 0 : pszTmpTextString[j] = pszTextString[i];
6237 :
6238 0 : if (QueryFontStyle(TABFSExpanded))
6239 : {
6240 0 : pszTmpTextString[j+1] = ' ';
6241 0 : ++j;
6242 : }
6243 : }
6244 :
6245 0 : pszTmpTextString[j] = '\0';
6246 0 : CPLFree(pszTextString);
6247 0 : pszTextString = (char*)CPLMalloc((strlen(pszTmpTextString)+1)*sizeof(char));
6248 0 : strcpy(pszTextString, pszTmpTextString);
6249 0 : CPLFree(pszTmpTextString);
6250 :
6251 : const char *pszBGColor = IsFontBGColorUsed() ? CPLSPrintf(",b:#%6.6x",
6252 0 : GetFontBGColor()) :"";
6253 : const char *pszOColor = IsFontOColorUsed() ? CPLSPrintf(",o:#%6.6x",
6254 0 : GetFontOColor()) :"";
6255 : const char *pszSColor = IsFontSColorUsed() ? CPLSPrintf(",h:#%6.6x",
6256 0 : GetFontSColor()) :"";
6257 0 : const char *pszBold = IsFontBold() ? ",bo:1" :"";
6258 0 : const char *pszItalic = IsFontItalic() ? ",it:1" :"";
6259 0 : const char *pszUnderline = IsFontUnderline() ? ",un:1" : "";
6260 :
6261 : pszStyle=CPLSPrintf("LABEL(t:\"%s\",a:%f,s:%fg,c:#%6.6x%s%s%s%s%s%s,p:%d,f:\"%s\")",
6262 : pszTextString,GetTextAngle(), dHeight,
6263 : GetFontFGColor(),pszBGColor,pszOColor,pszSColor,
6264 0 : pszBold,pszItalic,pszUnderline,nJustification,GetFontNameRef());
6265 :
6266 0 : CPLFree(pszTextString);
6267 0 : return pszStyle;
6268 :
6269 : }
6270 :
6271 : /**********************************************************************
6272 : * TABText::GetStyleString()
6273 : *
6274 : * Return style string for this feature.
6275 : *
6276 : * Style String is built only once during the first call to GetStyleString().
6277 : **********************************************************************/
6278 0 : const char *TABText::GetStyleString()
6279 : {
6280 0 : if (m_pszStyleString == NULL)
6281 : {
6282 0 : m_pszStyleString = CPLStrdup(GetLabelStyleString());
6283 : }
6284 :
6285 0 : return m_pszStyleString;
6286 : }
6287 :
6288 :
6289 :
6290 : /**********************************************************************
6291 : * TABText::DumpMIF()
6292 : *
6293 : * Dump feature geometry in a format similar to .MIF REGIONs.
6294 : **********************************************************************/
6295 0 : void TABText::DumpMIF(FILE *fpOut /*=NULL*/)
6296 : {
6297 : OGRGeometry *poGeom;
6298 0 : OGRPoint *poPoint = NULL;
6299 :
6300 0 : if (fpOut == NULL)
6301 0 : fpOut = stdout;
6302 :
6303 : /*-----------------------------------------------------------------
6304 : * Fetch and validate geometry
6305 : *----------------------------------------------------------------*/
6306 0 : poGeom = GetGeometryRef();
6307 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
6308 : {
6309 : /*-------------------------------------------------------------
6310 : * Generate output for text object
6311 : *------------------------------------------------------------*/
6312 0 : poPoint = (OGRPoint*)poGeom;
6313 :
6314 : fprintf(fpOut, "TEXT \"%s\" %.15g %.15g\n", m_pszString?m_pszString:"",
6315 0 : poPoint->getX(), poPoint->getY());
6316 :
6317 0 : fprintf(fpOut, " m_pszString = '%s'\n", m_pszString);
6318 0 : fprintf(fpOut, " m_dAngle = %.15g\n", m_dAngle);
6319 0 : fprintf(fpOut, " m_dHeight = %.15g\n", m_dHeight);
6320 : fprintf(fpOut, " m_rgbForeground = 0x%6.6x (%d)\n",
6321 0 : m_rgbForeground, m_rgbForeground);
6322 : fprintf(fpOut, " m_rgbBackground = 0x%6.6x (%d)\n",
6323 0 : m_rgbBackground, m_rgbBackground);
6324 0 : fprintf(fpOut, " m_nTextAlignment = 0x%4.4x\n", m_nTextAlignment);
6325 0 : fprintf(fpOut, " m_nFontStyle = 0x%4.4x\n", m_nFontStyle);
6326 : }
6327 : else
6328 : {
6329 : CPLError(CE_Failure, CPLE_AssertionFailed,
6330 0 : "TABText: Missing or Invalid Geometry!");
6331 0 : return;
6332 : }
6333 :
6334 : // Finish with PEN/BRUSH/etc. clauses
6335 0 : DumpPenDef();
6336 0 : DumpFontDef();
6337 :
6338 0 : fflush(fpOut);
6339 : }
6340 :
6341 : /*=====================================================================
6342 : * class TABMultiPoint
6343 : *====================================================================*/
6344 :
6345 : /**********************************************************************
6346 : * TABMultiPoint::TABMultiPoint()
6347 : *
6348 : * Constructor.
6349 : **********************************************************************/
6350 0 : TABMultiPoint::TABMultiPoint(OGRFeatureDefn *poDefnIn):
6351 0 : TABFeature(poDefnIn)
6352 : {
6353 0 : m_bCenterIsSet = FALSE;
6354 0 : }
6355 :
6356 : /**********************************************************************
6357 : * TABMultiPoint::~TABMultiPoint()
6358 : *
6359 : * Destructor.
6360 : **********************************************************************/
6361 0 : TABMultiPoint::~TABMultiPoint()
6362 : {
6363 0 : }
6364 :
6365 : /**********************************************************************
6366 : * TABMultiPoint::CloneTABFeature()
6367 : *
6368 : * Duplicate feature, including stuff specific to each TABFeature type.
6369 : *
6370 : * This method calls the generic TABFeature::CloneTABFeature() and
6371 : * then copies any members specific to its own type.
6372 : **********************************************************************/
6373 0 : TABFeature *TABMultiPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
6374 : {
6375 : /*-----------------------------------------------------------------
6376 : * Alloc new feature and copy the base stuff
6377 : *----------------------------------------------------------------*/
6378 0 : TABMultiPoint *poNew = new TABMultiPoint(poNewDefn?poNewDefn:GetDefnRef());
6379 :
6380 0 : CopyTABFeatureBase(poNew);
6381 :
6382 : /*-----------------------------------------------------------------
6383 : * And members specific to this class
6384 : *----------------------------------------------------------------*/
6385 : // ITABFeatureSymbol
6386 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
6387 :
6388 0 : poNew->m_bCenterIsSet = m_bCenterIsSet;
6389 0 : poNew->m_dCenterX = m_dCenterX;
6390 0 : poNew->m_dCenterY = m_dCenterY;
6391 :
6392 0 : return poNew;
6393 : }
6394 :
6395 :
6396 : /**********************************************************************
6397 : * TABMultiPoint::ValidateMapInfoType()
6398 : *
6399 : * Check the feature's geometry part and return the corresponding
6400 : * mapinfo object type code. The m_nMapInfoType member will also
6401 : * be updated for further calls to GetMapInfoType();
6402 : *
6403 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
6404 : * is expected for this object class.
6405 : **********************************************************************/
6406 0 : int TABMultiPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
6407 : {
6408 : OGRGeometry *poGeom;
6409 :
6410 : /*-----------------------------------------------------------------
6411 : * Fetch and validate geometry
6412 : *----------------------------------------------------------------*/
6413 0 : poGeom = GetGeometryRef();
6414 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6415 : {
6416 0 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
6417 :
6418 0 : if (poMPoint->getNumGeometries() > TAB_MULTIPOINT_650_MAX_VERTICES)
6419 0 : m_nMapInfoType = TAB_GEOM_V800_MULTIPOINT;
6420 : else
6421 0 : m_nMapInfoType = TAB_GEOM_MULTIPOINT;
6422 : }
6423 : else
6424 : {
6425 : CPLError(CE_Failure, CPLE_AssertionFailed,
6426 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6427 0 : m_nMapInfoType = TAB_GEOM_NONE;
6428 : }
6429 :
6430 : /*-----------------------------------------------------------------
6431 : * Decide if coordinates should be compressed or not.
6432 : *----------------------------------------------------------------*/
6433 0 : ValidateCoordType(poMapFile);
6434 :
6435 0 : return m_nMapInfoType;
6436 : }
6437 :
6438 :
6439 :
6440 : /**********************************************************************
6441 : * TABMultiPoint::ReadGeometryFromMAPFile()
6442 : *
6443 : * Fill the geometry and representation (color, etc...) part of the
6444 : * feature from the contents of the .MAP object pointed to by poMAPFile.
6445 : *
6446 : * It is assumed that poMAPFile currently points to the beginning of
6447 : * a map object.
6448 : *
6449 : * Returns 0 on success, -1 on error, in which case CPLError() will have
6450 : * been called.
6451 : **********************************************************************/
6452 0 : int TABMultiPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
6453 : TABMAPObjHdr *poObjHdr,
6454 : GBool bCoordBlockDataOnly /*=FALSE*/,
6455 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
6456 : {
6457 : GInt32 nX, nY;
6458 : double dX, dY, dXMin, dYMin, dXMax, dYMax;
6459 0 : OGRGeometry *poGeometry=NULL;
6460 0 : GBool bComprCoord = poObjHdr->IsCompressedType();
6461 0 : TABMAPCoordBlock *poCoordBlock = NULL;
6462 :
6463 : /*-----------------------------------------------------------------
6464 : * Fetch and validate geometry type
6465 : *----------------------------------------------------------------*/
6466 0 : m_nMapInfoType = poObjHdr->m_nType;
6467 :
6468 : /*-----------------------------------------------------------------
6469 : * Read object information
6470 : *----------------------------------------------------------------*/
6471 0 : if (m_nMapInfoType == TAB_GEOM_MULTIPOINT ||
6472 : m_nMapInfoType == TAB_GEOM_MULTIPOINT_C ||
6473 : m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT ||
6474 : m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT_C )
6475 : {
6476 : /*-------------------------------------------------------------
6477 : * Copy data from poObjHdr
6478 : *------------------------------------------------------------*/
6479 0 : TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
6480 :
6481 : // MBR
6482 : poMapFile->Int2Coordsys(poMPointHdr->m_nMinX, poMPointHdr->m_nMinY,
6483 0 : dXMin, dYMin);
6484 : poMapFile->Int2Coordsys(poMPointHdr->m_nMaxX, poMPointHdr->m_nMaxY,
6485 0 : dXMax, dYMax);
6486 :
6487 0 : if (!bCoordBlockDataOnly)
6488 : {
6489 0 : m_nSymbolDefIndex = poMPointHdr->m_nSymbolId; // Symbol index
6490 0 : poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
6491 : }
6492 :
6493 : // Centroid/label point
6494 : poMapFile->Int2Coordsys(poMPointHdr->m_nLabelX, poMPointHdr->m_nLabelY,
6495 0 : dX, dY);
6496 0 : SetCenter(dX, dY);
6497 :
6498 : // Compressed coordinate origin (useful only in compressed case!)
6499 0 : m_nComprOrgX = poMPointHdr->m_nComprOrgX;
6500 0 : m_nComprOrgY = poMPointHdr->m_nComprOrgY;
6501 :
6502 : /*-------------------------------------------------------------
6503 : * Read Point Coordinates
6504 : *------------------------------------------------------------*/
6505 : OGRMultiPoint *poMultiPoint;
6506 0 : poGeometry = poMultiPoint = new OGRMultiPoint();
6507 :
6508 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
6509 0 : poCoordBlock = *ppoCoordBlock;
6510 : else
6511 0 : poCoordBlock = poMapFile->GetCoordBlock(poMPointHdr->m_nCoordBlockPtr);
6512 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX,
6513 0 : m_nComprOrgY);
6514 :
6515 0 : for(int iPoint=0; iPoint<poMPointHdr->m_nNumPoints; iPoint++)
6516 : {
6517 0 : if (poCoordBlock->ReadIntCoord(bComprCoord, nX, nY) != 0)
6518 : {
6519 : CPLError(CE_Failure, CPLE_FileIO,
6520 : "Failed reading coordinate data at offset %d",
6521 0 : poMPointHdr->m_nCoordBlockPtr);
6522 0 : return -1;
6523 : }
6524 :
6525 0 : poMapFile->Int2Coordsys(nX, nY, dX, dY);
6526 0 : OGRPoint *poPoint = new OGRPoint(dX, dY);
6527 :
6528 0 : if (poMultiPoint->addGeometryDirectly(poPoint) != OGRERR_NONE)
6529 : {
6530 0 : CPLAssert(FALSE); // Just in case lower-level lib is modified
6531 : }
6532 : }
6533 :
6534 : }
6535 : else
6536 : {
6537 : CPLError(CE_Failure, CPLE_AssertionFailed,
6538 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
6539 0 : m_nMapInfoType, m_nMapInfoType);
6540 0 : return -1;
6541 : }
6542 :
6543 0 : SetGeometryDirectly(poGeometry);
6544 :
6545 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
6546 :
6547 : /* Copy int MBR to feature class members */
6548 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
6549 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
6550 :
6551 : /* Return a ref to coord block so that caller can continue reading
6552 : * after the end of this object (used by TABCollection and index splitting)
6553 : */
6554 0 : if (ppoCoordBlock)
6555 0 : *ppoCoordBlock = poCoordBlock;
6556 :
6557 0 : return 0;
6558 : }
6559 :
6560 : /**********************************************************************
6561 : * TABMultiPoint::WriteGeometryToMAPFile()
6562 : *
6563 : * Write the geometry and representation (color, etc...) part of the
6564 : * feature to the .MAP object pointed to by poMAPFile.
6565 : *
6566 : * It is assumed that poMAPFile currently points to a valid map object.
6567 : *
6568 : * Returns 0 on success, -1 on error, in which case CPLError() will have
6569 : * been called.
6570 : **********************************************************************/
6571 0 : int TABMultiPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
6572 : TABMAPObjHdr *poObjHdr,
6573 : GBool bCoordBlockDataOnly /*=FALSE*/,
6574 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
6575 : {
6576 : GInt32 nX, nY;
6577 : OGRGeometry *poGeom;
6578 : OGRMultiPoint *poMPoint;
6579 :
6580 : /*-----------------------------------------------------------------
6581 : * We assume that ValidateMapInfoType() was called already and that
6582 : * the type in poObjHdr->m_nType is valid.
6583 : *----------------------------------------------------------------*/
6584 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
6585 :
6586 0 : TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
6587 :
6588 : /*-----------------------------------------------------------------
6589 : * Fetch and validate geometry
6590 : *----------------------------------------------------------------*/
6591 0 : poGeom = GetGeometryRef();
6592 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6593 0 : poMPoint = (OGRMultiPoint*)poGeom;
6594 : else
6595 : {
6596 : CPLError(CE_Failure, CPLE_AssertionFailed,
6597 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6598 0 : return -1;
6599 : }
6600 :
6601 0 : poMPointHdr->m_nNumPoints = poMPoint->getNumGeometries();
6602 :
6603 : /*-----------------------------------------------------------------
6604 : * Write data to coordinate block
6605 : *----------------------------------------------------------------*/
6606 : int iPoint, nStatus;
6607 : TABMAPCoordBlock *poCoordBlock;
6608 0 : GBool bCompressed = poObjHdr->IsCompressedType();
6609 :
6610 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
6611 0 : poCoordBlock = *ppoCoordBlock;
6612 : else
6613 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
6614 0 : poCoordBlock->StartNewFeature();
6615 0 : poMPointHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
6616 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
6617 :
6618 :
6619 0 : for(iPoint=0, nStatus=0;
6620 : nStatus == 0 && iPoint < poMPointHdr->m_nNumPoints; iPoint++)
6621 : {
6622 0 : poGeom = poMPoint->getGeometryRef(iPoint);
6623 :
6624 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
6625 : {
6626 0 : OGRPoint *poPoint = (OGRPoint*)poGeom;
6627 :
6628 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
6629 0 : if (iPoint == 0)
6630 : {
6631 : // Default to the first point, we may use explicit value below
6632 0 : poMPointHdr->m_nLabelX = nX;
6633 0 : poMPointHdr->m_nLabelY = nY;
6634 : }
6635 :
6636 0 : if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY,
6637 : bCompressed)) != 0)
6638 : {
6639 : // Failed ... error message has already been produced
6640 0 : return nStatus;
6641 : }
6642 :
6643 : }
6644 : else
6645 : {
6646 : CPLError(CE_Failure, CPLE_AssertionFailed,
6647 0 : "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
6648 0 : return -1;
6649 : }
6650 : }
6651 :
6652 : /*-----------------------------------------------------------------
6653 : * Copy object information
6654 : *----------------------------------------------------------------*/
6655 :
6656 : // Compressed coordinate origin (useful only in compressed case!)
6657 0 : poMPointHdr->m_nComprOrgX = m_nComprOrgX;
6658 0 : poMPointHdr->m_nComprOrgY = m_nComprOrgY;
6659 :
6660 0 : poMPointHdr->m_nCoordDataSize = poCoordBlock->GetFeatureDataSize();
6661 0 : poMPointHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
6662 :
6663 : // Center/label point (default value already set above)
6664 : double dX, dY;
6665 0 : if (GetCenter(dX, dY) != -1)
6666 : {
6667 : poMapFile->Coordsys2Int(dX, dY, poMPointHdr->m_nLabelX,
6668 0 : poMPointHdr->m_nLabelY);
6669 : }
6670 :
6671 0 : if (!bCoordBlockDataOnly)
6672 : {
6673 0 : m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
6674 0 : poMPointHdr->m_nSymbolId = (GByte)m_nSymbolDefIndex; // Symbol index
6675 : }
6676 :
6677 0 : if (CPLGetLastErrorNo() != 0)
6678 0 : return -1;
6679 :
6680 : /* Return a ref to coord block so that caller can continue writing
6681 : * after the end of this object (used by index splitting)
6682 : */
6683 0 : if (ppoCoordBlock)
6684 0 : *ppoCoordBlock = poCoordBlock;
6685 :
6686 0 : return 0;
6687 : }
6688 :
6689 :
6690 : /**********************************************************************
6691 : * TABMultiPoint::GetXY()
6692 : *
6693 : * Return this point's X,Y coordinates.
6694 : **********************************************************************/
6695 0 : int TABMultiPoint::GetXY(int i, double &dX, double &dY)
6696 : {
6697 : OGRGeometry *poGeom;
6698 :
6699 : /*-----------------------------------------------------------------
6700 : * Fetch and validate geometry
6701 : *----------------------------------------------------------------*/
6702 0 : poGeom = GetGeometryRef();
6703 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6704 : {
6705 0 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
6706 :
6707 0 : if (i >= 0 && i < poMPoint->getNumGeometries() &&
6708 : (poGeom = poMPoint->getGeometryRef(i)) != NULL &&
6709 0 : wkbFlatten(poGeom->getGeometryType()) == wkbPoint )
6710 : {
6711 0 : OGRPoint *poPoint = (OGRPoint*)poGeom;
6712 :
6713 0 : dX = poPoint->getX();
6714 0 : dY = poPoint->getY();
6715 : }
6716 : }
6717 : else
6718 : {
6719 : CPLError(CE_Failure, CPLE_AssertionFailed,
6720 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6721 0 : dX = dY = 0.0;
6722 0 : return -1;
6723 : }
6724 :
6725 0 : return 0;
6726 : }
6727 :
6728 : /**********************************************************************
6729 : * TABMultiPoint::GetNumPoints()
6730 : *
6731 : * Return the number of points in this multipoint object
6732 : **********************************************************************/
6733 0 : int TABMultiPoint::GetNumPoints()
6734 : {
6735 : OGRGeometry *poGeom;
6736 :
6737 : /*-----------------------------------------------------------------
6738 : * Fetch and validate geometry
6739 : *----------------------------------------------------------------*/
6740 0 : poGeom = GetGeometryRef();
6741 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6742 : {
6743 0 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
6744 :
6745 0 : return poMPoint->getNumGeometries();
6746 : }
6747 : else
6748 : {
6749 : CPLError(CE_Failure, CPLE_AssertionFailed,
6750 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6751 0 : return 0;
6752 : }
6753 :
6754 : return 0;
6755 : }
6756 :
6757 :
6758 : /**********************************************************************
6759 : * TABMultiPoint::GetStyleString()
6760 : *
6761 : * Return style string for this feature.
6762 : *
6763 : * Style String is built only once during the first call to GetStyleString().
6764 : **********************************************************************/
6765 0 : const char *TABMultiPoint::GetStyleString()
6766 : {
6767 0 : if (m_pszStyleString == NULL)
6768 : {
6769 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
6770 : }
6771 :
6772 0 : return m_pszStyleString;
6773 : }
6774 :
6775 : /**********************************************************************
6776 : * TABMultiPoint::GetCenter()
6777 : *
6778 : * Returns the center point (or label point?) of the object. Compute one
6779 : * if it was not explicitly set:
6780 : *
6781 : * The default seems to be to use the first point in the collection as
6782 : * the center.. so we'll use that.
6783 : *
6784 : * Returns 0 on success, -1 on error.
6785 : **********************************************************************/
6786 0 : int TABMultiPoint::GetCenter(double &dX, double &dY)
6787 : {
6788 0 : if (!m_bCenterIsSet && GetNumPoints() > 0)
6789 : {
6790 : // The default seems to be to use the first point in the collection
6791 : // as the center... so we'll use that.
6792 0 : if (GetXY(0, m_dCenterX, m_dCenterY) == 0)
6793 0 : m_bCenterIsSet = TRUE;
6794 : }
6795 :
6796 0 : if (!m_bCenterIsSet)
6797 0 : return -1;
6798 :
6799 0 : dX = m_dCenterX;
6800 0 : dY = m_dCenterY;
6801 0 : return 0;
6802 : }
6803 :
6804 : /**********************************************************************
6805 : * TABMultiPoint::SetCenter()
6806 : *
6807 : * Set the X,Y coordinates to use as center point (or label point?)
6808 : **********************************************************************/
6809 0 : void TABMultiPoint::SetCenter(double dX, double dY)
6810 : {
6811 0 : m_dCenterX = dX;
6812 0 : m_dCenterY = dY;
6813 0 : m_bCenterIsSet = TRUE;
6814 0 : }
6815 :
6816 :
6817 : /**********************************************************************
6818 : * TABMultiPoint::DumpMIF()
6819 : *
6820 : * Dump feature geometry in a format similar to .MIF POINTs.
6821 : **********************************************************************/
6822 0 : void TABMultiPoint::DumpMIF(FILE *fpOut /*=NULL*/)
6823 : {
6824 : OGRGeometry *poGeom;
6825 : OGRMultiPoint *poMPoint;
6826 :
6827 0 : if (fpOut == NULL)
6828 0 : fpOut = stdout;
6829 :
6830 : /*-----------------------------------------------------------------
6831 : * Fetch and validate geometry
6832 : *----------------------------------------------------------------*/
6833 0 : poGeom = GetGeometryRef();
6834 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6835 0 : poMPoint = (OGRMultiPoint*)poGeom;
6836 : else
6837 : {
6838 : CPLError(CE_Failure, CPLE_AssertionFailed,
6839 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6840 0 : return;
6841 : }
6842 :
6843 : /*-----------------------------------------------------------------
6844 : * Generate output
6845 : *----------------------------------------------------------------*/
6846 0 : fprintf(fpOut, "MULTIPOINT %d\n", poMPoint->getNumGeometries());
6847 :
6848 0 : for (int iPoint=0; iPoint < poMPoint->getNumGeometries(); iPoint++)
6849 : {
6850 0 : poGeom = poMPoint->getGeometryRef(iPoint);
6851 :
6852 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
6853 : {
6854 0 : OGRPoint *poPoint = (OGRPoint*)poGeom;
6855 0 : fprintf(fpOut, " %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
6856 : }
6857 : else
6858 : {
6859 : CPLError(CE_Failure, CPLE_AssertionFailed,
6860 0 : "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
6861 0 : return;
6862 : }
6863 : }
6864 :
6865 0 : DumpSymbolDef(fpOut);
6866 :
6867 0 : if (m_bCenterIsSet)
6868 0 : fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
6869 :
6870 0 : fflush(fpOut);
6871 : }
6872 :
6873 : /*=====================================================================
6874 : * class TABCollection
6875 : *====================================================================*/
6876 :
6877 : /**********************************************************************
6878 : * TABCollection::TABCollection()
6879 : *
6880 : * Constructor.
6881 : **********************************************************************/
6882 0 : TABCollection::TABCollection(OGRFeatureDefn *poDefnIn):
6883 0 : TABFeature(poDefnIn)
6884 : {
6885 0 : m_poRegion = NULL;
6886 0 : m_poPline = NULL;
6887 0 : m_poMpoint = NULL;
6888 0 : }
6889 :
6890 : /**********************************************************************
6891 : * TABCollection::~TABCollection()
6892 : *
6893 : * Destructor.
6894 : **********************************************************************/
6895 0 : TABCollection::~TABCollection()
6896 : {
6897 0 : EmptyCollection();
6898 0 : }
6899 :
6900 : /**********************************************************************
6901 : * TABCollection::EmptyCollection()
6902 : *
6903 : * Delete/free all collection components.
6904 : **********************************************************************/
6905 0 : void TABCollection::EmptyCollection()
6906 : {
6907 :
6908 0 : if (m_poRegion)
6909 : {
6910 0 : delete m_poRegion;
6911 0 : m_poRegion = NULL;
6912 : }
6913 :
6914 0 : if (m_poPline)
6915 : {
6916 0 : delete m_poPline;
6917 0 : m_poPline = NULL;
6918 : }
6919 :
6920 0 : if (m_poMpoint)
6921 : {
6922 0 : delete m_poMpoint;
6923 0 : m_poMpoint = NULL;
6924 : }
6925 :
6926 : // Empty OGR Geometry Collection as well
6927 0 : SyncOGRGeometryCollection(TRUE, TRUE, TRUE);
6928 :
6929 0 : }
6930 :
6931 : /**********************************************************************
6932 : * TABCollection::CloneTABFeature()
6933 : *
6934 : * Duplicate feature, including stuff specific to each TABFeature type.
6935 : *
6936 : * This method calls the generic TABFeature::CloneTABFeature() and
6937 : * then copies any members specific to its own type.
6938 : **********************************************************************/
6939 0 : TABFeature *TABCollection::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
6940 : {
6941 : /*-----------------------------------------------------------------
6942 : * Alloc new feature and copy the base stuff
6943 : *----------------------------------------------------------------*/
6944 0 : TABCollection *poNew = new TABCollection(poNewDefn?poNewDefn:GetDefnRef());
6945 :
6946 0 : CopyTABFeatureBase(poNew);
6947 :
6948 : /*-----------------------------------------------------------------
6949 : * And members specific to this class
6950 : *----------------------------------------------------------------*/
6951 :
6952 0 : if (m_poRegion)
6953 0 : poNew->SetRegionDirectly((TABRegion*)m_poRegion->CloneTABFeature());
6954 :
6955 0 : if (m_poPline)
6956 0 : poNew->SetPolylineDirectly((TABPolyline*)m_poPline->CloneTABFeature());
6957 :
6958 0 : if (m_poMpoint)
6959 0 : poNew->SetMultiPointDirectly((TABMultiPoint*)m_poMpoint->CloneTABFeature());
6960 :
6961 0 : return poNew;
6962 : }
6963 :
6964 :
6965 : /**********************************************************************
6966 : * TABCollection::ValidateMapInfoType()
6967 : *
6968 : * Check the feature's geometry part and return the corresponding
6969 : * mapinfo object type code. The m_nMapInfoType member will also
6970 : * be updated for further calls to GetMapInfoType();
6971 : *
6972 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
6973 : * is expected for this object class.
6974 : **********************************************************************/
6975 0 : int TABCollection::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
6976 : {
6977 : OGRGeometry *poGeom;
6978 0 : int nRegionType=TAB_GEOM_NONE, nPLineType=TAB_GEOM_NONE,
6979 0 : nMPointType=TAB_GEOM_NONE, nVersion = 650;
6980 :
6981 : /*-----------------------------------------------------------------
6982 : * Fetch and validate geometry
6983 : *----------------------------------------------------------------*/
6984 0 : poGeom = GetGeometryRef();
6985 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
6986 : {
6987 0 : m_nMapInfoType = TAB_GEOM_COLLECTION;
6988 : }
6989 : else
6990 : {
6991 : CPLError(CE_Failure, CPLE_AssertionFailed,
6992 0 : "TABCollection: Missing or Invalid Geometry!");
6993 0 : m_nMapInfoType = TAB_GEOM_NONE;
6994 : }
6995 :
6996 : /*-----------------------------------------------------------------
6997 : * Decide if coordinates should be compressed or not.
6998 : *----------------------------------------------------------------*/
6999 0 : GBool bComprCoord = ValidateCoordType(poMapFile);
7000 :
7001 : /*-----------------------------------------------------------------
7002 : * Since all members of the collection share the same compressed coord
7003 : * origin, we should force the compressed origin in all components
7004 : * to be the same.
7005 : * This also implies that ValidateMapInfoType() should *NOT* be called
7006 : * again until the collection components are written by WriteGeom...()
7007 : *----------------------------------------------------------------*/
7008 :
7009 : // First pass to figure collection type...
7010 0 : if (m_poRegion)
7011 : {
7012 0 : m_poRegion->ValidateCoordType(poMapFile);
7013 0 : nRegionType = m_poRegion->ValidateMapInfoType(poMapFile);
7014 0 : if (TAB_GEOM_GET_VERSION(nRegionType) > nVersion)
7015 0 : nVersion = TAB_GEOM_GET_VERSION(nRegionType);
7016 : }
7017 :
7018 0 : if (m_poPline)
7019 : {
7020 0 : m_poPline->ValidateCoordType(poMapFile);
7021 0 : nPLineType = m_poPline->ValidateMapInfoType(poMapFile);
7022 0 : if (TAB_GEOM_GET_VERSION(nPLineType) > nVersion)
7023 0 : nVersion = TAB_GEOM_GET_VERSION(nPLineType);
7024 : }
7025 :
7026 0 : if (m_poMpoint)
7027 : {
7028 0 : m_poMpoint->ValidateCoordType(poMapFile);
7029 0 : nMPointType = m_poMpoint->ValidateMapInfoType(poMapFile);
7030 0 : if (TAB_GEOM_GET_VERSION(nMPointType) > nVersion)
7031 0 : nVersion = TAB_GEOM_GET_VERSION(nMPointType);
7032 : }
7033 :
7034 : // Need to upgrade native type of collection?
7035 0 : if (nVersion == 800)
7036 : {
7037 0 : m_nMapInfoType = TAB_GEOM_V800_COLLECTION;
7038 : }
7039 :
7040 : // Make another pass updating native type and coordinates type and origin
7041 : // of each component
7042 0 : if (m_poRegion && nRegionType != TAB_GEOM_NONE)
7043 : {
7044 0 : GInt32 nXMin=0, nYMin=0, nXMax=0, nYMax=0;
7045 0 : m_poRegion->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
7046 : m_poRegion->ForceCoordTypeAndOrigin((nVersion == 800 ?
7047 : TAB_GEOM_V800_REGION:
7048 : TAB_GEOM_V450_REGION),
7049 : bComprCoord,
7050 : m_nComprOrgX, m_nComprOrgY,
7051 0 : nXMin, nYMin, nXMax, nYMax);
7052 : }
7053 :
7054 :
7055 0 : if (m_poPline && nPLineType != TAB_GEOM_NONE)
7056 : {
7057 : GInt32 nXMin, nYMin, nXMax, nYMax;
7058 0 : m_poPline->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
7059 : m_poPline->ForceCoordTypeAndOrigin((nVersion == 800 ?
7060 : TAB_GEOM_V800_MULTIPLINE:
7061 : TAB_GEOM_V450_MULTIPLINE),
7062 : bComprCoord,
7063 : m_nComprOrgX, m_nComprOrgY,
7064 0 : nXMin, nYMin, nXMax, nYMax);
7065 : }
7066 :
7067 0 : if (m_poMpoint && nMPointType != TAB_GEOM_NONE)
7068 : {
7069 : GInt32 nXMin, nYMin, nXMax, nYMax;
7070 0 : m_poMpoint->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
7071 : m_poMpoint->ForceCoordTypeAndOrigin((nVersion == 800 ?
7072 : TAB_GEOM_V800_MULTIPOINT:
7073 : TAB_GEOM_MULTIPOINT),
7074 : bComprCoord,
7075 : m_nComprOrgX, m_nComprOrgY,
7076 0 : nXMin, nYMin, nXMax, nYMax);
7077 : }
7078 :
7079 :
7080 0 : return m_nMapInfoType;
7081 : }
7082 :
7083 :
7084 : /**********************************************************************
7085 : * TABCollection::ReadLabelAndMBR()
7086 : *
7087 : * Reads the label and MBR elements of the header of a collection component
7088 : *
7089 : * Returns 0 on success, -1 on failure.
7090 : **********************************************************************/
7091 0 : int TABCollection::ReadLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
7092 : GBool bComprCoord,
7093 : GInt32 nComprOrgX, GInt32 nComprOrgY,
7094 : GInt32 &pnMinX, GInt32 &pnMinY,
7095 : GInt32 &pnMaxX, GInt32 &pnMaxY,
7096 : GInt32 &pnLabelX, GInt32 &pnLabelY )
7097 : {
7098 : //
7099 : // The sections in the collection's coord blocks start with center/label
7100 : // point + MBR that are normally found in the object data blocks
7101 : // of regular region/pline/mulitpoint objects.
7102 : //
7103 :
7104 0 : if (bComprCoord)
7105 : {
7106 : // Region center/label point, relative to compr. coord. origin
7107 : // No it's not relative to the Object block center
7108 0 : pnLabelX = poCoordBlock->ReadInt16();
7109 0 : pnLabelY = poCoordBlock->ReadInt16();
7110 :
7111 0 : pnLabelX += nComprOrgX;
7112 0 : pnLabelY += nComprOrgY;
7113 :
7114 0 : pnMinX = nComprOrgX + poCoordBlock->ReadInt16(); // Read MBR
7115 0 : pnMinY = nComprOrgY + poCoordBlock->ReadInt16();
7116 0 : pnMaxX = nComprOrgX + poCoordBlock->ReadInt16();
7117 0 : pnMaxY = nComprOrgY + poCoordBlock->ReadInt16();
7118 : }
7119 : else
7120 : {
7121 : // Region center/label point, relative to compr. coord. origin
7122 : // No it's not relative to the Object block center
7123 0 : pnLabelX = poCoordBlock->ReadInt32();
7124 0 : pnLabelY = poCoordBlock->ReadInt32();
7125 :
7126 0 : pnMinX = poCoordBlock->ReadInt32(); // Read MBR
7127 0 : pnMinY = poCoordBlock->ReadInt32();
7128 0 : pnMaxX = poCoordBlock->ReadInt32();
7129 0 : pnMaxY = poCoordBlock->ReadInt32();
7130 : }
7131 :
7132 0 : return 0;
7133 : }
7134 :
7135 : /**********************************************************************
7136 : * TABCollection::WriteLabelAndMBR()
7137 : *
7138 : * Writes the label and MBR elements of the header of a collection component
7139 : *
7140 : * Returns 0 on success, -1 on failure.
7141 : **********************************************************************/
7142 0 : int TABCollection::WriteLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
7143 : GBool bComprCoord,
7144 : GInt32 nMinX, GInt32 nMinY,
7145 : GInt32 nMaxX, GInt32 nMaxY,
7146 : GInt32 nLabelX, GInt32 nLabelY )
7147 : {
7148 : int nStatus;
7149 :
7150 : //
7151 : // The sections in the collection's coord blocks start with center/label
7152 : // point + MBR that are normally found in the object data blocks
7153 : // of regular region/pline/mulitpoint objects.
7154 : //
7155 :
7156 0 : if ((nStatus = poCoordBlock->WriteIntCoord(nLabelX, nLabelY,
7157 : bComprCoord)) != 0 ||
7158 : (nStatus = poCoordBlock->WriteIntCoord(nMinX, nMinY,
7159 : bComprCoord)) != 0 ||
7160 : (nStatus = poCoordBlock->WriteIntCoord(nMaxX, nMaxY,
7161 : bComprCoord)) != 0 )
7162 : {
7163 : // Failed ... error message has already been produced
7164 0 : return nStatus;
7165 : }
7166 :
7167 0 : return 0;
7168 : }
7169 :
7170 :
7171 : /**********************************************************************
7172 : * TABCollection::ReadGeometryFromMAPFile()
7173 : *
7174 : * Fill the geometry and representation (color, etc...) part of the
7175 : * feature from the contents of the .MAP object pointed to by poMAPFile.
7176 : *
7177 : * It is assumed that poMAPFile currently points to the beginning of
7178 : * a map object.
7179 : *
7180 : * Returns 0 on success, -1 on error, in which case CPLError() will have
7181 : * been called.
7182 : **********************************************************************/
7183 0 : int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
7184 : TABMAPObjHdr *poObjHdr,
7185 : GBool bCoordBlockDataOnly /*=FALSE*/,
7186 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
7187 : {
7188 : double dXMin, dYMin, dXMax, dYMax;
7189 0 : GBool bComprCoord = poObjHdr->IsCompressedType();
7190 0 : TABMAPCoordBlock* poCoordBlock = NULL;
7191 : int nCurCoordBlockPtr;
7192 :
7193 : /*-----------------------------------------------------------------
7194 : * Fetch and validate geometry type
7195 : *----------------------------------------------------------------*/
7196 0 : m_nMapInfoType = poObjHdr->m_nType;
7197 :
7198 0 : if (m_nMapInfoType != TAB_GEOM_COLLECTION &&
7199 : m_nMapInfoType != TAB_GEOM_COLLECTION_C &&
7200 : m_nMapInfoType != TAB_GEOM_V800_COLLECTION &&
7201 : m_nMapInfoType != TAB_GEOM_V800_COLLECTION_C )
7202 : {
7203 : CPLError(CE_Failure, CPLE_AssertionFailed,
7204 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
7205 0 : m_nMapInfoType, m_nMapInfoType);
7206 0 : return -1;
7207 : }
7208 :
7209 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
7210 :
7211 : // Make sure collection is empty
7212 0 : EmptyCollection();
7213 :
7214 : /*-------------------------------------------------------------
7215 : * Copy data from poObjHdr
7216 : *------------------------------------------------------------*/
7217 0 : TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
7218 :
7219 : // MBR
7220 : poMapFile->Int2Coordsys(poCollHdr->m_nMinX, poCollHdr->m_nMinY,
7221 0 : dXMin, dYMin);
7222 : poMapFile->Int2Coordsys(poCollHdr->m_nMaxX, poCollHdr->m_nMaxY,
7223 0 : dXMax, dYMax);
7224 :
7225 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
7226 :
7227 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
7228 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
7229 :
7230 0 : nCurCoordBlockPtr = poCollHdr->m_nCoordBlockPtr;
7231 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
7232 0 : poCoordBlock = *ppoCoordBlock;
7233 : else
7234 0 : poCoordBlock = poMapFile->GetCoordBlock(nCurCoordBlockPtr);
7235 :
7236 : // Compressed coordinate origin (useful only in compressed case!)
7237 0 : m_nComprOrgX = poCollHdr->m_nComprOrgX;
7238 0 : m_nComprOrgY = poCollHdr->m_nComprOrgY;
7239 :
7240 : /*-----------------------------------------------------------------
7241 : * Region Component
7242 : *----------------------------------------------------------------*/
7243 0 : if(poCollHdr->m_nNumRegSections > 0)
7244 : {
7245 : //
7246 : // Build fake coord section header to pass to TABRegion::ReadGeom...()
7247 : //
7248 0 : TABMAPObjPLine oRegionHdr;
7249 :
7250 0 : oRegionHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
7251 0 : oRegionHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
7252 :
7253 : //
7254 : // The region section in the coord block starts with center/label
7255 : // point + MBR that are normally found in the object data blocks
7256 : // of regular region objects.
7257 : //
7258 :
7259 : // In V800 the mini-header starts with a copy of num_parts
7260 0 : if (nVersion >= 800)
7261 : {
7262 : int numParts;
7263 0 : numParts = poCoordBlock->ReadInt32();
7264 0 : CPLAssert(numParts == poCollHdr->m_nNumRegSections);
7265 : }
7266 :
7267 : ReadLabelAndMBR(poCoordBlock, bComprCoord,
7268 : oRegionHdr.m_nComprOrgX, oRegionHdr.m_nComprOrgY,
7269 : oRegionHdr.m_nMinX, oRegionHdr.m_nMinY,
7270 : oRegionHdr.m_nMaxX, oRegionHdr.m_nMaxY,
7271 0 : oRegionHdr.m_nLabelX, oRegionHdr.m_nLabelY);
7272 :
7273 : // Set CoordBlockPtr so that TABRegion continues reading here
7274 0 : oRegionHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7275 :
7276 0 : if (bComprCoord)
7277 0 : oRegionHdr.m_nType = TAB_GEOM_V450_REGION_C;
7278 : else
7279 0 : oRegionHdr.m_nType = TAB_GEOM_V450_REGION;
7280 0 : if (nVersion == 800)
7281 0 : oRegionHdr.m_nType += (TAB_GEOM_V800_REGION - TAB_GEOM_V450_REGION);
7282 :
7283 0 : oRegionHdr.m_numLineSections = poCollHdr->m_nNumRegSections;
7284 0 : oRegionHdr.m_nPenId = poCollHdr->m_nRegionPenId;
7285 0 : oRegionHdr.m_nBrushId = poCollHdr->m_nRegionBrushId;
7286 0 : oRegionHdr.m_bSmooth = 0; // TODO
7287 :
7288 : //
7289 : // Use a TABRegion to read/store the Region coord data
7290 : //
7291 0 : m_poRegion = new TABRegion(GetDefnRef());
7292 0 : if (m_poRegion->ReadGeometryFromMAPFile(poMapFile, &oRegionHdr,
7293 : bCoordBlockDataOnly,
7294 0 : &poCoordBlock) != 0)
7295 0 : return -1;
7296 :
7297 : // Set new coord block ptr for next object
7298 0 : if (poCoordBlock)
7299 0 : nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
7300 : }
7301 :
7302 :
7303 : /*-----------------------------------------------------------------
7304 : * PLine Component
7305 : *----------------------------------------------------------------*/
7306 0 : if(poCollHdr->m_nNumPLineSections > 0)
7307 : {
7308 : //
7309 : // Build fake coord section header to pass to TABPolyline::ReadGeom..()
7310 : //
7311 0 : TABMAPObjPLine oPLineHdr;
7312 :
7313 0 : oPLineHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
7314 0 : oPLineHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
7315 :
7316 : //
7317 : // The pline section in the coord block starts with center/label
7318 : // point + MBR that are normally found in the object data blocks
7319 : // of regular pline objects.
7320 : //
7321 :
7322 : // In V800 the mini-header starts with a copy of num_parts
7323 0 : if (nVersion >= 800)
7324 : {
7325 : int numParts;
7326 0 : numParts = poCoordBlock->ReadInt32();
7327 0 : CPLAssert(numParts == poCollHdr->m_nNumPLineSections);
7328 : }
7329 :
7330 : ReadLabelAndMBR(poCoordBlock, bComprCoord,
7331 : oPLineHdr.m_nComprOrgX, oPLineHdr.m_nComprOrgY,
7332 : oPLineHdr.m_nMinX, oPLineHdr.m_nMinY,
7333 : oPLineHdr.m_nMaxX, oPLineHdr.m_nMaxY,
7334 0 : oPLineHdr.m_nLabelX, oPLineHdr.m_nLabelY);
7335 :
7336 : // Set CoordBlockPtr so that TABRegion continues reading here
7337 0 : oPLineHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7338 :
7339 0 : if (bComprCoord)
7340 0 : oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE_C;
7341 : else
7342 0 : oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE;
7343 0 : if (nVersion == 800)
7344 : oPLineHdr.m_nType += (TAB_GEOM_V800_MULTIPLINE -
7345 0 : TAB_GEOM_V450_MULTIPLINE);
7346 :
7347 0 : oPLineHdr.m_numLineSections = poCollHdr->m_nNumPLineSections;
7348 0 : oPLineHdr.m_nPenId = poCollHdr->m_nPolylinePenId;
7349 0 : oPLineHdr.m_bSmooth = 0; // TODO
7350 :
7351 : //
7352 : // Use a TABPolyline to read/store the Polyline coord data
7353 : //
7354 0 : m_poPline = new TABPolyline(GetDefnRef());
7355 0 : if (m_poPline->ReadGeometryFromMAPFile(poMapFile, &oPLineHdr,
7356 : bCoordBlockDataOnly,
7357 0 : &poCoordBlock) != 0)
7358 0 : return -1;
7359 :
7360 : // Set new coord block ptr for next object
7361 0 : if (poCoordBlock)
7362 0 : nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
7363 : }
7364 :
7365 : /*-----------------------------------------------------------------
7366 : * MultiPoint Component
7367 : *----------------------------------------------------------------*/
7368 0 : if(poCollHdr->m_nNumMultiPoints > 0)
7369 : {
7370 : //
7371 : // Build fake coord section header to pass to TABMultiPoint::ReadGeom()
7372 : //
7373 0 : TABMAPObjMultiPoint oMPointHdr;
7374 :
7375 0 : oMPointHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
7376 0 : oMPointHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
7377 :
7378 : //
7379 : // The pline section in the coord block starts with center/label
7380 : // point + MBR that are normally found in the object data blocks
7381 : // of regular pline objects.
7382 : //
7383 : ReadLabelAndMBR(poCoordBlock, bComprCoord,
7384 : oMPointHdr.m_nComprOrgX, oMPointHdr.m_nComprOrgY,
7385 : oMPointHdr.m_nMinX, oMPointHdr.m_nMinY,
7386 : oMPointHdr.m_nMaxX, oMPointHdr.m_nMaxY,
7387 0 : oMPointHdr.m_nLabelX, oMPointHdr.m_nLabelY);
7388 :
7389 : // Set CoordBlockPtr so that TABRegion continues reading here
7390 0 : oMPointHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7391 :
7392 0 : if (bComprCoord)
7393 0 : oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT_C;
7394 : else
7395 0 : oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT;
7396 0 : if (nVersion == 800)
7397 : oMPointHdr.m_nType += (TAB_GEOM_V800_MULTIPOINT -
7398 0 : TAB_GEOM_MULTIPOINT);
7399 :
7400 0 : oMPointHdr.m_nNumPoints = poCollHdr->m_nNumMultiPoints;
7401 0 : oMPointHdr.m_nSymbolId = poCollHdr->m_nMultiPointSymbolId;
7402 :
7403 : //
7404 : // Use a TABMultiPoint to read/store the coord data
7405 : //
7406 0 : m_poMpoint = new TABMultiPoint(GetDefnRef());
7407 0 : if (m_poMpoint->ReadGeometryFromMAPFile(poMapFile, &oMPointHdr,
7408 : bCoordBlockDataOnly,
7409 0 : &poCoordBlock) != 0)
7410 0 : return -1;
7411 :
7412 : // Set new coord block ptr for next object (not really useful here)
7413 0 : if (poCoordBlock)
7414 0 : nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
7415 : }
7416 :
7417 : /*-----------------------------------------------------------------
7418 : * Set the main OGRFeature Geometry
7419 : * (this is actually duplicating geometries from each member)
7420 : *----------------------------------------------------------------*/
7421 0 : if (SyncOGRGeometryCollection(TRUE, TRUE, TRUE) != 0)
7422 0 : return -1;
7423 :
7424 : /* Return a ref to coord block so that caller can continue reading
7425 : * after the end of this object (used by index splitting)
7426 : */
7427 0 : if (ppoCoordBlock)
7428 0 : *ppoCoordBlock = poCoordBlock;
7429 :
7430 0 : return 0;
7431 : }
7432 :
7433 : /**********************************************************************
7434 : * TABCollection::WriteGeometryToMAPFile()
7435 : *
7436 : * Write the geometry and representation (color, etc...) part of the
7437 : * feature to the .MAP object pointed to by poMAPFile.
7438 : *
7439 : * It is assumed that poMAPFile currently points to a valid map object.
7440 : *
7441 : * Returns 0 on success, -1 on error, in which case CPLError() will have
7442 : * been called.
7443 : **********************************************************************/
7444 0 : int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
7445 : TABMAPObjHdr *poObjHdr,
7446 : GBool bCoordBlockDataOnly /*=FALSE*/,
7447 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
7448 : {
7449 : /*-----------------------------------------------------------------
7450 : * Note that the current implementation does not allow setting the
7451 : * Geometry via OGRFeature::SetGeometry(). The geometries must be set
7452 : * via the SetRegion/Pline/MpointDirectly() methods which will take
7453 : * care of keeping the OGRFeature's geometry in sync.
7454 : *
7455 : * TODO: If we ever want to support sync'ing changes from the OGRFeature's
7456 : * geometry to the m_poRegion/Pline/Mpoint then a call should be added
7457 : * here, or perhaps in ValidateMapInfoType(), or even better in
7458 : * custom TABCollection::SetGeometry*()... but then this last option
7459 : * won't work unless OGRFeature::SetGeometry*() are made virtual in OGR.
7460 : *----------------------------------------------------------------*/
7461 :
7462 :
7463 : /*-----------------------------------------------------------------
7464 : * We assume that ValidateMapInfoType() was called already and that
7465 : * the type in poObjHdr->m_nType is valid.
7466 : *----------------------------------------------------------------*/
7467 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
7468 :
7469 0 : TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
7470 :
7471 : /*-----------------------------------------------------------------
7472 : * Write data to coordinate block for each component...
7473 : *
7474 : * Note that at this point, the caller (TABFile) has called
7475 : * TABCollection::ValidateMapInfoType() which in turn has called
7476 : * each component's respective ValidateMapInfoType() and
7477 : * ForceCoordTypeAndCoordOrigin() so the objects are ready to have
7478 : * their respective WriteGeometryToMapFile() called.
7479 : *----------------------------------------------------------------*/
7480 : TABMAPCoordBlock *poCoordBlock;
7481 0 : GBool bCompressed = poObjHdr->IsCompressedType();
7482 : // TODO: ??? Do we need to track overall collection coord data size???
7483 0 : int nTotalFeatureDataSize = 0;
7484 :
7485 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
7486 :
7487 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
7488 0 : poCoordBlock = *ppoCoordBlock;
7489 : else
7490 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
7491 0 : poCoordBlock->StartNewFeature();
7492 0 : poCollHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7493 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
7494 :
7495 : /*-----------------------------------------------------------------
7496 : * Region component
7497 : *----------------------------------------------------------------*/
7498 0 : if (m_poRegion && m_poRegion->GetMapInfoType() != TAB_GEOM_NONE)
7499 : {
7500 0 : CPLAssert(m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION ||
7501 : m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION_C ||
7502 : m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION ||
7503 0 : m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION_C );
7504 :
7505 : TABMAPObjPLine *poRegionHdr = (TABMAPObjPLine *)
7506 0 : TABMAPObjHdr::NewObj((GByte)m_poRegion->GetMapInfoType(), -1);
7507 :
7508 : // Update count of objects by type in header
7509 0 : if (!bCoordBlockDataOnly)
7510 0 : poMapFile->UpdateMapHeaderInfo((GByte)m_poRegion->GetMapInfoType());
7511 :
7512 : // Write a placeholder for centroid/label point and MBR mini-header
7513 : // and we'll come back later to write the real values.
7514 : //
7515 : // Note that the call to WriteGeometryToMAPFile() below will call
7516 : // StartNewFeature() as well, so we need to track the current
7517 : // value before calling it
7518 :
7519 0 : poCoordBlock->StartNewFeature();
7520 0 : int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
7521 :
7522 : // In V800 the mini-header starts with a copy of num_parts
7523 0 : if (nVersion >= 800)
7524 : {
7525 0 : poCoordBlock->WriteInt32(0);
7526 : }
7527 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7528 0 : 0, 0, 0, 0, 0, 0);
7529 0 : nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
7530 :
7531 0 : if (m_poRegion->WriteGeometryToMAPFile(poMapFile, poRegionHdr,
7532 : bCoordBlockDataOnly,
7533 0 : &poCoordBlock) != 0)
7534 : {
7535 : CPLError(CE_Failure, CPLE_FileIO,
7536 0 : "Failed writing Region part in collection.");
7537 0 : delete poRegionHdr;
7538 0 : return -1;
7539 : }
7540 :
7541 0 : nTotalFeatureDataSize += poRegionHdr->m_nCoordDataSize;
7542 :
7543 : // Come back to write the real values in the mini-header
7544 0 : int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
7545 0 : poCoordBlock->StartNewFeature();
7546 :
7547 0 : if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
7548 : {
7549 0 : delete poRegionHdr;
7550 0 : return -1;
7551 : }
7552 :
7553 : // In V800 the mini-header starts with a copy of num_parts
7554 0 : if (nVersion >= 800)
7555 : {
7556 0 : poCoordBlock->WriteInt32(poRegionHdr->m_numLineSections);
7557 : }
7558 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7559 : poRegionHdr->m_nMinX, poRegionHdr->m_nMinY,
7560 : poRegionHdr->m_nMaxX, poRegionHdr->m_nMaxY,
7561 0 : poRegionHdr->m_nLabelX, poRegionHdr->m_nLabelY);
7562 :
7563 : // And finally move the pointer back to the end of this component
7564 0 : if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
7565 : {
7566 0 : delete poRegionHdr;
7567 0 : return -1;
7568 : }
7569 :
7570 : // Copy other header members to the main collection header
7571 : // TODO: Does m_nRegionDataSize need to include the centroid+mbr
7572 : // mini-header???
7573 0 : poCollHdr->m_nRegionDataSize = poRegionHdr->m_nCoordDataSize;
7574 0 : poCollHdr->m_nNumRegSections = poRegionHdr->m_numLineSections;
7575 :
7576 0 : if (!bCoordBlockDataOnly)
7577 : {
7578 0 : poCollHdr->m_nRegionPenId = poRegionHdr->m_nPenId;
7579 0 : poCollHdr->m_nRegionBrushId = poRegionHdr->m_nBrushId;
7580 : // TODO: Smooth flag = poRegionHdr->m_bSmooth;
7581 : }
7582 :
7583 0 : delete poRegionHdr;
7584 : }
7585 : else
7586 : {
7587 : // No Region component. Set corresponding header fields to 0
7588 :
7589 0 : poCollHdr->m_nRegionDataSize = 0;
7590 0 : poCollHdr->m_nNumRegSections = 0;
7591 0 : poCollHdr->m_nRegionPenId = 0;
7592 0 : poCollHdr->m_nRegionBrushId = 0;
7593 : }
7594 :
7595 : /*-----------------------------------------------------------------
7596 : * PLine component
7597 : *----------------------------------------------------------------*/
7598 0 : if (m_poPline && m_poPline->GetMapInfoType() != TAB_GEOM_NONE)
7599 : {
7600 0 : CPLAssert(m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE ||
7601 : m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE_C ||
7602 : m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE ||
7603 0 : m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE_C );
7604 :
7605 : TABMAPObjPLine *poPlineHdr = (TABMAPObjPLine *)
7606 0 : TABMAPObjHdr::NewObj((GByte)m_poPline->GetMapInfoType(), -1);
7607 :
7608 : // Update count of objects by type in header
7609 0 : if (!bCoordBlockDataOnly)
7610 0 : poMapFile->UpdateMapHeaderInfo((GByte)m_poPline->GetMapInfoType());
7611 :
7612 : // Write a placeholder for centroid/label point and MBR mini-header
7613 : // and we'll come back later to write the real values.
7614 : //
7615 : // Note that the call to WriteGeometryToMAPFile() below will call
7616 : // StartNewFeature() as well, so we need to track the current
7617 : // value before calling it
7618 :
7619 0 : poCoordBlock->StartNewFeature();
7620 0 : int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
7621 :
7622 : // In V800 the mini-header starts with a copy of num_parts
7623 0 : if (nVersion >= 800)
7624 : {
7625 0 : poCoordBlock->WriteInt32(0);
7626 : }
7627 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7628 0 : 0, 0, 0, 0, 0, 0);
7629 0 : nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
7630 :
7631 0 : if (m_poPline->WriteGeometryToMAPFile(poMapFile, poPlineHdr,
7632 : bCoordBlockDataOnly,
7633 0 : &poCoordBlock) != 0)
7634 : {
7635 : CPLError(CE_Failure, CPLE_FileIO,
7636 0 : "Failed writing Region part in collection.");
7637 0 : delete poPlineHdr;
7638 0 : return -1;
7639 : }
7640 :
7641 0 : nTotalFeatureDataSize += poPlineHdr->m_nCoordDataSize;
7642 :
7643 : // Come back to write the real values in the mini-header
7644 0 : int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
7645 0 : poCoordBlock->StartNewFeature();
7646 :
7647 0 : if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
7648 : {
7649 0 : delete poPlineHdr;
7650 0 : return -1;
7651 : }
7652 :
7653 : // In V800 the mini-header starts with a copy of num_parts
7654 0 : if (nVersion >= 800)
7655 : {
7656 0 : poCoordBlock->WriteInt32(poPlineHdr->m_numLineSections);
7657 : }
7658 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7659 : poPlineHdr->m_nMinX, poPlineHdr->m_nMinY,
7660 : poPlineHdr->m_nMaxX, poPlineHdr->m_nMaxY,
7661 0 : poPlineHdr->m_nLabelX, poPlineHdr->m_nLabelY);
7662 :
7663 : // And finally move the pointer back to the end of this component
7664 0 : if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
7665 : {
7666 0 : delete poPlineHdr;
7667 0 : return -1;
7668 : }
7669 :
7670 : // Copy other header members to the main collection header
7671 : // TODO: Does m_nRegionDataSize need to include the centroid+mbr
7672 : // mini-header???
7673 0 : poCollHdr->m_nPolylineDataSize = poPlineHdr->m_nCoordDataSize;
7674 0 : poCollHdr->m_nNumPLineSections = poPlineHdr->m_numLineSections;
7675 0 : if (!bCoordBlockDataOnly)
7676 : {
7677 0 : poCollHdr->m_nPolylinePenId = poPlineHdr->m_nPenId;
7678 : // TODO: Smooth flag = poPlineHdr->m_bSmooth;
7679 : }
7680 :
7681 0 : delete poPlineHdr;
7682 : }
7683 : else
7684 : {
7685 : // No Polyline component. Set corresponding header fields to 0
7686 :
7687 0 : poCollHdr->m_nPolylineDataSize = 0;
7688 0 : poCollHdr->m_nNumPLineSections = 0;
7689 0 : poCollHdr->m_nPolylinePenId = 0;
7690 : }
7691 :
7692 :
7693 : /*-----------------------------------------------------------------
7694 : * MultiPoint component
7695 : *----------------------------------------------------------------*/
7696 0 : if (m_poMpoint && m_poMpoint->GetMapInfoType() != TAB_GEOM_NONE)
7697 : {
7698 0 : CPLAssert(m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT ||
7699 : m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT_C ||
7700 : m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT ||
7701 0 : m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT_C );
7702 :
7703 : TABMAPObjMultiPoint *poMpointHdr = (TABMAPObjMultiPoint *)
7704 0 : TABMAPObjHdr::NewObj((GByte)m_poMpoint->GetMapInfoType(), -1);
7705 :
7706 : // Update count of objects by type in header
7707 0 : if (!bCoordBlockDataOnly)
7708 0 : poMapFile->UpdateMapHeaderInfo((GByte)m_poMpoint->GetMapInfoType());
7709 :
7710 : // Write a placeholder for centroid/label point and MBR mini-header
7711 : // and we'll come back later to write the real values.
7712 : //
7713 : // Note that the call to WriteGeometryToMAPFile() below will call
7714 : // StartNewFeature() as well, so we need to track the current
7715 : // value before calling it
7716 :
7717 0 : poCoordBlock->StartNewFeature();
7718 0 : int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
7719 :
7720 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7721 0 : 0, 0, 0, 0, 0, 0);
7722 0 : nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
7723 :
7724 0 : if (m_poMpoint->WriteGeometryToMAPFile(poMapFile, poMpointHdr,
7725 : bCoordBlockDataOnly,
7726 0 : &poCoordBlock) != 0)
7727 : {
7728 : CPLError(CE_Failure, CPLE_FileIO,
7729 0 : "Failed writing Region part in collection.");
7730 0 : delete poMpointHdr;
7731 0 : return -1;
7732 : }
7733 :
7734 0 : nTotalFeatureDataSize += poMpointHdr->m_nCoordDataSize;
7735 :
7736 : // Come back to write the real values in the mini-header
7737 0 : int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
7738 0 : poCoordBlock->StartNewFeature();
7739 :
7740 0 : if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
7741 : {
7742 0 : delete poMpointHdr;
7743 0 : return -1;
7744 : }
7745 :
7746 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7747 : poMpointHdr->m_nMinX, poMpointHdr->m_nMinY,
7748 : poMpointHdr->m_nMaxX, poMpointHdr->m_nMaxY,
7749 0 : poMpointHdr->m_nLabelX, poMpointHdr->m_nLabelY);
7750 :
7751 : // And finally move the pointer back to the end of this component
7752 0 : if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
7753 : {
7754 0 : delete poMpointHdr;
7755 0 : return -1;
7756 : }
7757 :
7758 : // Copy other header members to the main collection header
7759 : // TODO: Does m_nRegionDataSize need to include the centroid+mbr
7760 : // mini-header???
7761 0 : poCollHdr->m_nMPointDataSize = poMpointHdr->m_nCoordDataSize;
7762 0 : poCollHdr->m_nNumMultiPoints = poMpointHdr->m_nNumPoints;
7763 0 : if (!bCoordBlockDataOnly)
7764 : {
7765 0 : poCollHdr->m_nMultiPointSymbolId = poMpointHdr->m_nSymbolId;
7766 : }
7767 :
7768 0 : delete poMpointHdr;
7769 : }
7770 : else
7771 : {
7772 : // No Multipoint component. Set corresponding header fields to 0
7773 :
7774 0 : poCollHdr->m_nMPointDataSize = 0;
7775 0 : poCollHdr->m_nNumMultiPoints = 0;
7776 0 : poCollHdr->m_nMultiPointSymbolId = 0;
7777 : }
7778 :
7779 :
7780 : /*-----------------------------------------------------------------
7781 : * Copy object information
7782 : *----------------------------------------------------------------*/
7783 :
7784 : // Compressed coordinate origin (useful only in compressed case!)
7785 0 : poCollHdr->m_nComprOrgX = m_nComprOrgX;
7786 0 : poCollHdr->m_nComprOrgY = m_nComprOrgY;
7787 :
7788 0 : poCollHdr->m_nCoordDataSize = nTotalFeatureDataSize;
7789 :
7790 0 : poCollHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
7791 :
7792 :
7793 0 : if (CPLGetLastErrorNo() != 0)
7794 0 : return -1;
7795 :
7796 : /* Return a ref to coord block so that caller can continue writing
7797 : * after the end of this object (used by index splitting)
7798 : */
7799 0 : if (ppoCoordBlock)
7800 0 : *ppoCoordBlock = poCoordBlock;
7801 :
7802 0 : return 0;
7803 : }
7804 :
7805 :
7806 : /**********************************************************************
7807 : * TABCollection::SyncOGRGeometryCollection()
7808 : *
7809 : * Copy the region/pline/multipoint's geometries to the OGRFeature's
7810 : * geometry.
7811 : **********************************************************************/
7812 0 : int TABCollection::SyncOGRGeometryCollection(GBool bSyncRegion,
7813 : GBool bSyncPline,
7814 : GBool bSyncMpoint)
7815 : {
7816 0 : OGRGeometry *poThisGeom = GetGeometryRef();
7817 : OGRGeometryCollection *poGeomColl;
7818 :
7819 : // poGeometry is defined in the OGRFeature class
7820 0 : if (poThisGeom == NULL)
7821 : {
7822 0 : poThisGeom = poGeomColl = new OGRGeometryCollection();
7823 0 : SetGeometryDirectly(poGeomColl);
7824 : }
7825 0 : else if (wkbFlatten(poThisGeom->getGeometryType())==wkbGeometryCollection)
7826 : {
7827 0 : poGeomColl = (OGRGeometryCollection *)poThisGeom;
7828 : }
7829 : else
7830 : {
7831 : CPLError(CE_Failure, CPLE_AssertionFailed,
7832 0 : "TABCollection: Invalid Geometry. Type must be OGRCollection.");
7833 0 : return -1;
7834 : }
7835 :
7836 : /*-----------------------------------------------------------------
7837 : * Start by removing geometries that need to be replaced
7838 : * In theory there should be a single geometry of each type, but
7839 : * just in case, we'll loop over the whole collection and delete all
7840 : * instances of each type if there are some.
7841 : *----------------------------------------------------------------*/
7842 0 : int numGeometries = poGeomColl->getNumGeometries();
7843 0 : for (int i=0; i<numGeometries; i++)
7844 : {
7845 0 : OGRGeometry *poGeom = poGeomColl->getGeometryRef(i);
7846 0 : if (!poGeom)
7847 0 : continue;
7848 :
7849 0 : if ( (bSyncRegion &&
7850 0 : (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
7851 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) ) ||
7852 : (bSyncPline &&
7853 0 : (wkbFlatten(poGeom->getGeometryType()) == wkbLineString ||
7854 0 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)) ||
7855 : (bSyncMpoint &&
7856 0 : (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint) ) )
7857 : {
7858 : // Remove this geometry
7859 0 : poGeomColl->removeGeometry(i);
7860 :
7861 : // Unless this was the last geometry, we need to restart
7862 : // scanning the collection since we modified it
7863 0 : if (i != numGeometries-1)
7864 : {
7865 0 : i=0;
7866 0 : numGeometries = poGeomColl->getNumGeometries();
7867 : }
7868 : }
7869 : }
7870 :
7871 : /*-----------------------------------------------------------------
7872 : * Copy TAB Feature geometries to OGRGeometryCollection
7873 : *----------------------------------------------------------------*/
7874 0 : if(bSyncRegion && m_poRegion && m_poRegion->GetGeometryRef() != NULL)
7875 0 : poGeomColl->addGeometry(m_poRegion->GetGeometryRef());
7876 :
7877 0 : if(bSyncPline && m_poPline && m_poPline->GetGeometryRef() != NULL)
7878 0 : poGeomColl->addGeometry(m_poPline->GetGeometryRef());
7879 :
7880 0 : if(bSyncMpoint && m_poMpoint && m_poMpoint->GetGeometryRef() != NULL)
7881 0 : poGeomColl->addGeometry(m_poMpoint->GetGeometryRef());
7882 :
7883 0 : return 0;
7884 : }
7885 :
7886 :
7887 : /**********************************************************************
7888 : * TABCollection::SetRegionDirectly()
7889 : *
7890 : * Set the region component of the collection, deleting the current
7891 : * region component if there is one. The object is then owned by the
7892 : * TABCollection object. Passing NULL just deletes it.
7893 : *
7894 : * Note that an intentional side-effect is that calling this method
7895 : * with the same poRegion pointer that is already owned by this object
7896 : * will force resync'ing the OGR Geometry member.
7897 : **********************************************************************/
7898 0 : int TABCollection::SetRegionDirectly(TABRegion *poRegion)
7899 : {
7900 0 : if (m_poRegion && m_poRegion != poRegion)
7901 0 : delete m_poRegion;
7902 0 : m_poRegion = poRegion;
7903 :
7904 : // Update OGRGeometryCollection component as well
7905 0 : return SyncOGRGeometryCollection(TRUE, FALSE, FALSE);
7906 : }
7907 :
7908 : /**********************************************************************
7909 : * TABCollection::SetPolylineDirectly()
7910 : *
7911 : * Set the polyline component of the collection, deleting the current
7912 : * polyline component if there is one. The object is then owned by the
7913 : * TABCollection object. Passing NULL just deletes it.
7914 : *
7915 : * Note that an intentional side-effect is that calling this method
7916 : * with the same poPline pointer that is already owned by this object
7917 : * will force resync'ing the OGR Geometry member.
7918 : **********************************************************************/
7919 0 : int TABCollection::SetPolylineDirectly(TABPolyline *poPline)
7920 : {
7921 0 : if (m_poPline && m_poPline != poPline)
7922 0 : delete m_poPline;
7923 0 : m_poPline = poPline;
7924 :
7925 : // Update OGRGeometryCollection component as well
7926 0 : return SyncOGRGeometryCollection(FALSE, TRUE, FALSE);
7927 : }
7928 :
7929 : /**********************************************************************
7930 : * TABCollection::SetMultiPointDirectly()
7931 : *
7932 : * Set the multipoint component of the collection, deleting the current
7933 : * multipoint component if there is one. The object is then owned by the
7934 : * TABCollection object. Passing NULL just deletes it.
7935 : *
7936 : * Note that an intentional side-effect is that calling this method
7937 : * with the same poMpoint pointer that is already owned by this object
7938 : * will force resync'ing the OGR Geometry member.
7939 : **********************************************************************/
7940 0 : int TABCollection::SetMultiPointDirectly(TABMultiPoint *poMpoint)
7941 : {
7942 0 : if (m_poMpoint && m_poMpoint != poMpoint)
7943 0 : delete m_poMpoint;
7944 0 : m_poMpoint = poMpoint;
7945 :
7946 : // Update OGRGeometryCollection component as well
7947 0 : return SyncOGRGeometryCollection(FALSE, FALSE, TRUE);
7948 : }
7949 :
7950 :
7951 : /**********************************************************************
7952 : * TABCollection::GetStyleString()
7953 : *
7954 : * Return style string for this feature.
7955 : *
7956 : * Style String is built only once during the first call to GetStyleString().
7957 : **********************************************************************/
7958 0 : const char *TABCollection::GetStyleString()
7959 : {
7960 0 : if (m_pszStyleString == NULL)
7961 : {
7962 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
7963 : }
7964 :
7965 0 : return m_pszStyleString;
7966 : }
7967 :
7968 :
7969 : /**********************************************************************
7970 : * TABCollection::DumpMIF()
7971 : *
7972 : * Dump feature geometry
7973 : **********************************************************************/
7974 0 : void TABCollection::DumpMIF(FILE *fpOut /*=NULL*/)
7975 : {
7976 0 : if (fpOut == NULL)
7977 0 : fpOut = stdout;
7978 :
7979 : /*-----------------------------------------------------------------
7980 : * Generate output
7981 : *----------------------------------------------------------------*/
7982 0 : int numParts = 0;
7983 0 : if (m_poRegion) numParts++;
7984 0 : if (m_poPline) numParts++;
7985 0 : if (m_poMpoint) numParts++;
7986 :
7987 0 : fprintf(fpOut, "COLLECTION %d\n", numParts);
7988 :
7989 0 : if (m_poRegion)
7990 0 : m_poRegion->DumpMIF(fpOut);
7991 :
7992 0 : if (m_poPline)
7993 0 : m_poPline->DumpMIF(fpOut);
7994 :
7995 0 : if (m_poMpoint)
7996 0 : m_poMpoint->DumpMIF(fpOut);
7997 :
7998 :
7999 0 : DumpSymbolDef(fpOut);
8000 :
8001 0 : fflush(fpOut);
8002 0 : }
8003 :
8004 : /*=====================================================================
8005 : * class TABDebugFeature
8006 : *====================================================================*/
8007 :
8008 : /**********************************************************************
8009 : * TABDebugFeature::TABDebugFeature()
8010 : *
8011 : * Constructor.
8012 : **********************************************************************/
8013 0 : TABDebugFeature::TABDebugFeature(OGRFeatureDefn *poDefnIn):
8014 0 : TABFeature(poDefnIn)
8015 : {
8016 0 : }
8017 :
8018 : /**********************************************************************
8019 : * TABDebugFeature::~TABDebugFeature()
8020 : *
8021 : * Destructor.
8022 : **********************************************************************/
8023 0 : TABDebugFeature::~TABDebugFeature()
8024 : {
8025 0 : }
8026 :
8027 : /**********************************************************************
8028 : * TABDebugFeature::ReadGeometryFromMAPFile()
8029 : *
8030 : * Fill the geometry and representation (color, etc...) part of the
8031 : * feature from the contents of the .MAP object pointed to by poMAPFile.
8032 : *
8033 : * It is assumed that poMAPFile currently points to the beginning of
8034 : * a map object.
8035 : *
8036 : * Returns 0 on success, -1 on error, in which case CPLError() will have
8037 : * been called.
8038 : **********************************************************************/
8039 0 : int TABDebugFeature::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
8040 : TABMAPObjHdr *poObjHdr,
8041 : GBool /*bCoordBlockDataOnly=FALSE*/,
8042 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
8043 : {
8044 : TABMAPObjectBlock *poObjBlock;
8045 : TABMAPHeaderBlock *poHeader;
8046 :
8047 : /*-----------------------------------------------------------------
8048 : * Fetch geometry type
8049 : *----------------------------------------------------------------*/
8050 0 : m_nMapInfoType = poObjHdr->m_nType;
8051 :
8052 0 : poObjBlock = poMapFile->GetCurObjBlock();
8053 0 : poHeader = poMapFile->GetHeaderBlock();
8054 :
8055 : /*-----------------------------------------------------------------
8056 : * If object type has coords in a type 3 block, then its position
8057 : * follows
8058 : *----------------------------------------------------------------*/
8059 0 : if (poHeader->MapObjectUsesCoordBlock(m_nMapInfoType))
8060 : {
8061 0 : m_nCoordDataPtr = poObjBlock->ReadInt32();
8062 0 : m_nCoordDataSize = poObjBlock->ReadInt32();
8063 : }
8064 : else
8065 : {
8066 0 : m_nCoordDataPtr = -1;
8067 0 : m_nCoordDataSize = 0;
8068 : }
8069 :
8070 0 : m_nSize = poHeader->GetMapObjectSize(m_nMapInfoType);
8071 0 : if (m_nSize > 0)
8072 : {
8073 0 : poObjBlock->GotoByteRel(-5); // Go back to beginning of header
8074 0 : poObjBlock->ReadBytes(m_nSize, m_abyBuf);
8075 : }
8076 :
8077 0 : return 0;
8078 : }
8079 :
8080 : /**********************************************************************
8081 : * TABDebugFeature::WriteGeometryToMAPFile()
8082 : *
8083 : * Write the geometry and representation (color, etc...) part of the
8084 : * feature to the .MAP object pointed to by poMAPFile.
8085 : *
8086 : * It is assumed that poMAPFile currently points to a valid map object.
8087 : *
8088 : * Returns 0 on success, -1 on error, in which case CPLError() will have
8089 : * been called.
8090 : **********************************************************************/
8091 0 : int TABDebugFeature::WriteGeometryToMAPFile(TABMAPFile * /*poMapFile*/,
8092 : TABMAPObjHdr * /*poObjHdr*/,
8093 : GBool /*bCoordBlockDataOnly=FALSE*/,
8094 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
8095 : {
8096 : // Nothing to do here!
8097 :
8098 : CPLError(CE_Failure, CPLE_NotSupported,
8099 0 : "TABDebugFeature::WriteGeometryToMAPFile() not implemented.\n");
8100 :
8101 0 : return -1;
8102 : }
8103 :
8104 : /**********************************************************************
8105 : * TABDebugFeature::DumpMIF()
8106 : *
8107 : * Dump feature contents... available only in DEBUG mode.
8108 : **********************************************************************/
8109 0 : void TABDebugFeature::DumpMIF(FILE *fpOut /*=NULL*/)
8110 : {
8111 : int i;
8112 :
8113 0 : if (fpOut == NULL)
8114 0 : fpOut = stdout;
8115 :
8116 : fprintf(fpOut, "----- TABDebugFeature (type = 0x%2.2x) -----\n",
8117 0 : GetMapInfoType());
8118 0 : fprintf(fpOut, " Object size: %d bytes\n", m_nSize);
8119 0 : fprintf(fpOut, " m_nCoordDataPtr = %d\n", m_nCoordDataPtr);
8120 0 : fprintf(fpOut, " m_nCoordDataSize = %d\n", m_nCoordDataSize);
8121 0 : fprintf(fpOut, " ");
8122 :
8123 0 : for(i=0; i<m_nSize; i++)
8124 0 : fprintf(fpOut, " %2.2x", m_abyBuf[i]);
8125 :
8126 0 : fprintf(fpOut, " \n");
8127 :
8128 :
8129 0 : fflush(fpOut);
8130 0 : }
8131 :
8132 :
8133 : /*=====================================================================
8134 : * class ITABFeaturePen
8135 : *====================================================================*/
8136 :
8137 : /**********************************************************************
8138 : * ITABFeaturePen::ITABFeaturePen()
8139 : **********************************************************************/
8140 :
8141 102 : ITABFeaturePen::ITABFeaturePen()
8142 : {
8143 : static const TABPenDef csDefaultPen = MITAB_PEN_DEFAULT;
8144 :
8145 102 : m_nPenDefIndex=-1;
8146 :
8147 : /* MI default is PEN(1,2,0) */
8148 102 : m_sPenDef = csDefaultPen;
8149 102 : }
8150 :
8151 :
8152 : /**********************************************************************
8153 : * ITABFeaturePen::GetPenWidthPixel()
8154 : * ITABFeaturePen::SetPenWidthPixel()
8155 : * ITABFeaturePen::GetPenWidthPoint()
8156 : * ITABFeaturePen::SetPenWidthPoint()
8157 : *
8158 : * Pen width can be expressed in pixels (value from 1 to 7 pixels) or
8159 : * in points (value from 0.1 to 203.7 points). The default pen width
8160 : * in MapInfo is 1 pixel. Pen width in points exist only in file version 450.
8161 : *
8162 : * The following methods hide the way the pen width is stored in the files.
8163 : *
8164 : * In order to establish if a given pen def had its width specified in
8165 : * pixels or in points, one should first call GetPenWidthPoint(), and if
8166 : * it returns 0 then the Pixel width should be used instead:
8167 : * if (GetPenWidthPoint() == 0)
8168 : * ... use pen width in points ...
8169 : * else
8170 : * ... use Pixel width from GetPenWidthPixel()
8171 : *
8172 : * Note that the reverse is not true: the default pixel width is always 1,
8173 : * even when the pen width was actually set in points.
8174 : **********************************************************************/
8175 :
8176 7 : GByte ITABFeaturePen::GetPenWidthPixel()
8177 : {
8178 7 : return m_sPenDef.nPixelWidth;
8179 : }
8180 :
8181 0 : void ITABFeaturePen::SetPenWidthPixel(GByte val)
8182 : {
8183 0 : m_sPenDef.nPixelWidth = MIN(MAX(val, 1), 7);
8184 0 : m_sPenDef.nPointWidth = 0;
8185 0 : }
8186 :
8187 0 : double ITABFeaturePen::GetPenWidthPoint()
8188 : {
8189 : // We store point width internally as tenths of points
8190 0 : return m_sPenDef.nPointWidth/10.0;
8191 : }
8192 :
8193 0 : void ITABFeaturePen::SetPenWidthPoint(double val)
8194 : {
8195 0 : m_sPenDef.nPointWidth = MIN(MAX(((int)(val*10)), 1), 2037);
8196 0 : m_sPenDef.nPixelWidth = 1;
8197 0 : }
8198 :
8199 : /**********************************************************************
8200 : * ITABFeaturePen::GetPenWidthMIF()
8201 : * ITABFeaturePen::SetPenWidthMIF()
8202 : *
8203 : * The MIF representation for pen width is either a value from 1 to 7
8204 : * for a pen width in pixels, or a value from 11 to 2047 for a pen
8205 : * width in points = 10 + (point_width*10)
8206 : **********************************************************************/
8207 10 : int ITABFeaturePen::GetPenWidthMIF()
8208 : {
8209 : return ( m_sPenDef.nPointWidth > 0?
8210 10 : (m_sPenDef.nPointWidth+10): m_sPenDef.nPixelWidth );
8211 : }
8212 :
8213 28 : void ITABFeaturePen::SetPenWidthMIF(int val)
8214 : {
8215 28 : if (val > 10)
8216 : {
8217 0 : m_sPenDef.nPointWidth = MIN((val-10), 2037);
8218 0 : m_sPenDef.nPixelWidth = 0;
8219 : }
8220 : else
8221 : {
8222 28 : m_sPenDef.nPixelWidth = (GByte)MIN(MAX(val, 1), 7);
8223 28 : m_sPenDef.nPointWidth = 0;
8224 : }
8225 28 : }
8226 :
8227 : /**********************************************************************
8228 : * ITABFeaturePen::GetPenStyleString()
8229 : *
8230 : * Return a PEN() string. All representations info for the pen are here.
8231 : **********************************************************************/
8232 7 : const char *ITABFeaturePen::GetPenStyleString()
8233 : {
8234 7 : const char *pszStyle = NULL;
8235 7 : int nOGRStyle = 0;
8236 : char szPattern[20];
8237 :
8238 7 : szPattern[0] = '\0';
8239 :
8240 : // For now, I only add the 25 first styles
8241 7 : switch (GetPenPattern())
8242 : {
8243 : case 1:
8244 0 : nOGRStyle =1;
8245 0 : break;
8246 : case 2:
8247 7 : nOGRStyle = 0;
8248 7 : break;
8249 : case 3:
8250 0 : nOGRStyle = 3;
8251 0 : strcpy(szPattern,"1 1");
8252 0 : break;
8253 : case 4:
8254 0 : nOGRStyle = 3;
8255 0 : strcpy(szPattern,"2 1");
8256 0 : break;
8257 : case 5:
8258 0 : nOGRStyle = 3;
8259 0 : strcpy(szPattern,"3 1");
8260 0 : break;
8261 : case 6:
8262 0 : nOGRStyle = 3;
8263 0 : strcpy(szPattern,"6 1");
8264 0 : break;
8265 : case 7:
8266 0 : nOGRStyle = 4;
8267 0 : strcpy(szPattern,"12 2");
8268 0 : break;
8269 : case 8:
8270 0 : nOGRStyle = 4;
8271 0 : strcpy(szPattern,"24 4");
8272 0 : break;
8273 : case 9:
8274 0 : nOGRStyle = 3;
8275 0 : strcpy(szPattern,"4 3");
8276 0 : break;
8277 : case 10:
8278 0 : nOGRStyle = 5;
8279 0 : strcpy(szPattern,"1 4");
8280 0 : break;
8281 : case 11:
8282 0 : nOGRStyle = 3;
8283 0 : strcpy(szPattern,"4 6");
8284 0 : break;
8285 : case 12:
8286 0 : nOGRStyle = 3;
8287 0 : strcpy(szPattern,"6 4");
8288 0 : break;
8289 : case 13:
8290 0 : nOGRStyle = 4;
8291 0 : strcpy(szPattern,"12 12");
8292 0 : break;
8293 : case 14:
8294 0 : nOGRStyle = 6;
8295 0 : strcpy(szPattern,"8 2 1 2");
8296 0 : break;
8297 : case 15:
8298 0 : nOGRStyle = 6;
8299 0 : strcpy(szPattern,"12 1 1 1");
8300 0 : break;
8301 : case 16:
8302 0 : nOGRStyle = 6;
8303 0 : strcpy(szPattern,"12 1 3 1");
8304 0 : break;
8305 : case 17:
8306 0 : nOGRStyle = 6;
8307 0 : strcpy(szPattern,"24 6 4 6");
8308 0 : break;
8309 : case 18:
8310 0 : nOGRStyle = 7;
8311 0 : strcpy(szPattern,"24 3 3 3 3 3");
8312 0 : break;
8313 : case 19:
8314 0 : nOGRStyle = 7;
8315 0 : strcpy(szPattern,"24 3 3 3 3 3 3 3");
8316 0 : break;
8317 : case 20:
8318 0 : nOGRStyle = 7;
8319 0 : strcpy(szPattern,"6 3 1 3 1 3");
8320 0 : break;
8321 : case 21:
8322 0 : nOGRStyle = 7;
8323 0 : strcpy(szPattern,"12 2 1 2 1 2");
8324 0 : break;
8325 : case 22:
8326 0 : nOGRStyle = 7;
8327 0 : strcpy(szPattern,"12 2 1 2 1 2 1 2");
8328 0 : break;
8329 : case 23:
8330 0 : nOGRStyle = 6;
8331 0 : strcpy(szPattern,"4 1 1 1");
8332 0 : break;
8333 : case 24:
8334 0 : nOGRStyle = 7;
8335 0 : strcpy(szPattern,"4 1 1 1 1");
8336 0 : break;
8337 : case 25:
8338 0 : nOGRStyle = 6;
8339 0 : strcpy(szPattern,"4 1 1 1 2 1 1 1");
8340 0 : break;
8341 :
8342 : default:
8343 0 : nOGRStyle = 0;
8344 : break;
8345 : }
8346 :
8347 7 : if (strlen(szPattern) != 0)
8348 : {
8349 0 : if(m_sPenDef.nPointWidth > 0)
8350 : pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\"mapinfo-pen-%d,"
8351 : "ogr-pen-%d\",p:\"%spx\")",
8352 : ((int)GetPenWidthPoint()),
8353 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
8354 0 : szPattern);
8355 : else
8356 : pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\"mapinfo-pen-%d,"
8357 : "ogr-pen-%d\",p:\"%spx\")",
8358 : GetPenWidthPixel(),
8359 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
8360 0 : szPattern);
8361 : }
8362 : else
8363 : {
8364 7 : if(m_sPenDef.nPointWidth > 0)
8365 : pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\""
8366 : "mapinfo-pen-%d,ogr-pen-%d\")",
8367 : ((int)GetPenWidthPoint()),
8368 0 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
8369 : else
8370 : pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\""
8371 : "mapinfo-pen-%d,ogr-pen-%d\")",
8372 : GetPenWidthPixel(),
8373 7 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
8374 : }
8375 :
8376 7 : return pszStyle;
8377 : }
8378 :
8379 : /**********************************************************************
8380 : * ITABFeaturePen::SetPenFromStyleString()
8381 : *
8382 : * Init the Pen properties from a style string.
8383 : **********************************************************************/
8384 0 : void ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
8385 : {
8386 : int numParts, i;
8387 : GBool bIsNull;
8388 :
8389 : const char *pszPenName, *pszPenPattern;
8390 :
8391 : double nPenWidth;
8392 :
8393 : GInt32 nPenColor;
8394 : const char *pszPenColor;
8395 :
8396 : int nPenId;
8397 : char* pszPenId;
8398 :
8399 : // Use the Style Manager to retreive all the information we need.
8400 0 : OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
8401 : OGRStyleTool *poStylePart;
8402 :
8403 : // Init the StyleMgr with the StyleString.
8404 0 : poStyleMgr->InitStyleString(pszStyleString);
8405 :
8406 : // Retreive the Pen info.
8407 0 : numParts = poStyleMgr->GetPartCount();
8408 0 : for(i=0; i<numParts; i++)
8409 : {
8410 0 : poStylePart = poStyleMgr->GetPart(i);
8411 :
8412 0 : if(poStylePart->GetType() == OGRSTCPen)
8413 : {
8414 0 : break;
8415 : }
8416 : else
8417 : {
8418 0 : delete poStylePart;
8419 0 : poStylePart = NULL;
8420 : }
8421 : }
8422 :
8423 : // If the no Pen found, do nothing.
8424 0 : if(i >= numParts)
8425 : {
8426 0 : delete poStyleMgr;
8427 0 : return;
8428 : }
8429 :
8430 0 : OGRStylePen *poPenStyle = (OGRStylePen*)poStylePart;
8431 :
8432 : // With Pen, we always want to output points or pixels (which are the same,
8433 : // so just use points).
8434 : //
8435 : // It's very important to set the output unit of the feature.
8436 : // The default value is meter. If we don't do it all numerical values
8437 : // will be assumed to be converted from the input unit to meter when we
8438 : // will get them via GetParam...() functions.
8439 : // See OGRStyleTool::Parse() for more details.
8440 0 : poPenStyle->SetUnit(OGRSTUPoints, 1);
8441 :
8442 : // Get the Pen Id or pattern
8443 0 : pszPenName = poPenStyle->Id(bIsNull);
8444 0 : if (bIsNull) pszPenName = NULL;
8445 :
8446 : // Set the width
8447 0 : if(poPenStyle->Width(bIsNull))
8448 : {
8449 0 : nPenWidth = poPenStyle->Width(bIsNull);
8450 : // Width < 10 is a pixel
8451 0 : if(nPenWidth > 10)
8452 0 : SetPenWidthPoint(nPenWidth);
8453 : else
8454 0 : SetPenWidthPixel((GByte)nPenWidth);
8455 : }
8456 :
8457 : //Set the color
8458 0 : pszPenColor = poPenStyle->Color(bIsNull);
8459 0 : if(pszPenColor != NULL)
8460 : {
8461 0 : if(pszPenColor[0] == '#')
8462 0 : pszPenColor++;
8463 : // The Pen color is an Hexa string that need to be convert in a int
8464 0 : nPenColor = strtol(pszPenColor, NULL, 16);
8465 0 : SetPenColor(nPenColor);
8466 : }
8467 :
8468 : // Set the Id of the Pen, use Pattern if necessary.
8469 0 : if(pszPenName &&
8470 : (strstr(pszPenName, "mapinfo-pen-") || strstr(pszPenName, "ogr-pen-")) )
8471 : {
8472 0 : if((pszPenId = (char *) strstr(pszPenName, "mapinfo-pen-")))
8473 : {
8474 0 : nPenId = atoi(pszPenId+12);
8475 0 : SetPenPattern((GByte)nPenId);
8476 : }
8477 0 : else if((pszPenId = (char *) strstr(pszPenName, "ogr-pen-")))
8478 : {
8479 0 : nPenId = atoi(pszPenId+8);
8480 0 : if(nPenId == 0)
8481 0 : nPenId = 2;
8482 0 : SetPenPattern((GByte)nPenId);
8483 : }
8484 : }
8485 : else
8486 : {
8487 : // If no Pen Id, use the Pen Pattern to retreive the Id.
8488 0 : pszPenPattern = poPenStyle->Pattern(bIsNull);
8489 0 : if (bIsNull)
8490 0 : pszPenPattern = NULL;
8491 : else
8492 : {
8493 0 : if(strcmp(pszPenPattern, "1 1") == 0)
8494 0 : SetPenPattern(3);
8495 0 : else if(strcmp(pszPenPattern, "2 1") == 0)
8496 0 : SetPenPattern(4);
8497 0 : else if(strcmp(pszPenPattern, "3 1") == 0)
8498 0 : SetPenPattern(5);
8499 0 : else if(strcmp(pszPenPattern, "6 1") == 0)
8500 0 : SetPenPattern(6);
8501 0 : else if(strcmp(pszPenPattern, "12 2") == 0)
8502 0 : SetPenPattern(7);
8503 0 : else if(strcmp(pszPenPattern, "24 4") == 0)
8504 0 : SetPenPattern(8);
8505 0 : else if(strcmp(pszPenPattern, "4 3") == 0)
8506 0 : SetPenPattern(9);
8507 0 : else if(strcmp(pszPenPattern, "1 4") == 0)
8508 0 : SetPenPattern(10);
8509 0 : else if(strcmp(pszPenPattern, "4 6") == 0)
8510 0 : SetPenPattern(11);
8511 0 : else if(strcmp(pszPenPattern, "6 4") == 0)
8512 0 : SetPenPattern(12);
8513 0 : else if(strcmp(pszPenPattern, "12 12") == 0)
8514 0 : SetPenPattern(13);
8515 0 : else if(strcmp(pszPenPattern, "8 2 1 2") == 0)
8516 0 : SetPenPattern(14);
8517 0 : else if(strcmp(pszPenPattern, "12 1 1 1") == 0)
8518 0 : SetPenPattern(15);
8519 0 : else if(strcmp(pszPenPattern, "12 1 3 1") == 0)
8520 0 : SetPenPattern(16);
8521 0 : else if(strcmp(pszPenPattern, "24 6 4 6") == 0)
8522 0 : SetPenPattern(17);
8523 0 : else if(strcmp(pszPenPattern, "24 3 3 3 3 3") == 0)
8524 0 : SetPenPattern(18);
8525 0 : else if(strcmp(pszPenPattern, "24 3 3 3 3 3 3 3") == 0)
8526 0 : SetPenPattern(19);
8527 0 : else if(strcmp(pszPenPattern, "6 3 1 3 1 3") == 0)
8528 0 : SetPenPattern(20);
8529 0 : else if(strcmp(pszPenPattern, "12 2 1 2 1 2") == 0)
8530 0 : SetPenPattern(21);
8531 0 : else if(strcmp(pszPenPattern, "12 2 1 2 1 2 1 2") == 0)
8532 0 : SetPenPattern(22);
8533 0 : else if(strcmp(pszPenPattern, "4 1 1 1") == 0)
8534 0 : SetPenPattern(23);
8535 0 : else if(strcmp(pszPenPattern, "4 1 1 1 1") == 0)
8536 0 : SetPenPattern(24);
8537 0 : else if(strcmp(pszPenPattern, "4 1 1 1 2 1 1 1") == 0)
8538 0 : SetPenPattern(25);
8539 : }
8540 : }
8541 :
8542 0 : delete poStyleMgr;
8543 0 : delete poStylePart;
8544 :
8545 0 : return;
8546 : }
8547 :
8548 : /**********************************************************************
8549 : * ITABFeaturePen::DumpPenDef()
8550 : *
8551 : * Dump pen definition information.
8552 : **********************************************************************/
8553 0 : void ITABFeaturePen::DumpPenDef(FILE *fpOut /*=NULL*/)
8554 : {
8555 0 : if (fpOut == NULL)
8556 0 : fpOut = stdout;
8557 :
8558 0 : fprintf(fpOut, " m_nPenDefIndex = %d\n", m_nPenDefIndex);
8559 0 : fprintf(fpOut, " m_sPenDef.nRefCount = %d\n", m_sPenDef.nRefCount);
8560 0 : fprintf(fpOut, " m_sPenDef.nPixelWidth = %d\n", m_sPenDef.nPixelWidth);
8561 0 : fprintf(fpOut, " m_sPenDef.nLinePattern = %d\n", m_sPenDef.nLinePattern);
8562 0 : fprintf(fpOut, " m_sPenDef.nPointWidth = %d\n", m_sPenDef.nPointWidth);
8563 : fprintf(fpOut, " m_sPenDef.rgbColor = 0x%6.6x (%d)\n",
8564 0 : m_sPenDef.rgbColor, m_sPenDef.rgbColor);
8565 :
8566 0 : fflush(fpOut);
8567 0 : }
8568 :
8569 : /*=====================================================================
8570 : * class ITABFeatureBrush
8571 : *====================================================================*/
8572 :
8573 : /**********************************************************************
8574 : * ITABFeatureBrush::ITABFeatureBrush()
8575 : **********************************************************************/
8576 :
8577 100 : ITABFeatureBrush::ITABFeatureBrush()
8578 : {
8579 : static const TABBrushDef csDefaultBrush = MITAB_BRUSH_DEFAULT;
8580 :
8581 100 : m_nBrushDefIndex=-1;
8582 :
8583 : /* MI default is BRUSH(2,16777215,16777215) */
8584 100 : m_sBrushDef = csDefaultBrush;
8585 100 : }
8586 :
8587 :
8588 : /**********************************************************************
8589 : * ITABFeatureBrush::GetBrushStyleString()
8590 : *
8591 : * Return a Brush() string. All representations info for the Brush are here.
8592 : **********************************************************************/
8593 7 : const char *ITABFeatureBrush::GetBrushStyleString()
8594 : {
8595 7 : const char *pszStyle = NULL;
8596 7 : int nOGRStyle = 0;
8597 : char szPattern[20];
8598 :
8599 7 : szPattern[0] = '\0';
8600 :
8601 7 : if (m_sBrushDef.nFillPattern == 1)
8602 7 : nOGRStyle = 1;
8603 0 : else if (m_sBrushDef.nFillPattern == 3)
8604 0 : nOGRStyle = 2;
8605 0 : else if (m_sBrushDef.nFillPattern == 4)
8606 0 : nOGRStyle = 3;
8607 0 : else if (m_sBrushDef.nFillPattern == 5)
8608 0 : nOGRStyle = 5;
8609 0 : else if (m_sBrushDef.nFillPattern == 6)
8610 0 : nOGRStyle = 4;
8611 0 : else if (m_sBrushDef.nFillPattern == 7)
8612 0 : nOGRStyle = 6;
8613 0 : else if (m_sBrushDef.nFillPattern == 8)
8614 0 : nOGRStyle = 7;
8615 :
8616 :
8617 7 : if (GetBrushTransparent())
8618 : {
8619 : /* Omit BG Color for transparent brushes */
8620 : pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
8621 : m_sBrushDef.rgbFGColor,
8622 0 : m_sBrushDef.nFillPattern,nOGRStyle);
8623 : }
8624 : else
8625 : {
8626 : pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,bc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
8627 : m_sBrushDef.rgbFGColor,
8628 : m_sBrushDef.rgbBGColor,
8629 7 : m_sBrushDef.nFillPattern,nOGRStyle);
8630 : }
8631 :
8632 7 : return pszStyle;
8633 :
8634 : }
8635 :
8636 :
8637 : /**********************************************************************
8638 : * ITABFeatureBrush::SetBrushFromStyleString()
8639 : *
8640 : * Set all Brush elements from a StyleString.
8641 : * Use StyleMgr to do so.
8642 : **********************************************************************/
8643 0 : void ITABFeatureBrush::SetBrushFromStyleString(const char *pszStyleString)
8644 : {
8645 : int numParts, i;
8646 : GBool bIsNull;
8647 :
8648 : const char *pszBrushId;
8649 : int nBrushId;
8650 :
8651 : const char *pszBrushColor;
8652 : int nBrushColor;
8653 :
8654 : // Use the Style Manager to retreive all the information we need.
8655 0 : OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
8656 : OGRStyleTool *poStylePart;
8657 :
8658 : // Init the StyleMgr with the StyleString.
8659 0 : poStyleMgr->InitStyleString(pszStyleString);
8660 :
8661 : // Retreive the Brush info.
8662 0 : numParts = poStyleMgr->GetPartCount();
8663 0 : for(i=0; i<numParts; i++)
8664 : {
8665 0 : poStylePart = poStyleMgr->GetPart(i);
8666 :
8667 0 : if(poStylePart->GetType() == OGRSTCBrush)
8668 : {
8669 0 : break;
8670 : }
8671 : else
8672 : {
8673 0 : delete poStylePart;
8674 0 : poStylePart = NULL;
8675 : }
8676 : }
8677 :
8678 : // If the no Brush found, do nothing.
8679 0 : if(i >= numParts)
8680 : {
8681 0 : delete poStyleMgr;
8682 0 : return;
8683 : }
8684 :
8685 0 : OGRStyleBrush *poBrushStyle = (OGRStyleBrush*)poStylePart;
8686 :
8687 : // Set the Brush Id (FillPattern)
8688 0 : pszBrushId = poBrushStyle->Id(bIsNull);
8689 0 : if(bIsNull) pszBrushId = NULL;
8690 :
8691 0 : if(pszBrushId &&
8692 : (strstr(pszBrushId, "mapinfo-brush-") ||
8693 : strstr(pszBrushId, "ogr-brush-")) )
8694 : {
8695 0 : if(strstr(pszBrushId, "mapinfo-brush-"))
8696 : {
8697 0 : nBrushId = atoi(pszBrushId+14);
8698 0 : SetBrushPattern((GByte)nBrushId);
8699 : }
8700 0 : else if(strstr(pszBrushId, "ogr-brush-"))
8701 : {
8702 0 : nBrushId = atoi(pszBrushId+10);
8703 0 : if(nBrushId > 1)
8704 0 : nBrushId++;
8705 0 : SetBrushPattern((GByte)nBrushId);
8706 : }
8707 : }
8708 :
8709 : // Set the BackColor, if not set, then it's transparent
8710 0 : pszBrushColor = poBrushStyle->BackColor(bIsNull);
8711 0 : if(bIsNull) pszBrushColor = NULL;
8712 :
8713 0 : if(pszBrushColor)
8714 : {
8715 0 : if(pszBrushColor[0] == '#')
8716 0 : pszBrushColor++;
8717 0 : nBrushColor = strtol(pszBrushColor, NULL, 16);
8718 0 : SetBrushBGColor((GInt32)nBrushColor);
8719 : }
8720 : else
8721 : {
8722 0 : SetBrushTransparent(1);
8723 : }
8724 :
8725 : // Set the ForeColor
8726 0 : pszBrushColor = poBrushStyle->ForeColor(bIsNull);
8727 0 : if(bIsNull) pszBrushColor = NULL;
8728 :
8729 0 : if(pszBrushColor)
8730 : {
8731 0 : if(pszBrushColor[0] == '#')
8732 0 : pszBrushColor++;
8733 0 : nBrushColor = strtol(pszBrushColor, NULL, 16);
8734 0 : SetBrushFGColor((GInt32)nBrushColor);
8735 : }
8736 :
8737 0 : delete poStyleMgr;
8738 0 : delete poStylePart;
8739 :
8740 0 : return;
8741 : }
8742 :
8743 : /**********************************************************************
8744 : * ITABFeatureBrush::DumpBrushDef()
8745 : *
8746 : * Dump Brush definition information.
8747 : **********************************************************************/
8748 0 : void ITABFeatureBrush::DumpBrushDef(FILE *fpOut /*=NULL*/)
8749 : {
8750 0 : if (fpOut == NULL)
8751 0 : fpOut = stdout;
8752 :
8753 0 : fprintf(fpOut, " m_nBrushDefIndex = %d\n", m_nBrushDefIndex);
8754 0 : fprintf(fpOut, " m_sBrushDef.nRefCount = %d\n", m_sBrushDef.nRefCount);
8755 : fprintf(fpOut, " m_sBrushDef.nFillPattern = %d\n",
8756 0 : (int)m_sBrushDef.nFillPattern);
8757 : fprintf(fpOut, " m_sBrushDef.bTransparentFill = %d\n",
8758 0 : (int)m_sBrushDef.bTransparentFill);
8759 : fprintf(fpOut, " m_sBrushDef.rgbFGColor = 0x%6.6x (%d)\n",
8760 0 : m_sBrushDef.rgbFGColor, m_sBrushDef.rgbFGColor);
8761 : fprintf(fpOut, " m_sBrushDef.rgbBGColor = 0x%6.6x (%d)\n",
8762 0 : m_sBrushDef.rgbBGColor, m_sBrushDef.rgbBGColor);
8763 :
8764 0 : fflush(fpOut);
8765 0 : }
8766 :
8767 : /*=====================================================================
8768 : * class ITABFeatureFont
8769 : *====================================================================*/
8770 :
8771 : /**********************************************************************
8772 : * ITABFeatureFont::ITABFeatureFont()
8773 : **********************************************************************/
8774 :
8775 0 : ITABFeatureFont::ITABFeatureFont()
8776 : {
8777 : static const TABFontDef csDefaultFont = MITAB_FONT_DEFAULT;
8778 :
8779 0 : m_nFontDefIndex=-1;
8780 :
8781 : /* MI default is Font("Arial",0,0,0) */
8782 0 : m_sFontDef = csDefaultFont;
8783 0 : }
8784 :
8785 : /**********************************************************************
8786 : * ITABFeatureFont::SetFontName()
8787 : **********************************************************************/
8788 0 : void ITABFeatureFont::SetFontName(const char *pszName)
8789 : {
8790 0 : strncpy( m_sFontDef.szFontName, pszName, 32);
8791 0 : m_sFontDef.szFontName[32] = '\0';
8792 0 : }
8793 :
8794 : /**********************************************************************
8795 : * ITABFeatureFont::DumpFontDef()
8796 : *
8797 : * Dump Font definition information.
8798 : **********************************************************************/
8799 0 : void ITABFeatureFont::DumpFontDef(FILE *fpOut /*=NULL*/)
8800 : {
8801 0 : if (fpOut == NULL)
8802 0 : fpOut = stdout;
8803 :
8804 0 : fprintf(fpOut, " m_nFontDefIndex = %d\n", m_nFontDefIndex);
8805 0 : fprintf(fpOut, " m_sFontDef.nRefCount = %d\n", m_sFontDef.nRefCount);
8806 0 : fprintf(fpOut, " m_sFontDef.szFontName = '%s'\n", m_sFontDef.szFontName);
8807 :
8808 0 : fflush(fpOut);
8809 0 : }
8810 :
8811 :
8812 : /*=====================================================================
8813 : * class ITABFeatureSymbol
8814 : *====================================================================*/
8815 :
8816 : /**********************************************************************
8817 : * ITABFeatureSymbol::ITABFeatureSymbol()
8818 : **********************************************************************/
8819 :
8820 8 : ITABFeatureSymbol::ITABFeatureSymbol()
8821 : {
8822 : static const TABSymbolDef csDefaultSymbol = MITAB_SYMBOL_DEFAULT;
8823 :
8824 8 : m_nSymbolDefIndex=-1;
8825 :
8826 : /* MI default is Symbol(35,0,12) */
8827 8 : m_sSymbolDef = csDefaultSymbol;
8828 8 : }
8829 :
8830 : /**********************************************************************
8831 : * ITABFeatureSymbol::GetSymbolStyleString()
8832 : *
8833 : * Return a Symbol() string. All representations info for the Symbol are here.
8834 : **********************************************************************/
8835 0 : const char *ITABFeatureSymbol::GetSymbolStyleString(double dfAngle)
8836 : {
8837 0 : const char *pszStyle = NULL;
8838 0 : int nOGRStyle = 1;
8839 : char szPattern[20];
8840 0 : int nAngle = 0;
8841 :
8842 0 : szPattern[0] = '\0';
8843 :
8844 0 : if (m_sSymbolDef.nSymbolNo == 31)
8845 0 : nOGRStyle = 0;
8846 0 : else if (m_sSymbolDef.nSymbolNo == 32)
8847 0 : nOGRStyle = 6;
8848 0 : else if (m_sSymbolDef.nSymbolNo == 33)
8849 : {
8850 0 : nAngle = 45;
8851 0 : nOGRStyle = 6;
8852 : }
8853 0 : else if (m_sSymbolDef.nSymbolNo == 34)
8854 0 : nOGRStyle = 4;
8855 0 : else if (m_sSymbolDef.nSymbolNo == 35)
8856 0 : nOGRStyle = 10;
8857 0 : else if (m_sSymbolDef.nSymbolNo == 36)
8858 0 : nOGRStyle = 8;
8859 0 : else if (m_sSymbolDef.nSymbolNo == 37)
8860 : {
8861 0 : nAngle = 180;
8862 0 : nOGRStyle = 8;
8863 : }
8864 0 : else if (m_sSymbolDef.nSymbolNo == 38)
8865 0 : nOGRStyle = 5;
8866 0 : else if (m_sSymbolDef.nSymbolNo == 39)
8867 : {
8868 0 : nAngle = 45;
8869 0 : nOGRStyle = 5;
8870 : }
8871 0 : else if (m_sSymbolDef.nSymbolNo == 40)
8872 0 : nOGRStyle = 3;
8873 0 : else if (m_sSymbolDef.nSymbolNo == 41)
8874 0 : nOGRStyle = 9;
8875 0 : else if (m_sSymbolDef.nSymbolNo == 42)
8876 0 : nOGRStyle = 7;
8877 0 : else if (m_sSymbolDef.nSymbolNo == 43)
8878 : {
8879 0 : nAngle = 180;
8880 0 : nOGRStyle = 7;
8881 : }
8882 0 : else if (m_sSymbolDef.nSymbolNo == 44)
8883 0 : nOGRStyle = 6;
8884 0 : else if (m_sSymbolDef.nSymbolNo == 45)
8885 0 : nOGRStyle = 8;
8886 0 : else if (m_sSymbolDef.nSymbolNo == 46)
8887 0 : nOGRStyle = 4;
8888 0 : else if (m_sSymbolDef.nSymbolNo == 49)
8889 0 : nOGRStyle = 1;
8890 0 : else if (m_sSymbolDef.nSymbolNo == 50)
8891 0 : nOGRStyle = 2;
8892 :
8893 0 : nAngle += (int)dfAngle;
8894 :
8895 : pszStyle=CPLSPrintf("SYMBOL(a:%d,c:#%6.6x,s:%dpt,id:\"mapinfo-sym-%d,ogr-sym-%d\")",
8896 : nAngle,
8897 : m_sSymbolDef.rgbColor,
8898 : m_sSymbolDef.nPointSize,
8899 : m_sSymbolDef.nSymbolNo,
8900 0 : nOGRStyle);
8901 :
8902 0 : return pszStyle;
8903 :
8904 : }
8905 :
8906 : /**********************************************************************
8907 : * ITABFeatureSymbol::SetSymbolFromStyleString()
8908 : *
8909 : * Set all Symbol var from a StyleString. Use StyleMgr to do so.
8910 : **********************************************************************/
8911 0 : void ITABFeatureSymbol::SetSymbolFromStyleString(const char *pszStyleString)
8912 : {
8913 : int numParts, i;
8914 : GBool bIsNull;
8915 :
8916 : const char *pszSymbolId;
8917 : int nSymbolId;
8918 :
8919 : const char *pszSymbolColor;
8920 : int nSymbolColor;
8921 :
8922 : double dSymbolSize;
8923 :
8924 : // Use the Style Manager to retreive all the information we need.
8925 0 : OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
8926 : OGRStyleTool *poStylePart;
8927 :
8928 : // Init the StyleMgr with the StyleString.
8929 0 : poStyleMgr->InitStyleString(pszStyleString);
8930 :
8931 : // Retreive the Symbol info.
8932 0 : numParts = poStyleMgr->GetPartCount();
8933 0 : for(i=0; i<numParts; i++)
8934 : {
8935 0 : poStylePart = poStyleMgr->GetPart(i);
8936 :
8937 0 : if(poStylePart->GetType() == OGRSTCSymbol)
8938 : {
8939 0 : break;
8940 : }
8941 : else
8942 : {
8943 0 : delete poStylePart;
8944 0 : poStylePart = NULL;
8945 : }
8946 : }
8947 :
8948 : // If the no Symbol found, do nothing.
8949 0 : if(i >= numParts)
8950 : {
8951 0 : delete poStyleMgr;
8952 0 : return;
8953 : }
8954 :
8955 0 : OGRStyleSymbol *poSymbolStyle = (OGRStyleSymbol*)poStylePart;
8956 :
8957 : // With Symbol, we always want to output points
8958 : //
8959 : // It's very important to set the output unit of the feature.
8960 : // The default value is meter. If we don't do it all numerical values
8961 : // will be assumed to be converted from the input unit to meter when we
8962 : // will get them via GetParam...() functions.
8963 : // See OGRStyleTool::Parse() for more details.
8964 0 : poSymbolStyle->SetUnit(OGRSTUPoints, (72.0 * 39.37));
8965 :
8966 : // Set the Symbol Id (SymbolNo)
8967 0 : pszSymbolId = poSymbolStyle->Id(bIsNull);
8968 0 : if(bIsNull) pszSymbolId = NULL;
8969 :
8970 0 : if(pszSymbolId &&
8971 : (strstr(pszSymbolId, "mapinfo-sym-") ||
8972 : strstr(pszSymbolId, "ogr-sym-")) )
8973 : {
8974 0 : if(strstr(pszSymbolId, "mapinfo-sym-"))
8975 : {
8976 0 : nSymbolId = atoi(pszSymbolId+12);
8977 0 : SetSymbolNo((GByte)nSymbolId);
8978 : }
8979 0 : else if(strstr(pszSymbolId, "ogr-sym-"))
8980 : {
8981 0 : nSymbolId = atoi(pszSymbolId+8);
8982 :
8983 : // The OGR symbol is not the MapInfo one
8984 : // Here's some mapping
8985 0 : switch (nSymbolId)
8986 : {
8987 : case 0:
8988 0 : SetSymbolNo(31);
8989 0 : break;
8990 : case 1:
8991 0 : SetSymbolNo(49);
8992 0 : break;
8993 : case 2:
8994 0 : SetSymbolNo(50);
8995 0 : break;
8996 : case 3:
8997 0 : SetSymbolNo(40);
8998 0 : break;
8999 : case 4:
9000 0 : SetSymbolNo(34);
9001 0 : break;
9002 : case 5:
9003 0 : SetSymbolNo(38);
9004 0 : break;
9005 : case 6:
9006 0 : SetSymbolNo(32);
9007 0 : break;
9008 : case 7:
9009 0 : SetSymbolNo(42);
9010 0 : break;
9011 : case 8:
9012 0 : SetSymbolNo(36);
9013 0 : break;
9014 : case 9:
9015 0 : SetSymbolNo(41);
9016 0 : break;
9017 : case 10:
9018 0 : SetSymbolNo(35);
9019 : break;
9020 : }
9021 : }
9022 : }
9023 :
9024 : // Set SymbolSize
9025 0 : dSymbolSize = poSymbolStyle->Size(bIsNull);
9026 0 : if(dSymbolSize)
9027 : {
9028 0 : SetSymbolSize((GInt16)dSymbolSize);
9029 : }
9030 :
9031 : // Set Symbol Color
9032 0 : pszSymbolColor = poSymbolStyle->Color(bIsNull);
9033 0 : if(pszSymbolColor)
9034 : {
9035 0 : if(pszSymbolColor[0] == '#')
9036 0 : pszSymbolColor++;
9037 0 : nSymbolColor = strtol(pszSymbolColor, NULL, 16);
9038 0 : SetSymbolColor((GInt32)nSymbolColor);
9039 : }
9040 :
9041 0 : delete poStyleMgr;
9042 0 : delete poStylePart;
9043 :
9044 0 : return;
9045 : }
9046 :
9047 : /**********************************************************************
9048 : * ITABFeatureSymbol::DumpSymbolDef()
9049 : *
9050 : * Dump Symbol definition information.
9051 : **********************************************************************/
9052 0 : void ITABFeatureSymbol::DumpSymbolDef(FILE *fpOut /*=NULL*/)
9053 : {
9054 0 : if (fpOut == NULL)
9055 0 : fpOut = stdout;
9056 :
9057 0 : fprintf(fpOut, " m_nSymbolDefIndex = %d\n", m_nSymbolDefIndex);
9058 0 : fprintf(fpOut, " m_sSymbolDef.nRefCount = %d\n", m_sSymbolDef.nRefCount);
9059 0 : fprintf(fpOut, " m_sSymbolDef.nSymbolNo = %d\n", m_sSymbolDef.nSymbolNo);
9060 0 : fprintf(fpOut, " m_sSymbolDef.nPointSize = %d\n",m_sSymbolDef.nPointSize);
9061 : fprintf(fpOut, " m_sSymbolDef._unknown_ = %d\n",
9062 0 : (int)m_sSymbolDef._nUnknownValue_);
9063 : fprintf(fpOut, " m_sSymbolDef.rgbColor = 0x%6.6x (%d)\n",
9064 0 : m_sSymbolDef.rgbColor, m_sSymbolDef.rgbColor);
9065 :
9066 0 : fflush(fpOut);
9067 0 : }
|