1 : /**********************************************************************
2 : * $Id: mitab_feature.cpp,v 1.94 2008/11/18 16:47:44 dmorissette 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.94 2008/11/18 16:47:44 dmorissette
34 : * Fixed compile warning when MITAB_USE_OFTDATETIME is set
35 : *
36 : * Revision 1.93 2008/11/17 22:06:21 aboudreault
37 : * Added support to use OFTDateTime/OFTDate/OFTTime type when compiled with
38 : * OGR and fixed reading/writing support for these types.
39 : *
40 : * Revision 1.92 2008/07/29 13:06:17 aboudreault
41 : * Added Font Point styles support (halo, border) (bug 1925)
42 : *
43 : * Revision 1.91 2008/07/21 19:23:03 aboudreault
44 : * Fixed another small error with expanded text.
45 : *
46 : * Revision 1.90 2008/07/21 18:17:19 dmorissette
47 : * Fixed a few compile warnings
48 : *
49 : * Revision 1.89 2008/07/21 17:59:28 aboudreault
50 : * Fixed error in GetLabelStyleString() function: when text style expanded is
51 : * set, no space is needed after the last char.
52 : *
53 : * Revision 1.88 2008/07/21 14:09:41 aboudreault
54 : * Add font text styles support (bold, italic, etc.) (bug 1922)
55 : *
56 : * Revision 1.87 2008/07/17 14:09:30 aboudreault
57 : * Add text outline color support (halo background in MapInfo)
58 : *
59 : * Revision 1.86 2008/07/14 17:51:21 aboudreault
60 : * Fixed the text font size problem (bug 1918)
61 : *
62 : * Revision 1.85 2008/07/14 16:09:10 aboudreault
63 : * Fixed multi-line text height problem (bug 1919)
64 : *
65 : * Revision 1.84 2008/07/14 14:39:52 aboudreault
66 : * Fixed multi-line text rendering by adding support of the end of line char
67 : * "\n" as well as the "\\n".
68 : *
69 : * Revision 1.83 2008/07/01 14:33:17 aboudreault
70 : * * Fixed deprecated warnings generated by mitab.h by moving SetFontName to
71 : * mitab_feature.cpp.
72 : *
73 : * Revision 1.82 2008/02/22 20:20:44 dmorissette
74 : * Fixed the internal compressed coordinate range detection test to prevent
75 : * possible overflow of the compressed integer coordinate values leading
76 : * to some coord. errors in very rare cases while writing to TAB (bug 1854)
77 : *
78 : * Revision 1.81 2008/02/20 21:35:30 dmorissette
79 : * Added support for V800 COLLECTION of large objects (bug 1496)
80 : *
81 : * Revision 1.80 2008/02/05 22:22:48 dmorissette
82 : * Added support for TAB_GEOM_V800_MULTIPOINT (bug 1496)
83 : *
84 : * Revision 1.79 2008/02/01 19:36:31 dmorissette
85 : * Initial support for V800 REGION and MULTIPLINE (bug 1496)
86 : *
87 : * Revision 1.78 2008/01/29 20:46:32 dmorissette
88 : * Added support for v9 Time and DateTime fields (byg 1754)
89 : *
90 : * Revision 1.77 2007/12/11 04:21:54 dmorissette
91 : * Fixed leaks in ITABFeature???::Set???FromStyleString() (GDAL ticket 1696)
92 : *
93 : * Revision 1.76 2007/09/18 17:43:56 dmorissette
94 : * Fixed another index splitting issue: compr coordinates origin was not
95 : * stored in the TABFeature in ReadGeometry... (bug 1732)
96 : *
97 : * Revision 1.75 2007/09/14 19:29:24 dmorissette
98 : * Completed handling of bCoordBlockDataOnly arg to Read/WriteGeometry()
99 : * functions to avoid screwing up pen/brush ref counters (bug 1732)
100 : *
101 : * Revision 1.74 2007/09/14 18:30:19 dmorissette
102 : * Fixed the splitting of object blocks with the optimized spatial
103 : * index mode that was producing files with misaligned bytes that
104 : * confused MapInfo (bug 1732)
105 : *
106 : * Revision 1.73 2007/09/12 20:22:31 dmorissette
107 : * Added TABFeature::CreateFromMapInfoType()
108 : *
109 : * Revision 1.72 2007/06/12 14:17:16 dmorissette
110 : * Added TABFile::TwoPointLineAsPolyline() to allow writing two point lines
111 : * as polylines (bug 1735)
112 : *
113 : * Revision 1.71 2007/06/11 17:57:06 dmorissette
114 : * Removed stray calls to poMapFile->GetCurObjBlock()
115 : *
116 : * Revision 1.70 2007/06/11 14:52:30 dmorissette
117 : * Return a valid m_nCoordDatasize value for Collection objects to prevent
118 : * trashing of collection data during object splitting (bug 1728)
119 : *
120 : * Revision 1.69 2007/02/28 20:41:40 dmorissette
121 : * Added missing NULL pointer checks in SetPenFromStyleString(),
122 : * SetBrushFromStyleString() and SetSymbolFromStyleString() (bug 1670)
123 : *
124 : * Revision 1.68 2007/02/22 18:35:53 dmorissette
125 : * Fixed problem writing collections where MITAB was sometimes trying to
126 : * read past EOF in write mode (bug 1657).
127 : *
128 : * Revision 1.67 2006/11/28 18:49:07 dmorissette
129 : * Completed changes to split TABMAPObjectBlocks properly and produce an
130 : * optimal spatial index (bug 1585)
131 : *
132 : * Revision 1.66 2006/10/17 14:34:31 dmorissette
133 : * Fixed problem with null brush bg color (bug 1603)
134 : *
135 : * Revision 1.65 2006/07/25 13:22:58 dmorissette
136 : * Fixed initialization of MBR of TABCollection members (bug 1520)
137 : *
138 : * Revision 1.64 2006/06/29 19:49:35 dmorissette
139 : * Fixed problem writing PLINE MULTIPLE to TAB format introduced in
140 : * MITAB 1.5.0 (bug 1466).
141 : *
142 : * Revision 1.63 2006/02/08 05:02:57 dmorissette
143 : * Fixed crash when attempting to write TABPolyline object with an invalid
144 : * geometry (GDAL bug 1059)
145 : *
146 : * ...
147 : *
148 : * Revision 1.1 1999/07/12 04:18:24 daniel
149 : * Initial checkin
150 : *
151 : **********************************************************************/
152 :
153 : #include "mitab.h"
154 : #include "mitab_utils.h"
155 : #include "mitab_geometry.h"
156 :
157 : /*=====================================================================
158 : * class TABFeature
159 : *====================================================================*/
160 :
161 :
162 : /**********************************************************************
163 : * TABFeature::TABFeature()
164 : *
165 : * Constructor.
166 : **********************************************************************/
167 130 : TABFeature::TABFeature(OGRFeatureDefn *poDefnIn):
168 130 : OGRFeature(poDefnIn)
169 : {
170 130 : m_nMapInfoType = TAB_GEOM_NONE;
171 130 : m_bDeletedFlag = FALSE;
172 :
173 130 : SetMBR(0.0, 0.0, 0.0, 0.0);
174 130 : }
175 :
176 : /**********************************************************************
177 : * TABFeature::~TABFeature()
178 : *
179 : * Destructor.
180 : **********************************************************************/
181 130 : TABFeature::~TABFeature()
182 : {
183 130 : }
184 :
185 :
186 : /**********************************************************************
187 : * TABFeature::CreateFromMapInfoType()
188 : *
189 : * Factory that creates a TABFeature of the right class for the specified
190 : * MapInfo Type
191 : *
192 : **********************************************************************/
193 : TABFeature *TABFeature::CreateFromMapInfoType(int nMapInfoType,
194 53 : OGRFeatureDefn *poDefn)
195 : {
196 53 : TABFeature *poFeature = NULL;
197 :
198 : /*-----------------------------------------------------------------
199 : * Create new feature object of the right type
200 : *----------------------------------------------------------------*/
201 53 : switch(nMapInfoType)
202 : {
203 : case TAB_GEOM_NONE:
204 1 : poFeature = new TABFeature(poDefn);
205 1 : break;
206 : case TAB_GEOM_SYMBOL_C:
207 : case TAB_GEOM_SYMBOL:
208 0 : poFeature = new TABPoint(poDefn);
209 0 : break;
210 : case TAB_GEOM_FONTSYMBOL_C:
211 : case TAB_GEOM_FONTSYMBOL:
212 0 : poFeature = new TABFontPoint(poDefn);
213 0 : break;
214 : case TAB_GEOM_CUSTOMSYMBOL_C:
215 : case TAB_GEOM_CUSTOMSYMBOL:
216 0 : poFeature = new TABCustomPoint(poDefn);
217 0 : break;
218 : case TAB_GEOM_LINE_C:
219 : case TAB_GEOM_LINE:
220 : case TAB_GEOM_PLINE_C:
221 : case TAB_GEOM_PLINE:
222 : case TAB_GEOM_MULTIPLINE_C:
223 : case TAB_GEOM_MULTIPLINE:
224 : case TAB_GEOM_V450_MULTIPLINE_C:
225 : case TAB_GEOM_V450_MULTIPLINE:
226 : case TAB_GEOM_V800_MULTIPLINE_C:
227 : case TAB_GEOM_V800_MULTIPLINE:
228 1 : poFeature = new TABPolyline(poDefn);
229 1 : break;
230 : case TAB_GEOM_ARC_C:
231 : case TAB_GEOM_ARC:
232 0 : poFeature = new TABArc(poDefn);
233 0 : break;
234 :
235 : case TAB_GEOM_REGION_C:
236 : case TAB_GEOM_REGION:
237 : case TAB_GEOM_V450_REGION_C:
238 : case TAB_GEOM_V450_REGION:
239 : case TAB_GEOM_V800_REGION_C:
240 : case TAB_GEOM_V800_REGION:
241 51 : poFeature = new TABRegion(poDefn);
242 51 : break;
243 : case TAB_GEOM_RECT_C:
244 : case TAB_GEOM_RECT:
245 : case TAB_GEOM_ROUNDRECT_C:
246 : case TAB_GEOM_ROUNDRECT:
247 0 : poFeature = new TABRectangle(poDefn);
248 0 : break;
249 : case TAB_GEOM_ELLIPSE_C:
250 : case TAB_GEOM_ELLIPSE:
251 0 : poFeature = new TABEllipse(poDefn);
252 0 : break;
253 : case TAB_GEOM_TEXT_C:
254 : case TAB_GEOM_TEXT:
255 0 : poFeature = new TABText(poDefn);
256 0 : break;
257 : case TAB_GEOM_MULTIPOINT_C:
258 : case TAB_GEOM_MULTIPOINT:
259 : case TAB_GEOM_V800_MULTIPOINT_C:
260 : case TAB_GEOM_V800_MULTIPOINT:
261 0 : poFeature = new TABMultiPoint(poDefn);
262 0 : break;
263 : case TAB_GEOM_COLLECTION_C:
264 : case TAB_GEOM_COLLECTION:
265 : case TAB_GEOM_V800_COLLECTION_C:
266 : case TAB_GEOM_V800_COLLECTION:
267 0 : poFeature = new TABCollection(poDefn);
268 0 : break;
269 : default:
270 : /*-------------------------------------------------------------
271 : * Unsupported feature type... we still return a valid feature
272 : * with NONE geometry after producing a Warning.
273 : * Callers can trap that case by checking CPLGetLastErrorNo()
274 : * against TAB_WarningFeatureTypeNotSupported
275 : *------------------------------------------------------------*/
276 : // poFeature = new TABDebugFeature(poDefn);
277 0 : poFeature = new TABFeature(poDefn);
278 :
279 : CPLError(CE_Warning, TAB_WarningFeatureTypeNotSupported,
280 : "Unsupported object type %d (0x%2.2x). Feature will be "
281 : "returned with NONE geometry.",
282 0 : nMapInfoType, nMapInfoType);
283 : }
284 :
285 53 : return poFeature;
286 : }
287 :
288 :
289 : /**********************************************************************
290 : * TABFeature::CopyTABFeatureBase()
291 : *
292 : * Used by CloneTABFeature() to copy the basic (fields, geometry, etc.)
293 : * TABFeature members.
294 : *
295 : * The newly created feature is owned by the caller, and will have it's own
296 : * reference to the OGRFeatureDefn.
297 : *
298 : * It is possible to create the clone with a different OGRFeatureDefn,
299 : * in this case, the fields won't be copied of course.
300 : *
301 : **********************************************************************/
302 0 : void TABFeature::CopyTABFeatureBase(TABFeature *poDestFeature)
303 : {
304 : /*-----------------------------------------------------------------
305 : * Copy fields only if OGRFeatureDefn is the same
306 : *----------------------------------------------------------------*/
307 0 : OGRFeatureDefn *poThisDefnRef = GetDefnRef();
308 :
309 0 : if (poThisDefnRef == poDestFeature->GetDefnRef())
310 : {
311 0 : for( int i = 0; i < poThisDefnRef->GetFieldCount(); i++ )
312 : {
313 0 : poDestFeature->SetField( i, GetRawFieldRef( i ) );
314 : }
315 : }
316 :
317 : /*-----------------------------------------------------------------
318 : * Copy the geometry
319 : *----------------------------------------------------------------*/
320 0 : poDestFeature->SetGeometry( GetGeometryRef() );
321 :
322 : double dXMin, dYMin, dXMax, dYMax;
323 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
324 0 : poDestFeature->SetMBR(dXMin, dYMin, dXMax, dYMax);
325 :
326 : GInt32 nXMin, nYMin, nXMax, nYMax;
327 0 : GetIntMBR(nXMin, nYMin, nXMax, nYMax);
328 0 : poDestFeature->SetIntMBR(nXMin, nYMin, nXMax, nYMax);
329 :
330 : // m_nMapInfoType is not carried but it is not required anyways.
331 : // it will default to TAB_GEOM_NONE
332 0 : }
333 :
334 :
335 : /**********************************************************************
336 : * TABFeature::CloneTABFeature()
337 : *
338 : * Duplicate feature, including stuff specific to each TABFeature type.
339 : *
340 : * The newly created feature is owned by the caller, and will have it's own
341 : * reference to the OGRFeatureDefn.
342 : *
343 : * It is possible to create the clone with a different OGRFeatureDefn,
344 : * in this case, the fields won't be copied of course.
345 : *
346 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
347 : * then copies any members specific to its own type.
348 : **********************************************************************/
349 0 : TABFeature *TABFeature::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
350 : {
351 : /*-----------------------------------------------------------------
352 : * Alloc new feature and copy the base stuff
353 : *----------------------------------------------------------------*/
354 0 : TABFeature *poNew = new TABFeature(poNewDefn ? poNewDefn : GetDefnRef());
355 :
356 0 : CopyTABFeatureBase(poNew);
357 :
358 : /*-----------------------------------------------------------------
359 : * And members specific to this class
360 : *----------------------------------------------------------------*/
361 : // Nothing to do for this class
362 :
363 0 : return poNew;
364 : }
365 :
366 : /**********************************************************************
367 : * TABFeature::SetMBR()
368 : *
369 : * Set the values for the MBR corners for this feature.
370 : **********************************************************************/
371 : void TABFeature::SetMBR(double dXMin, double dYMin,
372 214 : double dXMax, double dYMax)
373 : {
374 214 : m_dXMin = MIN(dXMin, dXMax);
375 214 : m_dYMin = MIN(dYMin, dYMax);
376 214 : m_dXMax = MAX(dXMin, dXMax);
377 214 : m_dYMax = MAX(dYMin, dYMax);
378 214 : }
379 :
380 : /**********************************************************************
381 : * TABFeature::GetMBR()
382 : *
383 : * Return the values for the MBR corners for this feature.
384 : **********************************************************************/
385 : void TABFeature::GetMBR(double &dXMin, double &dYMin,
386 0 : double &dXMax, double &dYMax)
387 : {
388 0 : dXMin = m_dXMin;
389 0 : dYMin = m_dYMin;
390 0 : dXMax = m_dXMax;
391 0 : dYMax = m_dYMax;
392 0 : }
393 :
394 : /**********************************************************************
395 : * TABFeature::SetIntMBR()
396 : *
397 : * Set the integer coordinates values of the MBR of this feature.
398 : **********************************************************************/
399 : void TABFeature::SetIntMBR(GInt32 nXMin, GInt32 nYMin,
400 52 : GInt32 nXMax, GInt32 nYMax)
401 : {
402 52 : m_nXMin = nXMin;
403 52 : m_nYMin = nYMin;
404 52 : m_nXMax = nXMax;
405 52 : m_nYMax = nYMax;
406 52 : }
407 :
408 : /**********************************************************************
409 : * TABFeature::GetIntMBR()
410 : *
411 : * Return the integer coordinates values of the MBR of this feature.
412 : **********************************************************************/
413 : void TABFeature::GetIntMBR(GInt32 &nXMin, GInt32 &nYMin,
414 12 : GInt32 &nXMax, GInt32 &nYMax)
415 : {
416 12 : nXMin = m_nXMin;
417 12 : nYMin = m_nYMin;
418 12 : nXMax = m_nXMax;
419 12 : nYMax = m_nYMax;
420 12 : }
421 :
422 : /**********************************************************************
423 : * TABFeature::ReadRecordFromDATFile()
424 : *
425 : * Fill the fields part of the feature from the contents of the
426 : * table record pointed to by poDATFile.
427 : *
428 : * It is assumed that poDATFile currently points to the beginning of
429 : * the table record and that this feature's OGRFeatureDefn has been
430 : * properly initialized for this table.
431 : **********************************************************************/
432 53 : int TABFeature::ReadRecordFromDATFile(TABDATFile *poDATFile)
433 : {
434 : int iField, numFields, nValue;
435 : double dValue;
436 : const char *pszValue;
437 : #ifdef MITAB_USE_OFTDATETIME
438 : int nYear, nMonth, nDay, nHour, nMin, nSec, nMS;
439 53 : nYear = nMonth = nDay = nHour = nMin = nSec = nMS = 0;
440 : #endif
441 :
442 53 : CPLAssert(poDATFile);
443 :
444 53 : numFields = poDATFile->GetNumFields();
445 :
446 206 : for(iField=0; iField<numFields; iField++)
447 : {
448 153 : switch(poDATFile->GetFieldType(iField))
449 : {
450 : case TABFChar:
451 : pszValue = poDATFile->ReadCharField(poDATFile->
452 53 : GetFieldWidth(iField));
453 53 : SetField(iField, pszValue);
454 53 : break;
455 : case TABFDecimal:
456 : dValue = poDATFile->ReadDecimalField(poDATFile->
457 0 : GetFieldWidth(iField));
458 0 : SetField(iField, dValue);
459 0 : break;
460 : case TABFInteger:
461 : nValue = poDATFile->ReadIntegerField(poDATFile->
462 50 : GetFieldWidth(iField));
463 50 : SetField(iField, nValue);
464 50 : break;
465 : case TABFSmallInt:
466 : nValue = poDATFile->ReadSmallIntField(poDATFile->
467 0 : GetFieldWidth(iField));
468 0 : SetField(iField, nValue);
469 0 : break;
470 : case TABFFloat:
471 : dValue = poDATFile->ReadFloatField(poDATFile->
472 50 : GetFieldWidth(iField));
473 50 : SetField(iField, dValue);
474 50 : break;
475 : case TABFLogical:
476 : pszValue = poDATFile->ReadLogicalField(poDATFile->
477 0 : GetFieldWidth(iField));
478 0 : SetField(iField, pszValue);
479 0 : break;
480 : case TABFDate:
481 : pszValue = poDATFile->ReadDateField(poDATFile->
482 0 : GetFieldWidth(iField));
483 : #ifdef MITAB_USE_OFTDATETIME
484 : sscanf(pszValue, "%4d%2d%2d",
485 0 : &nYear, &nMonth, &nDay);
486 0 : SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
487 : #else
488 : SetField(iField, pszValue);
489 : #endif
490 0 : break;
491 : case TABFTime:
492 : pszValue = poDATFile->ReadTimeField(poDATFile->
493 0 : GetFieldWidth(iField));
494 : #ifdef MITAB_USE_OFTDATETIME
495 : sscanf(pszValue,"%2d%2d%2d%3d",
496 0 : &nHour, &nMin, &nSec, &nMS);
497 :
498 0 : SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
499 : #else
500 : SetField(iField, pszValue);
501 : #endif
502 0 : break;
503 : case TABFDateTime:
504 : pszValue = poDATFile->ReadDateTimeField(poDATFile->
505 0 : GetFieldWidth(iField));
506 : #ifdef MITAB_USE_OFTDATETIME
507 : sscanf(pszValue, "%4d%2d%2d%2d%2d%2d%3d",
508 0 : &nYear, &nMonth, &nDay, &nHour, &nMin, &nSec, &nMS);
509 0 : SetField(iField, nYear, nMonth, nDay, nHour, nMin, nSec, 0);
510 : #else
511 : SetField(iField, pszValue);
512 : #endif
513 0 : break;
514 : default:
515 : // Other type??? Impossible!
516 : CPLError(CE_Failure, CPLE_AssertionFailed,
517 0 : "Unsupported field type!");
518 : }
519 :
520 : }
521 :
522 53 : return 0;
523 : }
524 :
525 : /**********************************************************************
526 : * TABFeature::WriteRecordToDATFile()
527 : *
528 : * Write the attribute part of the feature to the .DAT file.
529 : *
530 : * It is assumed that poDATFile currently points to the beginning of
531 : * the table record and that this feature's OGRFeatureDefn has been
532 : * properly initialized for this table.
533 : *
534 : * Returns 0 on success, -1 on error.
535 : **********************************************************************/
536 : int TABFeature::WriteRecordToDATFile(TABDATFile *poDATFile,
537 13 : TABINDFile *poINDFile, int *panIndexNo)
538 : {
539 13 : int iField, numFields, nStatus=0;
540 : #ifdef MITAB_USE_OFTDATETIME
541 : int nYear, nMon, nDay, nHour, nMin, nSec;
542 : const char *pszValue;
543 : char *pszBuffer;
544 : #endif
545 :
546 13 : CPLAssert(poDATFile);
547 13 : CPLAssert(panIndexNo || GetDefnRef()->GetFieldCount() == 0);
548 :
549 13 : numFields = poDATFile->GetNumFields();
550 :
551 46 : for(iField=0; nStatus == 0 && iField<numFields; iField++)
552 : {
553 : // Hack for "extra" introduced field.
554 33 : if( iField >= GetDefnRef()->GetFieldCount() )
555 : {
556 0 : CPLAssert( poDATFile->GetFieldType(iField) == TABFInteger
557 : && iField == 0 );
558 0 : nStatus = poDATFile->WriteIntegerField( GetFID(), poINDFile, 0 );
559 0 : continue;
560 : }
561 :
562 33 : switch(poDATFile->GetFieldType(iField))
563 : {
564 : case TABFChar:
565 : nStatus = poDATFile->WriteCharField(GetFieldAsString(iField),
566 : poDATFile->GetFieldWidth(iField),
567 13 : poINDFile, panIndexNo[iField]);
568 13 : break;
569 : case TABFDecimal:
570 : nStatus = poDATFile->WriteDecimalField(GetFieldAsDouble(iField),
571 : poDATFile->GetFieldWidth(iField),
572 : poDATFile->GetFieldPrecision(iField),
573 0 : poINDFile, panIndexNo[iField]);
574 0 : break;
575 : case TABFInteger:
576 : nStatus = poDATFile->WriteIntegerField(GetFieldAsInteger(iField),
577 10 : poINDFile, panIndexNo[iField]);
578 10 : break;
579 : case TABFSmallInt:
580 : nStatus = poDATFile->WriteSmallIntField(GetFieldAsInteger(iField),
581 0 : poINDFile, panIndexNo[iField]);
582 0 : break;
583 : case TABFFloat:
584 : nStatus = poDATFile->WriteFloatField(GetFieldAsDouble(iField),
585 10 : poINDFile, panIndexNo[iField]);
586 10 : break;
587 : case TABFLogical:
588 : nStatus = poDATFile->WriteLogicalField(GetFieldAsString(iField),
589 0 : poINDFile, panIndexNo[iField]);
590 0 : break;
591 : case TABFDate:
592 : nStatus = poDATFile->WriteDateField(GetFieldAsString(iField),
593 0 : poINDFile, panIndexNo[iField]);
594 0 : break;
595 : case TABFTime:
596 : #ifdef MITAB_USE_OFTDATETIME
597 : /* Fix Time string returned by OGR: the hour must be 2 char */
598 0 : pszValue = GetFieldAsString(iField);
599 0 : pszBuffer = (char*)CPLMalloc((8+1)*sizeof(char));
600 0 : sscanf(pszValue, "%d:%d:%d", &nHour, &nMin, &nSec);
601 0 : sprintf(pszBuffer, "%02d:%02d:%02d", nHour, nMin, nSec);
602 : nStatus = poDATFile->WriteTimeField(pszBuffer,
603 0 : poINDFile, panIndexNo[iField]);
604 0 : CPLFree(pszBuffer);
605 : #else
606 : nStatus = poDATFile->WriteTimeField(GetFieldAsString(iField),
607 : poINDFile, panIndexNo[iField]);
608 : #endif
609 0 : break;
610 : case TABFDateTime:
611 : #ifdef MITAB_USE_OFTDATETIME
612 : /* Fix DateTime string returned by OGR: the hour must be 2 char */
613 0 : pszValue = GetFieldAsString(iField);
614 0 : pszBuffer = (char*)CPLMalloc((19+1)*sizeof(char));
615 : sscanf(pszValue, "%4d/%2d/%2d %2d:%2d:%2d",
616 0 : &nYear,&nMon, &nDay, &nHour, &nMin, &nSec);
617 : sprintf(pszBuffer, "%04d/%02d/%02d %02d:%02d:%02d",
618 0 : nYear, nMon, nDay, nHour, nMin, nSec);
619 : nStatus = poDATFile->WriteDateTimeField(pszBuffer,
620 0 : poINDFile, panIndexNo[iField]);
621 0 : CPLFree(pszBuffer);
622 : #else
623 : nStatus = poDATFile->WriteDateTimeField(GetFieldAsString(iField),
624 : poINDFile, panIndexNo[iField]);
625 : #endif
626 0 : break;
627 : default:
628 : // Other type??? Impossible!
629 : CPLError(CE_Failure, CPLE_AssertionFailed,
630 0 : "Unsupported field type!");
631 : }
632 :
633 : }
634 :
635 13 : if (poDATFile->CommitRecordToFile() != 0)
636 0 : return -1;
637 :
638 13 : return 0;
639 : }
640 :
641 : /**********************************************************************
642 : * TABFeature::ReadGeometryFromMAPFile()
643 : *
644 : * In derived classes, this method should be reimplemented to
645 : * fill the geometry and representation (color, etc...) part of the
646 : * feature from the contents of the .MAP object pointed to by poMAPFile.
647 : *
648 : * It is assumed that before calling ReadGeometryFromMAPFile(), poMAPFile
649 : * currently points to the beginning of a map object.
650 : *
651 : * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
652 : * the CoordBlock data during splitting of object blocks. In this case we
653 : * need to process only the information related to the CoordBlock. One
654 : * important thing to avoid is reading/writing pen/brush/symbol definitions
655 : * as that would screw up their ref counters.
656 : *
657 : * ppoCoordBlock is used by TABCollection and by index splitting code
658 : * to provide a CoordBlock to use instead of the one from the poMAPFile and
659 : * return the current pointer at the end of the call.
660 : *
661 : * The current implementation does nothing since instances of TABFeature
662 : * objects contain no geometry (i.e. TAB_GEOM_NONE).
663 : *
664 : * Returns 0 on success, -1 on error, in which case CPLError() will have
665 : * been called.
666 : **********************************************************************/
667 : int TABFeature::ReadGeometryFromMAPFile(TABMAPFile * /*poMapFile*/,
668 : TABMAPObjHdr * /*poObjHdr*/,
669 : GBool /*bCoordBlockDataOnly=FALSE*/,
670 1 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
671 : {
672 : /*-----------------------------------------------------------------
673 : * Nothing to do... instances of TABFeature objects contain no geometry.
674 : *----------------------------------------------------------------*/
675 :
676 1 : return 0;
677 : }
678 :
679 :
680 : /**********************************************************************
681 : * TABFeature::UpdateMBR()
682 : *
683 : * Fetch envelope of poGeom and update MBR.
684 : * Integer coord MBR is updated only if poMapFile is not NULL.
685 : *
686 : * Returns 0 on success, or -1 if there is no geometry in object
687 : **********************************************************************/
688 12 : int TABFeature::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
689 : {
690 : OGRGeometry *poGeom;
691 :
692 12 : poGeom = GetGeometryRef();
693 :
694 12 : if (poGeom)
695 : {
696 12 : OGREnvelope oEnv;
697 12 : poGeom->getEnvelope(&oEnv);
698 :
699 12 : m_dXMin = oEnv.MinX;
700 12 : m_dYMin = oEnv.MinY;
701 12 : m_dXMax = oEnv.MaxX;
702 12 : m_dYMax = oEnv.MaxY;
703 :
704 12 : if (poMapFile)
705 : {
706 12 : poMapFile->Coordsys2Int(oEnv.MinX, oEnv.MinY, m_nXMin, m_nYMin);
707 12 : poMapFile->Coordsys2Int(oEnv.MaxX, oEnv.MaxY, m_nXMax, m_nYMax);
708 : }
709 :
710 12 : return 0;
711 : }
712 :
713 0 : return -1;
714 : }
715 :
716 : /**********************************************************************
717 : * TABFeature::ValidateCoordType()
718 : *
719 : * Checks the feature envelope to establish if the feature should be
720 : * written using Compressed coordinates or not and adjust m_nMapInfoType
721 : * accordingly. Calling this method also sets (initializes) m_nXMin, m_nYMin,
722 : * m_nXMax, m_nYMax
723 : *
724 : * This function should be used only by the ValidateMapInfoType()
725 : * implementations.
726 : *
727 : * Returns TRUE if coord. should be compressed, FALSE otherwise
728 : **********************************************************************/
729 11 : GBool TABFeature::ValidateCoordType(TABMAPFile * poMapFile)
730 : {
731 11 : GBool bCompr = FALSE;
732 :
733 : /*-------------------------------------------------------------
734 : * Decide if coordinates should be compressed or not.
735 : *------------------------------------------------------------*/
736 11 : if (UpdateMBR(poMapFile) == 0)
737 : {
738 : /* Test for max range < 65535 here instead of < 65536 to avoid
739 : * compressed coordinate overflows in some boundary situations
740 : */
741 11 : if ((m_nXMax - m_nXMin) < 65535 && (m_nYMax-m_nYMin) < 65535)
742 : {
743 10 : bCompr = TRUE;
744 : }
745 11 : m_nComprOrgX = (m_nXMin + m_nXMax) / 2;
746 11 : m_nComprOrgY = (m_nYMin + m_nYMax) / 2;
747 : }
748 :
749 : /*-------------------------------------------------------------
750 : * Adjust native type
751 : *------------------------------------------------------------*/
752 21 : if (bCompr && ((m_nMapInfoType%3) == 2))
753 10 : m_nMapInfoType--; // compr = 1, 4, 7, ...
754 1 : else if (!bCompr && ((m_nMapInfoType%3) == 1))
755 0 : m_nMapInfoType++; // non-compr = 2, 5, 8, ...
756 :
757 11 : return bCompr;
758 : }
759 :
760 : /**********************************************************************
761 : * TABFeature::ForceCoordTypeAndOrigin()
762 : *
763 : * This function is used by TABCollection::ValidateMapInfoType() to force
764 : * the coord type and compressed origin of all members of a collection
765 : * to be the same. (A replacement for ValidateCoordType() for this
766 : * specific case)
767 : **********************************************************************/
768 : void TABFeature::ForceCoordTypeAndOrigin(int nMapInfoType, GBool bCompr,
769 : GInt32 nComprOrgX, GInt32 nComprOrgY,
770 : GInt32 nXMin, GInt32 nYMin,
771 0 : GInt32 nXMax, GInt32 nYMax)
772 : {
773 : /*-------------------------------------------------------------
774 : * Set Compressed Origin and adjust native type
775 : *------------------------------------------------------------*/
776 0 : m_nComprOrgX = nComprOrgX;
777 0 : m_nComprOrgY = nComprOrgY;
778 :
779 0 : m_nMapInfoType = nMapInfoType;
780 :
781 0 : if (bCompr && ((m_nMapInfoType%3) == 2))
782 0 : m_nMapInfoType--; // compr = 1, 4, 7, ...
783 0 : else if (!bCompr && ((m_nMapInfoType%3) == 1))
784 0 : m_nMapInfoType++; // non-compr = 2, 5, 8, ...
785 :
786 0 : m_nXMin = nXMin;
787 0 : m_nYMin = nYMin;
788 0 : m_nXMax = nXMax;
789 0 : m_nYMax = nYMax;
790 0 : }
791 :
792 : /**********************************************************************
793 : * TABFeature::WriteGeometryToMAPFile()
794 : *
795 : *
796 : * In derived classes, this method should be reimplemented to
797 : * write the geometry and representation (color, etc...) part of the
798 : * feature to the .MAP object pointed to by poMAPFile.
799 : *
800 : * It is assumed that before calling WriteGeometryToMAPFile(), poMAPFile
801 : * currently points to a valid map object.
802 : *
803 : * bCoordBlockDataOnly=TRUE is used when this method is called to copy only
804 : * the CoordBlock data during splitting of object blocks. In this case we
805 : * need to process only the information related to the CoordBlock. One
806 : * important thing to avoid is reading/writing pen/brush/symbol definitions
807 : * as that would screw up their ref counters.
808 : *
809 : * ppoCoordBlock is used by TABCollection and by index splitting code
810 : * to provide a CoordBlock to use instead of the one from the poMAPFile and
811 : * return the current pointer at the end of the call.
812 : *
813 : * The current implementation does nothing since instances of TABFeature
814 : * objects contain no geometry (i.e. TAB_GEOM_NONE).
815 : *
816 : * Returns 0 on success, -1 on error, in which case CPLError() will have
817 : * been called.
818 : **********************************************************************/
819 : int TABFeature::WriteGeometryToMAPFile(TABMAPFile * /* poMapFile*/,
820 : TABMAPObjHdr * /*poObjHdr*/,
821 : GBool /*bCoordBlockDataOnly=FALSE*/,
822 1 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
823 : {
824 : /*-----------------------------------------------------------------
825 : * Nothing to do... instances of TABFeature objects contain no geometry.
826 : *----------------------------------------------------------------*/
827 :
828 1 : return 0;
829 : }
830 :
831 : /**********************************************************************
832 : * TABFeature::DumpMID()
833 : *
834 : * Dump feature attributes in a format similar to .MID data records.
835 : **********************************************************************/
836 0 : void TABFeature::DumpMID(FILE *fpOut /*=NULL*/)
837 : {
838 0 : OGRFeatureDefn *poDefn = GetDefnRef();
839 :
840 0 : if (fpOut == NULL)
841 0 : fpOut = stdout;
842 :
843 0 : for( int iField = 0; iField < GetFieldCount(); iField++ )
844 : {
845 0 : OGRFieldDefn *poFDefn = poDefn->GetFieldDefn(iField);
846 :
847 : fprintf( fpOut, " %s (%s) = %s\n",
848 : poFDefn->GetNameRef(),
849 : OGRFieldDefn::GetFieldTypeName(poFDefn->GetType()),
850 0 : GetFieldAsString( iField ) );
851 : }
852 :
853 0 : fflush(fpOut);
854 0 : }
855 :
856 : /**********************************************************************
857 : * TABFeature::DumpMIF()
858 : *
859 : * Dump feature geometry in a format similar to .MIF files.
860 : **********************************************************************/
861 0 : void TABFeature::DumpMIF(FILE *fpOut /*=NULL*/)
862 : {
863 0 : if (fpOut == NULL)
864 0 : fpOut = stdout;
865 :
866 : /*-----------------------------------------------------------------
867 : * Generate output... not much to do, feature contains no geometry.
868 : *----------------------------------------------------------------*/
869 0 : fprintf(fpOut, "NONE\n" );
870 :
871 0 : fflush(fpOut);
872 0 : }
873 :
874 :
875 : /*=====================================================================
876 : * class TABPoint
877 : *====================================================================*/
878 :
879 :
880 : /**********************************************************************
881 : * TABPoint::TABPoint()
882 : *
883 : * Constructor.
884 : **********************************************************************/
885 8 : TABPoint::TABPoint(OGRFeatureDefn *poDefnIn):
886 8 : TABFeature(poDefnIn)
887 : {
888 8 : }
889 :
890 : /**********************************************************************
891 : * TABPoint::~TABPoint()
892 : *
893 : * Destructor.
894 : **********************************************************************/
895 8 : TABPoint::~TABPoint()
896 : {
897 8 : }
898 :
899 : /**********************************************************************
900 : * TABPoint::CloneTABFeature()
901 : *
902 : * Duplicate feature, including stuff specific to each TABFeature type.
903 : *
904 : * This method calls the generic TABFeature::CloneTABFeature() and
905 : * then copies any members specific to its own type.
906 : **********************************************************************/
907 0 : TABFeature *TABPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
908 : {
909 : /*-----------------------------------------------------------------
910 : * Alloc new feature and copy the base stuff
911 : *----------------------------------------------------------------*/
912 0 : TABPoint *poNew = new TABPoint(poNewDefn ? poNewDefn : GetDefnRef());
913 :
914 0 : CopyTABFeatureBase(poNew);
915 :
916 : /*-----------------------------------------------------------------
917 : * And members specific to this class
918 : *----------------------------------------------------------------*/
919 : // ITABFeatureSymbol
920 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
921 :
922 0 : return poNew;
923 : }
924 :
925 :
926 : /**********************************************************************
927 : * TABPoint::ValidateMapInfoType()
928 : *
929 : * Check the feature's geometry part and return the corresponding
930 : * mapinfo object type code. The m_nMapInfoType member will also
931 : * be updated for further calls to GetMapInfoType();
932 : *
933 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
934 : * is expected for this object class.
935 : **********************************************************************/
936 0 : int TABPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
937 : {
938 : OGRGeometry *poGeom;
939 :
940 : /*-----------------------------------------------------------------
941 : * Fetch and validate geometry
942 : * __TODO__ For now we always write in uncompressed format (until we
943 : * find that this is not correct... note that at this point the
944 : * decision to use compressed/uncompressed will likely be based on
945 : * the distance between the point and the object block center in
946 : * integer coordinates being > 32767 or not... remains to be verified)
947 : *----------------------------------------------------------------*/
948 0 : poGeom = GetGeometryRef();
949 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
950 : {
951 0 : switch(GetFeatureClass())
952 : {
953 : case TABFCFontPoint:
954 0 : m_nMapInfoType = TAB_GEOM_FONTSYMBOL;
955 0 : break;
956 : case TABFCCustomPoint:
957 0 : m_nMapInfoType = TAB_GEOM_CUSTOMSYMBOL;
958 0 : break;
959 : case TABFCPoint:
960 : default:
961 0 : m_nMapInfoType = TAB_GEOM_SYMBOL;
962 : break;
963 : }
964 : }
965 : else
966 : {
967 : CPLError(CE_Failure, CPLE_AssertionFailed,
968 0 : "TABPoint: Missing or Invalid Geometry!");
969 0 : m_nMapInfoType = TAB_GEOM_NONE;
970 : }
971 :
972 0 : UpdateMBR(poMapFile);
973 :
974 0 : return m_nMapInfoType;
975 : }
976 :
977 : /**********************************************************************
978 : * TABPoint::ReadGeometryFromMAPFile()
979 : *
980 : * Fill the geometry and representation (color, etc...) part of the
981 : * feature from the contents of the .MAP object pointed to by poMAPFile.
982 : *
983 : * It is assumed that poMAPFile currently points to the beginning of
984 : * a map object.
985 : *
986 : * Returns 0 on success, -1 on error, in which case CPLError() will have
987 : * been called.
988 : **********************************************************************/
989 : int TABPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
990 : TABMAPObjHdr *poObjHdr,
991 : GBool bCoordBlockDataOnly /*=FALSE*/,
992 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
993 : {
994 : double dX, dY;
995 : OGRGeometry *poGeometry;
996 :
997 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
998 0 : if (bCoordBlockDataOnly)
999 0 : return 0;
1000 :
1001 : /*-----------------------------------------------------------------
1002 : * Fetch and validate geometry type
1003 : *----------------------------------------------------------------*/
1004 0 : m_nMapInfoType = poObjHdr->m_nType;
1005 :
1006 0 : if (m_nMapInfoType != TAB_GEOM_SYMBOL &&
1007 : m_nMapInfoType != TAB_GEOM_SYMBOL_C )
1008 : {
1009 : CPLError(CE_Failure, CPLE_AssertionFailed,
1010 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
1011 0 : m_nMapInfoType, m_nMapInfoType);
1012 0 : return -1;
1013 : }
1014 :
1015 : /*-----------------------------------------------------------------
1016 : * Read object information
1017 : *----------------------------------------------------------------*/
1018 0 : TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
1019 :
1020 0 : m_nSymbolDefIndex = poPointHdr->m_nSymbolId; // Symbol index
1021 :
1022 0 : poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
1023 :
1024 : /*-----------------------------------------------------------------
1025 : * Create and fill geometry object
1026 : *----------------------------------------------------------------*/
1027 0 : poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
1028 0 : poGeometry = new OGRPoint(dX, dY);
1029 :
1030 0 : SetGeometryDirectly(poGeometry);
1031 :
1032 0 : SetMBR(dX, dY, dX, dY);
1033 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
1034 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
1035 :
1036 0 : return 0;
1037 : }
1038 :
1039 : /**********************************************************************
1040 : * TABPoint::WriteGeometryToMAPFile()
1041 : *
1042 : * Write the geometry and representation (color, etc...) part of the
1043 : * feature to the .MAP object pointed to by poMAPFile.
1044 : *
1045 : * It is assumed that poMAPFile currently points to a valid map object.
1046 : *
1047 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1048 : * been called.
1049 : **********************************************************************/
1050 : int TABPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
1051 : TABMAPObjHdr *poObjHdr,
1052 : GBool bCoordBlockDataOnly /*=FALSE*/,
1053 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1054 : {
1055 : GInt32 nX, nY;
1056 : OGRGeometry *poGeom;
1057 : OGRPoint *poPoint;
1058 :
1059 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1060 0 : if (bCoordBlockDataOnly)
1061 0 : return 0;
1062 :
1063 : /*-----------------------------------------------------------------
1064 : * We assume that ValidateMapInfoType() was called already and that
1065 : * the type in poObjHdr->m_nType is valid.
1066 : *----------------------------------------------------------------*/
1067 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
1068 :
1069 : /*-----------------------------------------------------------------
1070 : * Fetch and validate geometry
1071 : *----------------------------------------------------------------*/
1072 0 : poGeom = GetGeometryRef();
1073 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1074 0 : poPoint = (OGRPoint*)poGeom;
1075 : else
1076 : {
1077 : CPLError(CE_Failure, CPLE_AssertionFailed,
1078 0 : "TABPoint: Missing or Invalid Geometry!");
1079 0 : return -1;
1080 : }
1081 :
1082 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
1083 :
1084 : /*-----------------------------------------------------------------
1085 : * Copy object information
1086 : *----------------------------------------------------------------*/
1087 0 : TABMAPObjPoint *poPointHdr = (TABMAPObjPoint *)poObjHdr;
1088 :
1089 0 : poPointHdr->m_nX = nX;
1090 0 : poPointHdr->m_nY = nY;
1091 0 : poPointHdr->SetMBR(nX, nY, nX, nY);
1092 :
1093 0 : m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
1094 0 : poPointHdr->m_nSymbolId = m_nSymbolDefIndex; // Symbol index
1095 :
1096 0 : if (CPLGetLastErrorNo() != 0)
1097 0 : return -1;
1098 :
1099 0 : return 0;
1100 : }
1101 :
1102 :
1103 : /**********************************************************************
1104 : * TABPoint::GetX()
1105 : *
1106 : * Return this point's X coordinate.
1107 : **********************************************************************/
1108 0 : double TABPoint::GetX()
1109 : {
1110 : OGRGeometry *poGeom;
1111 0 : OGRPoint *poPoint=NULL;
1112 :
1113 : /*-----------------------------------------------------------------
1114 : * Fetch and validate geometry
1115 : *----------------------------------------------------------------*/
1116 0 : poGeom = GetGeometryRef();
1117 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1118 0 : poPoint = (OGRPoint*)poGeom;
1119 : else
1120 : {
1121 : CPLError(CE_Failure, CPLE_AssertionFailed,
1122 0 : "TABPoint: Missing or Invalid Geometry!");
1123 0 : return 0.0;
1124 : }
1125 :
1126 0 : return poPoint->getX();
1127 : }
1128 :
1129 : /**********************************************************************
1130 : * TABPoint::GetY()
1131 : *
1132 : * Return this point's Y coordinate.
1133 : **********************************************************************/
1134 0 : double TABPoint::GetY()
1135 : {
1136 : OGRGeometry *poGeom;
1137 0 : OGRPoint *poPoint=NULL;
1138 :
1139 : /*-----------------------------------------------------------------
1140 : * Fetch and validate geometry
1141 : *----------------------------------------------------------------*/
1142 0 : poGeom = GetGeometryRef();
1143 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1144 0 : poPoint = (OGRPoint*)poGeom;
1145 : else
1146 : {
1147 : CPLError(CE_Failure, CPLE_AssertionFailed,
1148 0 : "TABPoint: Missing or Invalid Geometry!");
1149 0 : return 0.0;
1150 : }
1151 :
1152 0 : return poPoint->getY();
1153 : }
1154 :
1155 :
1156 : /**********************************************************************
1157 : * TABPoint::GetStyleString()
1158 : *
1159 : * Return style string for this feature.
1160 : *
1161 : * Style String is built only once during the first call to GetStyleString().
1162 : **********************************************************************/
1163 0 : const char *TABPoint::GetStyleString()
1164 : {
1165 0 : if (m_pszStyleString == NULL)
1166 : {
1167 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
1168 : }
1169 :
1170 0 : return m_pszStyleString;
1171 : }
1172 :
1173 :
1174 : /**********************************************************************
1175 : * TABPoint::DumpMIF()
1176 : *
1177 : * Dump feature geometry in a format similar to .MIF POINTs.
1178 : **********************************************************************/
1179 0 : void TABPoint::DumpMIF(FILE *fpOut /*=NULL*/)
1180 : {
1181 : OGRGeometry *poGeom;
1182 : OGRPoint *poPoint;
1183 :
1184 0 : if (fpOut == NULL)
1185 0 : fpOut = stdout;
1186 :
1187 : /*-----------------------------------------------------------------
1188 : * Fetch and validate geometry
1189 : *----------------------------------------------------------------*/
1190 0 : poGeom = GetGeometryRef();
1191 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1192 0 : poPoint = (OGRPoint*)poGeom;
1193 : else
1194 : {
1195 : CPLError(CE_Failure, CPLE_AssertionFailed,
1196 0 : "TABPoint: Missing or Invalid Geometry!");
1197 0 : return;
1198 : }
1199 :
1200 : /*-----------------------------------------------------------------
1201 : * Generate output
1202 : *----------------------------------------------------------------*/
1203 0 : fprintf(fpOut, "POINT %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
1204 :
1205 0 : DumpSymbolDef(fpOut);
1206 :
1207 : /*-----------------------------------------------------------------
1208 : * Handle stuff specific to derived classes
1209 : *----------------------------------------------------------------*/
1210 0 : if (GetFeatureClass() == TABFCFontPoint)
1211 : {
1212 0 : TABFontPoint *poFeature = (TABFontPoint *)this;
1213 : fprintf(fpOut, " m_nFontStyle = 0x%2.2x (%d)\n",
1214 : poFeature->GetFontStyleTABValue(),
1215 0 : poFeature->GetFontStyleTABValue());
1216 :
1217 0 : poFeature->DumpFontDef(fpOut);
1218 : }
1219 0 : if (GetFeatureClass() == TABFCCustomPoint)
1220 : {
1221 0 : TABCustomPoint *poFeature = (TABCustomPoint *)this;
1222 :
1223 : fprintf(fpOut, " m_nUnknown_ = 0x%2.2x (%d)\n",
1224 0 : poFeature->m_nUnknown_, poFeature->m_nUnknown_);
1225 : fprintf(fpOut, " m_nCustomStyle = 0x%2.2x (%d)\n",
1226 : poFeature->GetCustomSymbolStyle(),
1227 0 : poFeature->GetCustomSymbolStyle());
1228 :
1229 0 : poFeature->DumpFontDef(fpOut);
1230 : }
1231 :
1232 0 : fflush(fpOut);
1233 : }
1234 :
1235 : /*=====================================================================
1236 : * class TABFontPoint
1237 : *====================================================================*/
1238 :
1239 :
1240 : /**********************************************************************
1241 : * TABFontPoint::TABFontPoint()
1242 : *
1243 : * Constructor.
1244 : **********************************************************************/
1245 0 : TABFontPoint::TABFontPoint(OGRFeatureDefn *poDefnIn):
1246 0 : TABPoint(poDefnIn)
1247 : {
1248 0 : m_nFontStyle = 0;
1249 0 : m_dAngle = 0.0;
1250 0 : }
1251 :
1252 : /**********************************************************************
1253 : * TABFontPoint::~TABFontPoint()
1254 : *
1255 : * Destructor.
1256 : **********************************************************************/
1257 0 : TABFontPoint::~TABFontPoint()
1258 : {
1259 0 : }
1260 :
1261 : /**********************************************************************
1262 : * TABFontPoint::CloneTABFeature()
1263 : *
1264 : * Duplicate feature, including stuff specific to each TABFeature type.
1265 : *
1266 : * This method calls the generic TABFeature::CloneTABFeature() and
1267 : * then copies any members specific to its own type.
1268 : **********************************************************************/
1269 0 : TABFeature *TABFontPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
1270 : {
1271 : /*-----------------------------------------------------------------
1272 : * Alloc new feature and copy the base stuff
1273 : *----------------------------------------------------------------*/
1274 : TABFontPoint *poNew = new TABFontPoint(poNewDefn ? poNewDefn :
1275 0 : GetDefnRef());
1276 :
1277 0 : CopyTABFeatureBase(poNew);
1278 :
1279 : /*-----------------------------------------------------------------
1280 : * And members specific to this class
1281 : *----------------------------------------------------------------*/
1282 : // ITABFeatureSymbol
1283 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
1284 :
1285 : // ITABFeatureFont
1286 0 : *(poNew->GetFontDefRef()) = *GetFontDefRef();
1287 :
1288 0 : poNew->SetSymbolAngle( GetSymbolAngle() );
1289 0 : poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
1290 :
1291 0 : return poNew;
1292 : }
1293 :
1294 : /**********************************************************************
1295 : * TABFontPoint::ReadGeometryFromMAPFile()
1296 : *
1297 : * Fill the geometry and representation (color, etc...) part of the
1298 : * feature from the contents of the .MAP object pointed to by poMAPFile.
1299 : *
1300 : * It is assumed that poMAPFile currently points to the beginning of
1301 : * a map object.
1302 : *
1303 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1304 : * been called.
1305 : **********************************************************************/
1306 : int TABFontPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
1307 : TABMAPObjHdr *poObjHdr,
1308 : GBool bCoordBlockDataOnly /*=FALSE*/,
1309 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1310 : {
1311 : double dX, dY;
1312 : OGRGeometry *poGeometry;
1313 :
1314 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1315 0 : if (bCoordBlockDataOnly)
1316 0 : return 0;
1317 :
1318 : /*-----------------------------------------------------------------
1319 : * Fetch and validate geometry type
1320 : *----------------------------------------------------------------*/
1321 0 : m_nMapInfoType = poObjHdr->m_nType;
1322 :
1323 0 : if (m_nMapInfoType != TAB_GEOM_FONTSYMBOL &&
1324 : m_nMapInfoType != TAB_GEOM_FONTSYMBOL_C )
1325 : {
1326 : CPLError(CE_Failure, CPLE_AssertionFailed,
1327 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
1328 0 : m_nMapInfoType, m_nMapInfoType);
1329 0 : return -1;
1330 : }
1331 :
1332 : /*-----------------------------------------------------------------
1333 : * Read object information
1334 : * NOTE: This symbol type does not contain a reference to a
1335 : * SymbolDef block in the file, but we still use the m_sSymbolDef
1336 : * structure to store the information inside the class so that the
1337 : * ITABFeatureSymbol methods work properly for the class user.
1338 : *----------------------------------------------------------------*/
1339 0 : TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
1340 :
1341 0 : m_nSymbolDefIndex = -1;
1342 0 : m_sSymbolDef.nRefCount = 0;
1343 :
1344 0 : m_sSymbolDef.nSymbolNo = poPointHdr->m_nSymbolId; // shape
1345 0 : m_sSymbolDef.nPointSize = poPointHdr->m_nPointSize; // point size
1346 :
1347 0 : m_nFontStyle = poPointHdr->m_nFontStyle; // font style
1348 :
1349 : m_sSymbolDef.rgbColor = (poPointHdr->m_nR*256*256 +
1350 : poPointHdr->m_nG*256 +
1351 0 : poPointHdr->m_nB);
1352 :
1353 : /*-------------------------------------------------------------
1354 : * Symbol Angle, in thenths of degree.
1355 : * Contrary to arc start/end angles, no conversion based on
1356 : * origin quadrant is required here
1357 : *------------------------------------------------------------*/
1358 0 : m_dAngle = poPointHdr->m_nAngle/10.0;
1359 :
1360 0 : m_nFontDefIndex = poPointHdr->m_nFontId; // Font name index
1361 :
1362 0 : poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
1363 :
1364 : /*-----------------------------------------------------------------
1365 : * Create and fill geometry object
1366 : *----------------------------------------------------------------*/
1367 0 : poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
1368 0 : poGeometry = new OGRPoint(dX, dY);
1369 :
1370 0 : SetGeometryDirectly(poGeometry);
1371 :
1372 0 : SetMBR(dX, dY, dX, dY);
1373 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
1374 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
1375 :
1376 0 : return 0;
1377 : }
1378 :
1379 : /**********************************************************************
1380 : * TABFontPoint::WriteGeometryToMAPFile()
1381 : *
1382 : * Write the geometry and representation (color, etc...) part of the
1383 : * feature to the .MAP object pointed to by poMAPFile.
1384 : *
1385 : * It is assumed that poMAPFile currently points to a valid map object.
1386 : *
1387 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1388 : * been called.
1389 : **********************************************************************/
1390 : int TABFontPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
1391 : TABMAPObjHdr *poObjHdr,
1392 : GBool bCoordBlockDataOnly /*=FALSE*/,
1393 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1394 : {
1395 : GInt32 nX, nY;
1396 : OGRGeometry *poGeom;
1397 : OGRPoint *poPoint;
1398 :
1399 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1400 0 : if (bCoordBlockDataOnly)
1401 0 : return 0;
1402 :
1403 : /*-----------------------------------------------------------------
1404 : * We assume that ValidateMapInfoType() was called already and that
1405 : * the type in poObjHdr->m_nType is valid.
1406 : *----------------------------------------------------------------*/
1407 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
1408 :
1409 : /*-----------------------------------------------------------------
1410 : * Fetch and validate geometry
1411 : *----------------------------------------------------------------*/
1412 0 : poGeom = GetGeometryRef();
1413 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1414 0 : poPoint = (OGRPoint*)poGeom;
1415 : else
1416 : {
1417 : CPLError(CE_Failure, CPLE_AssertionFailed,
1418 0 : "TABFontPoint: Missing or Invalid Geometry!");
1419 0 : return -1;
1420 : }
1421 :
1422 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
1423 :
1424 : /*-----------------------------------------------------------------
1425 : * Copy object information
1426 : * NOTE: This symbol type does not contain a reference to a
1427 : * SymbolDef block in the file, but we still use the m_sSymbolDef
1428 : * structure to store the information inside the class so that the
1429 : * ITABFeatureSymbol methods work properly for the class user.
1430 : *----------------------------------------------------------------*/
1431 0 : TABMAPObjFontPoint *poPointHdr = (TABMAPObjFontPoint *)poObjHdr;
1432 :
1433 0 : poPointHdr->m_nX = nX;
1434 0 : poPointHdr->m_nY = nY;
1435 0 : poPointHdr->SetMBR(nX, nY, nX, nY);
1436 :
1437 0 : poPointHdr->m_nSymbolId = (GByte)m_sSymbolDef.nSymbolNo; // shape
1438 0 : poPointHdr->m_nPointSize = (GByte)m_sSymbolDef.nPointSize; // point size
1439 0 : poPointHdr->m_nFontStyle = m_nFontStyle; // font style
1440 :
1441 0 : poPointHdr->m_nR = COLOR_R(m_sSymbolDef.rgbColor);
1442 0 : poPointHdr->m_nG = COLOR_G(m_sSymbolDef.rgbColor);
1443 0 : poPointHdr->m_nB = COLOR_B(m_sSymbolDef.rgbColor);
1444 :
1445 : /*-------------------------------------------------------------
1446 : * Symbol Angle, in thenths of degree.
1447 : * Contrary to arc start/end angles, no conversion based on
1448 : * origin quadrant is required here
1449 : *------------------------------------------------------------*/
1450 0 : poPointHdr->m_nAngle = ROUND_INT(m_dAngle * 10.0);
1451 :
1452 : // Write Font Def
1453 0 : m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
1454 0 : poPointHdr->m_nFontId = m_nFontDefIndex; // Font name index
1455 :
1456 0 : if (CPLGetLastErrorNo() != 0)
1457 0 : return -1;
1458 :
1459 0 : return 0;
1460 : }
1461 :
1462 : /**********************************************************************
1463 : * TABFontPoint::QueryFontStyle()
1464 : *
1465 : * Return TRUE if the specified font style attribute is turned ON,
1466 : * or FALSE otherwise. See enum TABFontStyle for the list of styles
1467 : * that can be queried on.
1468 : **********************************************************************/
1469 0 : GBool TABFontPoint::QueryFontStyle(TABFontStyle eStyleToQuery)
1470 : {
1471 0 : return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
1472 : }
1473 :
1474 0 : void TABFontPoint::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
1475 : {
1476 0 : if (bStyleOn)
1477 0 : m_nFontStyle |= (int)eStyleToToggle;
1478 : else
1479 0 : m_nFontStyle &= ~(int)eStyleToToggle;
1480 0 : }
1481 :
1482 : /**********************************************************************
1483 : * TABFontPoint::GetFontStyleMIFValue()
1484 : *
1485 : * Return the Font Style value for this object using the style values
1486 : * that are used in a MIF FONT() clause. See MIF specs (appendix A).
1487 : *
1488 : * The reason why we have to differentiate between the TAB and the MIF font
1489 : * style values is that in TAB, TABFSBox is included in the style value
1490 : * as code 0x100, but in MIF it is not included, instead it is implied by
1491 : * the presence of the BG color in the FONT() clause (the BG color is
1492 : * present only when TABFSBox or TABFSHalo is set).
1493 : * This also has the effect of shifting all the other style values > 0x100
1494 : * by 1 byte.
1495 : *
1496 : * NOTE: Even if there is no BG color for font symbols, we inherit this
1497 : * problem because Font Point styles use the same codes as Text Font styles.
1498 : **********************************************************************/
1499 0 : int TABFontPoint::GetFontStyleMIFValue()
1500 : {
1501 : // The conversion is simply to remove bit 0x100 from the value and shift
1502 : // down all values past this bit.
1503 0 : return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
1504 : }
1505 :
1506 0 : void TABFontPoint:: SetFontStyleMIFValue(int nStyle)
1507 : {
1508 0 : m_nFontStyle = (nStyle & 0xff) + (nStyle & 0x7f00)*2;
1509 0 : }
1510 :
1511 : /**********************************************************************
1512 : * TABFontPoint::SetSymbolAngle()
1513 : *
1514 : * Set the symbol angle value in degrees, making sure the value is
1515 : * always in the range [0..360]
1516 : **********************************************************************/
1517 0 : void TABFontPoint::SetSymbolAngle(double dAngle)
1518 : {
1519 0 : while(dAngle < 0.0) dAngle += 360.0;
1520 0 : while(dAngle > 360.0) dAngle -= 360.0;
1521 :
1522 0 : m_dAngle = dAngle;
1523 0 : }
1524 :
1525 :
1526 : /**********************************************************************
1527 : * TABFontPoint::GetStyleString()
1528 : *
1529 : * Return style string for this feature.
1530 : *
1531 : * Style String is built only once during the first call to GetStyleString().
1532 : **********************************************************************/
1533 0 : const char *TABFontPoint::GetStyleString()
1534 : {
1535 0 : if (m_pszStyleString == NULL)
1536 : {
1537 : /* Get the SymbolStyleString, and add the outline Color
1538 : (halo/border in MapInfo Symbol terminology) */
1539 0 : char *pszSymbolStyleString = CPLStrdup(GetSymbolStyleString(GetSymbolAngle()));
1540 0 : int nStyleStringlen = strlen(pszSymbolStyleString);
1541 0 : pszSymbolStyleString[nStyleStringlen-1] = '\0';
1542 :
1543 : const char *outlineColor;
1544 0 : if (m_nFontStyle & 16)
1545 0 : outlineColor = ",o:#000000";
1546 0 : else if (m_nFontStyle & 512)
1547 0 : outlineColor = ",o:#ffffff";
1548 : else
1549 0 : outlineColor = "";
1550 :
1551 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s%s)",
1552 : pszSymbolStyleString,
1553 0 : outlineColor));
1554 0 : CPLFree(pszSymbolStyleString);
1555 : }
1556 :
1557 0 : return m_pszStyleString;
1558 : }
1559 :
1560 :
1561 : /*=====================================================================
1562 : * class TABCustomPoint
1563 : *====================================================================*/
1564 :
1565 :
1566 : /**********************************************************************
1567 : * TABCustomPoint::TABCustomPoint()
1568 : *
1569 : * Constructor.
1570 : **********************************************************************/
1571 0 : TABCustomPoint::TABCustomPoint(OGRFeatureDefn *poDefnIn):
1572 0 : TABPoint(poDefnIn)
1573 : {
1574 0 : m_nUnknown_ = m_nCustomStyle = 0;
1575 0 : }
1576 :
1577 : /**********************************************************************
1578 : * TABCustomPoint::~TABCustomPoint()
1579 : *
1580 : * Destructor.
1581 : **********************************************************************/
1582 0 : TABCustomPoint::~TABCustomPoint()
1583 : {
1584 0 : }
1585 :
1586 : /**********************************************************************
1587 : * TABCustomPoint::CloneTABFeature()
1588 : *
1589 : * Duplicate feature, including stuff specific to each TABFeature type.
1590 : *
1591 : * This method calls the generic TABFeature::CloneTABFeature() and
1592 : * then copies any members specific to its own type.
1593 : **********************************************************************/
1594 0 : TABFeature *TABCustomPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
1595 : {
1596 : /*-----------------------------------------------------------------
1597 : * Alloc new feature and copy the base stuff
1598 : *----------------------------------------------------------------*/
1599 : TABCustomPoint *poNew = new TABCustomPoint(poNewDefn ? poNewDefn :
1600 0 : GetDefnRef());
1601 :
1602 0 : CopyTABFeatureBase(poNew);
1603 :
1604 : /*-----------------------------------------------------------------
1605 : * And members specific to this class
1606 : *----------------------------------------------------------------*/
1607 : // ITABFeatureSymbol
1608 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
1609 :
1610 : // ITABFeatureFont
1611 0 : *(poNew->GetFontDefRef()) = *GetFontDefRef();
1612 :
1613 0 : poNew->SetCustomSymbolStyle( GetCustomSymbolStyle() );
1614 :
1615 0 : return poNew;
1616 : }
1617 :
1618 : /**********************************************************************
1619 : * TABCustomPoint::ReadGeometryFromMAPFile()
1620 : *
1621 : * Fill the geometry and representation (color, etc...) part of the
1622 : * feature from the contents of the .MAP object pointed to by poMAPFile.
1623 : *
1624 : * It is assumed that poMAPFile currently points to the beginning of
1625 : * a map object.
1626 : *
1627 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1628 : * been called.
1629 : **********************************************************************/
1630 : int TABCustomPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
1631 : TABMAPObjHdr *poObjHdr,
1632 : GBool bCoordBlockDataOnly /*=FALSE*/,
1633 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1634 : {
1635 : double dX, dY;
1636 : OGRGeometry *poGeometry;
1637 :
1638 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1639 0 : if (bCoordBlockDataOnly)
1640 0 : return 0;
1641 :
1642 : /*-----------------------------------------------------------------
1643 : * Fetch and validate geometry type
1644 : *----------------------------------------------------------------*/
1645 0 : m_nMapInfoType = poObjHdr->m_nType;
1646 :
1647 0 : if (m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL &&
1648 : m_nMapInfoType != TAB_GEOM_CUSTOMSYMBOL_C )
1649 : {
1650 : CPLError(CE_Failure, CPLE_AssertionFailed,
1651 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
1652 0 : m_nMapInfoType, m_nMapInfoType);
1653 0 : return -1;
1654 : }
1655 :
1656 : /*-----------------------------------------------------------------
1657 : * Read object information
1658 : *----------------------------------------------------------------*/
1659 0 : TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
1660 :
1661 0 : m_nUnknown_ = poPointHdr->m_nUnknown_; // ???
1662 0 : m_nCustomStyle = poPointHdr->m_nCustomStyle;// 0x01=Show BG,
1663 : // 0x02=Apply Color
1664 :
1665 0 : m_nSymbolDefIndex = poPointHdr->m_nSymbolId; // Symbol index
1666 0 : poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
1667 :
1668 0 : m_nFontDefIndex = poPointHdr->m_nFontId; // Font index
1669 0 : poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
1670 :
1671 : /*-----------------------------------------------------------------
1672 : * Create and fill geometry object
1673 : *----------------------------------------------------------------*/
1674 0 : poMapFile->Int2Coordsys(poPointHdr->m_nX, poPointHdr->m_nY, dX, dY);
1675 0 : poGeometry = new OGRPoint(dX, dY);
1676 :
1677 0 : SetGeometryDirectly(poGeometry);
1678 :
1679 0 : SetMBR(dX, dY, dX, dY);
1680 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
1681 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
1682 :
1683 0 : return 0;
1684 : }
1685 :
1686 : /**********************************************************************
1687 : * TABCustomPoint::WriteGeometryToMAPFile()
1688 : *
1689 : * Write the geometry and representation (color, etc...) part of the
1690 : * feature to the .MAP object pointed to by poMAPFile.
1691 : *
1692 : * It is assumed that poMAPFile currently points to a valid map object.
1693 : *
1694 : * Returns 0 on success, -1 on error, in which case CPLError() will have
1695 : * been called.
1696 : **********************************************************************/
1697 : int TABCustomPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
1698 : TABMAPObjHdr *poObjHdr,
1699 : GBool bCoordBlockDataOnly /*=FALSE*/,
1700 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
1701 : {
1702 : GInt32 nX, nY;
1703 : OGRGeometry *poGeom;
1704 : OGRPoint *poPoint;
1705 :
1706 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
1707 0 : if (bCoordBlockDataOnly)
1708 0 : return 0;
1709 :
1710 : /*-----------------------------------------------------------------
1711 : * We assume that ValidateMapInfoType() was called already and that
1712 : * the type in poObjHdr->m_nType is valid.
1713 : *----------------------------------------------------------------*/
1714 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
1715 :
1716 : /*-----------------------------------------------------------------
1717 : * Fetch and validate geometry
1718 : *----------------------------------------------------------------*/
1719 0 : poGeom = GetGeometryRef();
1720 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
1721 0 : poPoint = (OGRPoint*)poGeom;
1722 : else
1723 : {
1724 : CPLError(CE_Failure, CPLE_AssertionFailed,
1725 0 : "TABCustomPoint: Missing or Invalid Geometry!");
1726 0 : return -1;
1727 : }
1728 :
1729 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
1730 :
1731 : /*-----------------------------------------------------------------
1732 : * Copy object information
1733 : *----------------------------------------------------------------*/
1734 0 : TABMAPObjCustomPoint *poPointHdr = (TABMAPObjCustomPoint *)poObjHdr;
1735 :
1736 0 : poPointHdr->m_nX = nX;
1737 0 : poPointHdr->m_nY = nY;
1738 0 : poPointHdr->SetMBR(nX, nY, nX, nY);
1739 0 : poPointHdr->m_nUnknown_ = m_nUnknown_;
1740 0 : poPointHdr->m_nCustomStyle = m_nCustomStyle;// 0x01=Show BG,
1741 : // 0x02=Apply Color
1742 :
1743 0 : m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
1744 0 : poPointHdr->m_nSymbolId = m_nSymbolDefIndex; // Symbol index
1745 :
1746 0 : m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
1747 0 : poPointHdr->m_nFontId = m_nFontDefIndex; // Font index
1748 :
1749 0 : if (CPLGetLastErrorNo() != 0)
1750 0 : return -1;
1751 :
1752 0 : return 0;
1753 : }
1754 :
1755 :
1756 : /**********************************************************************
1757 : * TABCustomPoint::GetStyleString()
1758 : *
1759 : * Return style string for this feature.
1760 : *
1761 : * Style String is built only once during the first call to GetStyleString().
1762 : **********************************************************************/
1763 0 : const char *TABCustomPoint::GetStyleString()
1764 : {
1765 0 : if (m_pszStyleString == NULL)
1766 : {
1767 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
1768 : }
1769 :
1770 0 : return m_pszStyleString;
1771 : }
1772 :
1773 : /*=====================================================================
1774 : * class TABPolyline
1775 : *====================================================================*/
1776 :
1777 :
1778 : /**********************************************************************
1779 : * TABPolyline::TABPolyline()
1780 : *
1781 : * Constructor.
1782 : **********************************************************************/
1783 2 : TABPolyline::TABPolyline(OGRFeatureDefn *poDefnIn):
1784 2 : TABFeature(poDefnIn)
1785 : {
1786 2 : m_bCenterIsSet = FALSE;
1787 2 : m_bSmooth = FALSE;
1788 2 : m_bWriteTwoPointLineAsPolyline = FALSE;
1789 2 : }
1790 :
1791 : /**********************************************************************
1792 : * TABPolyline::~TABPolyline()
1793 : *
1794 : * Destructor.
1795 : **********************************************************************/
1796 2 : TABPolyline::~TABPolyline()
1797 : {
1798 2 : }
1799 :
1800 : /**********************************************************************
1801 : * TABPolyline::CloneTABFeature()
1802 : *
1803 : * Duplicate feature, including stuff specific to each TABFeature type.
1804 : *
1805 : * This method calls the generic TABFeature::CloneTABFeature() and
1806 : * then copies any members specific to its own type.
1807 : **********************************************************************/
1808 0 : TABFeature *TABPolyline::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
1809 : {
1810 : /*-----------------------------------------------------------------
1811 : * Alloc new feature and copy the base stuff
1812 : *----------------------------------------------------------------*/
1813 0 : TABPolyline *poNew = new TABPolyline(poNewDefn ? poNewDefn : GetDefnRef());
1814 :
1815 0 : CopyTABFeatureBase(poNew);
1816 :
1817 : /*-----------------------------------------------------------------
1818 : * And members specific to this class
1819 : *----------------------------------------------------------------*/
1820 : // ITABFeaturePen
1821 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
1822 :
1823 0 : poNew->m_bSmooth = m_bSmooth;
1824 0 : poNew->m_bCenterIsSet = m_bCenterIsSet;
1825 0 : poNew->m_dCenterX = m_dCenterX;
1826 0 : poNew->m_dCenterY = m_dCenterY;
1827 :
1828 0 : return poNew;
1829 : }
1830 :
1831 : /**********************************************************************
1832 : * TABPolyline::GetNumParts()
1833 : *
1834 : * Return the total number of parts in this object.
1835 : *
1836 : * Returns 0 if the geometry contained in the object is invalid or missing.
1837 : **********************************************************************/
1838 0 : int TABPolyline::GetNumParts()
1839 : {
1840 : OGRGeometry *poGeom;
1841 0 : int numParts = 0;
1842 :
1843 0 : poGeom = GetGeometryRef();
1844 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
1845 : {
1846 : /*-------------------------------------------------------------
1847 : * Simple polyline
1848 : *------------------------------------------------------------*/
1849 0 : numParts = 1;
1850 : }
1851 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
1852 : {
1853 : /*-------------------------------------------------------------
1854 : * Multiple polyline
1855 : *------------------------------------------------------------*/
1856 0 : OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
1857 0 : numParts = poMultiLine->getNumGeometries();
1858 : }
1859 :
1860 0 : return numParts;
1861 : }
1862 :
1863 : /**********************************************************************
1864 : * TABPolyline::GetPartRef()
1865 : *
1866 : * Returns a reference to the specified OGRLineString number, hiding the
1867 : * complexity of dealing with OGRMultiLineString vs OGRLineString cases.
1868 : *
1869 : * Returns NULL if the geometry contained in the object is invalid or
1870 : * missing or if the specified part index is invalid.
1871 : **********************************************************************/
1872 0 : OGRLineString *TABPolyline::GetPartRef(int nPartIndex)
1873 : {
1874 : OGRGeometry *poGeom;
1875 :
1876 0 : poGeom = GetGeometryRef();
1877 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString && nPartIndex==0)
1878 : {
1879 : /*-------------------------------------------------------------
1880 : * Simple polyline
1881 : *------------------------------------------------------------*/
1882 0 : return (OGRLineString *)poGeom;
1883 : }
1884 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
1885 : {
1886 : /*-------------------------------------------------------------
1887 : * Multiple polyline
1888 : *------------------------------------------------------------*/
1889 0 : OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
1890 0 : if (nPartIndex >= 0 &&
1891 : nPartIndex < poMultiLine->getNumGeometries())
1892 : {
1893 0 : return (OGRLineString*)poMultiLine->getGeometryRef(nPartIndex);
1894 : }
1895 : else
1896 0 : return NULL;
1897 : }
1898 :
1899 0 : return NULL;
1900 : }
1901 :
1902 : /**********************************************************************
1903 : * TABPolyline::ValidateMapInfoType()
1904 : *
1905 : * Check the feature's geometry part and return the corresponding
1906 : * mapinfo object type code. The m_nMapInfoType member will also
1907 : * be updated for further calls to GetMapInfoType();
1908 : *
1909 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
1910 : * is expected for this object class.
1911 : **********************************************************************/
1912 1 : int TABPolyline::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
1913 : {
1914 : OGRGeometry *poGeom;
1915 1 : OGRMultiLineString *poMultiLine = NULL;
1916 :
1917 : /*-----------------------------------------------------------------
1918 : * Fetch and validate geometry
1919 : *----------------------------------------------------------------*/
1920 1 : poGeom = GetGeometryRef();
1921 1 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
1922 : {
1923 : /*-------------------------------------------------------------
1924 : * Simple polyline
1925 : *------------------------------------------------------------*/
1926 1 : OGRLineString *poLine = (OGRLineString*)poGeom;
1927 1 : if ( TAB_REGION_PLINE_REQUIRES_V800(1, poLine->getNumPoints()) )
1928 : {
1929 0 : m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
1930 : }
1931 1 : else if ( poLine->getNumPoints() > TAB_REGION_PLINE_300_MAX_VERTICES)
1932 : {
1933 0 : m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
1934 : }
1935 1 : else if ( poLine->getNumPoints() > 2 )
1936 : {
1937 0 : m_nMapInfoType = TAB_GEOM_PLINE;
1938 : }
1939 1 : else if ( (poLine->getNumPoints() == 2) &&
1940 : (m_bWriteTwoPointLineAsPolyline == TRUE) )
1941 : {
1942 0 : m_nMapInfoType = TAB_GEOM_PLINE;
1943 : }
1944 1 : else if ( (poLine->getNumPoints() == 2) &&
1945 : (m_bWriteTwoPointLineAsPolyline == FALSE) )
1946 : {
1947 1 : m_nMapInfoType = TAB_GEOM_LINE;
1948 : }
1949 : else
1950 : {
1951 : CPLError(CE_Failure, CPLE_AssertionFailed,
1952 0 : "TABPolyline: Geometry must contain at least 2 points.");
1953 0 : m_nMapInfoType = TAB_GEOM_NONE;
1954 : }
1955 : }
1956 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
1957 : {
1958 : /*-------------------------------------------------------------
1959 : * Multiple polyline... validate all components
1960 : *------------------------------------------------------------*/
1961 : int iLine, numLines;
1962 0 : GInt32 numPointsTotal = 0;
1963 0 : poMultiLine = (OGRMultiLineString*)poGeom;
1964 0 : numLines = poMultiLine->getNumGeometries();
1965 :
1966 0 : m_nMapInfoType = TAB_GEOM_MULTIPLINE;
1967 :
1968 0 : for(iLine=0; iLine < numLines; iLine++)
1969 : {
1970 0 : poGeom = poMultiLine->getGeometryRef(iLine);
1971 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) != wkbLineString)
1972 : {
1973 : CPLError(CE_Failure, CPLE_AssertionFailed,
1974 0 : "TABPolyline: Object contains an invalid Geometry!");
1975 0 : m_nMapInfoType = TAB_GEOM_NONE;
1976 0 : numPointsTotal = 0;
1977 0 : break;
1978 : }
1979 0 : OGRLineString *poLine = (OGRLineString*)poGeom;
1980 0 : numPointsTotal += poLine->getNumPoints();
1981 : }
1982 :
1983 0 : if ( TAB_REGION_PLINE_REQUIRES_V800(numLines, numPointsTotal) )
1984 0 : m_nMapInfoType = TAB_GEOM_V800_MULTIPLINE;
1985 0 : else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
1986 0 : m_nMapInfoType = TAB_GEOM_V450_MULTIPLINE;
1987 : }
1988 : else
1989 : {
1990 : CPLError(CE_Failure, CPLE_AssertionFailed,
1991 0 : "TABPolyline: Missing or Invalid Geometry!");
1992 0 : m_nMapInfoType = TAB_GEOM_NONE;
1993 : }
1994 :
1995 : /*-----------------------------------------------------------------
1996 : * Decide if coordinates should be compressed or not.
1997 : *
1998 : * __TODO__ We never write type LINE (2 points line) as compressed
1999 : * for the moment. If we ever do it, then the decision to write
2000 : * a 2 point line in compressed coordinates or not should take into
2001 : * account the location of the object block MBR, so this would be
2002 : * better handled directly by TABMAPObjLine::WriteObject() since the
2003 : * object block center is not known until it is written to disk.
2004 : *----------------------------------------------------------------*/
2005 1 : if (m_nMapInfoType != TAB_GEOM_LINE)
2006 : {
2007 0 : ValidateCoordType(poMapFile);
2008 : }
2009 : else
2010 : {
2011 1 : UpdateMBR(poMapFile);
2012 : }
2013 :
2014 1 : return m_nMapInfoType;
2015 : }
2016 :
2017 :
2018 : /**********************************************************************
2019 : * TABPolyline::ReadGeometryFromMAPFile()
2020 : *
2021 : * Fill the geometry and representation (color, etc...) part of the
2022 : * feature from the contents of the .MAP object pointed to by poMAPFile.
2023 : *
2024 : * It is assumed that poMAPFile currently points to the beginning of
2025 : * a map object.
2026 : *
2027 : * Returns 0 on success, -1 on error, in which case CPLError() will have
2028 : * been called.
2029 : **********************************************************************/
2030 : int TABPolyline::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
2031 : TABMAPObjHdr *poObjHdr,
2032 : GBool bCoordBlockDataOnly /*=FALSE*/,
2033 1 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
2034 : {
2035 : GInt32 nX, nY;
2036 : double dX, dY, dXMin, dYMin, dXMax, dYMax;
2037 : OGRGeometry *poGeometry;
2038 : OGRLineString *poLine;
2039 1 : GBool bComprCoord = poObjHdr->IsCompressedType();
2040 1 : TABMAPCoordBlock *poCoordBlock = NULL;
2041 :
2042 : /*-----------------------------------------------------------------
2043 : * Fetch and validate geometry type
2044 : *----------------------------------------------------------------*/
2045 1 : m_nMapInfoType = poObjHdr->m_nType;
2046 :
2047 2 : if (m_nMapInfoType == TAB_GEOM_LINE ||
2048 : m_nMapInfoType == TAB_GEOM_LINE_C )
2049 : {
2050 : /*=============================================================
2051 : * LINE (2 vertices)
2052 : *============================================================*/
2053 1 : TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
2054 :
2055 1 : m_bSmooth = FALSE;
2056 :
2057 1 : poGeometry = poLine = new OGRLineString();
2058 1 : poLine->setNumPoints(2);
2059 :
2060 : poMapFile->Int2Coordsys(poLineHdr->m_nX1, poLineHdr->m_nY1,
2061 1 : dXMin, dYMin);
2062 1 : poLine->setPoint(0, dXMin, dYMin);
2063 :
2064 : poMapFile->Int2Coordsys(poLineHdr->m_nX2, poLineHdr->m_nY2,
2065 1 : dXMax, dYMax);
2066 1 : poLine->setPoint(1, dXMax, dYMax);
2067 :
2068 1 : if (!bCoordBlockDataOnly)
2069 : {
2070 1 : m_nPenDefIndex = poLineHdr->m_nPenId; // Pen index
2071 1 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
2072 : }
2073 : }
2074 0 : else if (m_nMapInfoType == TAB_GEOM_PLINE ||
2075 : m_nMapInfoType == TAB_GEOM_PLINE_C )
2076 : {
2077 : /*=============================================================
2078 : * PLINE ( > 2 vertices)
2079 : *============================================================*/
2080 : int i, numPoints, nStatus;
2081 : GUInt32 nCoordDataSize;
2082 : GInt32 nCoordBlockPtr;
2083 :
2084 : /*-------------------------------------------------------------
2085 : * Copy data from poObjHdr
2086 : *------------------------------------------------------------*/
2087 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2088 :
2089 0 : nCoordBlockPtr = poPLineHdr->m_nCoordBlockPtr;
2090 0 : nCoordDataSize = poPLineHdr->m_nCoordDataSize;
2091 : //numLineSections = poPLineHdr->m_numLineSections; // Always 1
2092 0 : m_bSmooth = poPLineHdr->m_bSmooth;
2093 :
2094 : // Centroid/label point
2095 : poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY,
2096 0 : dX, dY);
2097 0 : SetCenter(dX, dY);
2098 :
2099 : // Compressed coordinate origin (useful only in compressed case!)
2100 0 : m_nComprOrgX = poPLineHdr->m_nComprOrgX;
2101 0 : m_nComprOrgY = poPLineHdr->m_nComprOrgY;
2102 :
2103 : // MBR
2104 : poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY,
2105 0 : dXMin, dYMin);
2106 : poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY,
2107 0 : dXMax, dYMax);
2108 :
2109 0 : if (!bCoordBlockDataOnly)
2110 : {
2111 0 : m_nPenDefIndex = poPLineHdr->m_nPenId; // Pen index
2112 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
2113 : }
2114 :
2115 : /*-------------------------------------------------------------
2116 : * Create Geometry and read coordinates
2117 : *------------------------------------------------------------*/
2118 0 : numPoints = nCoordDataSize/(bComprCoord?4:8);
2119 :
2120 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2121 0 : poCoordBlock = *ppoCoordBlock;
2122 : else
2123 0 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
2124 0 : if (poCoordBlock == NULL)
2125 : {
2126 : CPLError(CE_Failure, CPLE_FileIO,
2127 : "Can't access coordinate block at offset %d",
2128 0 : nCoordBlockPtr);
2129 0 : return -1;
2130 : }
2131 :
2132 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2133 :
2134 0 : poGeometry = poLine = new OGRLineString();
2135 0 : poLine->setNumPoints(numPoints);
2136 :
2137 0 : nStatus = 0;
2138 0 : for(i=0; nStatus == 0 && i<numPoints; i++)
2139 : {
2140 0 : nStatus = poCoordBlock->ReadIntCoord(bComprCoord, nX, nY);
2141 0 : if (nStatus != 0)
2142 0 : break;
2143 0 : poMapFile->Int2Coordsys(nX, nY, dX, dY);
2144 0 : poLine->setPoint(i, dX, dY);
2145 : }
2146 :
2147 0 : if (nStatus != 0)
2148 : {
2149 : // Failed ... error message has already been produced
2150 0 : delete poGeometry;
2151 0 : return nStatus;
2152 : }
2153 :
2154 : }
2155 0 : else if (m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
2156 : m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
2157 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
2158 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
2159 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
2160 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C )
2161 : {
2162 : /*=============================================================
2163 : * PLINE MULTIPLE
2164 : *============================================================*/
2165 : int i, iSection;
2166 : GInt32 nCoordBlockPtr, numLineSections;
2167 : GInt32 nCoordDataSize, numPointsTotal, *panXY;
2168 : OGRMultiLineString *poMultiLine;
2169 : TABMAPCoordSecHdr *pasSecHdrs;
2170 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
2171 :
2172 : /*-------------------------------------------------------------
2173 : * Copy data from poObjHdr
2174 : *------------------------------------------------------------*/
2175 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2176 :
2177 0 : nCoordBlockPtr = poPLineHdr->m_nCoordBlockPtr;
2178 0 : nCoordDataSize = poPLineHdr->m_nCoordDataSize;
2179 0 : numLineSections = poPLineHdr->m_numLineSections;
2180 0 : m_bSmooth = poPLineHdr->m_bSmooth;
2181 :
2182 : // Centroid/label point
2183 : poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY,
2184 0 : dX, dY);
2185 0 : SetCenter(dX, dY);
2186 :
2187 : // Compressed coordinate origin (useful only in compressed case!)
2188 0 : m_nComprOrgX = poPLineHdr->m_nComprOrgX;
2189 0 : m_nComprOrgY = poPLineHdr->m_nComprOrgY;
2190 :
2191 : // MBR
2192 : poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY,
2193 0 : dXMin, dYMin);
2194 : poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY,
2195 0 : dXMax, dYMax);
2196 :
2197 0 : if (!bCoordBlockDataOnly)
2198 : {
2199 0 : m_nPenDefIndex = poPLineHdr->m_nPenId; // Pen index
2200 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
2201 : }
2202 :
2203 : /*-------------------------------------------------------------
2204 : * Read data from the coord. block
2205 : *------------------------------------------------------------*/
2206 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
2207 0 : sizeof(TABMAPCoordSecHdr));
2208 :
2209 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2210 0 : poCoordBlock = *ppoCoordBlock;
2211 : else
2212 0 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
2213 :
2214 0 : if (poCoordBlock == NULL ||
2215 : poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion,
2216 : numLineSections,
2217 : pasSecHdrs, numPointsTotal) != 0)
2218 : {
2219 : CPLError(CE_Failure, CPLE_FileIO,
2220 : "Failed reading coordinate data at offset %d",
2221 0 : nCoordBlockPtr);
2222 0 : CPLFree(pasSecHdrs);
2223 0 : return -1;
2224 : }
2225 :
2226 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2227 :
2228 0 : panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
2229 :
2230 0 : if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
2231 : {
2232 : CPLError(CE_Failure, CPLE_FileIO,
2233 : "Failed reading coordinate data at offset %d",
2234 0 : nCoordBlockPtr);
2235 0 : CPLFree(pasSecHdrs);
2236 0 : CPLFree(panXY);
2237 0 : return -1;
2238 : }
2239 :
2240 : /*-------------------------------------------------------------
2241 : * Create a Geometry collection with one line geometry for
2242 : * each coordinates section
2243 : * If object contains only one section, then return a simple LineString
2244 : *------------------------------------------------------------*/
2245 0 : if (numLineSections > 1)
2246 0 : poGeometry = poMultiLine = new OGRMultiLineString();
2247 : else
2248 0 : poGeometry = poMultiLine = NULL;
2249 :
2250 0 : for(iSection=0; iSection<numLineSections; iSection++)
2251 : {
2252 : GInt32 *pnXYPtr;
2253 : int numSectionVertices;
2254 :
2255 0 : numSectionVertices = pasSecHdrs[iSection].numVertices;
2256 0 : pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
2257 :
2258 0 : poLine = new OGRLineString();
2259 0 : poLine->setNumPoints(numSectionVertices);
2260 :
2261 0 : for(i=0; i<numSectionVertices; i++)
2262 : {
2263 0 : poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
2264 0 : poLine->setPoint(i, dX, dY);
2265 0 : pnXYPtr += 2;
2266 : }
2267 :
2268 0 : if (poGeometry==NULL)
2269 0 : poGeometry = poLine;
2270 0 : else if (poMultiLine->addGeometryDirectly(poLine) != OGRERR_NONE)
2271 : {
2272 0 : CPLAssert(FALSE); // Just in case lower-level lib is modified
2273 : }
2274 0 : poLine = NULL;
2275 : }
2276 :
2277 0 : CPLFree(pasSecHdrs);
2278 0 : CPLFree(panXY);
2279 : }
2280 : else
2281 : {
2282 : CPLError(CE_Failure, CPLE_AssertionFailed,
2283 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
2284 0 : m_nMapInfoType, m_nMapInfoType);
2285 0 : return -1;
2286 : }
2287 :
2288 1 : SetGeometryDirectly(poGeometry);
2289 :
2290 1 : SetMBR(dXMin, dYMin, dXMax, dYMax);
2291 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
2292 1 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
2293 :
2294 : /* Return a ref to coord block so that caller can continue reading
2295 : * after the end of this object (used by TABCollection and index splitting)
2296 : */
2297 1 : if (ppoCoordBlock)
2298 0 : *ppoCoordBlock = poCoordBlock;
2299 :
2300 1 : return 0;
2301 : }
2302 :
2303 : /**********************************************************************
2304 : * TABPolyline::WriteGeometryToMAPFile()
2305 : *
2306 : * Write the geometry and representation (color, etc...) part of the
2307 : * feature to the .MAP object pointed to by poMAPFile.
2308 : *
2309 : * It is assumed that poMAPFile currently points to a valid map object.
2310 : *
2311 : * Returns 0 on success, -1 on error, in which case CPLError() will have
2312 : * been called.
2313 : **********************************************************************/
2314 : int TABPolyline::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
2315 : TABMAPObjHdr *poObjHdr,
2316 : GBool bCoordBlockDataOnly /*=FALSE*/,
2317 1 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
2318 : {
2319 : GInt32 nX, nY;
2320 : OGRGeometry *poGeom;
2321 1 : OGRLineString *poLine=NULL;
2322 1 : TABMAPCoordBlock *poCoordBlock = NULL;
2323 :
2324 : /*-----------------------------------------------------------------
2325 : * We assume that ValidateMapInfoType() was called already and that
2326 : * the type in poObjHdr->m_nType is valid.
2327 : *----------------------------------------------------------------*/
2328 1 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
2329 1 : CPLErrorReset();
2330 :
2331 : /*-----------------------------------------------------------------
2332 : * Fetch and validate geometry
2333 : *----------------------------------------------------------------*/
2334 1 : poGeom = GetGeometryRef();
2335 :
2336 1 : if ((m_nMapInfoType == TAB_GEOM_LINE ||
2337 : m_nMapInfoType == TAB_GEOM_LINE_C ) &&
2338 : poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString &&
2339 : (poLine = (OGRLineString*)poGeom)->getNumPoints() == 2)
2340 : {
2341 : /*=============================================================
2342 : * LINE (2 vertices)
2343 : *============================================================*/
2344 1 : TABMAPObjLine *poLineHdr = (TABMAPObjLine *)poObjHdr;
2345 :
2346 : poMapFile->Coordsys2Int(poLine->getX(0), poLine->getY(0),
2347 1 : poLineHdr->m_nX1, poLineHdr->m_nY1);
2348 : poMapFile->Coordsys2Int(poLine->getX(1), poLine->getY(1),
2349 1 : poLineHdr->m_nX2, poLineHdr->m_nY2);
2350 : poLineHdr->SetMBR(poLineHdr->m_nX1, poLineHdr->m_nY1,
2351 1 : poLineHdr->m_nX2, poLineHdr->m_nY2 );
2352 :
2353 1 : if (!bCoordBlockDataOnly)
2354 : {
2355 1 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
2356 1 : poLineHdr->m_nPenId = m_nPenDefIndex; // Pen index
2357 : }
2358 :
2359 : }
2360 0 : else if ((m_nMapInfoType == TAB_GEOM_PLINE ||
2361 : m_nMapInfoType == TAB_GEOM_PLINE_C ) &&
2362 : poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString )
2363 : {
2364 : /*=============================================================
2365 : * PLINE ( > 2 vertices and less than 32767 vertices)
2366 : *============================================================*/
2367 : int i, numPoints, nStatus;
2368 : GUInt32 nCoordDataSize;
2369 : GInt32 nCoordBlockPtr;
2370 0 : GBool bCompressed = poObjHdr->IsCompressedType();
2371 :
2372 : /*-------------------------------------------------------------
2373 : * Process geometry first...
2374 : *------------------------------------------------------------*/
2375 0 : poLine = (OGRLineString*)poGeom;
2376 0 : numPoints = poLine->getNumPoints();
2377 0 : CPLAssert(numPoints <= TAB_REGION_PLINE_300_MAX_VERTICES);
2378 :
2379 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2380 0 : poCoordBlock = *ppoCoordBlock;
2381 : else
2382 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
2383 0 : poCoordBlock->StartNewFeature();
2384 0 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
2385 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2386 :
2387 0 : nStatus = 0;
2388 0 : for(i=0; nStatus == 0 && i<numPoints; i++)
2389 : {
2390 0 : poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i), nX, nY);
2391 0 : if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY,
2392 : bCompressed)) != 0)
2393 : {
2394 : // Failed ... error message has already been produced
2395 0 : return nStatus;
2396 : }
2397 : }
2398 :
2399 0 : nCoordDataSize = poCoordBlock->GetFeatureDataSize();
2400 :
2401 : /*-------------------------------------------------------------
2402 : * Copy info to poObjHdr
2403 : *------------------------------------------------------------*/
2404 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2405 :
2406 0 : poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
2407 0 : poPLineHdr->m_nCoordDataSize = nCoordDataSize;
2408 0 : poPLineHdr->m_numLineSections = 1;
2409 :
2410 0 : poPLineHdr->m_bSmooth = m_bSmooth;
2411 :
2412 : // MBR
2413 0 : poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
2414 :
2415 : // Polyline center/label point
2416 : double dX, dY;
2417 0 : if (GetCenter(dX, dY) != -1)
2418 : {
2419 : poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX,
2420 0 : poPLineHdr->m_nLabelY);
2421 : }
2422 : else
2423 : {
2424 0 : poPLineHdr->m_nLabelX = m_nComprOrgX;
2425 0 : poPLineHdr->m_nLabelY = m_nComprOrgY;
2426 : }
2427 :
2428 : // Compressed coordinate origin (useful only in compressed case!)
2429 0 : poPLineHdr->m_nComprOrgX = m_nComprOrgX;
2430 0 : poPLineHdr->m_nComprOrgY = m_nComprOrgY;
2431 :
2432 0 : if (!bCoordBlockDataOnly)
2433 : {
2434 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
2435 0 : poPLineHdr->m_nPenId = m_nPenDefIndex; // Pen index
2436 : }
2437 :
2438 : }
2439 0 : else if ((m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
2440 : m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
2441 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
2442 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
2443 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
2444 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C) &&
2445 : poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString ||
2446 : wkbFlatten(poGeom->getGeometryType()) == wkbLineString) )
2447 : {
2448 : /*=============================================================
2449 : * PLINE MULTIPLE (or single PLINE with more than 32767 vertices)
2450 : *============================================================*/
2451 0 : int nStatus=0, i, iLine;
2452 : GInt32 numPointsTotal, numPoints;
2453 : GUInt32 nCoordDataSize;
2454 : GInt32 nCoordBlockPtr, numLines;
2455 0 : OGRMultiLineString *poMultiLine=NULL;
2456 : TABMAPCoordSecHdr *pasSecHdrs;
2457 0 : OGREnvelope sEnvelope;
2458 0 : GBool bCompressed = poObjHdr->IsCompressedType();
2459 :
2460 0 : CPLAssert(m_nMapInfoType == TAB_GEOM_MULTIPLINE ||
2461 : m_nMapInfoType == TAB_GEOM_MULTIPLINE_C ||
2462 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE ||
2463 : m_nMapInfoType == TAB_GEOM_V450_MULTIPLINE_C ||
2464 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE ||
2465 : m_nMapInfoType == TAB_GEOM_V800_MULTIPLINE_C);
2466 : /*-------------------------------------------------------------
2467 : * Process geometry first...
2468 : *------------------------------------------------------------*/
2469 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
2470 0 : poCoordBlock = *ppoCoordBlock;
2471 : else
2472 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
2473 0 : poCoordBlock->StartNewFeature();
2474 0 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
2475 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
2476 :
2477 0 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2478 : {
2479 0 : poMultiLine = (OGRMultiLineString*)poGeom;
2480 0 : numLines = poMultiLine->getNumGeometries();
2481 : }
2482 : else
2483 : {
2484 0 : poMultiLine = NULL;
2485 0 : numLines = 1;
2486 : }
2487 :
2488 : /*-------------------------------------------------------------
2489 : * Build and write array of coord sections headers
2490 : *------------------------------------------------------------*/
2491 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLCalloc(numLines,
2492 0 : sizeof(TABMAPCoordSecHdr));
2493 :
2494 : /*-------------------------------------------------------------
2495 : * In calculation of nDataOffset, we have to take into account that
2496 : * V450 header section uses int32 instead of int16 for numVertices
2497 : * and we add another 2 bytes to align with a 4 bytes boundary.
2498 : *------------------------------------------------------------*/
2499 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
2500 :
2501 : int nTotalHdrSizeUncompressed;
2502 0 : if (nVersion >= 450)
2503 0 : nTotalHdrSizeUncompressed = 28 * numLines;
2504 : else
2505 0 : nTotalHdrSizeUncompressed = 24 * numLines;
2506 :
2507 0 : numPointsTotal = 0;
2508 0 : for(iLine=0; iLine < numLines; iLine++)
2509 : {
2510 0 : if (poMultiLine)
2511 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2512 :
2513 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2514 : {
2515 0 : poLine = (OGRLineString*)poGeom;
2516 0 : numPoints = poLine->getNumPoints();
2517 0 : poLine->getEnvelope(&sEnvelope);
2518 :
2519 0 : pasSecHdrs[iLine].numVertices = poLine->getNumPoints();
2520 0 : pasSecHdrs[iLine].numHoles = 0; // It's a line!
2521 :
2522 : poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
2523 : pasSecHdrs[iLine].nXMin,
2524 0 : pasSecHdrs[iLine].nYMin);
2525 : poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
2526 : pasSecHdrs[iLine].nXMax,
2527 0 : pasSecHdrs[iLine].nYMax);
2528 : pasSecHdrs[iLine].nDataOffset = nTotalHdrSizeUncompressed +
2529 0 : numPointsTotal*4*2;
2530 0 : pasSecHdrs[iLine].nVertexOffset = numPointsTotal;
2531 :
2532 0 : numPointsTotal += numPoints;
2533 : }
2534 : else
2535 : {
2536 : CPLError(CE_Failure, CPLE_AssertionFailed,
2537 0 : "TABPolyline: Object contains an invalid Geometry!");
2538 0 : nStatus = -1;
2539 : }
2540 :
2541 : }
2542 :
2543 0 : if (nStatus == 0)
2544 : nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numLines,
2545 0 : pasSecHdrs, bCompressed);
2546 :
2547 0 : CPLFree(pasSecHdrs);
2548 0 : pasSecHdrs = NULL;
2549 :
2550 0 : if (nStatus != 0)
2551 0 : return nStatus; // Error has already been reported.
2552 :
2553 : /*-------------------------------------------------------------
2554 : * Then write the coordinates themselves...
2555 : *------------------------------------------------------------*/
2556 0 : for(iLine=0; nStatus == 0 && iLine < numLines; iLine++)
2557 : {
2558 0 : if (poMultiLine)
2559 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2560 :
2561 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2562 : {
2563 0 : poLine = (OGRLineString*)poGeom;
2564 0 : numPoints = poLine->getNumPoints();
2565 :
2566 0 : for(i=0; nStatus == 0 && i<numPoints; i++)
2567 : {
2568 : poMapFile->Coordsys2Int(poLine->getX(i), poLine->getY(i),
2569 0 : nX, nY);
2570 0 : if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
2571 : bCompressed)) != 0)
2572 : {
2573 : // Failed ... error message has already been produced
2574 0 : return nStatus;
2575 : }
2576 : }
2577 : }
2578 : else
2579 : {
2580 : CPLError(CE_Failure, CPLE_AssertionFailed,
2581 0 : "TABPolyline: Object contains an invalid Geometry!");
2582 0 : return -1;
2583 : }
2584 :
2585 : }
2586 :
2587 0 : nCoordDataSize = poCoordBlock->GetFeatureDataSize();
2588 :
2589 : /*-------------------------------------------------------------
2590 : * ... and finally copy info to poObjHdr
2591 : *------------------------------------------------------------*/
2592 0 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2593 :
2594 0 : poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
2595 0 : poPLineHdr->m_nCoordDataSize = nCoordDataSize;
2596 0 : poPLineHdr->m_numLineSections = numLines;
2597 :
2598 0 : poPLineHdr->m_bSmooth = m_bSmooth;
2599 :
2600 : // MBR
2601 0 : poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
2602 :
2603 : // Polyline center/label point
2604 : double dX, dY;
2605 0 : if (GetCenter(dX, dY) != -1)
2606 : {
2607 : poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX,
2608 0 : poPLineHdr->m_nLabelY);
2609 : }
2610 : else
2611 : {
2612 0 : poPLineHdr->m_nLabelX = m_nComprOrgX;
2613 0 : poPLineHdr->m_nLabelY = m_nComprOrgY;
2614 : }
2615 :
2616 : // Compressed coordinate origin (useful only in compressed case!)
2617 0 : poPLineHdr->m_nComprOrgX = m_nComprOrgX;
2618 0 : poPLineHdr->m_nComprOrgY = m_nComprOrgY;
2619 :
2620 0 : if (!bCoordBlockDataOnly)
2621 : {
2622 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
2623 0 : poPLineHdr->m_nPenId = m_nPenDefIndex; // Pen index
2624 : }
2625 :
2626 : }
2627 : else
2628 : {
2629 : CPLError(CE_Failure, CPLE_AssertionFailed,
2630 0 : "TABPolyline: Object contains an invalid Geometry!");
2631 0 : return -1;
2632 : }
2633 :
2634 1 : if (CPLGetLastErrorType() == CE_Failure )
2635 0 : return -1;
2636 :
2637 : /* Return a ref to coord block so that caller can continue writing
2638 : * after the end of this object (used by index splitting)
2639 : */
2640 1 : if (ppoCoordBlock)
2641 0 : *ppoCoordBlock = poCoordBlock;
2642 :
2643 1 : return 0;
2644 : }
2645 :
2646 : /**********************************************************************
2647 : * TABPolyline::GetStyleString()
2648 : *
2649 : * Return style string for this feature.
2650 : *
2651 : * Style String is built only once during the first call to GetStyleString().
2652 : **********************************************************************/
2653 0 : const char *TABPolyline::GetStyleString()
2654 : {
2655 0 : if (m_pszStyleString == NULL)
2656 : {
2657 0 : m_pszStyleString = CPLStrdup(GetPenStyleString());
2658 : }
2659 :
2660 0 : return m_pszStyleString;
2661 : }
2662 :
2663 :
2664 : /**********************************************************************
2665 : * TABPolyline::DumpMIF()
2666 : *
2667 : * Dump feature geometry in a format similar to .MIF PLINEs.
2668 : **********************************************************************/
2669 0 : void TABPolyline::DumpMIF(FILE *fpOut /*=NULL*/)
2670 : {
2671 : OGRGeometry *poGeom;
2672 0 : OGRMultiLineString *poMultiLine = NULL;
2673 0 : OGRLineString *poLine = NULL;
2674 : int i, numPoints;
2675 :
2676 0 : if (fpOut == NULL)
2677 0 : fpOut = stdout;
2678 :
2679 : /*-----------------------------------------------------------------
2680 : * Fetch and validate geometry
2681 : *----------------------------------------------------------------*/
2682 0 : poGeom = GetGeometryRef();
2683 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2684 : {
2685 : /*-------------------------------------------------------------
2686 : * Generate output for simple polyline
2687 : *------------------------------------------------------------*/
2688 0 : poLine = (OGRLineString*)poGeom;
2689 0 : numPoints = poLine->getNumPoints();
2690 0 : fprintf(fpOut, "PLINE %d\n", numPoints);
2691 0 : for(i=0; i<numPoints; i++)
2692 0 : fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
2693 : }
2694 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2695 : {
2696 : /*-------------------------------------------------------------
2697 : * Generate output for multiple polyline
2698 : *------------------------------------------------------------*/
2699 : int iLine, numLines;
2700 0 : poMultiLine = (OGRMultiLineString*)poGeom;
2701 0 : numLines = poMultiLine->getNumGeometries();
2702 0 : fprintf(fpOut, "PLINE MULTIPLE %d\n", numLines);
2703 0 : for(iLine=0; iLine < numLines; iLine++)
2704 : {
2705 0 : poGeom = poMultiLine->getGeometryRef(iLine);
2706 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2707 : {
2708 0 : poLine = (OGRLineString*)poGeom;
2709 0 : numPoints = poLine->getNumPoints();
2710 0 : fprintf(fpOut, " %d\n", numPoints);
2711 0 : for(i=0; i<numPoints; i++)
2712 0 : fprintf(fpOut, "%.15g %.15g\n",poLine->getX(i),poLine->getY(i));
2713 : }
2714 : else
2715 : {
2716 : CPLError(CE_Failure, CPLE_AssertionFailed,
2717 0 : "TABPolyline: Object contains an invalid Geometry!");
2718 0 : return;
2719 : }
2720 :
2721 : }
2722 : }
2723 : else
2724 : {
2725 : CPLError(CE_Failure, CPLE_AssertionFailed,
2726 0 : "TABPolyline: Missing or Invalid Geometry!");
2727 0 : return;
2728 : }
2729 :
2730 0 : if (m_bCenterIsSet)
2731 0 : fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
2732 :
2733 : // Finish with PEN/BRUSH/etc. clauses
2734 0 : DumpPenDef();
2735 :
2736 0 : fflush(fpOut);
2737 : }
2738 :
2739 : /**********************************************************************
2740 : * TABPolyline::GetCenter()
2741 : *
2742 : * Returns the center point of the line. Compute one if it was not
2743 : * explicitly set:
2744 : *
2745 : * In MapInfo, for a simple or multiple polyline (pline), the center point
2746 : * in the object definition is supposed to be either the center point of
2747 : * the pline or the first section of a multiple pline (if an odd number of
2748 : * points in the pline or first section), or the midway point between the
2749 : * two central points (if an even number of points involved).
2750 : *
2751 : * Returns 0 on success, -1 on error.
2752 : **********************************************************************/
2753 0 : int TABPolyline::GetCenter(double &dX, double &dY)
2754 : {
2755 0 : if (!m_bCenterIsSet)
2756 : {
2757 : OGRGeometry *poGeom;
2758 0 : OGRLineString *poLine = NULL;
2759 :
2760 0 : poGeom = GetGeometryRef();
2761 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
2762 : {
2763 0 : poLine = (OGRLineString *)poGeom;
2764 : }
2765 0 : else if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)
2766 : {
2767 0 : OGRMultiLineString *poMultiLine = (OGRMultiLineString*)poGeom;
2768 0 : if (poMultiLine->getNumGeometries() > 0)
2769 0 : poLine = (OGRLineString *)poMultiLine->getGeometryRef(0);
2770 : }
2771 :
2772 0 : if (poLine && poLine->getNumPoints() > 0)
2773 : {
2774 0 : int i = poLine->getNumPoints()/2;
2775 0 : if (poLine->getNumPoints() % 2 == 0)
2776 : {
2777 : // Return the midway between the 2 center points
2778 0 : m_dCenterX = (poLine->getX(i-1) + poLine->getX(i))/2.0;
2779 0 : m_dCenterY = (poLine->getY(i-1) + poLine->getY(i))/2.0;
2780 : }
2781 : else
2782 : {
2783 : // Return the center point
2784 0 : m_dCenterX = poLine->getX(i);
2785 0 : m_dCenterY = poLine->getY(i);
2786 : }
2787 0 : m_bCenterIsSet = TRUE;
2788 : }
2789 : }
2790 :
2791 0 : if (!m_bCenterIsSet)
2792 0 : return -1;
2793 :
2794 0 : dX = m_dCenterX;
2795 0 : dY = m_dCenterY;
2796 0 : return 0;
2797 : }
2798 :
2799 : /**********************************************************************
2800 : * TABPolyline::SetCenter()
2801 : *
2802 : * Set the X,Y coordinates to use as center point for the line.
2803 : **********************************************************************/
2804 0 : void TABPolyline::SetCenter(double dX, double dY)
2805 : {
2806 0 : m_dCenterX = dX;
2807 0 : m_dCenterY = dY;
2808 0 : m_bCenterIsSet = TRUE;
2809 0 : }
2810 :
2811 : /**********************************************************************
2812 : * TABPolyline::TwoPointLineAsPolyline()
2813 : *
2814 : * Returns the value of m_bWriteTwoPointLineAsPolyline
2815 : **********************************************************************/
2816 0 : GBool TABPolyline::TwoPointLineAsPolyline()
2817 : {
2818 0 : return m_bWriteTwoPointLineAsPolyline;
2819 : }
2820 :
2821 : /**********************************************************************
2822 : * TABPolyline::TwoPointLineAsPolyline()
2823 : *
2824 : * Sets the value of m_bWriteTwoPointLineAsPolyline
2825 : **********************************************************************/
2826 0 : void TABPolyline::TwoPointLineAsPolyline(GBool bTwoPointLineAsPolyline)
2827 : {
2828 0 : m_bWriteTwoPointLineAsPolyline = bTwoPointLineAsPolyline;
2829 0 : }
2830 :
2831 :
2832 : /*=====================================================================
2833 : * class TABRegion
2834 : *====================================================================*/
2835 :
2836 : /**********************************************************************
2837 : * TABRegion::TABRegion()
2838 : *
2839 : * Constructor.
2840 : **********************************************************************/
2841 100 : TABRegion::TABRegion(OGRFeatureDefn *poDefnIn):
2842 100 : TABFeature(poDefnIn)
2843 : {
2844 100 : m_bCenterIsSet = FALSE;
2845 100 : m_bSmooth = FALSE;
2846 100 : }
2847 :
2848 : /**********************************************************************
2849 : * TABRegion::~TABRegion()
2850 : *
2851 : * Destructor.
2852 : **********************************************************************/
2853 100 : TABRegion::~TABRegion()
2854 : {
2855 100 : }
2856 :
2857 : /**********************************************************************
2858 : * TABRegion::CloneTABFeature()
2859 : *
2860 : * Duplicate feature, including stuff specific to each TABFeature type.
2861 : *
2862 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
2863 : * then copies any members specific to its own type.
2864 : **********************************************************************/
2865 0 : TABFeature *TABRegion::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
2866 : {
2867 : /*-----------------------------------------------------------------
2868 : * Alloc new feature and copy the base stuff
2869 : *----------------------------------------------------------------*/
2870 0 : TABRegion *poNew = new TABRegion(poNewDefn ? poNewDefn : GetDefnRef());
2871 :
2872 0 : CopyTABFeatureBase(poNew);
2873 :
2874 : /*-----------------------------------------------------------------
2875 : * And members specific to this class
2876 : *----------------------------------------------------------------*/
2877 : // ITABFeaturePen
2878 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
2879 :
2880 : // ITABFeatureBrush
2881 0 : *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
2882 :
2883 0 : poNew->m_bSmooth = m_bSmooth;
2884 0 : poNew->m_bCenterIsSet = m_bCenterIsSet;
2885 0 : poNew->m_dCenterX = m_dCenterX;
2886 0 : poNew->m_dCenterY = m_dCenterY;
2887 :
2888 0 : return poNew;
2889 : }
2890 :
2891 : /**********************************************************************
2892 : * TABRegion::ValidateMapInfoType()
2893 : *
2894 : * Check the feature's geometry part and return the corresponding
2895 : * mapinfo object type code. The m_nMapInfoType member will also
2896 : * be updated for further calls to GetMapInfoType();
2897 : *
2898 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
2899 : * is expected for this object class.
2900 : **********************************************************************/
2901 11 : int TABRegion::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
2902 : {
2903 : OGRGeometry *poGeom;
2904 :
2905 : /*-----------------------------------------------------------------
2906 : * Fetch and validate geometry
2907 : *----------------------------------------------------------------*/
2908 11 : poGeom = GetGeometryRef();
2909 11 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
2910 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
2911 : {
2912 11 : GInt32 numPointsTotal=0, numRings=GetNumRings();
2913 22 : for(int i=0; i<numRings; i++)
2914 : {
2915 11 : OGRLinearRing *poRing = GetRingRef(i);
2916 11 : if (poRing)
2917 11 : numPointsTotal += poRing->getNumPoints();
2918 : }
2919 11 : if ( TAB_REGION_PLINE_REQUIRES_V800(numRings, numPointsTotal) )
2920 0 : m_nMapInfoType = TAB_GEOM_V800_REGION;
2921 11 : else if (numPointsTotal > TAB_REGION_PLINE_300_MAX_VERTICES)
2922 0 : m_nMapInfoType = TAB_GEOM_V450_REGION;
2923 : else
2924 11 : m_nMapInfoType = TAB_GEOM_REGION;
2925 :
2926 : }
2927 : else
2928 : {
2929 : CPLError(CE_Failure, CPLE_AssertionFailed,
2930 0 : "TABRegion: Missing or Invalid Geometry!");
2931 0 : m_nMapInfoType = TAB_GEOM_NONE;
2932 : }
2933 :
2934 : /*-----------------------------------------------------------------
2935 : * Decide if coordinates should be compressed or not.
2936 : *----------------------------------------------------------------*/
2937 11 : ValidateCoordType(poMapFile);
2938 :
2939 11 : return m_nMapInfoType;
2940 : }
2941 :
2942 : /**********************************************************************
2943 : * TABRegion::ReadGeometryFromMAPFile()
2944 : *
2945 : * Fill the geometry and representation (color, etc...) part of the
2946 : * feature from the contents of the .MAP object pointed to by poMAPFile.
2947 : *
2948 : * It is assumed that poMAPFile currently points to the beginning of
2949 : * a map object.
2950 : *
2951 : * Returns 0 on success, -1 on error, in which case CPLError() will have
2952 : * been called.
2953 : **********************************************************************/
2954 : int TABRegion::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
2955 : TABMAPObjHdr *poObjHdr,
2956 : GBool bCoordBlockDataOnly /*=FALSE*/,
2957 51 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
2958 : {
2959 : double dX, dY, dXMin, dYMin, dXMax, dYMax;
2960 : OGRGeometry *poGeometry;
2961 : OGRLinearRing *poRing;
2962 51 : TABMAPCoordBlock *poCoordBlock = NULL;
2963 :
2964 : /*-----------------------------------------------------------------
2965 : * Fetch and validate geometry type
2966 : *----------------------------------------------------------------*/
2967 51 : m_nMapInfoType = poObjHdr->m_nType;
2968 :
2969 51 : if (m_nMapInfoType == TAB_GEOM_REGION ||
2970 : m_nMapInfoType == TAB_GEOM_REGION_C ||
2971 : m_nMapInfoType == TAB_GEOM_V450_REGION ||
2972 : m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
2973 : m_nMapInfoType == TAB_GEOM_V800_REGION ||
2974 : m_nMapInfoType == TAB_GEOM_V800_REGION_C )
2975 : {
2976 : /*=============================================================
2977 : * REGION (Similar to PLINE MULTIPLE)
2978 : *============================================================*/
2979 : int i, iSection;
2980 : GInt32 nCoordBlockPtr, numLineSections;
2981 : GInt32 nCoordDataSize, numPointsTotal, *panXY;
2982 51 : OGRMultiPolygon *poMultiPolygon = NULL;
2983 51 : OGRPolygon *poPolygon = NULL;
2984 : TABMAPCoordSecHdr *pasSecHdrs;
2985 51 : GBool bComprCoord = poObjHdr->IsCompressedType();
2986 51 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
2987 :
2988 : /*-------------------------------------------------------------
2989 : * Copy data from poObjHdr
2990 : *------------------------------------------------------------*/
2991 51 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
2992 :
2993 51 : nCoordBlockPtr = poPLineHdr->m_nCoordBlockPtr;
2994 51 : nCoordDataSize = poPLineHdr->m_nCoordDataSize;
2995 51 : numLineSections = poPLineHdr->m_numLineSections;
2996 51 : m_bSmooth = poPLineHdr->m_bSmooth;
2997 :
2998 : // Centroid/label point
2999 : poMapFile->Int2Coordsys(poPLineHdr->m_nLabelX, poPLineHdr->m_nLabelY,
3000 51 : dX, dY);
3001 51 : SetCenter(dX, dY);
3002 :
3003 : // Compressed coordinate origin (useful only in compressed case!)
3004 51 : m_nComprOrgX = poPLineHdr->m_nComprOrgX;
3005 51 : m_nComprOrgY = poPLineHdr->m_nComprOrgY;
3006 :
3007 : // MBR
3008 : poMapFile->Int2Coordsys(poPLineHdr->m_nMinX, poPLineHdr->m_nMinY,
3009 51 : dXMin, dYMin);
3010 : poMapFile->Int2Coordsys(poPLineHdr->m_nMaxX, poPLineHdr->m_nMaxY,
3011 51 : dXMax, dYMax);
3012 :
3013 51 : if (!bCoordBlockDataOnly)
3014 : {
3015 51 : m_nPenDefIndex = poPLineHdr->m_nPenId; // Pen index
3016 51 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
3017 51 : m_nBrushDefIndex = poPLineHdr->m_nBrushId; // Brush index
3018 51 : poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
3019 : }
3020 :
3021 : /*-------------------------------------------------------------
3022 : * Read data from the coord. block
3023 : *------------------------------------------------------------*/
3024 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLMalloc(numLineSections*
3025 51 : sizeof(TABMAPCoordSecHdr));
3026 :
3027 51 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
3028 0 : poCoordBlock = *ppoCoordBlock;
3029 : else
3030 51 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
3031 :
3032 51 : if (poCoordBlock)
3033 51 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
3034 :
3035 51 : if (poCoordBlock == NULL ||
3036 : poCoordBlock->ReadCoordSecHdrs(bComprCoord, nVersion,
3037 : numLineSections,
3038 : pasSecHdrs, numPointsTotal) != 0)
3039 : {
3040 : CPLError(CE_Failure, CPLE_FileIO,
3041 : "Failed reading coordinate data at offset %d",
3042 0 : nCoordBlockPtr);
3043 0 : CPLFree(pasSecHdrs);
3044 0 : return -1;
3045 : }
3046 :
3047 51 : panXY = (GInt32*)CPLMalloc(numPointsTotal*2*sizeof(GInt32));
3048 :
3049 51 : if (poCoordBlock->ReadIntCoords(bComprCoord,numPointsTotal,panXY) != 0)
3050 : {
3051 : CPLError(CE_Failure, CPLE_FileIO,
3052 : "Failed reading coordinate data at offset %d",
3053 0 : nCoordBlockPtr);
3054 0 : CPLFree(pasSecHdrs);
3055 0 : CPLFree(panXY);
3056 0 : return -1;
3057 : }
3058 :
3059 : /*-------------------------------------------------------------
3060 : * Decide if we should return an OGRPolygon or an OGRMultiPolygon
3061 : * depending on the number of outer rings found in CoordSecHdr blocks.
3062 : * The CoodSecHdr block for each outer ring in the region has a flag
3063 : * indicating the number of inner rings that follow.
3064 : * In older versions of the format, the count of inner rings was
3065 : * always zero, so in this case we would always return MultiPolygons.
3066 : *
3067 : * Note: The current implementation assumes that there cannot be
3068 : * holes inside holes (i.e. multiple levels of inner rings)... if
3069 : * that case was encountered then we would return an OGRMultiPolygon
3070 : * in which the topological relationship between the rings would
3071 : * be lost.
3072 : *------------------------------------------------------------*/
3073 51 : int numOuterRings = 0;
3074 102 : for(iSection=0; iSection<numLineSections; iSection++)
3075 : {
3076 : // Count this as an outer ring.
3077 51 : numOuterRings++;
3078 : // Skip inner rings... so loop continues on an outer ring.
3079 51 : iSection += pasSecHdrs[iSection].numHoles;
3080 : }
3081 :
3082 51 : if (numOuterRings > 1)
3083 0 : poGeometry = poMultiPolygon = new OGRMultiPolygon;
3084 : else
3085 51 : poGeometry = NULL; // Will be set later
3086 :
3087 : /*-------------------------------------------------------------
3088 : * OK, build the OGRGeometry object.
3089 : *------------------------------------------------------------*/
3090 51 : int numHolesToRead = 0;
3091 51 : poPolygon = NULL;
3092 102 : for(iSection=0; iSection<numLineSections; iSection++)
3093 : {
3094 : GInt32 *pnXYPtr;
3095 : int numSectionVertices;
3096 :
3097 51 : if (poPolygon == NULL)
3098 51 : poPolygon = new OGRPolygon();
3099 :
3100 51 : if (numHolesToRead < 1)
3101 51 : numHolesToRead = pasSecHdrs[iSection].numHoles;
3102 : else
3103 0 : numHolesToRead--;
3104 :
3105 51 : numSectionVertices = pasSecHdrs[iSection].numVertices;
3106 51 : pnXYPtr = panXY + (pasSecHdrs[iSection].nVertexOffset * 2);
3107 :
3108 51 : poRing = new OGRLinearRing();
3109 51 : poRing->setNumPoints(numSectionVertices);
3110 :
3111 1281 : for(i=0; i<numSectionVertices; i++)
3112 : {
3113 1230 : poMapFile->Int2Coordsys(*pnXYPtr, *(pnXYPtr+1), dX, dY);
3114 1230 : poRing->setPoint(i, dX, dY);
3115 1230 : pnXYPtr += 2;
3116 : }
3117 :
3118 51 : poPolygon->addRingDirectly(poRing);
3119 51 : poRing = NULL;
3120 :
3121 51 : if (numHolesToRead < 1)
3122 : {
3123 51 : if (numOuterRings > 1)
3124 : {
3125 0 : poMultiPolygon->addGeometryDirectly(poPolygon);
3126 : }
3127 : else
3128 : {
3129 51 : poGeometry = poPolygon;
3130 51 : CPLAssert(iSection == numLineSections-1);
3131 : }
3132 :
3133 51 : poPolygon = NULL; // We'll alloc a new polygon next loop.
3134 : }
3135 :
3136 : }
3137 :
3138 51 : CPLFree(pasSecHdrs);
3139 51 : CPLFree(panXY);
3140 : }
3141 : else
3142 : {
3143 : CPLError(CE_Failure, CPLE_AssertionFailed,
3144 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
3145 0 : m_nMapInfoType, m_nMapInfoType);
3146 0 : return -1;
3147 : }
3148 :
3149 51 : SetGeometryDirectly(poGeometry);
3150 :
3151 51 : SetMBR(dXMin, dYMin, dXMax, dYMax);
3152 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
3153 51 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
3154 :
3155 : /* Return a ref to coord block so that caller can continue reading
3156 : * after the end of this object (used by TABCollection and index splitting)
3157 : */
3158 51 : if (ppoCoordBlock)
3159 0 : *ppoCoordBlock = poCoordBlock;
3160 :
3161 51 : return 0;
3162 : }
3163 :
3164 : /**********************************************************************
3165 : * TABRegion::WriteGeometryToMAPFile()
3166 : *
3167 : * Write the geometry and representation (color, etc...) part of the
3168 : * feature to the .MAP object pointed to by poMAPFile.
3169 : *
3170 : * It is assumed that poMAPFile currently points to a valid map object.
3171 : *
3172 : * Returns 0 on success, -1 on error, in which case CPLError() will have
3173 : * been called.
3174 : **********************************************************************/
3175 : int TABRegion::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
3176 : TABMAPObjHdr *poObjHdr,
3177 : GBool bCoordBlockDataOnly /*=FALSE*/,
3178 11 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
3179 : {
3180 : GInt32 nX, nY;
3181 : OGRGeometry *poGeom;
3182 11 : TABMAPCoordBlock *poCoordBlock=NULL;
3183 :
3184 : /*-----------------------------------------------------------------
3185 : * We assume that ValidateMapInfoType() was called already and that
3186 : * the type in poObjHdr->m_nType is valid.
3187 : *----------------------------------------------------------------*/
3188 11 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
3189 :
3190 : /*-----------------------------------------------------------------
3191 : * Fetch and validate geometry
3192 : *----------------------------------------------------------------*/
3193 11 : poGeom = GetGeometryRef();
3194 :
3195 11 : if ((m_nMapInfoType == TAB_GEOM_REGION ||
3196 : m_nMapInfoType == TAB_GEOM_REGION_C ||
3197 : m_nMapInfoType == TAB_GEOM_V450_REGION ||
3198 : m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
3199 : m_nMapInfoType == TAB_GEOM_V800_REGION ||
3200 : m_nMapInfoType == TAB_GEOM_V800_REGION_C) &&
3201 : poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3202 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3203 : {
3204 : /*=============================================================
3205 : * REGIONs are similar to PLINE MULTIPLE
3206 : *
3207 : * We accept both OGRPolygons (with one or multiple rings) and
3208 : * OGRMultiPolygons as input.
3209 : *============================================================*/
3210 11 : int nStatus=0, i, iRing;
3211 : int numRingsTotal;
3212 : GUInt32 nCoordDataSize;
3213 : GInt32 nCoordBlockPtr;
3214 11 : TABMAPCoordSecHdr *pasSecHdrs = NULL;
3215 11 : GBool bCompressed = poObjHdr->IsCompressedType();
3216 :
3217 : /*-------------------------------------------------------------
3218 : * Process geometry first...
3219 : *------------------------------------------------------------*/
3220 11 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
3221 0 : poCoordBlock = *ppoCoordBlock;
3222 : else
3223 11 : poCoordBlock = poMapFile->GetCurCoordBlock();
3224 11 : poCoordBlock->StartNewFeature();
3225 11 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
3226 11 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
3227 :
3228 : #ifdef TABDUMP
3229 : printf("TABRegion::WriteGeometryToMAPFile(): ComprOrgX,Y= (%d,%d)\n",
3230 : m_nComprOrgX, m_nComprOrgY);
3231 : #endif
3232 : /*-------------------------------------------------------------
3233 : * Fetch total number of rings and build array of coord
3234 : * sections headers.
3235 : *------------------------------------------------------------*/
3236 11 : numRingsTotal = ComputeNumRings(&pasSecHdrs, poMapFile);
3237 11 : if (numRingsTotal == 0)
3238 0 : nStatus = -1;
3239 :
3240 : /*-------------------------------------------------------------
3241 : * Write the Coord. Section Header
3242 : *------------------------------------------------------------*/
3243 11 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
3244 :
3245 11 : if (nStatus == 0)
3246 : nStatus = poCoordBlock->WriteCoordSecHdrs(nVersion, numRingsTotal,
3247 11 : pasSecHdrs, bCompressed);
3248 :
3249 11 : CPLFree(pasSecHdrs);
3250 11 : pasSecHdrs = NULL;
3251 :
3252 11 : if (nStatus != 0)
3253 0 : return nStatus; // Error has already been reported.
3254 :
3255 : /*-------------------------------------------------------------
3256 : * Go through all the rings in our OGRMultiPolygon or OGRPolygon
3257 : * to write the coordinates themselves...
3258 : *------------------------------------------------------------*/
3259 :
3260 22 : for(iRing=0; iRing < numRingsTotal; iRing++)
3261 : {
3262 : OGRLinearRing *poRing;
3263 :
3264 11 : poRing = GetRingRef(iRing);
3265 11 : if (poRing == NULL)
3266 : {
3267 : CPLError(CE_Failure, CPLE_AssertionFailed,
3268 0 : "TABRegion: Object Geometry contains NULL rings!");
3269 0 : return -1;
3270 : }
3271 :
3272 11 : int numPoints = poRing->getNumPoints();
3273 :
3274 261 : for(i=0; nStatus == 0 && i<numPoints; i++)
3275 : {
3276 : poMapFile->Coordsys2Int(poRing->getX(i), poRing->getY(i),
3277 250 : nX, nY);
3278 250 : if ((nStatus=poCoordBlock->WriteIntCoord(nX, nY,
3279 : bCompressed)) != 0)
3280 : {
3281 : // Failed ... error message has already been produced
3282 0 : return nStatus;
3283 : }
3284 : }
3285 : }/* for iRing*/
3286 :
3287 11 : nCoordDataSize = poCoordBlock->GetFeatureDataSize();
3288 :
3289 : /*-------------------------------------------------------------
3290 : * ... and finally copy info to poObjHdr
3291 : *------------------------------------------------------------*/
3292 11 : TABMAPObjPLine *poPLineHdr = (TABMAPObjPLine *)poObjHdr;
3293 :
3294 11 : poPLineHdr->m_nCoordBlockPtr = nCoordBlockPtr;
3295 11 : poPLineHdr->m_nCoordDataSize = nCoordDataSize;
3296 11 : poPLineHdr->m_numLineSections = numRingsTotal;
3297 :
3298 11 : poPLineHdr->m_bSmooth = m_bSmooth;
3299 :
3300 : // MBR
3301 11 : poPLineHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
3302 :
3303 : // Region center/label point
3304 : double dX, dY;
3305 11 : if (GetCenter(dX, dY) != -1)
3306 : {
3307 : poMapFile->Coordsys2Int(dX, dY, poPLineHdr->m_nLabelX,
3308 11 : poPLineHdr->m_nLabelY);
3309 : }
3310 : else
3311 : {
3312 0 : poPLineHdr->m_nLabelX = m_nComprOrgX;
3313 0 : poPLineHdr->m_nLabelY = m_nComprOrgY;
3314 : }
3315 :
3316 : // Compressed coordinate origin (useful only in compressed case!)
3317 11 : poPLineHdr->m_nComprOrgX = m_nComprOrgX;
3318 11 : poPLineHdr->m_nComprOrgY = m_nComprOrgY;
3319 :
3320 11 : if (!bCoordBlockDataOnly)
3321 : {
3322 11 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
3323 11 : poPLineHdr->m_nPenId = m_nPenDefIndex; // Pen index
3324 :
3325 11 : m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
3326 11 : poPLineHdr->m_nBrushId = m_nBrushDefIndex; // Brush index
3327 : }
3328 : }
3329 : else
3330 : {
3331 : CPLError(CE_Failure, CPLE_AssertionFailed,
3332 0 : "TABRegion: Object contains an invalid Geometry!");
3333 0 : return -1;
3334 : }
3335 :
3336 11 : if (CPLGetLastErrorNo() != 0)
3337 0 : return -1;
3338 :
3339 : /* Return a ref to coord block so that caller can continue writing
3340 : * after the end of this object (used by index splitting)
3341 : */
3342 11 : if (ppoCoordBlock)
3343 0 : *ppoCoordBlock = poCoordBlock;
3344 :
3345 11 : return 0;
3346 : }
3347 :
3348 :
3349 : /**********************************************************************
3350 : * TABRegion::GetNumRings()
3351 : *
3352 : * Return the total number of rings in this object making it look like
3353 : * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
3354 : * of rings... hides the complexity of handling OGRMultiPolygons vs
3355 : * OGRPolygons, etc.
3356 : *
3357 : * Returns 0 if the geometry contained in the object is invalid or missing.
3358 : **********************************************************************/
3359 21 : int TABRegion::GetNumRings()
3360 : {
3361 21 : return ComputeNumRings(NULL, NULL);
3362 : }
3363 :
3364 : int TABRegion::ComputeNumRings(TABMAPCoordSecHdr **ppasSecHdrs,
3365 32 : TABMAPFile *poMapFile)
3366 : {
3367 : OGRGeometry *poGeom;
3368 32 : int numRingsTotal = 0, iLastSect = 0;
3369 :
3370 32 : if (ppasSecHdrs)
3371 11 : *ppasSecHdrs = NULL;
3372 32 : poGeom = GetGeometryRef();
3373 :
3374 32 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3375 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3376 : {
3377 : /*-------------------------------------------------------------
3378 : * Calculate total number of rings...
3379 : *------------------------------------------------------------*/
3380 32 : OGRPolygon *poPolygon=NULL;
3381 32 : OGRMultiPolygon *poMultiPolygon = NULL;
3382 :
3383 32 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3384 : {
3385 0 : poMultiPolygon = (OGRMultiPolygon *)poGeom;
3386 0 : for(int iPoly=0; iPoly<poMultiPolygon->getNumGeometries(); iPoly++)
3387 : {
3388 : // We are guaranteed that all parts are OGRPolygons
3389 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
3390 0 : if (poPolygon == NULL)
3391 0 : continue;
3392 :
3393 0 : numRingsTotal += poPolygon->getNumInteriorRings()+1;
3394 :
3395 0 : if (ppasSecHdrs)
3396 : {
3397 0 : if (AppendSecHdrs(poPolygon, *ppasSecHdrs,
3398 : poMapFile, iLastSect) != 0)
3399 0 : return 0; // An error happened, return count=0
3400 : }
3401 :
3402 : }/*for*/
3403 : }
3404 : else
3405 : {
3406 32 : poPolygon = (OGRPolygon*)poGeom;
3407 32 : numRingsTotal = poPolygon->getNumInteriorRings()+1;
3408 :
3409 32 : if (ppasSecHdrs)
3410 : {
3411 11 : if (AppendSecHdrs(poPolygon, *ppasSecHdrs,
3412 : poMapFile, iLastSect) != 0)
3413 0 : return 0; // An error happened, return count=0
3414 : }
3415 : }
3416 : }
3417 :
3418 : /*-----------------------------------------------------------------
3419 : * If we're generating section header blocks, then init the
3420 : * coordinate offset values.
3421 : *
3422 : * In calculation of nDataOffset, we have to take into account that
3423 : * V450 header section uses int32 instead of int16 for numVertices
3424 : * and we add another 2 bytes to align with a 4 bytes boundary.
3425 : *------------------------------------------------------------*/
3426 : int nTotalHdrSizeUncompressed;
3427 32 : if (m_nMapInfoType == TAB_GEOM_V450_REGION ||
3428 : m_nMapInfoType == TAB_GEOM_V450_REGION_C ||
3429 : m_nMapInfoType == TAB_GEOM_V800_REGION ||
3430 : m_nMapInfoType == TAB_GEOM_V800_REGION_C)
3431 0 : nTotalHdrSizeUncompressed = 28 * numRingsTotal;
3432 : else
3433 32 : nTotalHdrSizeUncompressed = 24 * numRingsTotal;
3434 :
3435 32 : if (ppasSecHdrs)
3436 : {
3437 11 : int numPointsTotal = 0;
3438 11 : CPLAssert(iLastSect == numRingsTotal);
3439 22 : for (int iRing=0; iRing<numRingsTotal; iRing++)
3440 : {
3441 : (*ppasSecHdrs)[iRing].nDataOffset = nTotalHdrSizeUncompressed +
3442 11 : numPointsTotal*4*2;
3443 11 : (*ppasSecHdrs)[iRing].nVertexOffset = numPointsTotal;
3444 :
3445 11 : numPointsTotal += (*ppasSecHdrs)[iRing].numVertices;
3446 : }
3447 : }
3448 :
3449 32 : return numRingsTotal;
3450 : }
3451 :
3452 :
3453 : /**********************************************************************
3454 : * TABRegion::AppendSecHdrs()
3455 : *
3456 : * (Private method)
3457 : *
3458 : * Add a TABMAPCoordSecHdr for each ring in the specified polygon.
3459 : **********************************************************************/
3460 : int TABRegion::AppendSecHdrs(OGRPolygon *poPolygon,
3461 : TABMAPCoordSecHdr * &pasSecHdrs,
3462 : TABMAPFile *poMapFile,
3463 11 : int &iLastRing)
3464 : {
3465 : int iRing, numRingsInPolygon;
3466 : /*-------------------------------------------------------------
3467 : * Add a pasSecHdrs[] entry for each ring in this polygon.
3468 : * Note that the structs won't be fully initialized.
3469 : *------------------------------------------------------------*/
3470 11 : numRingsInPolygon = poPolygon->getNumInteriorRings()+1;
3471 :
3472 : pasSecHdrs = (TABMAPCoordSecHdr*)CPLRealloc(pasSecHdrs,
3473 : (iLastRing+numRingsInPolygon)*
3474 11 : sizeof(TABMAPCoordSecHdr));
3475 :
3476 22 : for(iRing=0; iRing < numRingsInPolygon; iRing++)
3477 : {
3478 : OGRLinearRing *poRing;
3479 11 : OGREnvelope sEnvelope;
3480 :
3481 11 : if (iRing == 0)
3482 11 : poRing = poPolygon->getExteriorRing();
3483 : else
3484 0 : poRing = poPolygon->getInteriorRing(iRing-1);
3485 :
3486 11 : if (poRing == NULL)
3487 : {
3488 : CPLError(CE_Failure, CPLE_AssertionFailed,
3489 0 : "Assertion Failed: Encountered NULL ring in OGRPolygon");
3490 0 : return -1;
3491 : }
3492 :
3493 11 : poRing->getEnvelope(&sEnvelope);
3494 :
3495 11 : pasSecHdrs[iLastRing].numVertices = poRing->getNumPoints();
3496 :
3497 11 : if (iRing == 0)
3498 11 : pasSecHdrs[iLastRing].numHoles = numRingsInPolygon-1;
3499 : else
3500 0 : pasSecHdrs[iLastRing].numHoles = 0;
3501 :
3502 : poMapFile->Coordsys2Int(sEnvelope.MinX, sEnvelope.MinY,
3503 : pasSecHdrs[iLastRing].nXMin,
3504 11 : pasSecHdrs[iLastRing].nYMin);
3505 : poMapFile->Coordsys2Int(sEnvelope.MaxX, sEnvelope.MaxY,
3506 : pasSecHdrs[iLastRing].nXMax,
3507 11 : pasSecHdrs[iLastRing].nYMax);
3508 :
3509 11 : iLastRing++;
3510 : }/* for iRing*/
3511 :
3512 11 : return 0;
3513 : }
3514 :
3515 : /**********************************************************************
3516 : * TABRegion::GetRingRef()
3517 : *
3518 : * Returns a reference to the specified ring number making it look like
3519 : * all parts of the OGRMultiPolygon (or OGRPolygon) are a single collection
3520 : * of rings... hides the complexity of handling OGRMultiPolygons vs
3521 : * OGRPolygons, etc.
3522 : *
3523 : * Returns NULL if the geometry contained in the object is invalid or
3524 : * missing or if the specified ring index is invalid.
3525 : **********************************************************************/
3526 32 : OGRLinearRing *TABRegion::GetRingRef(int nRequestedRingIndex)
3527 : {
3528 : OGRGeometry *poGeom;
3529 32 : OGRLinearRing *poRing = NULL;
3530 :
3531 32 : poGeom = GetGeometryRef();
3532 :
3533 32 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3534 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3535 : {
3536 : /*-------------------------------------------------------------
3537 : * Establish number of polygons based on geometry type
3538 : *------------------------------------------------------------*/
3539 32 : OGRPolygon *poPolygon=NULL;
3540 32 : OGRMultiPolygon *poMultiPolygon = NULL;
3541 32 : int iCurRing = 0;
3542 32 : int numOGRPolygons = 0;
3543 :
3544 32 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3545 : {
3546 0 : poMultiPolygon = (OGRMultiPolygon *)poGeom;
3547 0 : numOGRPolygons = poMultiPolygon->getNumGeometries();
3548 : }
3549 : else
3550 : {
3551 32 : poPolygon = (OGRPolygon*)poGeom;
3552 32 : numOGRPolygons = 1;
3553 : }
3554 :
3555 : /*-------------------------------------------------------------
3556 : * Loop through polygons until we find the requested ring.
3557 : *------------------------------------------------------------*/
3558 32 : iCurRing = 0;
3559 64 : for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
3560 : {
3561 32 : if (poMultiPolygon)
3562 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
3563 : else
3564 32 : poPolygon = (OGRPolygon*)poGeom;
3565 :
3566 32 : int numIntRings = poPolygon->getNumInteriorRings();
3567 :
3568 32 : if (iCurRing == nRequestedRingIndex)
3569 : {
3570 32 : poRing = poPolygon->getExteriorRing();
3571 : }
3572 0 : else if (nRequestedRingIndex > iCurRing &&
3573 : nRequestedRingIndex-(iCurRing+1) < numIntRings)
3574 : {
3575 : poRing = poPolygon->getInteriorRing(nRequestedRingIndex-
3576 0 : (iCurRing+1) );
3577 : }
3578 32 : iCurRing += numIntRings+1;
3579 : }
3580 : }
3581 :
3582 32 : return poRing;
3583 : }
3584 :
3585 : /**********************************************************************
3586 : * TABRegion::RingIsHole()
3587 : *
3588 : * Return false if the requested ring index is the first of a polygon
3589 : **********************************************************************/
3590 0 : GBool TABRegion::IsInteriorRing(int nRequestedRingIndex)
3591 : {
3592 : OGRGeometry *poGeom;
3593 0 : OGRLinearRing *poRing = NULL;
3594 :
3595 0 : poGeom = GetGeometryRef();
3596 :
3597 0 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3598 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3599 : {
3600 : /*-------------------------------------------------------------
3601 : * Establish number of polygons based on geometry type
3602 : *------------------------------------------------------------*/
3603 0 : OGRPolygon *poPolygon=NULL;
3604 0 : OGRMultiPolygon *poMultiPolygon = NULL;
3605 0 : int iCurRing = 0;
3606 0 : int numOGRPolygons = 0;
3607 :
3608 0 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3609 : {
3610 0 : poMultiPolygon = (OGRMultiPolygon *)poGeom;
3611 0 : numOGRPolygons = poMultiPolygon->getNumGeometries();
3612 : }
3613 : else
3614 : {
3615 0 : poPolygon = (OGRPolygon*)poGeom;
3616 0 : numOGRPolygons = 1;
3617 : }
3618 :
3619 : /*-------------------------------------------------------------
3620 : * Loop through polygons until we find the requested ring.
3621 : *------------------------------------------------------------*/
3622 0 : iCurRing = 0;
3623 0 : for(int iPoly=0; poRing == NULL && iPoly < numOGRPolygons; iPoly++)
3624 : {
3625 0 : if (poMultiPolygon)
3626 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(iPoly);
3627 : else
3628 0 : poPolygon = (OGRPolygon*)poGeom;
3629 :
3630 0 : int numIntRings = poPolygon->getNumInteriorRings();
3631 :
3632 0 : if (iCurRing == nRequestedRingIndex)
3633 : {
3634 0 : return FALSE;
3635 : }
3636 0 : else if (nRequestedRingIndex > iCurRing &&
3637 : nRequestedRingIndex-(iCurRing+1) < numIntRings)
3638 : {
3639 0 : return TRUE;
3640 : }
3641 0 : iCurRing += numIntRings+1;
3642 : }
3643 : }
3644 :
3645 0 : return FALSE;
3646 : }
3647 :
3648 : /**********************************************************************
3649 : * TABRegion::GetStyleString()
3650 : *
3651 : * Return style string for this feature.
3652 : *
3653 : * Style String is built only once during the first call to GetStyleString().
3654 : **********************************************************************/
3655 11 : const char *TABRegion::GetStyleString()
3656 : {
3657 11 : if (m_pszStyleString == NULL)
3658 : {
3659 : // Since GetPen/BrushStyleString() use CPLSPrintf(), we need
3660 : // to use temporary buffers
3661 7 : char *pszPen = CPLStrdup(GetPenStyleString());
3662 7 : char *pszBrush = CPLStrdup(GetBrushStyleString());
3663 :
3664 7 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
3665 :
3666 7 : CPLFree(pszPen);
3667 7 : CPLFree(pszBrush);
3668 : }
3669 :
3670 11 : return m_pszStyleString;
3671 : }
3672 :
3673 :
3674 :
3675 : /**********************************************************************
3676 : * TABRegion::DumpMIF()
3677 : *
3678 : * Dump feature geometry in a format similar to .MIF REGIONs.
3679 : **********************************************************************/
3680 0 : void TABRegion::DumpMIF(FILE *fpOut /*=NULL*/)
3681 : {
3682 : OGRGeometry *poGeom;
3683 : int i, numPoints;
3684 :
3685 0 : if (fpOut == NULL)
3686 0 : fpOut = stdout;
3687 :
3688 : /*-----------------------------------------------------------------
3689 : * Fetch and validate geometry
3690 : *----------------------------------------------------------------*/
3691 0 : poGeom = GetGeometryRef();
3692 0 : if (poGeom && (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
3693 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon))
3694 : {
3695 : /*-------------------------------------------------------------
3696 : * Generate output for region
3697 : *
3698 : * Note that we want to handle both OGRPolygons and OGRMultiPolygons
3699 : * that's why we use the GetNumRings()/GetRingRef() interface.
3700 : *------------------------------------------------------------*/
3701 0 : int iRing, numRingsTotal = GetNumRings();
3702 :
3703 0 : fprintf(fpOut, "REGION %d\n", numRingsTotal);
3704 :
3705 0 : for(iRing=0; iRing < numRingsTotal; iRing++)
3706 : {
3707 : OGRLinearRing *poRing;
3708 :
3709 0 : poRing = GetRingRef(iRing);
3710 :
3711 0 : if (poRing == NULL)
3712 : {
3713 : CPLError(CE_Failure, CPLE_AssertionFailed,
3714 0 : "TABRegion: Object Geometry contains NULL rings!");
3715 0 : return;
3716 : }
3717 :
3718 0 : numPoints = poRing->getNumPoints();
3719 0 : fprintf(fpOut, " %d\n", numPoints);
3720 0 : for(i=0; i<numPoints; i++)
3721 0 : fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
3722 : }
3723 : }
3724 : else
3725 : {
3726 : CPLError(CE_Failure, CPLE_AssertionFailed,
3727 0 : "TABRegion: Missing or Invalid Geometry!");
3728 0 : return;
3729 : }
3730 :
3731 0 : if (m_bCenterIsSet)
3732 0 : fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
3733 :
3734 : // Finish with PEN/BRUSH/etc. clauses
3735 0 : DumpPenDef();
3736 0 : DumpBrushDef();
3737 :
3738 0 : fflush(fpOut);
3739 : }
3740 :
3741 : /**********************************************************************
3742 : * TABRegion::GetCenter()
3743 : *
3744 : * Returns the center/label point of the region.
3745 : * Compute one using OGRPolygonLabelPoint() if it was not explicitly set
3746 : * before.
3747 : *
3748 : * Returns 0 on success, -1 on error.
3749 : **********************************************************************/
3750 11 : int TABRegion::GetCenter(double &dX, double &dY)
3751 : {
3752 11 : if (!m_bCenterIsSet)
3753 : {
3754 : /*-------------------------------------------------------------
3755 : * Calculate label point. If we have a multipolygon then we use
3756 : * the first OGRPolygon in the feature to calculate the point.
3757 : *------------------------------------------------------------*/
3758 11 : OGRPoint oLabelPoint;
3759 11 : OGRPolygon *poPolygon=NULL;
3760 : OGRGeometry *poGeom;
3761 :
3762 11 : poGeom = GetGeometryRef();
3763 11 : if (poGeom == NULL)
3764 0 : return -1;
3765 :
3766 11 : if (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon)
3767 : {
3768 0 : OGRMultiPolygon *poMultiPolygon = (OGRMultiPolygon *)poGeom;
3769 0 : if (poMultiPolygon->getNumGeometries() > 0)
3770 0 : poPolygon = (OGRPolygon*)poMultiPolygon->getGeometryRef(0);
3771 : }
3772 11 : else if (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
3773 : {
3774 11 : poPolygon = (OGRPolygon*)poGeom;
3775 : }
3776 :
3777 11 : if (poPolygon != NULL &&
3778 : OGRPolygonLabelPoint(poPolygon, &oLabelPoint) == OGRERR_NONE)
3779 : {
3780 11 : m_dCenterX = oLabelPoint.getX();
3781 11 : m_dCenterY = oLabelPoint.getY();
3782 : }
3783 : else
3784 : {
3785 0 : OGREnvelope oEnv;
3786 0 : poGeom->getEnvelope(&oEnv);
3787 0 : m_dCenterX = (oEnv.MaxX + oEnv.MinX)/2.0;
3788 0 : m_dCenterY = (oEnv.MaxY + oEnv.MinY)/2.0;
3789 : }
3790 :
3791 11 : m_bCenterIsSet = TRUE;
3792 : }
3793 :
3794 11 : if (!m_bCenterIsSet)
3795 0 : return -1;
3796 :
3797 11 : dX = m_dCenterX;
3798 11 : dY = m_dCenterY;
3799 11 : return 0;
3800 : }
3801 :
3802 : /**********************************************************************
3803 : * TABRegion::SetCenter()
3804 : *
3805 : * Set the X,Y coordinates to use as center/label point for the region.
3806 : **********************************************************************/
3807 51 : void TABRegion::SetCenter(double dX, double dY)
3808 : {
3809 51 : m_dCenterX = dX;
3810 51 : m_dCenterY = dY;
3811 51 : m_bCenterIsSet = TRUE;
3812 51 : }
3813 :
3814 :
3815 : /*=====================================================================
3816 : * class TABRectangle
3817 : *====================================================================*/
3818 :
3819 : /**********************************************************************
3820 : * TABRectangle::TABRectangle()
3821 : *
3822 : * Constructor.
3823 : **********************************************************************/
3824 0 : TABRectangle::TABRectangle(OGRFeatureDefn *poDefnIn):
3825 0 : TABFeature(poDefnIn)
3826 : {
3827 0 : m_bRoundCorners = FALSE;
3828 0 : m_dRoundXRadius = m_dRoundYRadius = 0.0;
3829 0 : }
3830 :
3831 : /**********************************************************************
3832 : * TABRectangle::~TABRectangle()
3833 : *
3834 : * Destructor.
3835 : **********************************************************************/
3836 0 : TABRectangle::~TABRectangle()
3837 : {
3838 0 : }
3839 :
3840 : /**********************************************************************
3841 : * TABRectangle::CloneTABFeature()
3842 : *
3843 : * Duplicate feature, including stuff specific to each TABFeature type.
3844 : *
3845 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
3846 : * then copies any members specific to its own type.
3847 : **********************************************************************/
3848 0 : TABFeature *TABRectangle::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
3849 : {
3850 : /*-----------------------------------------------------------------
3851 : * Alloc new feature and copy the base stuff
3852 : *----------------------------------------------------------------*/
3853 : TABRectangle *poNew = new TABRectangle(poNewDefn ? poNewDefn :
3854 0 : GetDefnRef());
3855 :
3856 0 : CopyTABFeatureBase(poNew);
3857 :
3858 : /*-----------------------------------------------------------------
3859 : * And members specific to this class
3860 : *----------------------------------------------------------------*/
3861 : // ITABFeaturePen
3862 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
3863 :
3864 : // ITABFeatureBrush
3865 0 : *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
3866 :
3867 0 : poNew->m_bRoundCorners = m_bRoundCorners;
3868 0 : poNew->m_dRoundXRadius = m_dRoundXRadius;
3869 0 : poNew->m_dRoundYRadius = m_dRoundYRadius;
3870 :
3871 0 : return poNew;
3872 : }
3873 :
3874 : /**********************************************************************
3875 : * TABRectangle::ValidateMapInfoType()
3876 : *
3877 : * Check the feature's geometry part and return the corresponding
3878 : * mapinfo object type code. The m_nMapInfoType member will also
3879 : * be updated for further calls to GetMapInfoType();
3880 : *
3881 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
3882 : * is expected for this object class.
3883 : **********************************************************************/
3884 0 : int TABRectangle::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
3885 : {
3886 : OGRGeometry *poGeom;
3887 :
3888 : /*-----------------------------------------------------------------
3889 : * Fetch and validate geometry
3890 : *----------------------------------------------------------------*/
3891 0 : poGeom = GetGeometryRef();
3892 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
3893 : {
3894 0 : if (m_bRoundCorners && m_dRoundXRadius!=0.0 && m_dRoundYRadius!=0.0)
3895 0 : m_nMapInfoType = TAB_GEOM_ROUNDRECT;
3896 : else
3897 0 : m_nMapInfoType = TAB_GEOM_RECT;
3898 : }
3899 : else
3900 : {
3901 : CPLError(CE_Failure, CPLE_AssertionFailed,
3902 0 : "TABRectangle: Missing or Invalid Geometry!");
3903 0 : m_nMapInfoType = TAB_GEOM_NONE;
3904 : }
3905 :
3906 : /*-----------------------------------------------------------------
3907 : * Decide if coordinates should be compressed or not.
3908 : *----------------------------------------------------------------*/
3909 : // __TODO__ For now we always write uncompressed for this class...
3910 : // ValidateCoordType(poMapFile);
3911 0 : UpdateMBR(poMapFile);
3912 :
3913 0 : return m_nMapInfoType;
3914 : }
3915 :
3916 : /**********************************************************************
3917 : * TABRectangle::UpdateMBR()
3918 : *
3919 : * Update the feature MBR members using the geometry
3920 : *
3921 : * Returns 0 on success, or -1 if there is no geometry in object
3922 : **********************************************************************/
3923 0 : int TABRectangle::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
3924 : {
3925 : OGRGeometry *poGeom;
3926 0 : OGREnvelope sEnvelope;
3927 :
3928 : /*-----------------------------------------------------------------
3929 : * Fetch and validate geometry
3930 : *----------------------------------------------------------------*/
3931 0 : poGeom = GetGeometryRef();
3932 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
3933 0 : poGeom->getEnvelope(&sEnvelope);
3934 : else
3935 : {
3936 : CPLError(CE_Failure, CPLE_AssertionFailed,
3937 0 : "TABRectangle: Missing or Invalid Geometry!");
3938 0 : return -1;
3939 : }
3940 :
3941 : /*-----------------------------------------------------------------
3942 : * Note that we will simply use the rectangle's MBR and don't really
3943 : * read the polygon geometry... this should be OK unless the
3944 : * polygon geometry was not really a rectangle.
3945 : *----------------------------------------------------------------*/
3946 0 : m_dXMin = sEnvelope.MinX;
3947 0 : m_dYMin = sEnvelope.MinY;
3948 0 : m_dXMax = sEnvelope.MaxX;
3949 0 : m_dYMax = sEnvelope.MaxY;
3950 :
3951 0 : if (poMapFile)
3952 : {
3953 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
3954 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
3955 : }
3956 :
3957 0 : return 0;
3958 : }
3959 :
3960 : /**********************************************************************
3961 : * TABRectangle::ReadGeometryFromMAPFile()
3962 : *
3963 : * Fill the geometry and representation (color, etc...) part of the
3964 : * feature from the contents of the .MAP object pointed to by poMAPFile.
3965 : *
3966 : * It is assumed that poMAPFile currently points to the beginning of
3967 : * a map object.
3968 : *
3969 : * Returns 0 on success, -1 on error, in which case CPLError() will have
3970 : * been called.
3971 : **********************************************************************/
3972 : int TABRectangle::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
3973 : TABMAPObjHdr *poObjHdr,
3974 : GBool bCoordBlockDataOnly /*=FALSE*/,
3975 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
3976 : {
3977 : double dXMin, dYMin, dXMax, dYMax;
3978 : OGRPolygon *poPolygon;
3979 : OGRLinearRing *poRing;
3980 :
3981 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
3982 0 : if (bCoordBlockDataOnly)
3983 0 : return 0;
3984 :
3985 : /*-----------------------------------------------------------------
3986 : * Fetch and validate geometry type
3987 : *----------------------------------------------------------------*/
3988 0 : m_nMapInfoType = poObjHdr->m_nType;
3989 :
3990 0 : if (m_nMapInfoType != TAB_GEOM_RECT &&
3991 : m_nMapInfoType != TAB_GEOM_RECT_C &&
3992 : m_nMapInfoType != TAB_GEOM_ROUNDRECT &&
3993 : m_nMapInfoType != TAB_GEOM_ROUNDRECT_C)
3994 : {
3995 : CPLError(CE_Failure, CPLE_AssertionFailed,
3996 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
3997 0 : m_nMapInfoType, m_nMapInfoType);
3998 0 : return -1;
3999 : }
4000 :
4001 : /*-----------------------------------------------------------------
4002 : * Read object information
4003 : *----------------------------------------------------------------*/
4004 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4005 :
4006 : // Read the corners radius
4007 :
4008 0 : if (m_nMapInfoType == TAB_GEOM_ROUNDRECT ||
4009 : m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
4010 : {
4011 : // Read the corner's diameters
4012 : poMapFile->Int2CoordsysDist(poRectHdr->m_nCornerWidth,
4013 : poRectHdr->m_nCornerHeight,
4014 0 : m_dRoundXRadius, m_dRoundYRadius);
4015 :
4016 : // Divide by 2 since we store the corner's radius
4017 0 : m_dRoundXRadius /= 2.0;
4018 0 : m_dRoundYRadius /= 2.0;
4019 :
4020 0 : m_bRoundCorners = TRUE;
4021 : }
4022 : else
4023 : {
4024 0 : m_bRoundCorners = FALSE;
4025 0 : m_dRoundXRadius = m_dRoundYRadius = 0.0;
4026 : }
4027 :
4028 : // A rectangle is defined by its MBR
4029 :
4030 : poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY,
4031 0 : dXMin, dYMin);
4032 : poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY,
4033 0 : dXMax, dYMax);
4034 :
4035 0 : m_nPenDefIndex = poRectHdr->m_nPenId; // Pen index
4036 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
4037 :
4038 0 : m_nBrushDefIndex = poRectHdr->m_nBrushId; // Brush index
4039 0 : poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
4040 :
4041 : /*-----------------------------------------------------------------
4042 : * Call SetMBR() and GetMBR() now to make sure that min values are
4043 : * really smaller than max values.
4044 : *----------------------------------------------------------------*/
4045 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
4046 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
4047 :
4048 : /* Copy int MBR to feature class members */
4049 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
4050 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
4051 :
4052 : /*-----------------------------------------------------------------
4053 : * Create and fill geometry object
4054 : *----------------------------------------------------------------*/
4055 0 : poPolygon = new OGRPolygon;
4056 0 : poRing = new OGRLinearRing();
4057 0 : if (m_bRoundCorners && m_dRoundXRadius != 0.0 && m_dRoundYRadius != 0.0)
4058 : {
4059 : /*-------------------------------------------------------------
4060 : * For rounded rectangles, we generate arcs with 45 line
4061 : * segments for each corner. We start with lower-left corner
4062 : * and proceed counterclockwise
4063 : * We also have to make sure that rounding radius is not too
4064 : * large for the MBR in the generated polygon... however, we
4065 : * always return the true X/Y radius (not adjusted) since this
4066 : * is the way MapInfo seems to do it when a radius bigger than
4067 : * the MBR is passed from TBA to MIF.
4068 : *------------------------------------------------------------*/
4069 0 : double dXRadius = MIN(m_dRoundXRadius, (dXMax-dXMin)/2.0);
4070 0 : double dYRadius = MIN(m_dRoundYRadius, (dYMax-dYMin)/2.0);
4071 : TABGenerateArc(poRing, 45,
4072 : dXMin + dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
4073 0 : PI, 3.0*PI/2.0);
4074 : TABGenerateArc(poRing, 45,
4075 : dXMax - dXRadius, dYMin + dYRadius, dXRadius, dYRadius,
4076 0 : 3.0*PI/2.0, 2.0*PI);
4077 : TABGenerateArc(poRing, 45,
4078 : dXMax - dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
4079 0 : 0.0, PI/2.0);
4080 : TABGenerateArc(poRing, 45,
4081 : dXMin + dXRadius, dYMax - dYRadius, dXRadius, dYRadius,
4082 0 : PI/2.0, PI);
4083 :
4084 0 : TABCloseRing(poRing);
4085 : }
4086 : else
4087 : {
4088 0 : poRing->addPoint(dXMin, dYMin);
4089 0 : poRing->addPoint(dXMax, dYMin);
4090 0 : poRing->addPoint(dXMax, dYMax);
4091 0 : poRing->addPoint(dXMin, dYMax);
4092 0 : poRing->addPoint(dXMin, dYMin);
4093 : }
4094 :
4095 0 : poPolygon->addRingDirectly(poRing);
4096 0 : SetGeometryDirectly(poPolygon);
4097 :
4098 0 : return 0;
4099 : }
4100 :
4101 : /**********************************************************************
4102 : * TABRectangle::WriteGeometryToMAPFile()
4103 : *
4104 : * Write the geometry and representation (color, etc...) part of the
4105 : * feature to the .MAP object pointed to by poMAPFile.
4106 : *
4107 : * It is assumed that poMAPFile currently points to a valid map object.
4108 : *
4109 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4110 : * been called.
4111 : **********************************************************************/
4112 : int TABRectangle::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
4113 : TABMAPObjHdr *poObjHdr,
4114 : GBool bCoordBlockDataOnly /*=FALSE*/,
4115 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4116 : {
4117 :
4118 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4119 0 : if (bCoordBlockDataOnly)
4120 0 : return 0;
4121 :
4122 : /*-----------------------------------------------------------------
4123 : * We assume that ValidateMapInfoType() was called already and that
4124 : * the type in poObjHdr->m_nType is valid.
4125 : *----------------------------------------------------------------*/
4126 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
4127 :
4128 : /*-----------------------------------------------------------------
4129 : * Fetch and validate geometry and update MBR
4130 : * Note that we will simply use the geometry's MBR and don't really
4131 : * read the polygon geometry... this should be OK unless the
4132 : * polygon geometry was not really a rectangle.
4133 : *----------------------------------------------------------------*/
4134 0 : if (UpdateMBR(poMapFile) != 0)
4135 0 : return -1; /* Error already reported */
4136 :
4137 : /*-----------------------------------------------------------------
4138 : * Copy object information
4139 : *----------------------------------------------------------------*/
4140 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4141 :
4142 0 : if (m_nMapInfoType == TAB_GEOM_ROUNDRECT ||
4143 : m_nMapInfoType == TAB_GEOM_ROUNDRECT_C)
4144 : {
4145 : poMapFile->Coordsys2IntDist(m_dRoundXRadius*2.0, m_dRoundYRadius*2.0,
4146 : poRectHdr->m_nCornerWidth,
4147 0 : poRectHdr->m_nCornerHeight);
4148 : }
4149 : else
4150 : {
4151 0 : poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
4152 : }
4153 :
4154 : // A rectangle is defined by its MBR (values were set in UpdateMBR())
4155 0 : poRectHdr->m_nMinX = m_nXMin;
4156 0 : poRectHdr->m_nMinY = m_nYMin;
4157 0 : poRectHdr->m_nMaxX = m_nXMax;
4158 0 : poRectHdr->m_nMaxY = m_nYMax;
4159 :
4160 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
4161 0 : poRectHdr->m_nPenId = m_nPenDefIndex; // Pen index
4162 :
4163 0 : m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
4164 0 : poRectHdr->m_nBrushId = m_nBrushDefIndex; // Brush index
4165 :
4166 0 : if (CPLGetLastErrorNo() != 0)
4167 0 : return -1;
4168 :
4169 0 : return 0;
4170 : }
4171 :
4172 : /**********************************************************************
4173 : * TABRectangle::GetStyleString()
4174 : *
4175 : * Return style string for this feature.
4176 : *
4177 : * Style String is built only once during the first call to GetStyleString().
4178 : **********************************************************************/
4179 0 : const char *TABRectangle::GetStyleString()
4180 : {
4181 0 : if (m_pszStyleString == NULL)
4182 : {
4183 : // Since GetPen/BrushStyleString() use CPLSPrintf(), we need
4184 : // to use temporary buffers
4185 0 : char *pszPen = CPLStrdup(GetPenStyleString());
4186 0 : char *pszBrush = CPLStrdup(GetBrushStyleString());
4187 :
4188 0 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
4189 :
4190 0 : CPLFree(pszPen);
4191 0 : CPLFree(pszBrush);
4192 : }
4193 :
4194 0 : return m_pszStyleString;
4195 : }
4196 :
4197 : /**********************************************************************
4198 : * TABRectangle::DumpMIF()
4199 : *
4200 : * Dump feature geometry in a format similar to .MIF REGIONs.
4201 : **********************************************************************/
4202 0 : void TABRectangle::DumpMIF(FILE *fpOut /*=NULL*/)
4203 : {
4204 : OGRGeometry *poGeom;
4205 0 : OGRPolygon *poPolygon = NULL;
4206 : int i, numPoints;
4207 :
4208 0 : if (fpOut == NULL)
4209 0 : fpOut = stdout;
4210 :
4211 : /*-----------------------------------------------------------------
4212 : * Output RECT or ROUNDRECT parameters
4213 : *----------------------------------------------------------------*/
4214 : double dXMin, dYMin, dXMax, dYMax;
4215 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
4216 0 : if (m_bRoundCorners)
4217 : fprintf(fpOut, "(ROUNDRECT %.15g %.15g %.15g %.15g %.15g %.15g)\n",
4218 : dXMin, dYMin, dXMax, dYMax,
4219 0 : m_dRoundXRadius, m_dRoundYRadius);
4220 : else
4221 0 : fprintf(fpOut, "(RECT %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
4222 :
4223 : /*-----------------------------------------------------------------
4224 : * Fetch and validate geometry
4225 : *----------------------------------------------------------------*/
4226 0 : poGeom = GetGeometryRef();
4227 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
4228 : {
4229 : /*-------------------------------------------------------------
4230 : * Generate rectangle output as a region
4231 : * We could also output as a RECT or ROUNDRECT in a real MIF generator
4232 : *------------------------------------------------------------*/
4233 : int iRing, numIntRings;
4234 0 : poPolygon = (OGRPolygon*)poGeom;
4235 0 : numIntRings = poPolygon->getNumInteriorRings();
4236 0 : fprintf(fpOut, "REGION %d\n", numIntRings+1);
4237 : // In this loop, iRing=-1 for the outer ring.
4238 0 : for(iRing=-1; iRing < numIntRings; iRing++)
4239 : {
4240 : OGRLinearRing *poRing;
4241 :
4242 0 : if (iRing == -1)
4243 0 : poRing = poPolygon->getExteriorRing();
4244 : else
4245 0 : poRing = poPolygon->getInteriorRing(iRing);
4246 :
4247 0 : if (poRing == NULL)
4248 : {
4249 : CPLError(CE_Failure, CPLE_AssertionFailed,
4250 0 : "TABRectangle: Object Geometry contains NULL rings!");
4251 0 : return;
4252 : }
4253 :
4254 0 : numPoints = poRing->getNumPoints();
4255 0 : fprintf(fpOut, " %d\n", numPoints);
4256 0 : for(i=0; i<numPoints; i++)
4257 0 : fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
4258 : }
4259 : }
4260 : else
4261 : {
4262 : CPLError(CE_Failure, CPLE_AssertionFailed,
4263 0 : "TABRectangle: Missing or Invalid Geometry!");
4264 0 : return;
4265 : }
4266 :
4267 : // Finish with PEN/BRUSH/etc. clauses
4268 0 : DumpPenDef();
4269 0 : DumpBrushDef();
4270 :
4271 0 : fflush(fpOut);
4272 : }
4273 :
4274 :
4275 : /*=====================================================================
4276 : * class TABEllipse
4277 : *====================================================================*/
4278 :
4279 : /**********************************************************************
4280 : * TABEllipse::TABEllipse()
4281 : *
4282 : * Constructor.
4283 : **********************************************************************/
4284 0 : TABEllipse::TABEllipse(OGRFeatureDefn *poDefnIn):
4285 0 : TABFeature(poDefnIn)
4286 : {
4287 0 : }
4288 :
4289 : /**********************************************************************
4290 : * TABEllipse::~TABEllipse()
4291 : *
4292 : * Destructor.
4293 : **********************************************************************/
4294 0 : TABEllipse::~TABEllipse()
4295 : {
4296 0 : }
4297 :
4298 : /**********************************************************************
4299 : * TABEllipse::CloneTABFeature()
4300 : *
4301 : * Duplicate feature, including stuff specific to each TABFeature type.
4302 : *
4303 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
4304 : * then copies any members specific to its own type.
4305 : **********************************************************************/
4306 0 : TABFeature *TABEllipse::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
4307 : {
4308 : /*-----------------------------------------------------------------
4309 : * Alloc new feature and copy the base stuff
4310 : *----------------------------------------------------------------*/
4311 : TABEllipse *poNew = new TABEllipse(poNewDefn ? poNewDefn :
4312 0 : GetDefnRef());
4313 :
4314 0 : CopyTABFeatureBase(poNew);
4315 :
4316 : /*-----------------------------------------------------------------
4317 : * And members specific to this class
4318 : *----------------------------------------------------------------*/
4319 : // ITABFeaturePen
4320 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
4321 :
4322 : // ITABFeatureBrush
4323 0 : *(poNew->GetBrushDefRef()) = *GetBrushDefRef();
4324 :
4325 0 : poNew->m_dCenterX = m_dCenterX;
4326 0 : poNew->m_dCenterY = m_dCenterY;
4327 0 : poNew->m_dXRadius = m_dXRadius;
4328 0 : poNew->m_dYRadius = m_dYRadius;
4329 :
4330 0 : return poNew;
4331 : }
4332 :
4333 : /**********************************************************************
4334 : * TABEllipse::ValidateMapInfoType()
4335 : *
4336 : * Check the feature's geometry part and return the corresponding
4337 : * mapinfo object type code. The m_nMapInfoType member will also
4338 : * be updated for further calls to GetMapInfoType();
4339 : *
4340 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
4341 : * is expected for this object class.
4342 : **********************************************************************/
4343 0 : int TABEllipse::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
4344 : {
4345 : OGRGeometry *poGeom;
4346 :
4347 : /*-----------------------------------------------------------------
4348 : * Fetch and validate geometry
4349 : *----------------------------------------------------------------*/
4350 0 : poGeom = GetGeometryRef();
4351 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
4352 : (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4353 : {
4354 0 : m_nMapInfoType = TAB_GEOM_ELLIPSE;
4355 : }
4356 : else
4357 : {
4358 : CPLError(CE_Failure, CPLE_AssertionFailed,
4359 0 : "TABEllipse: Missing or Invalid Geometry!");
4360 0 : m_nMapInfoType = TAB_GEOM_NONE;
4361 : }
4362 :
4363 : /*-----------------------------------------------------------------
4364 : * Decide if coordinates should be compressed or not.
4365 : *----------------------------------------------------------------*/
4366 : // __TODO__ For now we always write uncompressed for this class...
4367 : // ValidateCoordType(poMapFile);
4368 0 : UpdateMBR(poMapFile);
4369 :
4370 0 : return m_nMapInfoType;
4371 : }
4372 :
4373 : /**********************************************************************
4374 : * TABEllipse::UpdateMBR()
4375 : *
4376 : * Update the feature MBR members using the geometry
4377 : *
4378 : * Returns 0 on success, or -1 if there is no geometry in object
4379 : **********************************************************************/
4380 0 : int TABEllipse::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
4381 : {
4382 : OGRGeometry *poGeom;
4383 0 : OGREnvelope sEnvelope;
4384 :
4385 : /*-----------------------------------------------------------------
4386 : * Fetch and validate geometry... Polygon and point are accepted.
4387 : * Note that we will simply use the ellipse's MBR and don't really
4388 : * read the polygon geometry... this should be OK unless the
4389 : * polygon geometry was not really an ellipse.
4390 : *----------------------------------------------------------------*/
4391 0 : poGeom = GetGeometryRef();
4392 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ) ||
4393 : (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4394 0 : poGeom->getEnvelope(&sEnvelope);
4395 : else
4396 : {
4397 : CPLError(CE_Failure, CPLE_AssertionFailed,
4398 0 : "TABEllipse: Missing or Invalid Geometry!");
4399 0 : return -1;
4400 : }
4401 :
4402 : /*-----------------------------------------------------------------
4403 : * We use the center of the MBR as the ellipse center, and the
4404 : * X/Y radius to define the MBR size. If X/Y radius are null then
4405 : * we'll try to use the MBR to recompute them.
4406 : *----------------------------------------------------------------*/
4407 : double dXCenter, dYCenter;
4408 0 : dXCenter = (sEnvelope.MaxX + sEnvelope.MinX)/2.0;
4409 0 : dYCenter = (sEnvelope.MaxY + sEnvelope.MinY)/2.0;
4410 0 : if (m_dXRadius == 0.0 && m_dYRadius == 0.0)
4411 : {
4412 0 : m_dXRadius = ABS(sEnvelope.MaxX - sEnvelope.MinX) / 2.0;
4413 0 : m_dYRadius = ABS(sEnvelope.MaxY - sEnvelope.MinY) / 2.0;
4414 : }
4415 :
4416 0 : m_dXMin = dXCenter - m_dXRadius;
4417 0 : m_dYMin = dYCenter - m_dYRadius;
4418 0 : m_dXMax = dXCenter + m_dXRadius;
4419 0 : m_dYMax = dYCenter + m_dYRadius;
4420 :
4421 0 : if (poMapFile)
4422 : {
4423 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
4424 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
4425 : }
4426 :
4427 0 : return 0;
4428 : }
4429 :
4430 : /**********************************************************************
4431 : * TABEllipse::ReadGeometryFromMAPFile()
4432 : *
4433 : * Fill the geometry and representation (color, etc...) part of the
4434 : * feature from the contents of the .MAP object pointed to by poMAPFile.
4435 : *
4436 : * It is assumed that poMAPFile currently points to the beginning of
4437 : * a map object.
4438 : *
4439 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4440 : * been called.
4441 : **********************************************************************/
4442 : int TABEllipse::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
4443 : TABMAPObjHdr *poObjHdr,
4444 : GBool bCoordBlockDataOnly /*=FALSE*/,
4445 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4446 : {
4447 : double dXMin, dYMin, dXMax, dYMax;
4448 : OGRPolygon *poPolygon;
4449 : OGRLinearRing *poRing;
4450 :
4451 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4452 0 : if (bCoordBlockDataOnly)
4453 0 : return 0;
4454 :
4455 : /*-----------------------------------------------------------------
4456 : * Fetch and validate geometry type
4457 : *----------------------------------------------------------------*/
4458 0 : m_nMapInfoType = poObjHdr->m_nType;
4459 :
4460 0 : if (m_nMapInfoType != TAB_GEOM_ELLIPSE &&
4461 : m_nMapInfoType != TAB_GEOM_ELLIPSE_C )
4462 : {
4463 : CPLError(CE_Failure, CPLE_AssertionFailed,
4464 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
4465 0 : m_nMapInfoType, m_nMapInfoType);
4466 0 : return -1;
4467 : }
4468 :
4469 : /*-----------------------------------------------------------------
4470 : * Read object information
4471 : *----------------------------------------------------------------*/
4472 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4473 :
4474 : // An ellipse is defined by its MBR
4475 :
4476 : poMapFile->Int2Coordsys(poRectHdr->m_nMinX, poRectHdr->m_nMinY,
4477 0 : dXMin, dYMin);
4478 : poMapFile->Int2Coordsys(poRectHdr->m_nMaxX, poRectHdr->m_nMaxY,
4479 0 : dXMax, dYMax);
4480 :
4481 0 : m_nPenDefIndex = poRectHdr->m_nPenId; // Pen index
4482 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
4483 :
4484 0 : m_nBrushDefIndex = poRectHdr->m_nBrushId; // Brush index
4485 0 : poMapFile->ReadBrushDef(m_nBrushDefIndex, &m_sBrushDef);
4486 :
4487 : /*-----------------------------------------------------------------
4488 : * Save info about the ellipse def. inside class members
4489 : *----------------------------------------------------------------*/
4490 0 : m_dCenterX = (dXMin + dXMax) / 2.0;
4491 0 : m_dCenterY = (dYMin + dYMax) / 2.0;
4492 0 : m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
4493 0 : m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
4494 :
4495 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
4496 :
4497 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
4498 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
4499 :
4500 : /*-----------------------------------------------------------------
4501 : * Create and fill geometry object
4502 : *----------------------------------------------------------------*/
4503 0 : poPolygon = new OGRPolygon;
4504 0 : poRing = new OGRLinearRing();
4505 :
4506 :
4507 : /*-----------------------------------------------------------------
4508 : * For the OGR geometry, we generate an ellipse with 2 degrees line
4509 : * segments.
4510 : *----------------------------------------------------------------*/
4511 : TABGenerateArc(poRing, 180,
4512 : m_dCenterX, m_dCenterY,
4513 : m_dXRadius, m_dYRadius,
4514 0 : 0.0, 2.0*PI);
4515 0 : TABCloseRing(poRing);
4516 :
4517 0 : poPolygon->addRingDirectly(poRing);
4518 0 : SetGeometryDirectly(poPolygon);
4519 :
4520 0 : return 0;
4521 : }
4522 :
4523 : /**********************************************************************
4524 : * TABEllipse::WriteGeometryToMAPFile()
4525 : *
4526 : * Write the geometry and representation (color, etc...) part of the
4527 : * feature to the .MAP object pointed to by poMAPFile.
4528 : *
4529 : * It is assumed that poMAPFile currently points to a valid map object.
4530 : *
4531 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4532 : * been called.
4533 : **********************************************************************/
4534 : int TABEllipse::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
4535 : TABMAPObjHdr *poObjHdr,
4536 : GBool bCoordBlockDataOnly /*=FALSE*/,
4537 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4538 : {
4539 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4540 0 : if (bCoordBlockDataOnly)
4541 0 : return 0;
4542 :
4543 : /*-----------------------------------------------------------------
4544 : * We assume that ValidateMapInfoType() was called already and that
4545 : * the type in poObjHdr->m_nType is valid.
4546 : *----------------------------------------------------------------*/
4547 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
4548 :
4549 : /*-----------------------------------------------------------------
4550 : * Fetch and validate geometry... Polygon and point are accepted.
4551 : * Note that we will simply use the ellipse's MBR and don't really
4552 : * read the polygon geometry... this should be OK unless the
4553 : * polygon geometry was not really an ellipse.
4554 : *
4555 : * We use the center of the MBR as the ellipse center, and the
4556 : * X/Y radius to define the MBR size. If X/Y radius are null then
4557 : * we'll try to use the MBR to recompute them.
4558 : *----------------------------------------------------------------*/
4559 0 : if (UpdateMBR(poMapFile) != 0)
4560 0 : return -1; /* Error already reported */
4561 :
4562 : /*-----------------------------------------------------------------
4563 : * Copy object information
4564 : *----------------------------------------------------------------*/
4565 0 : TABMAPObjRectEllipse *poRectHdr = (TABMAPObjRectEllipse *)poObjHdr;
4566 :
4567 : // Reset RoundRect Corner members... just in case (unused for ellipse)
4568 0 : poRectHdr->m_nCornerWidth = poRectHdr->m_nCornerHeight = 0;
4569 :
4570 : // An ellipse is defined by its MBR (values were set in UpdateMBR())
4571 0 : poRectHdr->m_nMinX = m_nXMin;
4572 0 : poRectHdr->m_nMinY = m_nYMin;
4573 0 : poRectHdr->m_nMaxX = m_nXMax;
4574 0 : poRectHdr->m_nMaxY = m_nYMax;
4575 :
4576 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
4577 0 : poRectHdr->m_nPenId = m_nPenDefIndex; // Pen index
4578 :
4579 0 : m_nBrushDefIndex = poMapFile->WriteBrushDef(&m_sBrushDef);
4580 0 : poRectHdr->m_nBrushId = m_nBrushDefIndex; // Brush index
4581 :
4582 0 : if (CPLGetLastErrorNo() != 0)
4583 0 : return -1;
4584 :
4585 0 : return 0;
4586 : }
4587 :
4588 : /**********************************************************************
4589 : * TABEllipse::GetStyleString()
4590 : *
4591 : * Return style string for this feature.
4592 : *
4593 : * Style String is built only once during the first call to GetStyleString().
4594 : **********************************************************************/
4595 0 : const char *TABEllipse::GetStyleString()
4596 : {
4597 0 : if (m_pszStyleString == NULL)
4598 : {
4599 : // Since GetPen/BrushStyleString() use CPLSPrintf(), we need
4600 : // to use temporary buffers
4601 0 : char *pszPen = CPLStrdup(GetPenStyleString());
4602 0 : char *pszBrush = CPLStrdup(GetBrushStyleString());
4603 :
4604 0 : m_pszStyleString = CPLStrdup(CPLSPrintf("%s;%s", pszBrush, pszPen));
4605 :
4606 0 : CPLFree(pszPen);
4607 0 : CPLFree(pszBrush);
4608 : }
4609 :
4610 0 : return m_pszStyleString;
4611 : }
4612 :
4613 :
4614 : /**********************************************************************
4615 : * TABEllipse::DumpMIF()
4616 : *
4617 : * Dump feature geometry in a format similar to .MIF REGIONs.
4618 : **********************************************************************/
4619 0 : void TABEllipse::DumpMIF(FILE *fpOut /*=NULL*/)
4620 : {
4621 : OGRGeometry *poGeom;
4622 0 : OGRPolygon *poPolygon = NULL;
4623 : int i, numPoints;
4624 :
4625 0 : if (fpOut == NULL)
4626 0 : fpOut = stdout;
4627 :
4628 : /*-----------------------------------------------------------------
4629 : * Output ELLIPSE parameters
4630 : *----------------------------------------------------------------*/
4631 : double dXMin, dYMin, dXMax, dYMax;
4632 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
4633 0 : fprintf(fpOut, "(ELLIPSE %.15g %.15g %.15g %.15g)\n", dXMin, dYMin, dXMax, dYMax);
4634 :
4635 : /*-----------------------------------------------------------------
4636 : * Fetch and validate geometry
4637 : *----------------------------------------------------------------*/
4638 0 : poGeom = GetGeometryRef();
4639 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPolygon)
4640 : {
4641 : /*-------------------------------------------------------------
4642 : * Generate ellipse output as a region
4643 : * We could also output as an ELLIPSE in a real MIF generator
4644 : *------------------------------------------------------------*/
4645 : int iRing, numIntRings;
4646 0 : poPolygon = (OGRPolygon*)poGeom;
4647 0 : numIntRings = poPolygon->getNumInteriorRings();
4648 0 : fprintf(fpOut, "REGION %d\n", numIntRings+1);
4649 : // In this loop, iRing=-1 for the outer ring.
4650 0 : for(iRing=-1; iRing < numIntRings; iRing++)
4651 : {
4652 : OGRLinearRing *poRing;
4653 :
4654 0 : if (iRing == -1)
4655 0 : poRing = poPolygon->getExteriorRing();
4656 : else
4657 0 : poRing = poPolygon->getInteriorRing(iRing);
4658 :
4659 0 : if (poRing == NULL)
4660 : {
4661 : CPLError(CE_Failure, CPLE_AssertionFailed,
4662 0 : "TABEllipse: Object Geometry contains NULL rings!");
4663 0 : return;
4664 : }
4665 :
4666 0 : numPoints = poRing->getNumPoints();
4667 0 : fprintf(fpOut, " %d\n", numPoints);
4668 0 : for(i=0; i<numPoints; i++)
4669 0 : fprintf(fpOut, "%.15g %.15g\n",poRing->getX(i),poRing->getY(i));
4670 : }
4671 : }
4672 : else
4673 : {
4674 : CPLError(CE_Failure, CPLE_AssertionFailed,
4675 0 : "TABEllipse: Missing or Invalid Geometry!");
4676 0 : return;
4677 : }
4678 :
4679 : // Finish with PEN/BRUSH/etc. clauses
4680 0 : DumpPenDef();
4681 0 : DumpBrushDef();
4682 :
4683 0 : fflush(fpOut);
4684 : }
4685 :
4686 :
4687 : /*=====================================================================
4688 : * class TABArc
4689 : *====================================================================*/
4690 :
4691 : /**********************************************************************
4692 : * TABArc::TABArc()
4693 : *
4694 : * Constructor.
4695 : **********************************************************************/
4696 0 : TABArc::TABArc(OGRFeatureDefn *poDefnIn):
4697 0 : TABFeature(poDefnIn)
4698 : {
4699 0 : m_dStartAngle = m_dEndAngle = 0.0;
4700 0 : m_dCenterX = m_dCenterY = m_dXRadius = m_dYRadius = 0.0;
4701 :
4702 0 : }
4703 :
4704 : /**********************************************************************
4705 : * TABArc::~TABArc()
4706 : *
4707 : * Destructor.
4708 : **********************************************************************/
4709 0 : TABArc::~TABArc()
4710 : {
4711 0 : }
4712 :
4713 : /**********************************************************************
4714 : * TABArc::CloneTABFeature()
4715 : *
4716 : * Duplicate feature, including stuff specific to each TABFeature type.
4717 : *
4718 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
4719 : * then copies any members specific to its own type.
4720 : **********************************************************************/
4721 0 : TABFeature *TABArc::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
4722 : {
4723 : /*-----------------------------------------------------------------
4724 : * Alloc new feature and copy the base stuff
4725 : *----------------------------------------------------------------*/
4726 0 : TABArc *poNew = new TABArc(poNewDefn ? poNewDefn : GetDefnRef());
4727 :
4728 0 : CopyTABFeatureBase(poNew);
4729 :
4730 : /*-----------------------------------------------------------------
4731 : * And members specific to this class
4732 : *----------------------------------------------------------------*/
4733 : // ITABFeaturePen
4734 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
4735 :
4736 0 : poNew->SetStartAngle( GetStartAngle() );
4737 0 : poNew->SetEndAngle( GetEndAngle() );
4738 :
4739 0 : poNew->m_dCenterX = m_dCenterX;
4740 0 : poNew->m_dCenterY = m_dCenterY;
4741 0 : poNew->m_dXRadius = m_dXRadius;
4742 0 : poNew->m_dYRadius = m_dYRadius;
4743 :
4744 0 : return poNew;
4745 : }
4746 :
4747 : /**********************************************************************
4748 : * TABArc::ValidateMapInfoType()
4749 : *
4750 : * Check the feature's geometry part and return the corresponding
4751 : * mapinfo object type code. The m_nMapInfoType member will also
4752 : * be updated for further calls to GetMapInfoType();
4753 : *
4754 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
4755 : * is expected for this object class.
4756 : **********************************************************************/
4757 0 : int TABArc::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
4758 : {
4759 : OGRGeometry *poGeom;
4760 :
4761 : /*-----------------------------------------------------------------
4762 : * Fetch and validate geometry
4763 : *----------------------------------------------------------------*/
4764 0 : poGeom = GetGeometryRef();
4765 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) ||
4766 : (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4767 : {
4768 0 : m_nMapInfoType = TAB_GEOM_ARC;
4769 : }
4770 : else
4771 : {
4772 : CPLError(CE_Failure, CPLE_AssertionFailed,
4773 0 : "TABArc: Missing or Invalid Geometry!");
4774 0 : m_nMapInfoType = TAB_GEOM_NONE;
4775 : }
4776 :
4777 : /*-----------------------------------------------------------------
4778 : * Decide if coordinates should be compressed or not.
4779 : *----------------------------------------------------------------*/
4780 : // __TODO__ For now we always write uncompressed for this class...
4781 : // ValidateCoordType(poMapFile);
4782 0 : UpdateMBR(poMapFile);
4783 :
4784 0 : return m_nMapInfoType;
4785 : }
4786 :
4787 : /**********************************************************************
4788 : * TABArc::UpdateMBR()
4789 : *
4790 : * Update the feature MBR members using the geometry
4791 : *
4792 : * Returns 0 on success, or -1 if there is no geometry in object
4793 : **********************************************************************/
4794 0 : int TABArc::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
4795 : {
4796 : OGRGeometry *poGeom;
4797 0 : OGREnvelope sEnvelope;
4798 :
4799 0 : poGeom = GetGeometryRef();
4800 0 : if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString ) )
4801 : {
4802 : /*-------------------------------------------------------------
4803 : * POLYGON geometry:
4804 : * Note that we will simply use the ellipse's MBR and don't really
4805 : * read the polygon geometry... this should be OK unless the
4806 : * polygon geometry was not really an ellipse.
4807 : * In the case of a polygon geometry. the m_dCenterX/Y values MUST
4808 : * have been set by the caller.
4809 : *------------------------------------------------------------*/
4810 0 : poGeom->getEnvelope(&sEnvelope);
4811 : }
4812 0 : else if ( (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint ) )
4813 : {
4814 : /*-------------------------------------------------------------
4815 : * In the case of a POINT GEOMETRY, we will make sure the the
4816 : * feature's m_dCenterX/Y are in sync with the point's X,Y coords.
4817 : *
4818 : * In this case we have to reconstruct the arc inside a temporary
4819 : * geometry object in order to find its real MBR.
4820 : *------------------------------------------------------------*/
4821 0 : OGRPoint *poPoint = (OGRPoint *)poGeom;
4822 0 : m_dCenterX = poPoint->getX();
4823 0 : m_dCenterY = poPoint->getY();
4824 :
4825 0 : OGRLineString oTmpLine;
4826 0 : int numPts=0;
4827 0 : if (m_dEndAngle < m_dStartAngle)
4828 0 : numPts = (int) ABS( ((m_dEndAngle+360)-m_dStartAngle)/2 ) + 1;
4829 : else
4830 0 : numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2 ) + 1;
4831 0 : numPts = MAX(2, numPts);
4832 :
4833 : TABGenerateArc(&oTmpLine, numPts,
4834 : m_dCenterX, m_dCenterY,
4835 : m_dXRadius, m_dYRadius,
4836 0 : m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
4837 :
4838 0 : oTmpLine.getEnvelope(&sEnvelope);
4839 : }
4840 : else
4841 : {
4842 : CPLError(CE_Failure, CPLE_AssertionFailed,
4843 0 : "TABArc: Missing or Invalid Geometry!");
4844 0 : return -1;
4845 : }
4846 :
4847 : // Update the Arc's MBR
4848 0 : m_dXMin = sEnvelope.MinX;
4849 0 : m_dYMin = sEnvelope.MinY;
4850 0 : m_dXMax = sEnvelope.MaxX;
4851 0 : m_dYMax = sEnvelope.MaxY;
4852 :
4853 0 : if (poMapFile)
4854 : {
4855 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
4856 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
4857 : }
4858 :
4859 0 : return 0;
4860 : }
4861 :
4862 : /**********************************************************************
4863 : * TABArc::ReadGeometryFromMAPFile()
4864 : *
4865 : * Fill the geometry and representation (color, etc...) part of the
4866 : * feature from the contents of the .MAP object pointed to by poMAPFile.
4867 : *
4868 : * It is assumed that poMAPFile currently points to the beginning of
4869 : * a map object.
4870 : *
4871 : * Returns 0 on success, -1 on error, in which case CPLError() will have
4872 : * been called.
4873 : **********************************************************************/
4874 : int TABArc::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
4875 : TABMAPObjHdr *poObjHdr,
4876 : GBool bCoordBlockDataOnly /*=FALSE*/,
4877 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
4878 : {
4879 : double dXMin, dYMin, dXMax, dYMax;
4880 : OGRLineString *poLine;
4881 : int numPts;
4882 :
4883 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
4884 0 : if (bCoordBlockDataOnly)
4885 0 : return 0;
4886 :
4887 : /*-----------------------------------------------------------------
4888 : * Fetch and validate geometry type
4889 : *----------------------------------------------------------------*/
4890 0 : m_nMapInfoType = poObjHdr->m_nType;
4891 :
4892 0 : if (m_nMapInfoType != TAB_GEOM_ARC &&
4893 : m_nMapInfoType != TAB_GEOM_ARC_C )
4894 : {
4895 : CPLError(CE_Failure, CPLE_AssertionFailed,
4896 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
4897 0 : m_nMapInfoType, m_nMapInfoType);
4898 0 : return -1;
4899 : }
4900 :
4901 :
4902 : /*-----------------------------------------------------------------
4903 : * Read object information
4904 : *----------------------------------------------------------------*/
4905 0 : TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
4906 :
4907 : /*-------------------------------------------------------------
4908 : * Start/End angles
4909 : * Since the angles are specified for integer coordinates, and
4910 : * that these coordinates can have the X axis reversed, we have to
4911 : * adjust the angle values for the change in the X axis
4912 : * direction.
4913 : *
4914 : * This should be necessary only when X axis is flipped.
4915 : * __TODO__ Why is order of start/end values reversed as well???
4916 : *------------------------------------------------------------*/
4917 :
4918 : /*-------------------------------------------------------------
4919 : * OK, Arc angles again!!!!!!!!!!!!
4920 : * After some tests in 1999-11, it appeared that the angle values
4921 : * ALWAYS had to be flipped (read order= end angle followed by
4922 : * start angle), no matter which quadrant the file is in.
4923 : * This does not make any sense, so I suspect that there is something
4924 : * that we are missing here!
4925 : *
4926 : * 2000-01-14.... Again!!! Based on some sample data files:
4927 : * File Ver Quadr ReflXAxis Read_Order Adjust_Angle
4928 : * test_symb.tab 300 2 1 end,start X=yes Y=no
4929 : * alltypes.tab: 300 1 0 start,end X=no Y=no
4930 : * arcs.tab: 300 2 0 end,start X=yes Y=no
4931 : *
4932 : * Until we prove it wrong, the rule would be:
4933 : * -> Quadrant 1 and 3, angles order = start, end
4934 : * -> Quadrant 2 and 4, angles order = end, start
4935 : * + Always adjust angles for x and y axis based on quadrant.
4936 : *
4937 : * This was confirmed using some more files in which the quadrant was
4938 : * manually changed, but whether these are valid results is
4939 : * discutable.
4940 : *
4941 : * The ReflectXAxis flag seems to have no effect here...
4942 : *------------------------------------------------------------*/
4943 :
4944 : /*-------------------------------------------------------------
4945 : * In version 100 .tab files (version 400 .map), it is possible
4946 : * to have a quadrant value of 0 and it should be treated the
4947 : * same way as quadrant 3
4948 : *------------------------------------------------------------*/
4949 0 : if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==1 ||
4950 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
4951 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
4952 : {
4953 : // Quadrants 1 and 3 ... read order = start, end
4954 0 : m_dStartAngle = poArcHdr->m_nStartAngle/10.0;
4955 0 : m_dEndAngle = poArcHdr->m_nEndAngle/10.0;
4956 : }
4957 : else
4958 : {
4959 : // Quadrants 2 and 4 ... read order = end, start
4960 0 : m_dStartAngle = poArcHdr->m_nEndAngle/10.0;
4961 0 : m_dEndAngle = poArcHdr->m_nStartAngle/10.0;
4962 : }
4963 :
4964 0 : if ( poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==2 ||
4965 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
4966 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
4967 : {
4968 : // X axis direction is flipped... adjust angle
4969 : m_dStartAngle = (m_dStartAngle<=180.0) ? (180.0-m_dStartAngle):
4970 0 : (540.0-m_dStartAngle);
4971 : m_dEndAngle = (m_dEndAngle<=180.0) ? (180.0-m_dEndAngle):
4972 0 : (540.0-m_dEndAngle);
4973 : }
4974 :
4975 0 : if (poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==3 ||
4976 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==4 ||
4977 : poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant==0 )
4978 : {
4979 : // Y axis direction is flipped... this reverses angle direction
4980 : // Unfortunately we never found any file that contains this case,
4981 : // but this should be the behavior to expect!!!
4982 : //
4983 : // 2000-01-14: some files in which quadrant was set to 3 and 4
4984 : // manually seemed to confirm that this is the right thing to do.
4985 0 : m_dStartAngle = 360.0 - m_dStartAngle;
4986 0 : m_dEndAngle = 360.0 - m_dEndAngle;
4987 : }
4988 :
4989 : // An arc is defined by its defining ellipse's MBR:
4990 :
4991 : poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMinX,
4992 0 : poArcHdr->m_nArcEllipseMinY , dXMin, dYMin);
4993 : poMapFile->Int2Coordsys(poArcHdr->m_nArcEllipseMaxX,
4994 0 : poArcHdr->m_nArcEllipseMaxY , dXMax, dYMax);
4995 :
4996 0 : m_dCenterX = (dXMin + dXMax) / 2.0;
4997 0 : m_dCenterY = (dYMin + dYMax) / 2.0;
4998 0 : m_dXRadius = ABS( (dXMax - dXMin) / 2.0 );
4999 0 : m_dYRadius = ABS( (dYMax - dYMin) / 2.0 );
5000 :
5001 : // Read the Arc's MBR and use that as this feature's MBR
5002 : poMapFile->Int2Coordsys(poArcHdr->m_nMinX, poArcHdr->m_nMinY,
5003 0 : dXMin, dYMin);
5004 : poMapFile->Int2Coordsys(poArcHdr->m_nMaxX, poArcHdr->m_nMaxY,
5005 0 : dXMax, dYMax);
5006 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
5007 :
5008 0 : m_nPenDefIndex = poArcHdr->m_nPenId; // Pen index
5009 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
5010 :
5011 :
5012 : /*-----------------------------------------------------------------
5013 : * Create and fill geometry object
5014 : * For the OGR geometry, we generate an arc with 2 degrees line
5015 : * segments.
5016 : *----------------------------------------------------------------*/
5017 0 : poLine = new OGRLineString;
5018 :
5019 0 : if (m_dEndAngle < m_dStartAngle)
5020 0 : numPts = (int) ABS( ((m_dEndAngle+360.0)-m_dStartAngle)/2.0 ) + 1;
5021 : else
5022 0 : numPts = (int) ABS( (m_dEndAngle-m_dStartAngle)/2.0 ) + 1;
5023 0 : numPts = MAX(2, numPts);
5024 :
5025 : TABGenerateArc(poLine, numPts,
5026 : m_dCenterX, m_dCenterY,
5027 : m_dXRadius, m_dYRadius,
5028 0 : m_dStartAngle*PI/180.0, m_dEndAngle*PI/180.0);
5029 :
5030 0 : SetGeometryDirectly(poLine);
5031 :
5032 0 : return 0;
5033 : }
5034 :
5035 : /**********************************************************************
5036 : * TABArc::WriteGeometryToMAPFile()
5037 : *
5038 : * Write the geometry and representation (color, etc...) part of the
5039 : * feature to the .MAP object pointed to by poMAPFile.
5040 : *
5041 : * It is assumed that poMAPFile currently points to a valid map object.
5042 : *
5043 : * Returns 0 on success, -1 on error, in which case CPLError() will have
5044 : * been called.
5045 : **********************************************************************/
5046 : int TABArc::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
5047 : TABMAPObjHdr *poObjHdr,
5048 : GBool bCoordBlockDataOnly /*=FALSE*/,
5049 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
5050 : {
5051 : /* Nothing to do for bCoordBlockDataOnly (used by index splitting) */
5052 0 : if (bCoordBlockDataOnly)
5053 0 : return 0;
5054 :
5055 : /*-----------------------------------------------------------------
5056 : * We assume that ValidateMapInfoType() was called already and that
5057 : * the type in poObjHdr->m_nType is valid.
5058 : *----------------------------------------------------------------*/
5059 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
5060 :
5061 : /*-----------------------------------------------------------------
5062 : * Fetch and validate geometry
5063 : * In the case of ARCs, this is all done inside UpdateMBR()
5064 : *----------------------------------------------------------------*/
5065 0 : if (UpdateMBR(poMapFile) != 0)
5066 0 : return -1; /* Error already reported */
5067 :
5068 : /*-----------------------------------------------------------------
5069 : * Copy object information
5070 : *----------------------------------------------------------------*/
5071 0 : TABMAPObjArc *poArcHdr = (TABMAPObjArc *)poObjHdr;
5072 :
5073 : /*-------------------------------------------------------------
5074 : * Start/End angles
5075 : * Since we ALWAYS produce files in quadrant 1 then we can
5076 : * ignore the special angle conversion required by flipped axis.
5077 : *
5078 : * See the notes about Arc angles in TABArc::ReadGeometryFromMAPFile()
5079 : *------------------------------------------------------------*/
5080 0 : CPLAssert(poMapFile->GetHeaderBlock()->m_nCoordOriginQuadrant == 1);
5081 :
5082 0 : poArcHdr->m_nStartAngle = ROUND_INT(m_dStartAngle*10.0);
5083 0 : poArcHdr->m_nEndAngle = ROUND_INT(m_dEndAngle*10.0);
5084 :
5085 : // An arc is defined by its defining ellipse's MBR:
5086 : poMapFile->Coordsys2Int(m_dCenterX-m_dXRadius, m_dCenterY-m_dYRadius,
5087 : poArcHdr->m_nArcEllipseMinX,
5088 0 : poArcHdr->m_nArcEllipseMinY);
5089 : poMapFile->Coordsys2Int(m_dCenterX+m_dXRadius, m_dCenterY+m_dYRadius,
5090 : poArcHdr->m_nArcEllipseMaxX,
5091 0 : poArcHdr->m_nArcEllipseMaxY);
5092 :
5093 : // Pass the Arc's actual MBR (values were set in UpdateMBR())
5094 0 : poArcHdr->m_nMinX = m_nXMin;
5095 0 : poArcHdr->m_nMinY = m_nYMin;
5096 0 : poArcHdr->m_nMaxX = m_nXMax;
5097 0 : poArcHdr->m_nMaxY = m_nYMax;
5098 :
5099 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
5100 0 : poArcHdr->m_nPenId = m_nPenDefIndex; // Pen index
5101 :
5102 0 : if (CPLGetLastErrorNo() != 0)
5103 0 : return -1;
5104 :
5105 0 : return 0;
5106 : }
5107 :
5108 : /**********************************************************************
5109 : * TABArc::SetStart/EndAngle()
5110 : *
5111 : * Set the start/end angle values in degrees, making sure the values are
5112 : * always in the range [0..360]
5113 : **********************************************************************/
5114 0 : void TABArc::SetStartAngle(double dAngle)
5115 : {
5116 0 : while(dAngle < 0.0) dAngle += 360.0;
5117 0 : while(dAngle > 360.0) dAngle -= 360.0;
5118 :
5119 0 : m_dStartAngle = dAngle;
5120 0 : }
5121 :
5122 0 : void TABArc::SetEndAngle(double dAngle)
5123 : {
5124 0 : while(dAngle < 0.0) dAngle += 360.0;
5125 0 : while(dAngle > 360.0) dAngle -= 360.0;
5126 :
5127 0 : m_dEndAngle = dAngle;
5128 0 : }
5129 :
5130 :
5131 : /**********************************************************************
5132 : * TABArc::GetStyleString()
5133 : *
5134 : * Return style string for this feature.
5135 : *
5136 : * Style String is built only once during the first call to GetStyleString().
5137 : **********************************************************************/
5138 0 : const char *TABArc::GetStyleString()
5139 : {
5140 0 : if (m_pszStyleString == NULL)
5141 : {
5142 0 : m_pszStyleString = CPLStrdup(GetPenStyleString());
5143 : }
5144 :
5145 0 : return m_pszStyleString;
5146 : }
5147 :
5148 : /**********************************************************************
5149 : * TABArc::DumpMIF()
5150 : *
5151 : * Dump feature geometry in a format similar to .MIF REGIONs.
5152 : **********************************************************************/
5153 0 : void TABArc::DumpMIF(FILE *fpOut /*=NULL*/)
5154 : {
5155 : OGRGeometry *poGeom;
5156 0 : OGRLineString *poLine = NULL;
5157 : int i, numPoints;
5158 :
5159 0 : if (fpOut == NULL)
5160 0 : fpOut = stdout;
5161 :
5162 : /*-----------------------------------------------------------------
5163 : * Output ARC parameters
5164 : *----------------------------------------------------------------*/
5165 : fprintf(fpOut, "(ARC %.15g %.15g %.15g %.15g %d %d)\n",
5166 : m_dCenterX - m_dXRadius, m_dCenterY - m_dYRadius,
5167 : m_dCenterX + m_dXRadius, m_dCenterY + m_dYRadius,
5168 0 : (int)m_dStartAngle, (int)m_dEndAngle);
5169 :
5170 : /*-----------------------------------------------------------------
5171 : * Fetch and validate geometry
5172 : *----------------------------------------------------------------*/
5173 0 : poGeom = GetGeometryRef();
5174 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbLineString)
5175 : {
5176 : /*-------------------------------------------------------------
5177 : * Generate arc output as a simple polyline
5178 : * We could also output as an ELLIPSE in a real MIF generator
5179 : *------------------------------------------------------------*/
5180 0 : poLine = (OGRLineString*)poGeom;
5181 0 : numPoints = poLine->getNumPoints();
5182 0 : fprintf(fpOut, "PLINE %d\n", numPoints);
5183 0 : for(i=0; i<numPoints; i++)
5184 0 : fprintf(fpOut, "%.15g %.15g\n", poLine->getX(i), poLine->getY(i));
5185 : }
5186 : else
5187 : {
5188 : CPLError(CE_Failure, CPLE_AssertionFailed,
5189 0 : "TABArc: Missing or Invalid Geometry!");
5190 0 : return;
5191 : }
5192 :
5193 : // Finish with PEN/BRUSH/etc. clauses
5194 0 : DumpPenDef();
5195 :
5196 0 : fflush(fpOut);
5197 : }
5198 :
5199 :
5200 :
5201 : /*=====================================================================
5202 : * class TABText
5203 : *====================================================================*/
5204 :
5205 : /**********************************************************************
5206 : * TABText::TABText()
5207 : *
5208 : * Constructor.
5209 : **********************************************************************/
5210 0 : TABText::TABText(OGRFeatureDefn *poDefnIn):
5211 0 : TABFeature(poDefnIn)
5212 : {
5213 0 : m_pszString = NULL;
5214 :
5215 0 : m_dAngle = m_dHeight = 0.0;
5216 0 : m_dfLineEndX = m_dfLineEndY = 0.0;
5217 0 : m_bLineEndSet = FALSE;
5218 :
5219 0 : m_rgbForeground = 0x000000;
5220 0 : m_rgbBackground = 0xffffff;
5221 0 : m_rgbOutline = 0xffffff;
5222 0 : m_rgbShadow = 0x808080;
5223 :
5224 0 : m_nTextAlignment = 0;
5225 0 : m_nFontStyle = 0;
5226 0 : m_dWidth = 0;
5227 0 : }
5228 :
5229 : /**********************************************************************
5230 : * TABText::~TABText()
5231 : *
5232 : * Destructor.
5233 : **********************************************************************/
5234 0 : TABText::~TABText()
5235 : {
5236 0 : CPLFree(m_pszString);
5237 0 : }
5238 :
5239 : /**********************************************************************
5240 : * TABText::CloneTABFeature()
5241 : *
5242 : * Duplicate feature, including stuff specific to each TABFeature type.
5243 : *
5244 : * This method calls the generic TABFeature::CopyTABFeatureBase() and
5245 : * then copies any members specific to its own type.
5246 : **********************************************************************/
5247 0 : TABFeature *TABText::CloneTABFeature(OGRFeatureDefn *poNewDefn/*=NULL*/)
5248 : {
5249 : /*-----------------------------------------------------------------
5250 : * Alloc new feature and copy the base stuff
5251 : *----------------------------------------------------------------*/
5252 0 : TABText *poNew = new TABText(poNewDefn ? poNewDefn : GetDefnRef());
5253 :
5254 0 : CopyTABFeatureBase(poNew);
5255 :
5256 : /*-----------------------------------------------------------------
5257 : * And members specific to this class
5258 : *----------------------------------------------------------------*/
5259 : // ITABFeaturePen
5260 0 : *(poNew->GetPenDefRef()) = *GetPenDefRef();
5261 :
5262 : // ITABFeatureFont
5263 0 : *(poNew->GetFontDefRef()) = *GetFontDefRef();
5264 :
5265 :
5266 0 : poNew->SetTextString( GetTextString() );
5267 0 : poNew->SetTextAngle( GetTextAngle() );
5268 0 : poNew->SetTextBoxHeight( GetTextBoxHeight() );
5269 0 : poNew->SetTextBoxWidth( GetTextBoxWidth() );
5270 0 : poNew->SetFontStyleTABValue( GetFontStyleTABValue() );
5271 0 : poNew->SetFontBGColor( GetFontBGColor() );
5272 0 : poNew->SetFontFGColor( GetFontFGColor() );
5273 0 : poNew->SetFontOColor( GetFontOColor() );
5274 0 : poNew->SetFontSColor( GetFontSColor() );
5275 :
5276 0 : poNew->SetTextJustification( GetTextJustification() );
5277 0 : poNew->SetTextSpacing( GetTextSpacing() );
5278 : // Note: Text arrow/line coordinates are not transported... but
5279 : // we ignore them most of the time anyways.
5280 0 : poNew->SetTextLineType( TABTLNoLine );
5281 :
5282 0 : return poNew;
5283 : }
5284 :
5285 : /**********************************************************************
5286 : * TABText::ValidateMapInfoType()
5287 : *
5288 : * Check the feature's geometry part and return the corresponding
5289 : * mapinfo object type code. The m_nMapInfoType member will also
5290 : * be updated for further calls to GetMapInfoType();
5291 : *
5292 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
5293 : * is expected for this object class.
5294 : **********************************************************************/
5295 0 : int TABText::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
5296 : {
5297 : OGRGeometry *poGeom;
5298 :
5299 : /*-----------------------------------------------------------------
5300 : * Fetch and validate geometry
5301 : *----------------------------------------------------------------*/
5302 0 : poGeom = GetGeometryRef();
5303 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
5304 : {
5305 0 : m_nMapInfoType = TAB_GEOM_TEXT;
5306 : }
5307 : else
5308 : {
5309 : CPLError(CE_Failure, CPLE_AssertionFailed,
5310 0 : "TABText: Missing or Invalid Geometry!");
5311 0 : m_nMapInfoType = TAB_GEOM_NONE;
5312 : }
5313 :
5314 : /*-----------------------------------------------------------------
5315 : * Decide if coordinates should be compressed or not.
5316 : *----------------------------------------------------------------*/
5317 : // __TODO__ For now we always write uncompressed for this class...
5318 : // ValidateCoordType(poMapFile);
5319 0 : UpdateMBR(poMapFile);
5320 :
5321 0 : return m_nMapInfoType;
5322 : }
5323 :
5324 : /**********************************************************************
5325 : * TABText::ReadGeometryFromMAPFile()
5326 : *
5327 : * Fill the geometry and representation (color, etc...) part of the
5328 : * feature from the contents of the .MAP object pointed to by poMAPFile.
5329 : *
5330 : * It is assumed that poMAPFile currently points to the beginning of
5331 : * a map object.
5332 : *
5333 : * Returns 0 on success, -1 on error, in which case CPLError() will have
5334 : * been called.
5335 : **********************************************************************/
5336 : int TABText::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
5337 : TABMAPObjHdr *poObjHdr,
5338 : GBool bCoordBlockDataOnly /*=FALSE*/,
5339 0 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
5340 : {
5341 : double dXMin, dYMin, dXMax, dYMax;
5342 : OGRGeometry *poGeometry;
5343 :
5344 : /*-----------------------------------------------------------------
5345 : * Fetch and validate geometry type
5346 : *----------------------------------------------------------------*/
5347 0 : m_nMapInfoType = poObjHdr->m_nType;
5348 :
5349 0 : if (m_nMapInfoType != TAB_GEOM_TEXT &&
5350 : m_nMapInfoType != TAB_GEOM_TEXT_C )
5351 : {
5352 : CPLError(CE_Failure, CPLE_AssertionFailed,
5353 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
5354 0 : m_nMapInfoType, m_nMapInfoType);
5355 0 : return -1;
5356 : }
5357 :
5358 : /*=============================================================
5359 : * TEXT
5360 : *============================================================*/
5361 : int nStringLen;
5362 : GInt32 nCoordBlockPtr;
5363 : double dJunk;
5364 :
5365 : /*-----------------------------------------------------------------
5366 : * Read object information
5367 : *----------------------------------------------------------------*/
5368 0 : TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
5369 :
5370 0 : nCoordBlockPtr = poTextHdr->m_nCoordBlockPtr; // String position
5371 0 : nStringLen = poTextHdr->m_nCoordDataSize; // String length
5372 0 : m_nTextAlignment = poTextHdr->m_nTextAlignment; // just./spacing/arrow
5373 :
5374 : /*-------------------------------------------------------------
5375 : * Text Angle, in thenths of degree.
5376 : * Contrary to arc start/end angles, no conversion based on
5377 : * origin quadrant is required here
5378 : *------------------------------------------------------------*/
5379 0 : m_dAngle = poTextHdr->m_nAngle/10.0;
5380 :
5381 0 : m_nFontStyle = poTextHdr->m_nFontStyle; // Font style
5382 :
5383 : m_rgbForeground = (poTextHdr->m_nFGColorR*256*256 +
5384 : poTextHdr->m_nFGColorG*256 +
5385 0 : poTextHdr->m_nFGColorB);
5386 : m_rgbBackground = (poTextHdr->m_nBGColorR*256*256 +
5387 : poTextHdr->m_nBGColorG*256 +
5388 0 : poTextHdr->m_nBGColorB);
5389 0 : m_rgbOutline = m_rgbBackground;
5390 : // In MapInfo, the shadow color is always gray (128,128,128)
5391 0 : m_rgbShadow = 0x808080;
5392 :
5393 : // arrow endpoint
5394 : poMapFile->Int2Coordsys(poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY,
5395 0 : m_dfLineEndX, m_dfLineEndY);
5396 0 : m_bLineEndSet = TRUE;
5397 :
5398 : // Text Height
5399 0 : poMapFile->Int2CoordsysDist(0, poTextHdr->m_nHeight, dJunk, m_dHeight);
5400 :
5401 0 : if (!bCoordBlockDataOnly)
5402 : {
5403 0 : m_nFontDefIndex = poTextHdr->m_nFontId; // Font name index
5404 0 : poMapFile->ReadFontDef(m_nFontDefIndex, &m_sFontDef);
5405 : }
5406 :
5407 : // MBR after rotation
5408 : poMapFile->Int2Coordsys(poTextHdr->m_nMinX, poTextHdr->m_nMinY,
5409 0 : dXMin, dYMin);
5410 : poMapFile->Int2Coordsys(poTextHdr->m_nMaxX, poTextHdr->m_nMaxY,
5411 0 : dXMax, dYMax);
5412 :
5413 0 : if (!bCoordBlockDataOnly)
5414 : {
5415 0 : m_nPenDefIndex = poTextHdr->m_nPenId; // Pen index for line
5416 0 : poMapFile->ReadPenDef(m_nPenDefIndex, &m_sPenDef);
5417 : }
5418 :
5419 : /*-------------------------------------------------------------
5420 : * Read text string from the coord. block
5421 : * Note that the string may contain binary '\n' and '\\' chars
5422 : * that we keep to an unescaped form internally. This is to
5423 : * be like OGR drivers. See bug 1107 for details.
5424 : *------------------------------------------------------------*/
5425 0 : char *pszTmpString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
5426 :
5427 0 : if (nStringLen > 0)
5428 : {
5429 : TABMAPCoordBlock *poCoordBlock;
5430 0 : CPLAssert(nCoordBlockPtr > 0);
5431 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
5432 0 : poCoordBlock = *ppoCoordBlock;
5433 : else
5434 0 : poCoordBlock = poMapFile->GetCoordBlock(nCoordBlockPtr);
5435 0 : if (poCoordBlock == NULL ||
5436 : poCoordBlock->ReadBytes(nStringLen,(GByte*)pszTmpString) != 0)
5437 : {
5438 : CPLError(CE_Failure, CPLE_FileIO,
5439 : "Failed reading text string at offset %d",
5440 0 : nCoordBlockPtr);
5441 0 : CPLFree(pszTmpString);
5442 0 : return -1;
5443 : }
5444 :
5445 : /* Return a ref to coord block so that caller can continue reading
5446 : * after the end of this object (used by index splitting)
5447 : */
5448 0 : if (ppoCoordBlock)
5449 0 : *ppoCoordBlock = poCoordBlock;
5450 : }
5451 :
5452 0 : pszTmpString[nStringLen] = '\0';
5453 :
5454 0 : CPLFree(m_pszString);
5455 0 : m_pszString = pszTmpString; // This string was Escaped before 20050714
5456 :
5457 :
5458 : /* Set/retrieve the MBR to make sure Mins are smaller than Maxs
5459 : */
5460 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
5461 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
5462 :
5463 : /* Copy int MBR to feature class members */
5464 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
5465 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
5466 :
5467 : /*-----------------------------------------------------------------
5468 : * Create an OGRPoint Geometry...
5469 : * The point X,Y values will be the coords of the lower-left corner before
5470 : * rotation is applied. (Note that the rotation in MapInfo is done around
5471 : * the upper-left corner)
5472 : * We need to calculate the true lower left corner of the text based
5473 : * on the MBR after rotation, the text height and the rotation angle.
5474 : *----------------------------------------------------------------*/
5475 : double dCos, dSin, dX, dY;
5476 0 : dSin = sin(m_dAngle*PI/180.0);
5477 0 : dCos = cos(m_dAngle*PI/180.0);
5478 0 : if (dSin > 0.0 && dCos > 0.0)
5479 : {
5480 0 : dX = dXMin + m_dHeight * dSin;
5481 0 : dY = dYMin;
5482 : }
5483 0 : else if (dSin > 0.0 && dCos < 0.0)
5484 : {
5485 0 : dX = dXMax;
5486 0 : dY = dYMin - m_dHeight * dCos;
5487 : }
5488 0 : else if (dSin < 0.0 && dCos < 0.0)
5489 : {
5490 0 : dX = dXMax + m_dHeight * dSin;
5491 0 : dY = dYMax;
5492 : }
5493 : else // dSin < 0 && dCos > 0
5494 : {
5495 0 : dX = dXMin;
5496 0 : dY = dYMax - m_dHeight * dCos;
5497 : }
5498 :
5499 0 : poGeometry = new OGRPoint(dX, dY);
5500 :
5501 0 : SetGeometryDirectly(poGeometry);
5502 :
5503 : /*-----------------------------------------------------------------
5504 : * Compute Text Width: the width of the Text MBR before rotation
5505 : * in ground units... unfortunately this value is not stored in the
5506 : * file, so we have to compute it with the MBR after rotation and
5507 : * the height of the MBR before rotation:
5508 : * With W = Width of MBR before rotation
5509 : * H = Height of MBR before rotation
5510 : * dX = Width of MBR after rotation
5511 : * dY = Height of MBR after rotation
5512 : * teta = rotation angle
5513 : *
5514 : * For [-PI/4..teta..+PI/4] or [3*PI/4..teta..5*PI/4], we'll use:
5515 : * W = H * (dX - H * sin(teta)) / (H * cos(teta))
5516 : *
5517 : * and for other teta values, use:
5518 : * W = H * (dY - H * cos(teta)) / (H * sin(teta))
5519 : *----------------------------------------------------------------*/
5520 0 : dSin = ABS(dSin);
5521 0 : dCos = ABS(dCos);
5522 0 : if (m_dHeight == 0.0)
5523 0 : m_dWidth = 0.0;
5524 0 : else if ( dCos > dSin )
5525 : m_dWidth = m_dHeight * ((dXMax-dXMin) - m_dHeight*dSin) /
5526 0 : (m_dHeight*dCos);
5527 : else
5528 : m_dWidth = m_dHeight * ((dYMax-dYMin) - m_dHeight*dCos) /
5529 0 : (m_dHeight*dSin);
5530 0 : m_dWidth = ABS(m_dWidth);
5531 :
5532 0 : return 0;
5533 : }
5534 :
5535 : /**********************************************************************
5536 : * TABText::WriteGeometryToMAPFile()
5537 : *
5538 : * Write the geometry and representation (color, etc...) part of the
5539 : * feature to the .MAP object pointed to by poMAPFile.
5540 : *
5541 : * It is assumed that poMAPFile currently points to a valid map object.
5542 : *
5543 : * Returns 0 on success, -1 on error, in which case CPLError() will have
5544 : * been called.
5545 : **********************************************************************/
5546 : int TABText::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
5547 : TABMAPObjHdr *poObjHdr,
5548 : GBool bCoordBlockDataOnly /*=FALSE*/,
5549 0 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
5550 : {
5551 : GInt32 nX, nY, nXMin, nYMin, nXMax, nYMax;
5552 : OGRGeometry *poGeom;
5553 : OGRPoint *poPoint;
5554 : GInt32 nCoordBlockPtr;
5555 : TABMAPCoordBlock *poCoordBlock;
5556 : int nStringLen;
5557 :
5558 : /*-----------------------------------------------------------------
5559 : * We assume that ValidateMapInfoType() was called already and that
5560 : * the type in poObjHdr->m_nType is valid.
5561 : *----------------------------------------------------------------*/
5562 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
5563 :
5564 : /*-----------------------------------------------------------------
5565 : * Fetch and validate geometry
5566 : *----------------------------------------------------------------*/
5567 0 : poGeom = GetGeometryRef();
5568 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
5569 0 : poPoint = (OGRPoint*)poGeom;
5570 : else
5571 : {
5572 : CPLError(CE_Failure, CPLE_AssertionFailed,
5573 0 : "TABText: Missing or Invalid Geometry!");
5574 0 : return -1;
5575 : }
5576 :
5577 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
5578 :
5579 : /*-----------------------------------------------------------------
5580 : * Write string to a coord block first...
5581 : * Note that the string may contain unescaped '\n' and '\\'
5582 : * that we have to keep like that for the MAP file.
5583 : * See MapTools bug 1107 for more details.
5584 : *----------------------------------------------------------------*/
5585 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
5586 0 : poCoordBlock = *ppoCoordBlock;
5587 : else
5588 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
5589 0 : poCoordBlock->StartNewFeature();
5590 0 : nCoordBlockPtr = poCoordBlock->GetCurAddress();
5591 :
5592 : // This string was escaped before 20050714
5593 0 : char *pszTmpString = m_pszString;
5594 :
5595 0 : nStringLen = strlen(pszTmpString);
5596 :
5597 0 : if (nStringLen > 0)
5598 : {
5599 0 : poCoordBlock->WriteBytes(nStringLen, (GByte *)pszTmpString);
5600 : }
5601 : else
5602 : {
5603 0 : nCoordBlockPtr = 0;
5604 : }
5605 :
5606 0 : pszTmpString = NULL;
5607 :
5608 : /*-----------------------------------------------------------------
5609 : * Copy object information
5610 : *----------------------------------------------------------------*/
5611 0 : TABMAPObjText *poTextHdr = (TABMAPObjText *)poObjHdr;
5612 :
5613 0 : poTextHdr->m_nCoordBlockPtr = nCoordBlockPtr; // String position
5614 0 : poTextHdr->m_nCoordDataSize = nStringLen; // String length
5615 0 : poTextHdr->m_nTextAlignment = m_nTextAlignment; // just./spacing/arrow
5616 :
5617 : /*-----------------------------------------------------------------
5618 : * Text Angle, (written in thenths of degrees)
5619 : * Contrary to arc start/end angles, no conversion based on
5620 : * origin quadrant is required here
5621 : *----------------------------------------------------------------*/
5622 0 : poTextHdr->m_nAngle = ROUND_INT(m_dAngle*10.0);
5623 :
5624 0 : poTextHdr->m_nFontStyle = m_nFontStyle; // Font style/effect
5625 :
5626 0 : poTextHdr->m_nFGColorR = COLOR_R(m_rgbForeground);
5627 0 : poTextHdr->m_nFGColorG = COLOR_G(m_rgbForeground);
5628 0 : poTextHdr->m_nFGColorB = COLOR_B(m_rgbForeground);
5629 :
5630 0 : poTextHdr->m_nBGColorR = COLOR_R(m_rgbBackground);
5631 0 : poTextHdr->m_nBGColorG = COLOR_G(m_rgbBackground);
5632 0 : poTextHdr->m_nBGColorB = COLOR_B(m_rgbBackground);
5633 :
5634 : /*-----------------------------------------------------------------
5635 : * The OGRPoint's X,Y values were the coords of the lower-left corner
5636 : * before rotation was applied. (Note that the rotation in MapInfo is
5637 : * done around the upper-left corner)
5638 : * The Feature's MBR is the MBR of the text after rotation... that's
5639 : * what MapInfo uses to define the text location.
5640 : *----------------------------------------------------------------*/
5641 : double dXMin, dYMin, dXMax, dYMax;
5642 : // Make sure Feature MBR is in sync with other params
5643 :
5644 0 : UpdateMBR();
5645 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
5646 :
5647 0 : poMapFile->Coordsys2Int(dXMin, dYMin, nXMin, nYMin);
5648 0 : poMapFile->Coordsys2Int(dXMax, dYMax, nXMax, nYMax);
5649 :
5650 : // Label line end point
5651 : double dX, dY;
5652 0 : GetTextLineEndPoint(dX, dY); // Make sure a default line end point is set
5653 : poMapFile->Coordsys2Int(m_dfLineEndX, m_dfLineEndY,
5654 0 : poTextHdr->m_nLineEndX, poTextHdr->m_nLineEndY);
5655 :
5656 : // Text Height
5657 0 : poMapFile->Coordsys2IntDist(0.0, m_dHeight, nX, nY);
5658 0 : poTextHdr->m_nHeight = nY;
5659 :
5660 0 : if (!bCoordBlockDataOnly)
5661 : {
5662 : // Font name
5663 0 : m_nFontDefIndex = poMapFile->WriteFontDef(&m_sFontDef);
5664 0 : poTextHdr->m_nFontId = m_nFontDefIndex; // Font name index
5665 : }
5666 :
5667 : // MBR after rotation
5668 0 : poTextHdr->SetMBR(nXMin, nYMin, nXMax, nYMax);
5669 :
5670 0 : if (!bCoordBlockDataOnly)
5671 : {
5672 0 : m_nPenDefIndex = poMapFile->WritePenDef(&m_sPenDef);
5673 0 : poTextHdr->m_nPenId = m_nPenDefIndex; // Pen index for line/arrow
5674 : }
5675 :
5676 0 : if (CPLGetLastErrorNo() != 0)
5677 0 : return -1;
5678 :
5679 : /* Return a ref to coord block so that caller can continue writing
5680 : * after the end of this object (used by index splitting)
5681 : */
5682 0 : if (ppoCoordBlock)
5683 0 : *ppoCoordBlock = poCoordBlock;
5684 :
5685 0 : return 0;
5686 : }
5687 :
5688 :
5689 : /**********************************************************************
5690 : * TABText::GetTextString()
5691 : *
5692 : * Return ref to text string value.
5693 : *
5694 : * Returned string is a reference to the internal string buffer and should
5695 : * not be modified or freed by the caller.
5696 : **********************************************************************/
5697 0 : const char *TABText::GetTextString()
5698 : {
5699 0 : if (m_pszString == NULL)
5700 0 : return "";
5701 :
5702 0 : return m_pszString;
5703 : }
5704 :
5705 : /**********************************************************************
5706 : * TABText::SetTextString()
5707 : *
5708 : * Set new text string value.
5709 : *
5710 : * Note: The text string may contain "\n" chars or "\\" chars
5711 : * and we expect to receive them in a 2 chars escaped form as
5712 : * described in the MIF format specs.
5713 : **********************************************************************/
5714 0 : void TABText::SetTextString(const char *pszNewStr)
5715 : {
5716 0 : CPLFree(m_pszString);
5717 0 : m_pszString = CPLStrdup(pszNewStr);
5718 0 : }
5719 :
5720 : /**********************************************************************
5721 : * TABText::GetTextAngle()
5722 : *
5723 : * Return text angle in degrees.
5724 : **********************************************************************/
5725 0 : double TABText::GetTextAngle()
5726 : {
5727 0 : return m_dAngle;
5728 : }
5729 :
5730 0 : void TABText::SetTextAngle(double dAngle)
5731 : {
5732 : // Make sure angle is in the range [0..360]
5733 0 : while(dAngle < 0.0) dAngle += 360.0;
5734 0 : while(dAngle > 360.0) dAngle -= 360.0;
5735 0 : m_dAngle = dAngle;
5736 0 : UpdateMBR();
5737 0 : }
5738 :
5739 : /**********************************************************************
5740 : * TABText::GetTextBoxHeight()
5741 : *
5742 : * Return text height in Y axis coord. units of the text box before rotation.
5743 : **********************************************************************/
5744 0 : double TABText::GetTextBoxHeight()
5745 : {
5746 0 : return m_dHeight;
5747 : }
5748 :
5749 0 : void TABText::SetTextBoxHeight(double dHeight)
5750 : {
5751 0 : m_dHeight = dHeight;
5752 0 : UpdateMBR();
5753 0 : }
5754 :
5755 : /**********************************************************************
5756 : * TABText::GetTextBoxWidth()
5757 : *
5758 : * Return text width in X axis coord. units. of the text box before rotation.
5759 : *
5760 : * If value has not been set, then we force a default value that assumes
5761 : * that one char's box width is 60% of its height... and we ignore
5762 : * the multiline case. This should not matter when the user PROPERLY sets
5763 : * the value.
5764 : **********************************************************************/
5765 0 : double TABText::GetTextBoxWidth()
5766 : {
5767 0 : if (m_dWidth == 0.0 && m_pszString)
5768 : {
5769 0 : m_dWidth = 0.6 * m_dHeight * strlen(m_pszString);
5770 : }
5771 0 : return m_dWidth;
5772 : }
5773 :
5774 0 : void TABText::SetTextBoxWidth(double dWidth)
5775 : {
5776 0 : m_dWidth = dWidth;
5777 0 : UpdateMBR();
5778 0 : }
5779 :
5780 : /**********************************************************************
5781 : * TABText::GetTextLineEndPoint()
5782 : *
5783 : * Return X,Y coordinates of the text label line end point.
5784 : * Default is the center of the text MBR.
5785 : **********************************************************************/
5786 0 : void TABText::GetTextLineEndPoint(double &dX, double &dY)
5787 : {
5788 0 : if (!m_bLineEndSet)
5789 : {
5790 : // Set default location at center of text MBR
5791 : double dXMin, dYMin, dXMax, dYMax;
5792 0 : UpdateMBR();
5793 0 : GetMBR(dXMin, dYMin, dXMax, dYMax);
5794 0 : m_dfLineEndX = (dXMin + dXMax) /2.0;
5795 0 : m_dfLineEndY = (dYMin + dYMax) /2.0;
5796 0 : m_bLineEndSet = TRUE;
5797 : }
5798 :
5799 : // Return values
5800 0 : dX = m_dfLineEndX;
5801 0 : dY = m_dfLineEndY;
5802 0 : }
5803 :
5804 0 : void TABText::SetTextLineEndPoint(double dX, double dY)
5805 : {
5806 0 : m_dfLineEndX = dX;
5807 0 : m_dfLineEndY = dY;
5808 0 : m_bLineEndSet = TRUE;
5809 0 : }
5810 :
5811 : /**********************************************************************
5812 : * TABText::UpdateMBR()
5813 : *
5814 : * Update the feature MBR using the text origin (OGRPoint geometry), the
5815 : * rotation angle, and the Width/height before rotation.
5816 : *
5817 : * This function cannot perform properly unless all the above have been set.
5818 : *
5819 : * Returns 0 on success, or -1 if there is no geometry in object
5820 : **********************************************************************/
5821 0 : int TABText::UpdateMBR(TABMAPFile * poMapFile /*=NULL*/)
5822 : {
5823 : OGRGeometry *poGeom;
5824 0 : OGRPoint *poPoint=NULL;
5825 :
5826 0 : poGeom = GetGeometryRef();
5827 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
5828 : {
5829 : double dSin, dCos, dX0, dY0, dX1, dY1;
5830 : double dX[4], dY[4];
5831 0 : poPoint = (OGRPoint *)poGeom;
5832 :
5833 0 : dX0 = poPoint->getX();
5834 0 : dY0 = poPoint->getY();
5835 :
5836 0 : dSin = sin(m_dAngle*PI/180.0);
5837 0 : dCos = cos(m_dAngle*PI/180.0);
5838 :
5839 0 : GetTextBoxWidth(); // Force default width value if necessary.
5840 :
5841 0 : dX[0] = dX0;
5842 0 : dY[0] = dY0;
5843 0 : dX[1] = dX0 + m_dWidth;
5844 0 : dY[1] = dY0;
5845 0 : dX[2] = dX0 + m_dWidth;
5846 0 : dY[2] = dY0 + m_dHeight;
5847 0 : dX[3] = dX0;
5848 0 : dY[3] = dY0 + m_dHeight;
5849 :
5850 0 : SetMBR(dX0, dY0, dX0, dY0);
5851 0 : for(int i=0; i<4; i++)
5852 : {
5853 : // Rotate one of the box corners
5854 0 : dX1 = dX0 + (dX[i]-dX0)*dCos - (dY[i]-dY0)*dSin;
5855 0 : dY1 = dY0 + (dX[i]-dX0)*dSin + (dY[i]-dY0)*dCos;
5856 :
5857 : // And update feature MBR with rotated coordinate
5858 0 : if (dX1 < m_dXMin) m_dXMin = dX1;
5859 0 : if (dX1 > m_dXMax) m_dXMax = dX1;
5860 0 : if (dY1 < m_dYMin) m_dYMin = dY1;
5861 0 : if (dY1 > m_dYMax) m_dYMax = dY1;
5862 : }
5863 :
5864 0 : if (poMapFile)
5865 : {
5866 0 : poMapFile->Coordsys2Int(m_dXMin, m_dYMin, m_nXMin, m_nYMin);
5867 0 : poMapFile->Coordsys2Int(m_dXMax, m_dYMax, m_nXMax, m_nYMax);
5868 : }
5869 :
5870 0 : return 0;
5871 : }
5872 :
5873 0 : return -1;
5874 : }
5875 :
5876 : /**********************************************************************
5877 : * TABText::GetFontBGColor()
5878 : *
5879 : * Return background color.
5880 : **********************************************************************/
5881 0 : GInt32 TABText::GetFontBGColor()
5882 : {
5883 0 : return m_rgbBackground;
5884 : }
5885 :
5886 0 : void TABText::SetFontBGColor(GInt32 rgbColor)
5887 : {
5888 0 : m_rgbBackground = rgbColor;
5889 0 : }
5890 :
5891 : /**********************************************************************
5892 : * TABText::GetFontOColor()
5893 : *
5894 : * Return outline color.
5895 : **********************************************************************/
5896 0 : GInt32 TABText::GetFontOColor()
5897 : {
5898 0 : return m_rgbOutline;
5899 : }
5900 :
5901 0 : void TABText::SetFontOColor(GInt32 rgbColor)
5902 : {
5903 0 : m_rgbOutline = rgbColor;
5904 0 : }
5905 :
5906 : /**********************************************************************
5907 : * TABText::GetFontSColor()
5908 : *
5909 : * Return shadow color.
5910 : **********************************************************************/
5911 0 : GInt32 TABText::GetFontSColor()
5912 : {
5913 0 : return m_rgbShadow;
5914 : }
5915 :
5916 0 : void TABText::SetFontSColor(GInt32 rgbColor)
5917 : {
5918 0 : m_rgbShadow = rgbColor;
5919 0 : }
5920 :
5921 : /**********************************************************************
5922 : * TABText::GetFontFGColor()
5923 : *
5924 : * Return foreground color.
5925 : **********************************************************************/
5926 0 : GInt32 TABText::GetFontFGColor()
5927 : {
5928 0 : return m_rgbForeground;
5929 : }
5930 :
5931 0 : void TABText::SetFontFGColor(GInt32 rgbColor)
5932 : {
5933 0 : m_rgbForeground = rgbColor;
5934 0 : }
5935 :
5936 : /**********************************************************************
5937 : * TABText::GetTextJustification()
5938 : *
5939 : * Return text justification. Default is TABTJLeft
5940 : **********************************************************************/
5941 0 : TABTextJust TABText::GetTextJustification()
5942 : {
5943 0 : TABTextJust eJust = TABTJLeft;
5944 :
5945 0 : if (m_nTextAlignment & 0x0200)
5946 0 : eJust = TABTJCenter;
5947 0 : else if (m_nTextAlignment & 0x0400)
5948 0 : eJust = TABTJRight;
5949 :
5950 0 : return eJust;
5951 : }
5952 :
5953 0 : void TABText::SetTextJustification(TABTextJust eJustification)
5954 : {
5955 : // Flush current value... default is TABTJLeft
5956 0 : m_nTextAlignment &= ~ 0x0600;
5957 : // ... and set new one.
5958 0 : if (eJustification == TABTJCenter)
5959 0 : m_nTextAlignment |= 0x0200;
5960 0 : else if (eJustification == TABTJRight)
5961 0 : m_nTextAlignment |= 0x0400;
5962 0 : }
5963 :
5964 : /**********************************************************************
5965 : * TABText::GetTextSpacing()
5966 : *
5967 : * Return text vertical spacing factor. Default is TABTSSingle
5968 : **********************************************************************/
5969 0 : TABTextSpacing TABText::GetTextSpacing()
5970 : {
5971 0 : TABTextSpacing eSpacing = TABTSSingle;
5972 :
5973 0 : if (m_nTextAlignment & 0x0800)
5974 0 : eSpacing = TABTS1_5;
5975 0 : else if (m_nTextAlignment & 0x1000)
5976 0 : eSpacing = TABTSDouble;
5977 :
5978 0 : return eSpacing;
5979 : }
5980 :
5981 0 : void TABText::SetTextSpacing(TABTextSpacing eSpacing)
5982 : {
5983 : // Flush current value... default is TABTSSingle
5984 0 : m_nTextAlignment &= ~ 0x1800;
5985 : // ... and set new one.
5986 0 : if (eSpacing == TABTS1_5)
5987 0 : m_nTextAlignment |= 0x0800;
5988 0 : else if (eSpacing == TABTSDouble)
5989 0 : m_nTextAlignment |= 0x1000;
5990 0 : }
5991 :
5992 : /**********************************************************************
5993 : * TABText::GetTextLineType()
5994 : *
5995 : * Return text line (arrow) type. Default is TABTLNoLine
5996 : **********************************************************************/
5997 0 : TABTextLineType TABText::GetTextLineType()
5998 : {
5999 0 : TABTextLineType eLine = TABTLNoLine;
6000 :
6001 0 : if (m_nTextAlignment & 0x2000)
6002 0 : eLine = TABTLSimple;
6003 0 : else if (m_nTextAlignment & 0x4000)
6004 0 : eLine = TABTLArrow;
6005 :
6006 0 : return eLine;
6007 : }
6008 :
6009 0 : void TABText::SetTextLineType(TABTextLineType eLineType)
6010 : {
6011 : // Flush current value... default is TABTLNoLine
6012 0 : m_nTextAlignment &= ~ 0x6000;
6013 : // ... and set new one.
6014 0 : if (eLineType == TABTLSimple)
6015 0 : m_nTextAlignment |= 0x2000;
6016 0 : else if (eLineType == TABTLArrow)
6017 0 : m_nTextAlignment |= 0x4000;
6018 0 : }
6019 :
6020 : /**********************************************************************
6021 : * TABText::QueryFontStyle()
6022 : *
6023 : * Return TRUE if the specified font style attribute is turned ON,
6024 : * or FALSE otherwise. See enum TABFontStyle for the list of styles
6025 : * that can be queried on.
6026 : **********************************************************************/
6027 0 : GBool TABText::QueryFontStyle(TABFontStyle eStyleToQuery)
6028 : {
6029 0 : return (m_nFontStyle & (int)eStyleToQuery) ? TRUE: FALSE;
6030 : }
6031 :
6032 0 : void TABText::ToggleFontStyle(TABFontStyle eStyleToToggle, GBool bStyleOn)
6033 : {
6034 0 : if (bStyleOn)
6035 0 : m_nFontStyle |= (int)eStyleToToggle;
6036 : else
6037 0 : m_nFontStyle &= ~ (int)eStyleToToggle;
6038 0 : }
6039 :
6040 :
6041 : /**********************************************************************
6042 : * TABText::GetFontStyleMIFValue()
6043 : *
6044 : * Return the Font Style value for this object using the style values
6045 : * that are used in a MIF FONT() clause. See MIF specs (appendix A).
6046 : *
6047 : * The reason why we have to differentiate between the TAB and the MIF font
6048 : * style values is that in TAB, TABFSBox is included in the style value
6049 : * as code 0x100, but in MIF it is not included, instead it is implied by
6050 : * the presence of the BG color in the FONT() clause (the BG color is
6051 : * present only when TABFSBox or TABFSHalo is set).
6052 : * This also has the effect of shifting all the other style values > 0x100
6053 : * by 1 byte.
6054 : **********************************************************************/
6055 0 : int TABText::GetFontStyleMIFValue()
6056 : {
6057 : // The conversion is simply to remove bit 0x100 from the value and shift
6058 : // down all values past this bit.
6059 0 : return (m_nFontStyle & 0xff) + (m_nFontStyle & (0xff00-0x0100))/2;
6060 : }
6061 :
6062 0 : void TABText:: SetFontStyleMIFValue(int nStyle, GBool bBGColorSet)
6063 : {
6064 0 : m_nFontStyle = (nStyle & 0xff) + (nStyle & 0x7f00)*2;
6065 : // When BG color is set, then either BOX or HALO should be set.
6066 0 : if (bBGColorSet && !QueryFontStyle(TABFSHalo))
6067 0 : ToggleFontStyle(TABFSBox, TRUE);
6068 0 : }
6069 :
6070 0 : int TABText::IsFontBGColorUsed()
6071 : {
6072 : // Font BG color is used only when BOX is set.
6073 0 : return (QueryFontStyle(TABFSBox));
6074 : }
6075 :
6076 0 : int TABText::IsFontOColorUsed()
6077 : {
6078 : // Font outline color is used only when HALO is set.
6079 0 : return (QueryFontStyle(TABFSHalo));
6080 : }
6081 :
6082 0 : int TABText::IsFontSColorUsed()
6083 : {
6084 : // Font shadow color is used only when Shadow is set.
6085 0 : return (QueryFontStyle(TABFSShadow));
6086 : }
6087 :
6088 0 : int TABText::IsFontBold()
6089 : {
6090 : // Font bold is used only when Bold is set.
6091 0 : return (QueryFontStyle(TABFSBold));
6092 : }
6093 :
6094 0 : int TABText::IsFontItalic()
6095 : {
6096 : // Font italic is used only when Italic is set.
6097 0 : return (QueryFontStyle(TABFSItalic));
6098 : }
6099 :
6100 0 : int TABText::IsFontUnderline()
6101 : {
6102 : // Font underline is used only when Underline is set.
6103 0 : return (QueryFontStyle(TABFSUnderline));
6104 : }
6105 :
6106 : /**********************************************************************
6107 : * TABText::GetLabelStyleString()
6108 : *
6109 : * This is not the correct location, it should be in ITABFeatureFont,
6110 : * but it's really more easy to put it here. This fct return a complete
6111 : * string for the representation with the string to display
6112 : **********************************************************************/
6113 0 : const char *TABText::GetLabelStyleString()
6114 : {
6115 0 : const char *pszStyle = NULL;
6116 0 : int nStringLen = strlen(GetTextString());
6117 : // ALL Caps, Extpanded need to modify the string value
6118 0 : char *pszTextString = (char*)CPLMalloc((nStringLen+1)*sizeof(char));
6119 : char szPattern[20];
6120 0 : int nJustification = 1;
6121 :
6122 0 : strcpy(pszTextString, GetTextString());
6123 0 : szPattern[0] = '\0';
6124 :
6125 :
6126 0 : switch(GetTextJustification())
6127 : {
6128 : case TABTJCenter:
6129 0 : nJustification = 2;
6130 0 : break;
6131 : case TABTJRight:
6132 0 : nJustification = 1;
6133 0 : break;
6134 : case TABTJLeft:
6135 : default:
6136 0 : nJustification =1;
6137 : break;
6138 : }
6139 :
6140 : // Compute real font size, taking number of lines ("\\n", "\n") and line
6141 : // spacing into account.
6142 0 : int numLines = 1;
6143 0 : for (int i=0; pszTextString[i];
6144 : numLines += ((pszTextString[i]=='\n' ||
6145 : (pszTextString[i]=='\\' && pszTextString[i+1]=='n')) &&
6146 : pszTextString[i+1] != '\0' ),++i);
6147 :
6148 0 : double dHeight = GetTextBoxHeight()/numLines;
6149 :
6150 : // In all cases, take out 20% of font height to account for line spacing
6151 0 : if (numLines > 1)
6152 : {
6153 0 : switch(GetTextSpacing())
6154 : {
6155 : case TABTS1_5:
6156 0 : dHeight *= (0.80 * 0.69);
6157 0 : break;
6158 : case TABTSDouble:
6159 0 : dHeight *= (0.66 * 0.69);
6160 0 : break;
6161 : default:
6162 0 : dHeight *= 0.69;
6163 : }
6164 : }
6165 : else
6166 : {
6167 0 : dHeight *= 0.69;
6168 : }
6169 :
6170 0 : if (QueryFontStyle(TABFSAllCaps))
6171 0 : for (int i=0; pszTextString[i];++i)
6172 0 : if (isalpha(pszTextString[i]))
6173 0 : pszTextString[i] = (char)toupper(pszTextString[i]);
6174 :
6175 0 : if (QueryFontStyle(TABFSExpanded))
6176 : {
6177 0 : char *pszTmpTextString = (char*)CPLMalloc(((nStringLen*2)+1)*sizeof(char));
6178 0 : int j = 0;
6179 :
6180 0 : for (int i =0; i < nStringLen; ++i)
6181 : {
6182 0 : pszTmpTextString[j] = pszTextString[i];
6183 0 : pszTmpTextString[j+1] = ' ';
6184 0 : j += 2;
6185 : }
6186 :
6187 0 : pszTmpTextString[j-1] = '\0';
6188 0 : CPLFree(pszTextString);
6189 0 : pszTextString = (char*)CPLMalloc((strlen(pszTmpTextString)+1)*sizeof(char));
6190 0 : strcpy(pszTextString, pszTmpTextString);
6191 0 : CPLFree(pszTmpTextString);
6192 : }
6193 :
6194 : const char *pszBGColor = IsFontBGColorUsed() ? CPLSPrintf(",b:#%6.6x",
6195 0 : GetFontBGColor()) :"";
6196 : const char *pszOColor = IsFontOColorUsed() ? CPLSPrintf(",o:#%6.6x",
6197 0 : GetFontOColor()) :"";
6198 : const char *pszSColor = IsFontSColorUsed() ? CPLSPrintf(",h:#%6.6x",
6199 0 : GetFontSColor()) :"";
6200 0 : const char *pszBold = IsFontBold() ? ",bo:1" :"";
6201 0 : const char *pszItalic = IsFontItalic() ? ",it:1" :"";
6202 0 : const char *pszUnderline = IsFontUnderline() ? ",un:1" : "";
6203 :
6204 : pszStyle=CPLSPrintf("LABEL(t:\"%s\",a:%f,s:%fg,c:#%6.6x%s%s%s%s%s%s,p:%d,f:\"%s\")",
6205 : pszTextString,GetTextAngle(), dHeight,
6206 : GetFontFGColor(),pszBGColor,pszOColor,pszSColor,
6207 0 : pszBold,pszItalic,pszUnderline,nJustification,GetFontNameRef());
6208 :
6209 0 : CPLFree(pszTextString);
6210 0 : return pszStyle;
6211 :
6212 : }
6213 :
6214 : /**********************************************************************
6215 : * TABText::GetStyleString()
6216 : *
6217 : * Return style string for this feature.
6218 : *
6219 : * Style String is built only once during the first call to GetStyleString().
6220 : **********************************************************************/
6221 0 : const char *TABText::GetStyleString()
6222 : {
6223 0 : if (m_pszStyleString == NULL)
6224 : {
6225 0 : m_pszStyleString = CPLStrdup(GetLabelStyleString());
6226 : }
6227 :
6228 0 : return m_pszStyleString;
6229 : }
6230 :
6231 :
6232 :
6233 : /**********************************************************************
6234 : * TABText::DumpMIF()
6235 : *
6236 : * Dump feature geometry in a format similar to .MIF REGIONs.
6237 : **********************************************************************/
6238 0 : void TABText::DumpMIF(FILE *fpOut /*=NULL*/)
6239 : {
6240 : OGRGeometry *poGeom;
6241 0 : OGRPoint *poPoint = NULL;
6242 :
6243 0 : if (fpOut == NULL)
6244 0 : fpOut = stdout;
6245 :
6246 : /*-----------------------------------------------------------------
6247 : * Fetch and validate geometry
6248 : *----------------------------------------------------------------*/
6249 0 : poGeom = GetGeometryRef();
6250 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
6251 : {
6252 : /*-------------------------------------------------------------
6253 : * Generate output for text object
6254 : *------------------------------------------------------------*/
6255 0 : poPoint = (OGRPoint*)poGeom;
6256 :
6257 : fprintf(fpOut, "TEXT \"%s\" %.15g %.15g\n", m_pszString?m_pszString:"",
6258 0 : poPoint->getX(), poPoint->getY());
6259 :
6260 0 : fprintf(fpOut, " m_pszString = '%s'\n", m_pszString);
6261 0 : fprintf(fpOut, " m_dAngle = %.15g\n", m_dAngle);
6262 0 : fprintf(fpOut, " m_dHeight = %.15g\n", m_dHeight);
6263 : fprintf(fpOut, " m_rgbForeground = 0x%6.6x (%d)\n",
6264 0 : m_rgbForeground, m_rgbForeground);
6265 : fprintf(fpOut, " m_rgbBackground = 0x%6.6x (%d)\n",
6266 0 : m_rgbBackground, m_rgbBackground);
6267 0 : fprintf(fpOut, " m_nTextAlignment = 0x%4.4x\n", m_nTextAlignment);
6268 0 : fprintf(fpOut, " m_nFontStyle = 0x%4.4x\n", m_nFontStyle);
6269 : }
6270 : else
6271 : {
6272 : CPLError(CE_Failure, CPLE_AssertionFailed,
6273 0 : "TABText: Missing or Invalid Geometry!");
6274 0 : return;
6275 : }
6276 :
6277 : // Finish with PEN/BRUSH/etc. clauses
6278 0 : DumpPenDef();
6279 0 : DumpFontDef();
6280 :
6281 0 : fflush(fpOut);
6282 : }
6283 :
6284 : /*=====================================================================
6285 : * class TABMultiPoint
6286 : *====================================================================*/
6287 :
6288 : /**********************************************************************
6289 : * TABMultiPoint::TABMultiPoint()
6290 : *
6291 : * Constructor.
6292 : **********************************************************************/
6293 0 : TABMultiPoint::TABMultiPoint(OGRFeatureDefn *poDefnIn):
6294 0 : TABFeature(poDefnIn)
6295 : {
6296 0 : m_bCenterIsSet = FALSE;
6297 0 : }
6298 :
6299 : /**********************************************************************
6300 : * TABMultiPoint::~TABMultiPoint()
6301 : *
6302 : * Destructor.
6303 : **********************************************************************/
6304 0 : TABMultiPoint::~TABMultiPoint()
6305 : {
6306 0 : }
6307 :
6308 : /**********************************************************************
6309 : * TABMultiPoint::CloneTABFeature()
6310 : *
6311 : * Duplicate feature, including stuff specific to each TABFeature type.
6312 : *
6313 : * This method calls the generic TABFeature::CloneTABFeature() and
6314 : * then copies any members specific to its own type.
6315 : **********************************************************************/
6316 0 : TABFeature *TABMultiPoint::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
6317 : {
6318 : /*-----------------------------------------------------------------
6319 : * Alloc new feature and copy the base stuff
6320 : *----------------------------------------------------------------*/
6321 0 : TABMultiPoint *poNew = new TABMultiPoint(poNewDefn?poNewDefn:GetDefnRef());
6322 :
6323 0 : CopyTABFeatureBase(poNew);
6324 :
6325 : /*-----------------------------------------------------------------
6326 : * And members specific to this class
6327 : *----------------------------------------------------------------*/
6328 : // ITABFeatureSymbol
6329 0 : *(poNew->GetSymbolDefRef()) = *GetSymbolDefRef();
6330 :
6331 0 : poNew->m_bCenterIsSet = m_bCenterIsSet;
6332 0 : poNew->m_dCenterX = m_dCenterX;
6333 0 : poNew->m_dCenterY = m_dCenterY;
6334 :
6335 0 : return poNew;
6336 : }
6337 :
6338 :
6339 : /**********************************************************************
6340 : * TABMultiPoint::ValidateMapInfoType()
6341 : *
6342 : * Check the feature's geometry part and return the corresponding
6343 : * mapinfo object type code. The m_nMapInfoType member will also
6344 : * be updated for further calls to GetMapInfoType();
6345 : *
6346 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
6347 : * is expected for this object class.
6348 : **********************************************************************/
6349 0 : int TABMultiPoint::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
6350 : {
6351 : OGRGeometry *poGeom;
6352 :
6353 : /*-----------------------------------------------------------------
6354 : * Fetch and validate geometry
6355 : *----------------------------------------------------------------*/
6356 0 : poGeom = GetGeometryRef();
6357 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6358 : {
6359 0 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
6360 :
6361 0 : if (poMPoint->getNumGeometries() > TAB_MULTIPOINT_650_MAX_VERTICES)
6362 0 : m_nMapInfoType = TAB_GEOM_V800_MULTIPOINT;
6363 : else
6364 0 : m_nMapInfoType = TAB_GEOM_MULTIPOINT;
6365 : }
6366 : else
6367 : {
6368 : CPLError(CE_Failure, CPLE_AssertionFailed,
6369 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6370 0 : m_nMapInfoType = TAB_GEOM_NONE;
6371 : }
6372 :
6373 : /*-----------------------------------------------------------------
6374 : * Decide if coordinates should be compressed or not.
6375 : *----------------------------------------------------------------*/
6376 0 : ValidateCoordType(poMapFile);
6377 :
6378 0 : return m_nMapInfoType;
6379 : }
6380 :
6381 :
6382 :
6383 : /**********************************************************************
6384 : * TABMultiPoint::ReadGeometryFromMAPFile()
6385 : *
6386 : * Fill the geometry and representation (color, etc...) part of the
6387 : * feature from the contents of the .MAP object pointed to by poMAPFile.
6388 : *
6389 : * It is assumed that poMAPFile currently points to the beginning of
6390 : * a map object.
6391 : *
6392 : * Returns 0 on success, -1 on error, in which case CPLError() will have
6393 : * been called.
6394 : **********************************************************************/
6395 : int TABMultiPoint::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
6396 : TABMAPObjHdr *poObjHdr,
6397 : GBool bCoordBlockDataOnly /*=FALSE*/,
6398 0 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
6399 : {
6400 : GInt32 nX, nY;
6401 : double dX, dY, dXMin, dYMin, dXMax, dYMax;
6402 0 : OGRGeometry *poGeometry=NULL;
6403 0 : GBool bComprCoord = poObjHdr->IsCompressedType();
6404 0 : TABMAPCoordBlock *poCoordBlock = NULL;
6405 :
6406 : /*-----------------------------------------------------------------
6407 : * Fetch and validate geometry type
6408 : *----------------------------------------------------------------*/
6409 0 : m_nMapInfoType = poObjHdr->m_nType;
6410 :
6411 : /*-----------------------------------------------------------------
6412 : * Read object information
6413 : *----------------------------------------------------------------*/
6414 0 : if (m_nMapInfoType == TAB_GEOM_MULTIPOINT ||
6415 : m_nMapInfoType == TAB_GEOM_MULTIPOINT_C ||
6416 : m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT ||
6417 : m_nMapInfoType == TAB_GEOM_V800_MULTIPOINT_C )
6418 : {
6419 : /*-------------------------------------------------------------
6420 : * Copy data from poObjHdr
6421 : *------------------------------------------------------------*/
6422 0 : TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
6423 :
6424 : // MBR
6425 : poMapFile->Int2Coordsys(poMPointHdr->m_nMinX, poMPointHdr->m_nMinY,
6426 0 : dXMin, dYMin);
6427 : poMapFile->Int2Coordsys(poMPointHdr->m_nMaxX, poMPointHdr->m_nMaxY,
6428 0 : dXMax, dYMax);
6429 :
6430 0 : if (!bCoordBlockDataOnly)
6431 : {
6432 0 : m_nSymbolDefIndex = poMPointHdr->m_nSymbolId; // Symbol index
6433 0 : poMapFile->ReadSymbolDef(m_nSymbolDefIndex, &m_sSymbolDef);
6434 : }
6435 :
6436 : // Centroid/label point
6437 : poMapFile->Int2Coordsys(poMPointHdr->m_nLabelX, poMPointHdr->m_nLabelY,
6438 0 : dX, dY);
6439 0 : SetCenter(dX, dY);
6440 :
6441 : // Compressed coordinate origin (useful only in compressed case!)
6442 0 : m_nComprOrgX = poMPointHdr->m_nComprOrgX;
6443 0 : m_nComprOrgY = poMPointHdr->m_nComprOrgY;
6444 :
6445 : /*-------------------------------------------------------------
6446 : * Read Point Coordinates
6447 : *------------------------------------------------------------*/
6448 : OGRMultiPoint *poMultiPoint;
6449 0 : poGeometry = poMultiPoint = new OGRMultiPoint();
6450 :
6451 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
6452 0 : poCoordBlock = *ppoCoordBlock;
6453 : else
6454 0 : poCoordBlock = poMapFile->GetCoordBlock(poMPointHdr->m_nCoordBlockPtr);
6455 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX,
6456 0 : m_nComprOrgY);
6457 :
6458 0 : for(int iPoint=0; iPoint<poMPointHdr->m_nNumPoints; iPoint++)
6459 : {
6460 0 : if (poCoordBlock->ReadIntCoord(bComprCoord, nX, nY) != 0)
6461 : {
6462 : CPLError(CE_Failure, CPLE_FileIO,
6463 : "Failed reading coordinate data at offset %d",
6464 0 : poMPointHdr->m_nCoordBlockPtr);
6465 0 : return -1;
6466 : }
6467 :
6468 0 : poMapFile->Int2Coordsys(nX, nY, dX, dY);
6469 0 : OGRPoint *poPoint = new OGRPoint(dX, dY);
6470 :
6471 0 : if (poMultiPoint->addGeometryDirectly(poPoint) != OGRERR_NONE)
6472 : {
6473 0 : CPLAssert(FALSE); // Just in case lower-level lib is modified
6474 : }
6475 : }
6476 :
6477 : }
6478 : else
6479 : {
6480 : CPLError(CE_Failure, CPLE_AssertionFailed,
6481 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
6482 0 : m_nMapInfoType, m_nMapInfoType);
6483 0 : return -1;
6484 : }
6485 :
6486 0 : SetGeometryDirectly(poGeometry);
6487 :
6488 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
6489 :
6490 : /* Copy int MBR to feature class members */
6491 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
6492 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
6493 :
6494 : /* Return a ref to coord block so that caller can continue reading
6495 : * after the end of this object (used by TABCollection and index splitting)
6496 : */
6497 0 : if (ppoCoordBlock)
6498 0 : *ppoCoordBlock = poCoordBlock;
6499 :
6500 0 : return 0;
6501 : }
6502 :
6503 : /**********************************************************************
6504 : * TABMultiPoint::WriteGeometryToMAPFile()
6505 : *
6506 : * Write the geometry and representation (color, etc...) part of the
6507 : * feature to the .MAP object pointed to by poMAPFile.
6508 : *
6509 : * It is assumed that poMAPFile currently points to a valid map object.
6510 : *
6511 : * Returns 0 on success, -1 on error, in which case CPLError() will have
6512 : * been called.
6513 : **********************************************************************/
6514 : int TABMultiPoint::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
6515 : TABMAPObjHdr *poObjHdr,
6516 : GBool bCoordBlockDataOnly /*=FALSE*/,
6517 0 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
6518 : {
6519 : GInt32 nX, nY;
6520 : OGRGeometry *poGeom;
6521 : OGRMultiPoint *poMPoint;
6522 :
6523 : /*-----------------------------------------------------------------
6524 : * We assume that ValidateMapInfoType() was called already and that
6525 : * the type in poObjHdr->m_nType is valid.
6526 : *----------------------------------------------------------------*/
6527 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
6528 :
6529 0 : TABMAPObjMultiPoint *poMPointHdr = (TABMAPObjMultiPoint *)poObjHdr;
6530 :
6531 : /*-----------------------------------------------------------------
6532 : * Fetch and validate geometry
6533 : *----------------------------------------------------------------*/
6534 0 : poGeom = GetGeometryRef();
6535 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6536 0 : poMPoint = (OGRMultiPoint*)poGeom;
6537 : else
6538 : {
6539 : CPLError(CE_Failure, CPLE_AssertionFailed,
6540 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6541 0 : return -1;
6542 : }
6543 :
6544 0 : poMPointHdr->m_nNumPoints = poMPoint->getNumGeometries();
6545 :
6546 : /*-----------------------------------------------------------------
6547 : * Write data to coordinate block
6548 : *----------------------------------------------------------------*/
6549 : int iPoint, nStatus;
6550 : TABMAPCoordBlock *poCoordBlock;
6551 0 : GBool bCompressed = poObjHdr->IsCompressedType();
6552 :
6553 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
6554 0 : poCoordBlock = *ppoCoordBlock;
6555 : else
6556 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
6557 0 : poCoordBlock->StartNewFeature();
6558 0 : poMPointHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
6559 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
6560 :
6561 :
6562 0 : for(iPoint=0, nStatus=0;
6563 : nStatus == 0 && iPoint < poMPointHdr->m_nNumPoints; iPoint++)
6564 : {
6565 0 : poGeom = poMPoint->getGeometryRef(iPoint);
6566 :
6567 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
6568 : {
6569 0 : OGRPoint *poPoint = (OGRPoint*)poGeom;
6570 :
6571 0 : poMapFile->Coordsys2Int(poPoint->getX(), poPoint->getY(), nX, nY);
6572 0 : if (iPoint == 0)
6573 : {
6574 : // Default to the first point, we may use explicit value below
6575 0 : poMPointHdr->m_nLabelX = nX;
6576 0 : poMPointHdr->m_nLabelY = nY;
6577 : }
6578 :
6579 0 : if ((nStatus = poCoordBlock->WriteIntCoord(nX, nY,
6580 : bCompressed)) != 0)
6581 : {
6582 : // Failed ... error message has already been produced
6583 0 : return nStatus;
6584 : }
6585 :
6586 : }
6587 : else
6588 : {
6589 : CPLError(CE_Failure, CPLE_AssertionFailed,
6590 0 : "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
6591 0 : return -1;
6592 : }
6593 : }
6594 :
6595 : /*-----------------------------------------------------------------
6596 : * Copy object information
6597 : *----------------------------------------------------------------*/
6598 :
6599 : // Compressed coordinate origin (useful only in compressed case!)
6600 0 : poMPointHdr->m_nComprOrgX = m_nComprOrgX;
6601 0 : poMPointHdr->m_nComprOrgY = m_nComprOrgY;
6602 :
6603 0 : poMPointHdr->m_nCoordDataSize = poCoordBlock->GetFeatureDataSize();
6604 0 : poMPointHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
6605 :
6606 : // Center/label point (default value already set above)
6607 : double dX, dY;
6608 0 : if (GetCenter(dX, dY) != -1)
6609 : {
6610 : poMapFile->Coordsys2Int(dX, dY, poMPointHdr->m_nLabelX,
6611 0 : poMPointHdr->m_nLabelY);
6612 : }
6613 :
6614 0 : if (!bCoordBlockDataOnly)
6615 : {
6616 0 : m_nSymbolDefIndex = poMapFile->WriteSymbolDef(&m_sSymbolDef);
6617 0 : poMPointHdr->m_nSymbolId = m_nSymbolDefIndex; // Symbol index
6618 : }
6619 :
6620 0 : if (CPLGetLastErrorNo() != 0)
6621 0 : return -1;
6622 :
6623 : /* Return a ref to coord block so that caller can continue writing
6624 : * after the end of this object (used by index splitting)
6625 : */
6626 0 : if (ppoCoordBlock)
6627 0 : *ppoCoordBlock = poCoordBlock;
6628 :
6629 0 : return 0;
6630 : }
6631 :
6632 :
6633 : /**********************************************************************
6634 : * TABMultiPoint::GetXY()
6635 : *
6636 : * Return this point's X,Y coordinates.
6637 : **********************************************************************/
6638 0 : int TABMultiPoint::GetXY(int i, double &dX, double &dY)
6639 : {
6640 : OGRGeometry *poGeom;
6641 :
6642 : /*-----------------------------------------------------------------
6643 : * Fetch and validate geometry
6644 : *----------------------------------------------------------------*/
6645 0 : poGeom = GetGeometryRef();
6646 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6647 : {
6648 0 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
6649 :
6650 0 : if (i >= 0 && i < poMPoint->getNumGeometries() &&
6651 : (poGeom = poMPoint->getGeometryRef(i)) != NULL &&
6652 : wkbFlatten(poGeom->getGeometryType()) == wkbPoint )
6653 : {
6654 0 : OGRPoint *poPoint = (OGRPoint*)poGeom;
6655 :
6656 0 : dX = poPoint->getX();
6657 0 : dY = poPoint->getY();
6658 : }
6659 : }
6660 : else
6661 : {
6662 : CPLError(CE_Failure, CPLE_AssertionFailed,
6663 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6664 0 : dX = dY = 0.0;
6665 0 : return -1;
6666 : }
6667 :
6668 0 : return 0;
6669 : }
6670 :
6671 : /**********************************************************************
6672 : * TABMultiPoint::GetNumPoints()
6673 : *
6674 : * Return the number of points in this multipoint object
6675 : **********************************************************************/
6676 0 : int TABMultiPoint::GetNumPoints()
6677 : {
6678 : OGRGeometry *poGeom;
6679 :
6680 : /*-----------------------------------------------------------------
6681 : * Fetch and validate geometry
6682 : *----------------------------------------------------------------*/
6683 0 : poGeom = GetGeometryRef();
6684 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6685 : {
6686 0 : OGRMultiPoint *poMPoint = (OGRMultiPoint*)poGeom;
6687 :
6688 0 : return poMPoint->getNumGeometries();
6689 : }
6690 : else
6691 : {
6692 : CPLError(CE_Failure, CPLE_AssertionFailed,
6693 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6694 0 : return 0;
6695 : }
6696 :
6697 : return 0;
6698 : }
6699 :
6700 :
6701 : /**********************************************************************
6702 : * TABMultiPoint::GetStyleString()
6703 : *
6704 : * Return style string for this feature.
6705 : *
6706 : * Style String is built only once during the first call to GetStyleString().
6707 : **********************************************************************/
6708 0 : const char *TABMultiPoint::GetStyleString()
6709 : {
6710 0 : if (m_pszStyleString == NULL)
6711 : {
6712 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
6713 : }
6714 :
6715 0 : return m_pszStyleString;
6716 : }
6717 :
6718 : /**********************************************************************
6719 : * TABMultiPoint::GetCenter()
6720 : *
6721 : * Returns the center point (or label point?) of the object. Compute one
6722 : * if it was not explicitly set:
6723 : *
6724 : * The default seems to be to use the first point in the collection as
6725 : * the center.. so we'll use that.
6726 : *
6727 : * Returns 0 on success, -1 on error.
6728 : **********************************************************************/
6729 0 : int TABMultiPoint::GetCenter(double &dX, double &dY)
6730 : {
6731 0 : if (!m_bCenterIsSet && GetNumPoints() > 0)
6732 : {
6733 : // The default seems to be to use the first point in the collection
6734 : // as the center... so we'll use that.
6735 0 : if (GetXY(0, m_dCenterX, m_dCenterY) == 0)
6736 0 : m_bCenterIsSet = TRUE;
6737 : }
6738 :
6739 0 : if (!m_bCenterIsSet)
6740 0 : return -1;
6741 :
6742 0 : dX = m_dCenterX;
6743 0 : dY = m_dCenterY;
6744 0 : return 0;
6745 : }
6746 :
6747 : /**********************************************************************
6748 : * TABMultiPoint::SetCenter()
6749 : *
6750 : * Set the X,Y coordinates to use as center point (or label point?)
6751 : **********************************************************************/
6752 0 : void TABMultiPoint::SetCenter(double dX, double dY)
6753 : {
6754 0 : m_dCenterX = dX;
6755 0 : m_dCenterY = dY;
6756 0 : m_bCenterIsSet = TRUE;
6757 0 : }
6758 :
6759 :
6760 : /**********************************************************************
6761 : * TABMultiPoint::DumpMIF()
6762 : *
6763 : * Dump feature geometry in a format similar to .MIF POINTs.
6764 : **********************************************************************/
6765 0 : void TABMultiPoint::DumpMIF(FILE *fpOut /*=NULL*/)
6766 : {
6767 : OGRGeometry *poGeom;
6768 : OGRMultiPoint *poMPoint;
6769 :
6770 0 : if (fpOut == NULL)
6771 0 : fpOut = stdout;
6772 :
6773 : /*-----------------------------------------------------------------
6774 : * Fetch and validate geometry
6775 : *----------------------------------------------------------------*/
6776 0 : poGeom = GetGeometryRef();
6777 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint)
6778 0 : poMPoint = (OGRMultiPoint*)poGeom;
6779 : else
6780 : {
6781 : CPLError(CE_Failure, CPLE_AssertionFailed,
6782 0 : "TABMultiPoint: Missing or Invalid Geometry!");
6783 0 : return;
6784 : }
6785 :
6786 : /*-----------------------------------------------------------------
6787 : * Generate output
6788 : *----------------------------------------------------------------*/
6789 0 : fprintf(fpOut, "MULTIPOINT %d\n", poMPoint->getNumGeometries());
6790 :
6791 0 : for (int iPoint=0; iPoint < poMPoint->getNumGeometries(); iPoint++)
6792 : {
6793 0 : poGeom = poMPoint->getGeometryRef(iPoint);
6794 :
6795 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbPoint)
6796 : {
6797 0 : OGRPoint *poPoint = (OGRPoint*)poGeom;
6798 0 : fprintf(fpOut, " %.15g %.15g\n", poPoint->getX(), poPoint->getY() );
6799 : }
6800 : else
6801 : {
6802 : CPLError(CE_Failure, CPLE_AssertionFailed,
6803 0 : "TABMultiPoint: Invalid Geometry, expecting OGRPoint!");
6804 0 : return;
6805 : }
6806 : }
6807 :
6808 0 : DumpSymbolDef(fpOut);
6809 :
6810 0 : if (m_bCenterIsSet)
6811 0 : fprintf(fpOut, "Center %.15g %.15g\n", m_dCenterX, m_dCenterY);
6812 :
6813 0 : fflush(fpOut);
6814 : }
6815 :
6816 : /*=====================================================================
6817 : * class TABCollection
6818 : *====================================================================*/
6819 :
6820 : /**********************************************************************
6821 : * TABCollection::TABCollection()
6822 : *
6823 : * Constructor.
6824 : **********************************************************************/
6825 0 : TABCollection::TABCollection(OGRFeatureDefn *poDefnIn):
6826 0 : TABFeature(poDefnIn)
6827 : {
6828 0 : m_poRegion = NULL;
6829 0 : m_poPline = NULL;
6830 0 : m_poMpoint = NULL;
6831 0 : }
6832 :
6833 : /**********************************************************************
6834 : * TABCollection::~TABCollection()
6835 : *
6836 : * Destructor.
6837 : **********************************************************************/
6838 0 : TABCollection::~TABCollection()
6839 : {
6840 0 : EmptyCollection();
6841 0 : }
6842 :
6843 : /**********************************************************************
6844 : * TABCollection::EmptyCollection()
6845 : *
6846 : * Delete/free all collection components.
6847 : **********************************************************************/
6848 0 : void TABCollection::EmptyCollection()
6849 : {
6850 :
6851 0 : if (m_poRegion)
6852 : {
6853 0 : delete m_poRegion;
6854 0 : m_poRegion = NULL;
6855 : }
6856 :
6857 0 : if (m_poPline)
6858 : {
6859 0 : delete m_poPline;
6860 0 : m_poPline = NULL;
6861 : }
6862 :
6863 0 : if (m_poMpoint)
6864 : {
6865 0 : delete m_poMpoint;
6866 0 : m_poMpoint = NULL;
6867 : }
6868 :
6869 : // Empty OGR Geometry Collection as well
6870 0 : SyncOGRGeometryCollection(TRUE, TRUE, TRUE);
6871 :
6872 0 : }
6873 :
6874 : /**********************************************************************
6875 : * TABCollection::CloneTABFeature()
6876 : *
6877 : * Duplicate feature, including stuff specific to each TABFeature type.
6878 : *
6879 : * This method calls the generic TABFeature::CloneTABFeature() and
6880 : * then copies any members specific to its own type.
6881 : **********************************************************************/
6882 0 : TABFeature *TABCollection::CloneTABFeature(OGRFeatureDefn *poNewDefn /*=NULL*/)
6883 : {
6884 : /*-----------------------------------------------------------------
6885 : * Alloc new feature and copy the base stuff
6886 : *----------------------------------------------------------------*/
6887 0 : TABCollection *poNew = new TABCollection(poNewDefn?poNewDefn:GetDefnRef());
6888 :
6889 0 : CopyTABFeatureBase(poNew);
6890 :
6891 : /*-----------------------------------------------------------------
6892 : * And members specific to this class
6893 : *----------------------------------------------------------------*/
6894 :
6895 0 : if (m_poRegion)
6896 0 : poNew->SetRegionDirectly((TABRegion*)m_poRegion->CloneTABFeature());
6897 :
6898 0 : if (m_poPline)
6899 0 : poNew->SetPolylineDirectly((TABPolyline*)m_poPline->CloneTABFeature());
6900 :
6901 0 : if (m_poMpoint)
6902 0 : poNew->SetMultiPointDirectly((TABMultiPoint*)m_poMpoint->CloneTABFeature());
6903 :
6904 0 : return poNew;
6905 : }
6906 :
6907 :
6908 : /**********************************************************************
6909 : * TABCollection::ValidateMapInfoType()
6910 : *
6911 : * Check the feature's geometry part and return the corresponding
6912 : * mapinfo object type code. The m_nMapInfoType member will also
6913 : * be updated for further calls to GetMapInfoType();
6914 : *
6915 : * Returns TAB_GEOM_NONE if the geometry is not compatible with what
6916 : * is expected for this object class.
6917 : **********************************************************************/
6918 0 : int TABCollection::ValidateMapInfoType(TABMAPFile *poMapFile /*=NULL*/)
6919 : {
6920 : OGRGeometry *poGeom;
6921 0 : int nRegionType=TAB_GEOM_NONE, nPLineType=TAB_GEOM_NONE,
6922 0 : nMPointType=TAB_GEOM_NONE, nVersion = 650;
6923 :
6924 : /*-----------------------------------------------------------------
6925 : * Fetch and validate geometry
6926 : *----------------------------------------------------------------*/
6927 0 : poGeom = GetGeometryRef();
6928 0 : if (poGeom && wkbFlatten(poGeom->getGeometryType()) == wkbGeometryCollection)
6929 : {
6930 0 : m_nMapInfoType = TAB_GEOM_COLLECTION;
6931 : }
6932 : else
6933 : {
6934 : CPLError(CE_Failure, CPLE_AssertionFailed,
6935 0 : "TABCollection: Missing or Invalid Geometry!");
6936 0 : m_nMapInfoType = TAB_GEOM_NONE;
6937 : }
6938 :
6939 : /*-----------------------------------------------------------------
6940 : * Decide if coordinates should be compressed or not.
6941 : *----------------------------------------------------------------*/
6942 0 : GBool bComprCoord = ValidateCoordType(poMapFile);
6943 :
6944 : /*-----------------------------------------------------------------
6945 : * Since all members of the collection share the same compressed coord
6946 : * origin, we should force the compressed origin in all components
6947 : * to be the same.
6948 : * This also implies that ValidateMapInfoType() should *NOT* be called
6949 : * again until the collection components are written by WriteGeom...()
6950 : *----------------------------------------------------------------*/
6951 :
6952 : // First pass to figure collection type...
6953 0 : if (m_poRegion)
6954 : {
6955 0 : m_poRegion->ValidateCoordType(poMapFile);
6956 0 : nRegionType = m_poRegion->ValidateMapInfoType(poMapFile);
6957 0 : if (TAB_GEOM_GET_VERSION(nRegionType) > nVersion)
6958 0 : nVersion = TAB_GEOM_GET_VERSION(nRegionType);
6959 : }
6960 :
6961 0 : if (m_poPline)
6962 : {
6963 0 : m_poPline->ValidateCoordType(poMapFile);
6964 0 : nPLineType = m_poPline->ValidateMapInfoType(poMapFile);
6965 0 : if (TAB_GEOM_GET_VERSION(nPLineType) > nVersion)
6966 0 : nVersion = TAB_GEOM_GET_VERSION(nPLineType);
6967 : }
6968 :
6969 0 : if (m_poMpoint)
6970 : {
6971 0 : m_poMpoint->ValidateCoordType(poMapFile);
6972 0 : nMPointType = m_poMpoint->ValidateMapInfoType(poMapFile);
6973 0 : if (TAB_GEOM_GET_VERSION(nMPointType) > nVersion)
6974 0 : nVersion = TAB_GEOM_GET_VERSION(nMPointType);
6975 : }
6976 :
6977 : // Need to upgrade native type of collection?
6978 0 : if (nVersion == 800)
6979 : {
6980 0 : m_nMapInfoType = TAB_GEOM_V800_COLLECTION;
6981 : }
6982 :
6983 : // Make another pass updating native type and coordinates type and origin
6984 : // of each component
6985 0 : if (m_poRegion && nRegionType != TAB_GEOM_NONE)
6986 : {
6987 0 : GInt32 nXMin=0, nYMin=0, nXMax=0, nYMax=0;
6988 0 : m_poRegion->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
6989 : m_poRegion->ForceCoordTypeAndOrigin((nVersion == 800 ?
6990 : TAB_GEOM_V800_REGION:
6991 : TAB_GEOM_V450_REGION),
6992 : bComprCoord,
6993 : m_nComprOrgX, m_nComprOrgY,
6994 0 : nXMin, nYMin, nXMax, nYMax);
6995 : }
6996 :
6997 :
6998 0 : if (m_poPline && nPLineType != TAB_GEOM_NONE)
6999 : {
7000 : GInt32 nXMin, nYMin, nXMax, nYMax;
7001 0 : m_poPline->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
7002 : m_poPline->ForceCoordTypeAndOrigin((nVersion == 800 ?
7003 : TAB_GEOM_V800_MULTIPLINE:
7004 : TAB_GEOM_V450_MULTIPLINE),
7005 : bComprCoord,
7006 : m_nComprOrgX, m_nComprOrgY,
7007 0 : nXMin, nYMin, nXMax, nYMax);
7008 : }
7009 :
7010 0 : if (m_poMpoint && nMPointType != TAB_GEOM_NONE)
7011 : {
7012 : GInt32 nXMin, nYMin, nXMax, nYMax;
7013 0 : m_poMpoint->GetIntMBR(nXMin, nYMin, nXMax, nYMax);
7014 : m_poMpoint->ForceCoordTypeAndOrigin((nVersion == 800 ?
7015 : TAB_GEOM_V800_MULTIPOINT:
7016 : TAB_GEOM_MULTIPOINT),
7017 : bComprCoord,
7018 : m_nComprOrgX, m_nComprOrgY,
7019 0 : nXMin, nYMin, nXMax, nYMax);
7020 : }
7021 :
7022 :
7023 0 : return m_nMapInfoType;
7024 : }
7025 :
7026 :
7027 : /**********************************************************************
7028 : * TABCollection::ReadLabelAndMBR()
7029 : *
7030 : * Reads the label and MBR elements of the header of a collection component
7031 : *
7032 : * Returns 0 on success, -1 on failure.
7033 : **********************************************************************/
7034 : int TABCollection::ReadLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
7035 : GBool bComprCoord,
7036 : GInt32 nComprOrgX, GInt32 nComprOrgY,
7037 : GInt32 &pnMinX, GInt32 &pnMinY,
7038 : GInt32 &pnMaxX, GInt32 &pnMaxY,
7039 0 : GInt32 &pnLabelX, GInt32 &pnLabelY )
7040 : {
7041 : //
7042 : // The sections in the collection's coord blocks start with center/label
7043 : // point + MBR that are normally found in the object data blocks
7044 : // of regular region/pline/mulitpoint objects.
7045 : //
7046 :
7047 0 : if (bComprCoord)
7048 : {
7049 : // Region center/label point, relative to compr. coord. origin
7050 : // No it's not relative to the Object block center
7051 0 : pnLabelX = poCoordBlock->ReadInt16();
7052 0 : pnLabelY = poCoordBlock->ReadInt16();
7053 :
7054 0 : pnLabelX += nComprOrgX;
7055 0 : pnLabelY += nComprOrgY;
7056 :
7057 0 : pnMinX = nComprOrgX + poCoordBlock->ReadInt16(); // Read MBR
7058 0 : pnMinY = nComprOrgY + poCoordBlock->ReadInt16();
7059 0 : pnMaxX = nComprOrgX + poCoordBlock->ReadInt16();
7060 0 : pnMaxY = nComprOrgY + poCoordBlock->ReadInt16();
7061 : }
7062 : else
7063 : {
7064 : // Region center/label point, relative to compr. coord. origin
7065 : // No it's not relative to the Object block center
7066 0 : pnLabelX = poCoordBlock->ReadInt32();
7067 0 : pnLabelY = poCoordBlock->ReadInt32();
7068 :
7069 0 : pnMinX = poCoordBlock->ReadInt32(); // Read MBR
7070 0 : pnMinY = poCoordBlock->ReadInt32();
7071 0 : pnMaxX = poCoordBlock->ReadInt32();
7072 0 : pnMaxY = poCoordBlock->ReadInt32();
7073 : }
7074 :
7075 0 : return 0;
7076 : }
7077 :
7078 : /**********************************************************************
7079 : * TABCollection::WriteLabelAndMBR()
7080 : *
7081 : * Writes the label and MBR elements of the header of a collection component
7082 : *
7083 : * Returns 0 on success, -1 on failure.
7084 : **********************************************************************/
7085 : int TABCollection::WriteLabelAndMBR(TABMAPCoordBlock *poCoordBlock,
7086 : GBool bComprCoord,
7087 : GInt32 nMinX, GInt32 nMinY,
7088 : GInt32 nMaxX, GInt32 nMaxY,
7089 0 : GInt32 nLabelX, GInt32 nLabelY )
7090 : {
7091 : int nStatus;
7092 :
7093 : //
7094 : // The sections in the collection's coord blocks start with center/label
7095 : // point + MBR that are normally found in the object data blocks
7096 : // of regular region/pline/mulitpoint objects.
7097 : //
7098 :
7099 0 : if ((nStatus = poCoordBlock->WriteIntCoord(nLabelX, nLabelY,
7100 : bComprCoord)) != 0 ||
7101 : (nStatus = poCoordBlock->WriteIntCoord(nMinX, nMinY,
7102 : bComprCoord)) != 0 ||
7103 : (nStatus = poCoordBlock->WriteIntCoord(nMaxX, nMaxY,
7104 : bComprCoord)) != 0 )
7105 : {
7106 : // Failed ... error message has already been produced
7107 0 : return nStatus;
7108 : }
7109 :
7110 0 : return 0;
7111 : }
7112 :
7113 :
7114 : /**********************************************************************
7115 : * TABCollection::ReadGeometryFromMAPFile()
7116 : *
7117 : * Fill the geometry and representation (color, etc...) part of the
7118 : * feature from the contents of the .MAP object pointed to by poMAPFile.
7119 : *
7120 : * It is assumed that poMAPFile currently points to the beginning of
7121 : * a map object.
7122 : *
7123 : * Returns 0 on success, -1 on error, in which case CPLError() will have
7124 : * been called.
7125 : **********************************************************************/
7126 : int TABCollection::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
7127 : TABMAPObjHdr *poObjHdr,
7128 : GBool bCoordBlockDataOnly /*=FALSE*/,
7129 0 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
7130 : {
7131 : double dXMin, dYMin, dXMax, dYMax;
7132 0 : GBool bComprCoord = poObjHdr->IsCompressedType();
7133 0 : TABMAPCoordBlock* poCoordBlock = NULL;
7134 : int nCurCoordBlockPtr;
7135 :
7136 : /*-----------------------------------------------------------------
7137 : * Fetch and validate geometry type
7138 : *----------------------------------------------------------------*/
7139 0 : m_nMapInfoType = poObjHdr->m_nType;
7140 :
7141 0 : if (m_nMapInfoType != TAB_GEOM_COLLECTION &&
7142 : m_nMapInfoType != TAB_GEOM_COLLECTION_C &&
7143 : m_nMapInfoType != TAB_GEOM_V800_COLLECTION &&
7144 : m_nMapInfoType != TAB_GEOM_V800_COLLECTION_C )
7145 : {
7146 : CPLError(CE_Failure, CPLE_AssertionFailed,
7147 : "ReadGeometryFromMAPFile(): unsupported geometry type %d (0x%2.2x)",
7148 0 : m_nMapInfoType, m_nMapInfoType);
7149 0 : return -1;
7150 : }
7151 :
7152 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
7153 :
7154 : // Make sure collection is empty
7155 0 : EmptyCollection();
7156 :
7157 : /*-------------------------------------------------------------
7158 : * Copy data from poObjHdr
7159 : *------------------------------------------------------------*/
7160 0 : TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
7161 :
7162 : // MBR
7163 : poMapFile->Int2Coordsys(poCollHdr->m_nMinX, poCollHdr->m_nMinY,
7164 0 : dXMin, dYMin);
7165 : poMapFile->Int2Coordsys(poCollHdr->m_nMaxX, poCollHdr->m_nMaxY,
7166 0 : dXMax, dYMax);
7167 :
7168 0 : SetMBR(dXMin, dYMin, dXMax, dYMax);
7169 :
7170 : SetIntMBR(poObjHdr->m_nMinX, poObjHdr->m_nMinY,
7171 0 : poObjHdr->m_nMaxX, poObjHdr->m_nMaxY);
7172 :
7173 0 : nCurCoordBlockPtr = poCollHdr->m_nCoordBlockPtr;
7174 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
7175 0 : poCoordBlock = *ppoCoordBlock;
7176 : else
7177 0 : poCoordBlock = poMapFile->GetCoordBlock(nCurCoordBlockPtr);
7178 :
7179 : // Compressed coordinate origin (useful only in compressed case!)
7180 0 : m_nComprOrgX = poCollHdr->m_nComprOrgX;
7181 0 : m_nComprOrgY = poCollHdr->m_nComprOrgY;
7182 :
7183 : /*-----------------------------------------------------------------
7184 : * Region Component
7185 : *----------------------------------------------------------------*/
7186 0 : if(poCollHdr->m_nNumRegSections > 0)
7187 : {
7188 : //
7189 : // Build fake coord section header to pass to TABRegion::ReadGeom...()
7190 : //
7191 0 : TABMAPObjPLine oRegionHdr;
7192 :
7193 0 : oRegionHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
7194 0 : oRegionHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
7195 :
7196 : //
7197 : // The region section in the coord block starts with center/label
7198 : // point + MBR that are normally found in the object data blocks
7199 : // of regular region objects.
7200 : //
7201 :
7202 : // In V800 the mini-header starts with a copy of num_parts
7203 0 : if (nVersion >= 800)
7204 : {
7205 : int numParts;
7206 0 : numParts = poCoordBlock->ReadInt32();
7207 0 : CPLAssert(numParts == poCollHdr->m_nNumRegSections);
7208 : }
7209 :
7210 : ReadLabelAndMBR(poCoordBlock, bComprCoord,
7211 : oRegionHdr.m_nComprOrgX, oRegionHdr.m_nComprOrgY,
7212 : oRegionHdr.m_nMinX, oRegionHdr.m_nMinY,
7213 : oRegionHdr.m_nMaxX, oRegionHdr.m_nMaxY,
7214 0 : oRegionHdr.m_nLabelX, oRegionHdr.m_nLabelY);
7215 :
7216 : // Set CoordBlockPtr so that TABRegion continues reading here
7217 0 : oRegionHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7218 :
7219 0 : if (bComprCoord)
7220 0 : oRegionHdr.m_nType = TAB_GEOM_V450_REGION_C;
7221 : else
7222 0 : oRegionHdr.m_nType = TAB_GEOM_V450_REGION;
7223 0 : if (nVersion == 800)
7224 0 : oRegionHdr.m_nType += (TAB_GEOM_V800_REGION - TAB_GEOM_V450_REGION);
7225 :
7226 0 : oRegionHdr.m_numLineSections = poCollHdr->m_nNumRegSections;
7227 0 : oRegionHdr.m_nPenId = poCollHdr->m_nRegionPenId;
7228 0 : oRegionHdr.m_nBrushId = poCollHdr->m_nRegionBrushId;
7229 0 : oRegionHdr.m_bSmooth = 0; // TODO
7230 :
7231 : //
7232 : // Use a TABRegion to read/store the Region coord data
7233 : //
7234 0 : m_poRegion = new TABRegion(GetDefnRef());
7235 0 : if (m_poRegion->ReadGeometryFromMAPFile(poMapFile, &oRegionHdr,
7236 : bCoordBlockDataOnly,
7237 : &poCoordBlock) != 0)
7238 0 : return -1;
7239 :
7240 : // Set new coord block ptr for next object
7241 0 : if (poCoordBlock)
7242 0 : nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
7243 : }
7244 :
7245 :
7246 : /*-----------------------------------------------------------------
7247 : * PLine Component
7248 : *----------------------------------------------------------------*/
7249 0 : if(poCollHdr->m_nNumPLineSections > 0)
7250 : {
7251 : //
7252 : // Build fake coord section header to pass to TABPolyline::ReadGeom..()
7253 : //
7254 0 : TABMAPObjPLine oPLineHdr;
7255 :
7256 0 : oPLineHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
7257 0 : oPLineHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
7258 :
7259 : //
7260 : // The pline section in the coord block starts with center/label
7261 : // point + MBR that are normally found in the object data blocks
7262 : // of regular pline objects.
7263 : //
7264 :
7265 : // In V800 the mini-header starts with a copy of num_parts
7266 0 : if (nVersion >= 800)
7267 : {
7268 : int numParts;
7269 0 : numParts = poCoordBlock->ReadInt32();
7270 0 : CPLAssert(numParts == poCollHdr->m_nNumPLineSections);
7271 : }
7272 :
7273 : ReadLabelAndMBR(poCoordBlock, bComprCoord,
7274 : oPLineHdr.m_nComprOrgX, oPLineHdr.m_nComprOrgY,
7275 : oPLineHdr.m_nMinX, oPLineHdr.m_nMinY,
7276 : oPLineHdr.m_nMaxX, oPLineHdr.m_nMaxY,
7277 0 : oPLineHdr.m_nLabelX, oPLineHdr.m_nLabelY);
7278 :
7279 : // Set CoordBlockPtr so that TABRegion continues reading here
7280 0 : oPLineHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7281 :
7282 0 : if (bComprCoord)
7283 0 : oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE_C;
7284 : else
7285 0 : oPLineHdr.m_nType = TAB_GEOM_V450_MULTIPLINE;
7286 0 : if (nVersion == 800)
7287 : oPLineHdr.m_nType += (TAB_GEOM_V800_MULTIPLINE -
7288 0 : TAB_GEOM_V450_MULTIPLINE);
7289 :
7290 0 : oPLineHdr.m_numLineSections = poCollHdr->m_nNumPLineSections;
7291 0 : oPLineHdr.m_nPenId = poCollHdr->m_nPolylinePenId;
7292 0 : oPLineHdr.m_bSmooth = 0; // TODO
7293 :
7294 : //
7295 : // Use a TABPolyline to read/store the Polyline coord data
7296 : //
7297 0 : m_poPline = new TABPolyline(GetDefnRef());
7298 0 : if (m_poPline->ReadGeometryFromMAPFile(poMapFile, &oPLineHdr,
7299 : bCoordBlockDataOnly,
7300 : &poCoordBlock) != 0)
7301 0 : return -1;
7302 :
7303 : // Set new coord block ptr for next object
7304 0 : if (poCoordBlock)
7305 0 : nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
7306 : }
7307 :
7308 : /*-----------------------------------------------------------------
7309 : * MultiPoint Component
7310 : *----------------------------------------------------------------*/
7311 0 : if(poCollHdr->m_nNumMultiPoints > 0)
7312 : {
7313 : //
7314 : // Build fake coord section header to pass to TABMultiPoint::ReadGeom()
7315 : //
7316 0 : TABMAPObjMultiPoint oMPointHdr;
7317 :
7318 0 : oMPointHdr.m_nComprOrgX = poCollHdr->m_nComprOrgX;
7319 0 : oMPointHdr.m_nComprOrgY = poCollHdr->m_nComprOrgY;
7320 :
7321 : //
7322 : // The pline section in the coord block starts with center/label
7323 : // point + MBR that are normally found in the object data blocks
7324 : // of regular pline objects.
7325 : //
7326 : ReadLabelAndMBR(poCoordBlock, bComprCoord,
7327 : oMPointHdr.m_nComprOrgX, oMPointHdr.m_nComprOrgY,
7328 : oMPointHdr.m_nMinX, oMPointHdr.m_nMinY,
7329 : oMPointHdr.m_nMaxX, oMPointHdr.m_nMaxY,
7330 0 : oMPointHdr.m_nLabelX, oMPointHdr.m_nLabelY);
7331 :
7332 : // Set CoordBlockPtr so that TABRegion continues reading here
7333 0 : oMPointHdr.m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7334 :
7335 0 : if (bComprCoord)
7336 0 : oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT_C;
7337 : else
7338 0 : oMPointHdr.m_nType = TAB_GEOM_MULTIPOINT;
7339 0 : if (nVersion == 800)
7340 : oMPointHdr.m_nType += (TAB_GEOM_V800_MULTIPOINT -
7341 0 : TAB_GEOM_MULTIPOINT);
7342 :
7343 0 : oMPointHdr.m_nNumPoints = poCollHdr->m_nNumMultiPoints;
7344 0 : oMPointHdr.m_nSymbolId = poCollHdr->m_nMultiPointSymbolId;
7345 :
7346 : //
7347 : // Use a TABMultiPoint to read/store the coord data
7348 : //
7349 0 : m_poMpoint = new TABMultiPoint(GetDefnRef());
7350 0 : if (m_poMpoint->ReadGeometryFromMAPFile(poMapFile, &oMPointHdr,
7351 : bCoordBlockDataOnly,
7352 : &poCoordBlock) != 0)
7353 0 : return -1;
7354 :
7355 : // Set new coord block ptr for next object (not really useful here)
7356 0 : if (poCoordBlock)
7357 0 : nCurCoordBlockPtr = poCoordBlock->GetCurAddress();
7358 : }
7359 :
7360 : /*-----------------------------------------------------------------
7361 : * Set the main OGRFeature Geometry
7362 : * (this is actually duplicating geometries from each member)
7363 : *----------------------------------------------------------------*/
7364 0 : if (SyncOGRGeometryCollection(TRUE, TRUE, TRUE) != 0)
7365 0 : return -1;
7366 :
7367 : /* Return a ref to coord block so that caller can continue reading
7368 : * after the end of this object (used by index splitting)
7369 : */
7370 0 : if (ppoCoordBlock)
7371 0 : *ppoCoordBlock = poCoordBlock;
7372 :
7373 0 : return 0;
7374 : }
7375 :
7376 : /**********************************************************************
7377 : * TABCollection::WriteGeometryToMAPFile()
7378 : *
7379 : * Write the geometry and representation (color, etc...) part of the
7380 : * feature to the .MAP object pointed to by poMAPFile.
7381 : *
7382 : * It is assumed that poMAPFile currently points to a valid map object.
7383 : *
7384 : * Returns 0 on success, -1 on error, in which case CPLError() will have
7385 : * been called.
7386 : **********************************************************************/
7387 : int TABCollection::WriteGeometryToMAPFile(TABMAPFile *poMapFile,
7388 : TABMAPObjHdr *poObjHdr,
7389 : GBool bCoordBlockDataOnly /*=FALSE*/,
7390 0 : TABMAPCoordBlock **ppoCoordBlock/*=NULL*/)
7391 : {
7392 : /*-----------------------------------------------------------------
7393 : * Note that the current implementation does not allow setting the
7394 : * Geometry via OGRFeature::SetGeometry(). The geometries must be set
7395 : * via the SetRegion/Pline/MpointDirectly() methods which will take
7396 : * care of keeping the OGRFeature's geometry in sync.
7397 : *
7398 : * TODO: If we ever want to support sync'ing changes from the OGRFeature's
7399 : * geometry to the m_poRegion/Pline/Mpoint then a call should be added
7400 : * here, or perhaps in ValidateMapInfoType(), or even better in
7401 : * custom TABCollection::SetGeometry*()... but then this last option
7402 : * won't work unless OGRFeature::SetGeometry*() are made virtual in OGR.
7403 : *----------------------------------------------------------------*/
7404 :
7405 :
7406 : /*-----------------------------------------------------------------
7407 : * We assume that ValidateMapInfoType() was called already and that
7408 : * the type in poObjHdr->m_nType is valid.
7409 : *----------------------------------------------------------------*/
7410 0 : CPLAssert(m_nMapInfoType == poObjHdr->m_nType);
7411 :
7412 0 : TABMAPObjCollection *poCollHdr = (TABMAPObjCollection *)poObjHdr;
7413 :
7414 : /*-----------------------------------------------------------------
7415 : * Write data to coordinate block for each component...
7416 : *
7417 : * Note that at this point, the caller (TABFile) has called
7418 : * TABCollection::ValidateMapInfoType() which in turn has called
7419 : * each component's respective ValidateMapInfoType() and
7420 : * ForceCoordTypeAndCoordOrigin() so the objects are ready to have
7421 : * their respective WriteGeometryToMapFile() called.
7422 : *----------------------------------------------------------------*/
7423 : TABMAPCoordBlock *poCoordBlock;
7424 0 : GBool bCompressed = poObjHdr->IsCompressedType();
7425 : // TODO: ??? Do we need to track overall collection coord data size???
7426 0 : int nTotalFeatureDataSize = 0;
7427 :
7428 0 : int nVersion = TAB_GEOM_GET_VERSION(m_nMapInfoType);
7429 :
7430 0 : if (ppoCoordBlock != NULL && *ppoCoordBlock != NULL)
7431 0 : poCoordBlock = *ppoCoordBlock;
7432 : else
7433 0 : poCoordBlock = poMapFile->GetCurCoordBlock();
7434 0 : poCoordBlock->StartNewFeature();
7435 0 : poCollHdr->m_nCoordBlockPtr = poCoordBlock->GetCurAddress();
7436 0 : poCoordBlock->SetComprCoordOrigin(m_nComprOrgX, m_nComprOrgY);
7437 :
7438 : /*-----------------------------------------------------------------
7439 : * Region component
7440 : *----------------------------------------------------------------*/
7441 0 : if (m_poRegion && m_poRegion->GetMapInfoType() != TAB_GEOM_NONE)
7442 : {
7443 0 : CPLAssert(m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION ||
7444 : m_poRegion->GetMapInfoType() == TAB_GEOM_V450_REGION_C ||
7445 : m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION ||
7446 : m_poRegion->GetMapInfoType() == TAB_GEOM_V800_REGION_C );
7447 :
7448 : TABMAPObjPLine *poRegionHdr = (TABMAPObjPLine *)
7449 0 : TABMAPObjHdr::NewObj(m_poRegion->GetMapInfoType(), -1);
7450 :
7451 : // Update count of objects by type in header
7452 0 : if (!bCoordBlockDataOnly)
7453 0 : poMapFile->UpdateMapHeaderInfo(m_poRegion->GetMapInfoType());
7454 :
7455 : // Write a placeholder for centroid/label point and MBR mini-header
7456 : // and we'll come back later to write the real values.
7457 : //
7458 : // Note that the call to WriteGeometryToMAPFile() below will call
7459 : // StartNewFeature() as well, so we need to track the current
7460 : // value before calling it
7461 :
7462 0 : poCoordBlock->StartNewFeature();
7463 0 : int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
7464 :
7465 : // In V800 the mini-header starts with a copy of num_parts
7466 0 : if (nVersion >= 800)
7467 : {
7468 0 : poCoordBlock->WriteInt32(0);
7469 : }
7470 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7471 0 : 0, 0, 0, 0, 0, 0);
7472 0 : nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
7473 :
7474 0 : if (m_poRegion->WriteGeometryToMAPFile(poMapFile, poRegionHdr,
7475 : bCoordBlockDataOnly,
7476 : &poCoordBlock) != 0)
7477 : {
7478 : CPLError(CE_Failure, CPLE_FileIO,
7479 0 : "Failed writing Region part in collection.");
7480 0 : delete poRegionHdr;
7481 0 : return -1;
7482 : }
7483 :
7484 0 : nTotalFeatureDataSize += poRegionHdr->m_nCoordDataSize;
7485 :
7486 : // Come back to write the real values in the mini-header
7487 0 : int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
7488 0 : poCoordBlock->StartNewFeature();
7489 :
7490 0 : if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
7491 : {
7492 0 : delete poRegionHdr;
7493 0 : return -1;
7494 : }
7495 :
7496 : // In V800 the mini-header starts with a copy of num_parts
7497 0 : if (nVersion >= 800)
7498 : {
7499 0 : poCoordBlock->WriteInt32(poRegionHdr->m_numLineSections);
7500 : }
7501 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7502 : poRegionHdr->m_nMinX, poRegionHdr->m_nMinY,
7503 : poRegionHdr->m_nMaxX, poRegionHdr->m_nMaxY,
7504 0 : poRegionHdr->m_nLabelX, poRegionHdr->m_nLabelY);
7505 :
7506 : // And finally move the pointer back to the end of this component
7507 0 : if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
7508 : {
7509 0 : delete poRegionHdr;
7510 0 : return -1;
7511 : }
7512 :
7513 : // Copy other header members to the main collection header
7514 : // TODO: Does m_nRegionDataSize need to include the centroid+mbr
7515 : // mini-header???
7516 0 : poCollHdr->m_nRegionDataSize = poRegionHdr->m_nCoordDataSize;
7517 0 : poCollHdr->m_nNumRegSections = poRegionHdr->m_numLineSections;
7518 :
7519 0 : if (!bCoordBlockDataOnly)
7520 : {
7521 0 : poCollHdr->m_nRegionPenId = poRegionHdr->m_nPenId;
7522 0 : poCollHdr->m_nRegionBrushId = poRegionHdr->m_nBrushId;
7523 : // TODO: Smooth flag = poRegionHdr->m_bSmooth;
7524 : }
7525 :
7526 0 : delete poRegionHdr;
7527 : }
7528 : else
7529 : {
7530 : // No Region component. Set corresponding header fields to 0
7531 :
7532 0 : poCollHdr->m_nRegionDataSize = 0;
7533 0 : poCollHdr->m_nNumRegSections = 0;
7534 0 : poCollHdr->m_nRegionPenId = 0;
7535 0 : poCollHdr->m_nRegionBrushId = 0;
7536 : }
7537 :
7538 : /*-----------------------------------------------------------------
7539 : * PLine component
7540 : *----------------------------------------------------------------*/
7541 0 : if (m_poPline && m_poPline->GetMapInfoType() != TAB_GEOM_NONE)
7542 : {
7543 0 : CPLAssert(m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE ||
7544 : m_poPline->GetMapInfoType() == TAB_GEOM_V450_MULTIPLINE_C ||
7545 : m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE ||
7546 : m_poPline->GetMapInfoType() == TAB_GEOM_V800_MULTIPLINE_C );
7547 :
7548 : TABMAPObjPLine *poPlineHdr = (TABMAPObjPLine *)
7549 0 : TABMAPObjHdr::NewObj(m_poPline->GetMapInfoType(), -1);
7550 :
7551 : // Update count of objects by type in header
7552 0 : if (!bCoordBlockDataOnly)
7553 0 : poMapFile->UpdateMapHeaderInfo(m_poPline->GetMapInfoType());
7554 :
7555 : // Write a placeholder for centroid/label point and MBR mini-header
7556 : // and we'll come back later to write the real values.
7557 : //
7558 : // Note that the call to WriteGeometryToMAPFile() below will call
7559 : // StartNewFeature() as well, so we need to track the current
7560 : // value before calling it
7561 :
7562 0 : poCoordBlock->StartNewFeature();
7563 0 : int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
7564 :
7565 : // In V800 the mini-header starts with a copy of num_parts
7566 0 : if (nVersion >= 800)
7567 : {
7568 0 : poCoordBlock->WriteInt32(0);
7569 : }
7570 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7571 0 : 0, 0, 0, 0, 0, 0);
7572 0 : nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
7573 :
7574 0 : if (m_poPline->WriteGeometryToMAPFile(poMapFile, poPlineHdr,
7575 : bCoordBlockDataOnly,
7576 : &poCoordBlock) != 0)
7577 : {
7578 : CPLError(CE_Failure, CPLE_FileIO,
7579 0 : "Failed writing Region part in collection.");
7580 0 : delete poPlineHdr;
7581 0 : return -1;
7582 : }
7583 :
7584 0 : nTotalFeatureDataSize += poPlineHdr->m_nCoordDataSize;
7585 :
7586 : // Come back to write the real values in the mini-header
7587 0 : int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
7588 0 : poCoordBlock->StartNewFeature();
7589 :
7590 0 : if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
7591 : {
7592 0 : delete poPlineHdr;
7593 0 : return -1;
7594 : }
7595 :
7596 : // In V800 the mini-header starts with a copy of num_parts
7597 0 : if (nVersion >= 800)
7598 : {
7599 0 : poCoordBlock->WriteInt32(poPlineHdr->m_numLineSections);
7600 : }
7601 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7602 : poPlineHdr->m_nMinX, poPlineHdr->m_nMinY,
7603 : poPlineHdr->m_nMaxX, poPlineHdr->m_nMaxY,
7604 0 : poPlineHdr->m_nLabelX, poPlineHdr->m_nLabelY);
7605 :
7606 : // And finally move the pointer back to the end of this component
7607 0 : if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
7608 : {
7609 0 : delete poPlineHdr;
7610 0 : return -1;
7611 : }
7612 :
7613 : // Copy other header members to the main collection header
7614 : // TODO: Does m_nRegionDataSize need to include the centroid+mbr
7615 : // mini-header???
7616 0 : poCollHdr->m_nPolylineDataSize = poPlineHdr->m_nCoordDataSize;
7617 0 : poCollHdr->m_nNumPLineSections = poPlineHdr->m_numLineSections;
7618 0 : if (!bCoordBlockDataOnly)
7619 : {
7620 0 : poCollHdr->m_nPolylinePenId = poPlineHdr->m_nPenId;
7621 : // TODO: Smooth flag = poPlineHdr->m_bSmooth;
7622 : }
7623 :
7624 0 : delete poPlineHdr;
7625 : }
7626 : else
7627 : {
7628 : // No Polyline component. Set corresponding header fields to 0
7629 :
7630 0 : poCollHdr->m_nPolylineDataSize = 0;
7631 0 : poCollHdr->m_nNumPLineSections = 0;
7632 0 : poCollHdr->m_nPolylinePenId = 0;
7633 : }
7634 :
7635 :
7636 : /*-----------------------------------------------------------------
7637 : * MultiPoint component
7638 : *----------------------------------------------------------------*/
7639 0 : if (m_poMpoint && m_poMpoint->GetMapInfoType() != TAB_GEOM_NONE)
7640 : {
7641 0 : CPLAssert(m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT ||
7642 : m_poMpoint->GetMapInfoType() == TAB_GEOM_MULTIPOINT_C ||
7643 : m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT ||
7644 : m_poMpoint->GetMapInfoType() == TAB_GEOM_V800_MULTIPOINT_C );
7645 :
7646 : TABMAPObjMultiPoint *poMpointHdr = (TABMAPObjMultiPoint *)
7647 0 : TABMAPObjHdr::NewObj(m_poMpoint->GetMapInfoType(), -1);
7648 :
7649 : // Update count of objects by type in header
7650 0 : if (!bCoordBlockDataOnly)
7651 0 : poMapFile->UpdateMapHeaderInfo(m_poMpoint->GetMapInfoType());
7652 :
7653 : // Write a placeholder for centroid/label point and MBR mini-header
7654 : // and we'll come back later to write the real values.
7655 : //
7656 : // Note that the call to WriteGeometryToMAPFile() below will call
7657 : // StartNewFeature() as well, so we need to track the current
7658 : // value before calling it
7659 :
7660 0 : poCoordBlock->StartNewFeature();
7661 0 : int nMiniHeaderPtr = poCoordBlock->GetCurAddress();
7662 :
7663 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7664 0 : 0, 0, 0, 0, 0, 0);
7665 0 : nTotalFeatureDataSize += poCoordBlock->GetFeatureDataSize();
7666 :
7667 0 : if (m_poMpoint->WriteGeometryToMAPFile(poMapFile, poMpointHdr,
7668 : bCoordBlockDataOnly,
7669 : &poCoordBlock) != 0)
7670 : {
7671 : CPLError(CE_Failure, CPLE_FileIO,
7672 0 : "Failed writing Region part in collection.");
7673 0 : delete poMpointHdr;
7674 0 : return -1;
7675 : }
7676 :
7677 0 : nTotalFeatureDataSize += poMpointHdr->m_nCoordDataSize;
7678 :
7679 : // Come back to write the real values in the mini-header
7680 0 : int nEndOfObjectPtr = poCoordBlock->GetCurAddress();
7681 0 : poCoordBlock->StartNewFeature();
7682 :
7683 0 : if (poCoordBlock->GotoByteInFile(nMiniHeaderPtr, TRUE, TRUE) != 0)
7684 : {
7685 0 : delete poMpointHdr;
7686 0 : return -1;
7687 : }
7688 :
7689 : WriteLabelAndMBR(poCoordBlock, bCompressed,
7690 : poMpointHdr->m_nMinX, poMpointHdr->m_nMinY,
7691 : poMpointHdr->m_nMaxX, poMpointHdr->m_nMaxY,
7692 0 : poMpointHdr->m_nLabelX, poMpointHdr->m_nLabelY);
7693 :
7694 : // And finally move the pointer back to the end of this component
7695 0 : if (poCoordBlock->GotoByteInFile(nEndOfObjectPtr, TRUE, TRUE) != 0)
7696 : {
7697 0 : delete poMpointHdr;
7698 0 : return -1;
7699 : }
7700 :
7701 : // Copy other header members to the main collection header
7702 : // TODO: Does m_nRegionDataSize need to include the centroid+mbr
7703 : // mini-header???
7704 0 : poCollHdr->m_nMPointDataSize = poMpointHdr->m_nCoordDataSize;
7705 0 : poCollHdr->m_nNumMultiPoints = poMpointHdr->m_nNumPoints;
7706 0 : if (!bCoordBlockDataOnly)
7707 : {
7708 0 : poCollHdr->m_nMultiPointSymbolId = poMpointHdr->m_nSymbolId;
7709 : }
7710 :
7711 0 : delete poMpointHdr;
7712 : }
7713 : else
7714 : {
7715 : // No Multipoint component. Set corresponding header fields to 0
7716 :
7717 0 : poCollHdr->m_nMPointDataSize = 0;
7718 0 : poCollHdr->m_nNumMultiPoints = 0;
7719 0 : poCollHdr->m_nMultiPointSymbolId = 0;
7720 : }
7721 :
7722 :
7723 : /*-----------------------------------------------------------------
7724 : * Copy object information
7725 : *----------------------------------------------------------------*/
7726 :
7727 : // Compressed coordinate origin (useful only in compressed case!)
7728 0 : poCollHdr->m_nComprOrgX = m_nComprOrgX;
7729 0 : poCollHdr->m_nComprOrgY = m_nComprOrgY;
7730 :
7731 0 : poCollHdr->m_nCoordDataSize = nTotalFeatureDataSize;
7732 :
7733 0 : poCollHdr->SetMBR(m_nXMin, m_nYMin, m_nXMax, m_nYMax);
7734 :
7735 :
7736 0 : if (CPLGetLastErrorNo() != 0)
7737 0 : return -1;
7738 :
7739 : /* Return a ref to coord block so that caller can continue writing
7740 : * after the end of this object (used by index splitting)
7741 : */
7742 0 : if (ppoCoordBlock)
7743 0 : *ppoCoordBlock = poCoordBlock;
7744 :
7745 0 : return 0;
7746 : }
7747 :
7748 :
7749 : /**********************************************************************
7750 : * TABCollection::SyncOGRGeometryCollection()
7751 : *
7752 : * Copy the region/pline/multipoint's geometries to the OGRFeature's
7753 : * geometry.
7754 : **********************************************************************/
7755 : int TABCollection::SyncOGRGeometryCollection(GBool bSyncRegion,
7756 : GBool bSyncPline,
7757 0 : GBool bSyncMpoint)
7758 : {
7759 0 : OGRGeometry *poThisGeom = GetGeometryRef();
7760 : OGRGeometryCollection *poGeomColl;
7761 :
7762 : // poGeometry is defined in the OGRFeature class
7763 0 : if (poThisGeom == NULL)
7764 : {
7765 0 : poThisGeom = poGeomColl = new OGRGeometryCollection();
7766 0 : SetGeometryDirectly(poGeomColl);
7767 : }
7768 0 : else if (wkbFlatten(poThisGeom->getGeometryType())==wkbGeometryCollection)
7769 : {
7770 0 : poGeomColl = (OGRGeometryCollection *)poThisGeom;
7771 : }
7772 : else
7773 : {
7774 : CPLError(CE_Failure, CPLE_AssertionFailed,
7775 0 : "TABCollection: Invalid Geometry. Type must be OGRCollection.");
7776 0 : return -1;
7777 : }
7778 :
7779 : /*-----------------------------------------------------------------
7780 : * Start by removing geometries that need to be replaced
7781 : * In theory there should be a single geometry of each type, but
7782 : * just in case, we'll loop over the whole collection and delete all
7783 : * instances of each type if there are some.
7784 : *----------------------------------------------------------------*/
7785 0 : int numGeometries = poGeomColl->getNumGeometries();
7786 0 : for (int i=0; i<numGeometries; i++)
7787 : {
7788 0 : OGRGeometry *poGeom = poGeomColl->getGeometryRef(i);
7789 0 : if (!poGeom)
7790 0 : continue;
7791 :
7792 0 : if ( (bSyncRegion &&
7793 : (wkbFlatten(poGeom->getGeometryType()) == wkbPolygon ||
7794 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiPolygon) ) ||
7795 : (bSyncPline &&
7796 : (wkbFlatten(poGeom->getGeometryType()) == wkbLineString ||
7797 : wkbFlatten(poGeom->getGeometryType()) == wkbMultiLineString)) ||
7798 : (bSyncMpoint &&
7799 : (wkbFlatten(poGeom->getGeometryType()) == wkbMultiPoint) ) )
7800 : {
7801 : // Remove this geometry
7802 0 : poGeomColl->removeGeometry(i);
7803 :
7804 : // Unless this was the last geometry, we need to restart
7805 : // scanning the collection since we modified it
7806 0 : if (i != numGeometries-1)
7807 : {
7808 0 : i=0;
7809 0 : numGeometries = poGeomColl->getNumGeometries();
7810 : }
7811 : }
7812 : }
7813 :
7814 : /*-----------------------------------------------------------------
7815 : * Copy TAB Feature geometries to OGRGeometryCollection
7816 : *----------------------------------------------------------------*/
7817 0 : if(bSyncRegion && m_poRegion && m_poRegion->GetGeometryRef() != NULL)
7818 0 : poGeomColl->addGeometry(m_poRegion->GetGeometryRef());
7819 :
7820 0 : if(bSyncPline && m_poPline && m_poPline->GetGeometryRef() != NULL)
7821 0 : poGeomColl->addGeometry(m_poPline->GetGeometryRef());
7822 :
7823 0 : if(bSyncMpoint && m_poMpoint && m_poMpoint->GetGeometryRef() != NULL)
7824 0 : poGeomColl->addGeometry(m_poMpoint->GetGeometryRef());
7825 :
7826 0 : return 0;
7827 : }
7828 :
7829 :
7830 : /**********************************************************************
7831 : * TABCollection::SetRegionDirectly()
7832 : *
7833 : * Set the region component of the collection, deleting the current
7834 : * region component if there is one. The object is then owned by the
7835 : * TABCollection object. Passing NULL just deletes it.
7836 : *
7837 : * Note that an intentional side-effect is that calling this method
7838 : * with the same poRegion pointer that is already owned by this object
7839 : * will force resync'ing the OGR Geometry member.
7840 : **********************************************************************/
7841 0 : int TABCollection::SetRegionDirectly(TABRegion *poRegion)
7842 : {
7843 0 : if (m_poRegion && m_poRegion != poRegion)
7844 0 : delete m_poRegion;
7845 0 : m_poRegion = poRegion;
7846 :
7847 : // Update OGRGeometryCollection component as well
7848 0 : return SyncOGRGeometryCollection(TRUE, FALSE, FALSE);
7849 : }
7850 :
7851 : /**********************************************************************
7852 : * TABCollection::SetPolylineDirectly()
7853 : *
7854 : * Set the polyline component of the collection, deleting the current
7855 : * polyline component if there is one. The object is then owned by the
7856 : * TABCollection object. Passing NULL just deletes it.
7857 : *
7858 : * Note that an intentional side-effect is that calling this method
7859 : * with the same poPline pointer that is already owned by this object
7860 : * will force resync'ing the OGR Geometry member.
7861 : **********************************************************************/
7862 0 : int TABCollection::SetPolylineDirectly(TABPolyline *poPline)
7863 : {
7864 0 : if (m_poPline && m_poPline != poPline)
7865 0 : delete m_poPline;
7866 0 : m_poPline = poPline;
7867 :
7868 : // Update OGRGeometryCollection component as well
7869 0 : return SyncOGRGeometryCollection(FALSE, TRUE, FALSE);
7870 : }
7871 :
7872 : /**********************************************************************
7873 : * TABCollection::SetMultiPointDirectly()
7874 : *
7875 : * Set the multipoint component of the collection, deleting the current
7876 : * multipoint component if there is one. The object is then owned by the
7877 : * TABCollection object. Passing NULL just deletes it.
7878 : *
7879 : * Note that an intentional side-effect is that calling this method
7880 : * with the same poMpoint pointer that is already owned by this object
7881 : * will force resync'ing the OGR Geometry member.
7882 : **********************************************************************/
7883 0 : int TABCollection::SetMultiPointDirectly(TABMultiPoint *poMpoint)
7884 : {
7885 0 : if (m_poMpoint && m_poMpoint != poMpoint)
7886 0 : delete m_poMpoint;
7887 0 : m_poMpoint = poMpoint;
7888 :
7889 : // Update OGRGeometryCollection component as well
7890 0 : return SyncOGRGeometryCollection(FALSE, FALSE, TRUE);
7891 : }
7892 :
7893 :
7894 : /**********************************************************************
7895 : * TABCollection::GetStyleString()
7896 : *
7897 : * Return style string for this feature.
7898 : *
7899 : * Style String is built only once during the first call to GetStyleString().
7900 : **********************************************************************/
7901 0 : const char *TABCollection::GetStyleString()
7902 : {
7903 0 : if (m_pszStyleString == NULL)
7904 : {
7905 0 : m_pszStyleString = CPLStrdup(GetSymbolStyleString());
7906 : }
7907 :
7908 0 : return m_pszStyleString;
7909 : }
7910 :
7911 :
7912 : /**********************************************************************
7913 : * TABCollection::DumpMIF()
7914 : *
7915 : * Dump feature geometry
7916 : **********************************************************************/
7917 0 : void TABCollection::DumpMIF(FILE *fpOut /*=NULL*/)
7918 : {
7919 0 : if (fpOut == NULL)
7920 0 : fpOut = stdout;
7921 :
7922 : /*-----------------------------------------------------------------
7923 : * Generate output
7924 : *----------------------------------------------------------------*/
7925 0 : int numParts = 0;
7926 0 : if (m_poRegion) numParts++;
7927 0 : if (m_poPline) numParts++;
7928 0 : if (m_poMpoint) numParts++;
7929 :
7930 0 : fprintf(fpOut, "COLLECTION %d\n", numParts);
7931 :
7932 0 : if (m_poRegion)
7933 0 : m_poRegion->DumpMIF(fpOut);
7934 :
7935 0 : if (m_poPline)
7936 0 : m_poPline->DumpMIF(fpOut);
7937 :
7938 0 : if (m_poMpoint)
7939 0 : m_poMpoint->DumpMIF(fpOut);
7940 :
7941 :
7942 0 : DumpSymbolDef(fpOut);
7943 :
7944 0 : fflush(fpOut);
7945 0 : }
7946 :
7947 : /*=====================================================================
7948 : * class TABDebugFeature
7949 : *====================================================================*/
7950 :
7951 : /**********************************************************************
7952 : * TABDebugFeature::TABDebugFeature()
7953 : *
7954 : * Constructor.
7955 : **********************************************************************/
7956 0 : TABDebugFeature::TABDebugFeature(OGRFeatureDefn *poDefnIn):
7957 0 : TABFeature(poDefnIn)
7958 : {
7959 0 : }
7960 :
7961 : /**********************************************************************
7962 : * TABDebugFeature::~TABDebugFeature()
7963 : *
7964 : * Destructor.
7965 : **********************************************************************/
7966 0 : TABDebugFeature::~TABDebugFeature()
7967 : {
7968 0 : }
7969 :
7970 : /**********************************************************************
7971 : * TABDebugFeature::ReadGeometryFromMAPFile()
7972 : *
7973 : * Fill the geometry and representation (color, etc...) part of the
7974 : * feature from the contents of the .MAP object pointed to by poMAPFile.
7975 : *
7976 : * It is assumed that poMAPFile currently points to the beginning of
7977 : * a map object.
7978 : *
7979 : * Returns 0 on success, -1 on error, in which case CPLError() will have
7980 : * been called.
7981 : **********************************************************************/
7982 : int TABDebugFeature::ReadGeometryFromMAPFile(TABMAPFile *poMapFile,
7983 : TABMAPObjHdr *poObjHdr,
7984 : GBool /*bCoordBlockDataOnly=FALSE*/,
7985 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
7986 : {
7987 : TABMAPObjectBlock *poObjBlock;
7988 : TABMAPHeaderBlock *poHeader;
7989 :
7990 : /*-----------------------------------------------------------------
7991 : * Fetch geometry type
7992 : *----------------------------------------------------------------*/
7993 0 : m_nMapInfoType = poObjHdr->m_nType;
7994 :
7995 0 : poObjBlock = poMapFile->GetCurObjBlock();
7996 0 : poHeader = poMapFile->GetHeaderBlock();
7997 :
7998 : /*-----------------------------------------------------------------
7999 : * If object type has coords in a type 3 block, then its position
8000 : * follows
8001 : *----------------------------------------------------------------*/
8002 0 : if (poHeader->MapObjectUsesCoordBlock(m_nMapInfoType))
8003 : {
8004 0 : m_nCoordDataPtr = poObjBlock->ReadInt32();
8005 0 : m_nCoordDataSize = poObjBlock->ReadInt32();
8006 : }
8007 : else
8008 : {
8009 0 : m_nCoordDataPtr = -1;
8010 0 : m_nCoordDataSize = 0;
8011 : }
8012 :
8013 0 : m_nSize = poHeader->GetMapObjectSize(m_nMapInfoType);
8014 0 : if (m_nSize > 0)
8015 : {
8016 0 : poObjBlock->GotoByteRel(-5); // Go back to beginning of header
8017 0 : poObjBlock->ReadBytes(m_nSize, m_abyBuf);
8018 : }
8019 :
8020 0 : return 0;
8021 : }
8022 :
8023 : /**********************************************************************
8024 : * TABDebugFeature::WriteGeometryToMAPFile()
8025 : *
8026 : * Write the geometry and representation (color, etc...) part of the
8027 : * feature to the .MAP object pointed to by poMAPFile.
8028 : *
8029 : * It is assumed that poMAPFile currently points to a valid map object.
8030 : *
8031 : * Returns 0 on success, -1 on error, in which case CPLError() will have
8032 : * been called.
8033 : **********************************************************************/
8034 : int TABDebugFeature::WriteGeometryToMAPFile(TABMAPFile * /*poMapFile*/,
8035 : TABMAPObjHdr * /*poObjHdr*/,
8036 : GBool /*bCoordBlockDataOnly=FALSE*/,
8037 0 : TABMAPCoordBlock ** /*ppoCoordBlock=NULL*/)
8038 : {
8039 : // Nothing to do here!
8040 :
8041 : CPLError(CE_Failure, CPLE_NotSupported,
8042 0 : "TABDebugFeature::WriteGeometryToMAPFile() not implemented.\n");
8043 :
8044 0 : return -1;
8045 : }
8046 :
8047 : /**********************************************************************
8048 : * TABDebugFeature::DumpMIF()
8049 : *
8050 : * Dump feature contents... available only in DEBUG mode.
8051 : **********************************************************************/
8052 0 : void TABDebugFeature::DumpMIF(FILE *fpOut /*=NULL*/)
8053 : {
8054 : int i;
8055 :
8056 0 : if (fpOut == NULL)
8057 0 : fpOut = stdout;
8058 :
8059 : fprintf(fpOut, "----- TABDebugFeature (type = 0x%2.2x) -----\n",
8060 0 : GetMapInfoType());
8061 0 : fprintf(fpOut, " Object size: %d bytes\n", m_nSize);
8062 0 : fprintf(fpOut, " m_nCoordDataPtr = %d\n", m_nCoordDataPtr);
8063 0 : fprintf(fpOut, " m_nCoordDataSize = %d\n", m_nCoordDataSize);
8064 0 : fprintf(fpOut, " ");
8065 :
8066 0 : for(i=0; i<m_nSize; i++)
8067 0 : fprintf(fpOut, " %2.2x", m_abyBuf[i]);
8068 :
8069 0 : fprintf(fpOut, " \n");
8070 :
8071 :
8072 0 : fflush(fpOut);
8073 0 : }
8074 :
8075 :
8076 : /*=====================================================================
8077 : * class ITABFeaturePen
8078 : *====================================================================*/
8079 :
8080 : /**********************************************************************
8081 : * ITABFeaturePen::ITABFeaturePen()
8082 : **********************************************************************/
8083 :
8084 102 : ITABFeaturePen::ITABFeaturePen()
8085 : {
8086 : static const TABPenDef csDefaultPen = MITAB_PEN_DEFAULT;
8087 :
8088 102 : m_nPenDefIndex=-1;
8089 :
8090 : /* MI default is PEN(1,2,0) */
8091 102 : m_sPenDef = csDefaultPen;
8092 102 : }
8093 :
8094 :
8095 : /**********************************************************************
8096 : * ITABFeaturePen::GetPenWidthPixel()
8097 : * ITABFeaturePen::SetPenWidthPixel()
8098 : * ITABFeaturePen::GetPenWidthPoint()
8099 : * ITABFeaturePen::SetPenWidthPoint()
8100 : *
8101 : * Pen width can be expressed in pixels (value from 1 to 7 pixels) or
8102 : * in points (value from 0.1 to 203.7 points). The default pen width
8103 : * in MapInfo is 1 pixel. Pen width in points exist only in file version 450.
8104 : *
8105 : * The following methods hide the way the pen width is stored in the files.
8106 : *
8107 : * In order to establish if a given pen def had its width specified in
8108 : * pixels or in points, one should first call GetPenWidthPoint(), and if
8109 : * it returns 0 then the Pixel width should be used instead:
8110 : * if (GetPenWidthPoint() == 0)
8111 : * ... use pen width in points ...
8112 : * else
8113 : * ... use Pixel width from GetPenWidthPixel()
8114 : *
8115 : * Note that the reverse is not true: the default pixel width is always 1,
8116 : * even when the pen width was actually set in points.
8117 : **********************************************************************/
8118 :
8119 7 : GByte ITABFeaturePen::GetPenWidthPixel()
8120 : {
8121 7 : return m_sPenDef.nPixelWidth;
8122 : }
8123 :
8124 0 : void ITABFeaturePen::SetPenWidthPixel(GByte val)
8125 : {
8126 0 : m_sPenDef.nPixelWidth = MIN(MAX(val, 1), 7);
8127 0 : m_sPenDef.nPointWidth = 0;
8128 0 : }
8129 :
8130 0 : double ITABFeaturePen::GetPenWidthPoint()
8131 : {
8132 : // We store point width internally as tenths of points
8133 0 : return m_sPenDef.nPointWidth/10.0;
8134 : }
8135 :
8136 0 : void ITABFeaturePen::SetPenWidthPoint(double val)
8137 : {
8138 0 : m_sPenDef.nPointWidth = MIN(MAX(((int)(val*10)), 1), 2037);
8139 0 : m_sPenDef.nPixelWidth = 1;
8140 0 : }
8141 :
8142 : /**********************************************************************
8143 : * ITABFeaturePen::GetPenWidthMIF()
8144 : * ITABFeaturePen::SetPenWidthMIF()
8145 : *
8146 : * The MIF representation for pen width is either a value from 1 to 7
8147 : * for a pen width in pixels, or a value from 11 to 2047 for a pen
8148 : * width in points = 10 + (point_width*10)
8149 : **********************************************************************/
8150 10 : int ITABFeaturePen::GetPenWidthMIF()
8151 : {
8152 : return ( m_sPenDef.nPointWidth > 0?
8153 10 : (m_sPenDef.nPointWidth+10): m_sPenDef.nPixelWidth );
8154 : }
8155 :
8156 28 : void ITABFeaturePen::SetPenWidthMIF(int val)
8157 : {
8158 28 : if (val > 10)
8159 : {
8160 0 : m_sPenDef.nPointWidth = MIN((val-10), 2037);
8161 0 : m_sPenDef.nPixelWidth = 0;
8162 : }
8163 : else
8164 : {
8165 28 : m_sPenDef.nPixelWidth = (GByte)MIN(MAX(val, 1), 7);
8166 28 : m_sPenDef.nPointWidth = 0;
8167 : }
8168 28 : }
8169 :
8170 : /**********************************************************************
8171 : * ITABFeaturePen::GetPenStyleString()
8172 : *
8173 : * Return a PEN() string. All representations info for the pen are here.
8174 : **********************************************************************/
8175 7 : const char *ITABFeaturePen::GetPenStyleString()
8176 : {
8177 7 : const char *pszStyle = NULL;
8178 7 : int nOGRStyle = 0;
8179 : char szPattern[20];
8180 :
8181 7 : szPattern[0] = '\0';
8182 :
8183 : // For now, I only add the 25 first styles
8184 7 : switch (GetPenPattern())
8185 : {
8186 : case 1:
8187 0 : nOGRStyle =1;
8188 0 : break;
8189 : case 2:
8190 7 : nOGRStyle = 0;
8191 7 : break;
8192 : case 3:
8193 0 : nOGRStyle = 3;
8194 0 : strcpy(szPattern,"1 1");
8195 0 : break;
8196 : case 4:
8197 0 : nOGRStyle = 3;
8198 0 : strcpy(szPattern,"2 1");
8199 0 : break;
8200 : case 5:
8201 0 : nOGRStyle = 3;
8202 0 : strcpy(szPattern,"3 1");
8203 0 : break;
8204 : case 6:
8205 0 : nOGRStyle = 3;
8206 0 : strcpy(szPattern,"6 1");
8207 0 : break;
8208 : case 7:
8209 0 : nOGRStyle = 4;
8210 0 : strcpy(szPattern,"12 2");
8211 0 : break;
8212 : case 8:
8213 0 : nOGRStyle = 4;
8214 0 : strcpy(szPattern,"24 4");
8215 0 : break;
8216 : case 9:
8217 0 : nOGRStyle = 3;
8218 0 : strcpy(szPattern,"4 3");
8219 0 : break;
8220 : case 10:
8221 0 : nOGRStyle = 5;
8222 0 : strcpy(szPattern,"1 4");
8223 0 : break;
8224 : case 11:
8225 0 : nOGRStyle = 3;
8226 0 : strcpy(szPattern,"4 6");
8227 0 : break;
8228 : case 12:
8229 0 : nOGRStyle = 3;
8230 0 : strcpy(szPattern,"6 4");
8231 0 : break;
8232 : case 13:
8233 0 : nOGRStyle = 4;
8234 0 : strcpy(szPattern,"12 12");
8235 0 : break;
8236 : case 14:
8237 0 : nOGRStyle = 6;
8238 0 : strcpy(szPattern,"8 2 1 2");
8239 0 : break;
8240 : case 15:
8241 0 : nOGRStyle = 6;
8242 0 : strcpy(szPattern,"12 1 1 1");
8243 0 : break;
8244 : case 16:
8245 0 : nOGRStyle = 6;
8246 0 : strcpy(szPattern,"12 1 3 1");
8247 0 : break;
8248 : case 17:
8249 0 : nOGRStyle = 6;
8250 0 : strcpy(szPattern,"24 6 4 6");
8251 0 : break;
8252 : case 18:
8253 0 : nOGRStyle = 7;
8254 0 : strcpy(szPattern,"24 3 3 3 3 3");
8255 0 : break;
8256 : case 19:
8257 0 : nOGRStyle = 7;
8258 0 : strcpy(szPattern,"24 3 3 3 3 3 3 3");
8259 0 : break;
8260 : case 20:
8261 0 : nOGRStyle = 7;
8262 0 : strcpy(szPattern,"6 3 1 3 1 3");
8263 0 : break;
8264 : case 21:
8265 0 : nOGRStyle = 7;
8266 0 : strcpy(szPattern,"12 2 1 2 1 2");
8267 0 : break;
8268 : case 22:
8269 0 : nOGRStyle = 7;
8270 0 : strcpy(szPattern,"12 2 1 2 1 2 1 2");
8271 0 : break;
8272 : case 23:
8273 0 : nOGRStyle = 6;
8274 0 : strcpy(szPattern,"4 1 1 1");
8275 0 : break;
8276 : case 24:
8277 0 : nOGRStyle = 7;
8278 0 : strcpy(szPattern,"4 1 1 1 1");
8279 0 : break;
8280 : case 25:
8281 0 : nOGRStyle = 6;
8282 0 : strcpy(szPattern,"4 1 1 1 2 1 1 1");
8283 0 : break;
8284 :
8285 : default:
8286 0 : nOGRStyle = 0;
8287 : break;
8288 : }
8289 :
8290 7 : if (strlen(szPattern) != 0)
8291 : {
8292 0 : if(m_sPenDef.nPointWidth > 0)
8293 : pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\"mapinfo-pen-%d,"
8294 : "ogr-pen-%d\",p:\"%spx\")",
8295 : ((int)GetPenWidthPoint()),
8296 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
8297 0 : szPattern);
8298 : else
8299 : pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\"mapinfo-pen-%d,"
8300 : "ogr-pen-%d\",p:\"%spx\")",
8301 : GetPenWidthPixel(),
8302 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle,
8303 0 : szPattern);
8304 : }
8305 : else
8306 : {
8307 7 : if(m_sPenDef.nPointWidth > 0)
8308 : pszStyle =CPLSPrintf("PEN(w:%dpt,c:#%6.6x,id:\""
8309 : "mapinfo-pen-%d,ogr-pen-%d\")",
8310 : ((int)GetPenWidthPoint()),
8311 0 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
8312 : else
8313 : pszStyle =CPLSPrintf("PEN(w:%dpx,c:#%6.6x,id:\""
8314 : "mapinfo-pen-%d,ogr-pen-%d\")",
8315 : GetPenWidthPixel(),
8316 7 : m_sPenDef.rgbColor,GetPenPattern(),nOGRStyle);
8317 : }
8318 :
8319 7 : return pszStyle;
8320 : }
8321 :
8322 : /**********************************************************************
8323 : * ITABFeaturePen::SetPenFromStyleString()
8324 : *
8325 : * Init the Pen properties from a style string.
8326 : **********************************************************************/
8327 0 : void ITABFeaturePen::SetPenFromStyleString(const char *pszStyleString)
8328 : {
8329 : int numParts, i;
8330 : GBool bIsNull;
8331 :
8332 : const char *pszPenName, *pszPenPattern;
8333 :
8334 : double nPenWidth;
8335 :
8336 : GInt32 nPenColor;
8337 : const char *pszPenColor;
8338 :
8339 : int nPenId;
8340 : char* pszPenId;
8341 :
8342 : // Use the Style Manager to retreive all the information we need.
8343 0 : OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
8344 : OGRStyleTool *poStylePart;
8345 :
8346 : // Init the StyleMgr with the StyleString.
8347 0 : poStyleMgr->InitStyleString(pszStyleString);
8348 :
8349 : // Retreive the Pen info.
8350 0 : numParts = poStyleMgr->GetPartCount();
8351 0 : for(i=0; i<numParts; i++)
8352 : {
8353 0 : poStylePart = poStyleMgr->GetPart(i);
8354 :
8355 0 : if(poStylePart->GetType() == OGRSTCPen)
8356 : {
8357 0 : break;
8358 : }
8359 : }
8360 :
8361 : // If the no Pen found, do nothing.
8362 0 : if(i >= numParts)
8363 0 : return;
8364 :
8365 0 : OGRStylePen *poPenStyle = (OGRStylePen*)poStylePart;
8366 :
8367 : // With Pen, we always want to output points or pixels (which are the same,
8368 : // so just use points).
8369 : //
8370 : // It's very important to set the output unit of the feature.
8371 : // The default value is meter. If we don't do it all numerical values
8372 : // will be assumed to be converted from the input unit to meter when we
8373 : // will get them via GetParam...() functions.
8374 : // See OGRStyleTool::Parse() for more details.
8375 0 : poPenStyle->SetUnit(OGRSTUPoints, 1);
8376 :
8377 : // Get the Pen Id or pattern
8378 0 : pszPenName = poPenStyle->Id(bIsNull);
8379 0 : if (bIsNull) pszPenName = NULL;
8380 :
8381 : // Set the width
8382 0 : if(poPenStyle->Width(bIsNull))
8383 : {
8384 0 : nPenWidth = poPenStyle->Width(bIsNull);
8385 : // Width < 10 is a pixel
8386 0 : if(nPenWidth > 10)
8387 0 : SetPenWidthPoint(nPenWidth);
8388 : else
8389 0 : SetPenWidthPixel((GByte)nPenWidth);
8390 : }
8391 :
8392 : //Set the color
8393 0 : pszPenColor = poPenStyle->Color(bIsNull);
8394 0 : if(pszPenColor != NULL)
8395 : {
8396 0 : if(pszPenColor[0] == '#')
8397 0 : pszPenColor++;
8398 : // The Pen color is an Hexa string that need to be convert in a int
8399 0 : nPenColor = strtol(pszPenColor, NULL, 16);
8400 0 : SetPenColor(nPenColor);
8401 : }
8402 :
8403 : // Set the Id of the Pen, use Pattern if necessary.
8404 0 : if(pszPenName &&
8405 : (strstr(pszPenName, "mapinfo-pen-") || strstr(pszPenName, "ogr-pen-")) )
8406 : {
8407 0 : if((pszPenId = (char *) strstr(pszPenName, "mapinfo-pen-")))
8408 : {
8409 0 : nPenId = atoi(pszPenId+12);
8410 0 : SetPenPattern(nPenId);
8411 : }
8412 0 : else if((pszPenId = (char *) strstr(pszPenName, "ogr-pen-")))
8413 : {
8414 0 : nPenId = atoi(pszPenId+8);
8415 0 : if(nPenId == 0)
8416 0 : nPenId = 2;
8417 0 : SetPenPattern(nPenId);
8418 : }
8419 : }
8420 : else
8421 : {
8422 : // If no Pen Id, use the Pen Pattern to retreive the Id.
8423 0 : pszPenPattern = poPenStyle->Pattern(bIsNull);
8424 0 : if (bIsNull)
8425 0 : pszPenPattern = NULL;
8426 : else
8427 : {
8428 0 : if(strcmp(pszPenPattern, "1 1") == 0)
8429 0 : SetPenPattern(3);
8430 0 : else if(strcmp(pszPenPattern, "2 1") == 0)
8431 0 : SetPenPattern(4);
8432 0 : else if(strcmp(pszPenPattern, "3 1") == 0)
8433 0 : SetPenPattern(5);
8434 0 : else if(strcmp(pszPenPattern, "6 1") == 0)
8435 0 : SetPenPattern(6);
8436 0 : else if(strcmp(pszPenPattern, "12 2") == 0)
8437 0 : SetPenPattern(7);
8438 0 : else if(strcmp(pszPenPattern, "24 4") == 0)
8439 0 : SetPenPattern(8);
8440 0 : else if(strcmp(pszPenPattern, "4 3") == 0)
8441 0 : SetPenPattern(9);
8442 0 : else if(strcmp(pszPenPattern, "1 4") == 0)
8443 0 : SetPenPattern(10);
8444 0 : else if(strcmp(pszPenPattern, "4 6") == 0)
8445 0 : SetPenPattern(11);
8446 0 : else if(strcmp(pszPenPattern, "6 4") == 0)
8447 0 : SetPenPattern(12);
8448 0 : else if(strcmp(pszPenPattern, "12 12") == 0)
8449 0 : SetPenPattern(13);
8450 0 : else if(strcmp(pszPenPattern, "8 2 1 2") == 0)
8451 0 : SetPenPattern(14);
8452 0 : else if(strcmp(pszPenPattern, "12 1 1 1") == 0)
8453 0 : SetPenPattern(15);
8454 0 : else if(strcmp(pszPenPattern, "12 1 3 1") == 0)
8455 0 : SetPenPattern(16);
8456 0 : else if(strcmp(pszPenPattern, "24 6 4 6") == 0)
8457 0 : SetPenPattern(17);
8458 0 : else if(strcmp(pszPenPattern, "24 3 3 3 3 3") == 0)
8459 0 : SetPenPattern(18);
8460 0 : else if(strcmp(pszPenPattern, "24 3 3 3 3 3 3 3") == 0)
8461 0 : SetPenPattern(19);
8462 0 : else if(strcmp(pszPenPattern, "6 3 1 3 1 3") == 0)
8463 0 : SetPenPattern(20);
8464 0 : else if(strcmp(pszPenPattern, "12 2 1 2 1 2") == 0)
8465 0 : SetPenPattern(21);
8466 0 : else if(strcmp(pszPenPattern, "12 2 1 2 1 2 1 2") == 0)
8467 0 : SetPenPattern(22);
8468 0 : else if(strcmp(pszPenPattern, "4 1 1 1") == 0)
8469 0 : SetPenPattern(23);
8470 0 : else if(strcmp(pszPenPattern, "4 1 1 1 1") == 0)
8471 0 : SetPenPattern(24);
8472 0 : else if(strcmp(pszPenPattern, "4 1 1 1 2 1 1 1") == 0)
8473 0 : SetPenPattern(25);
8474 : }
8475 : }
8476 :
8477 0 : delete poStyleMgr;
8478 0 : delete poStylePart;
8479 :
8480 0 : return;
8481 : }
8482 :
8483 : /**********************************************************************
8484 : * ITABFeaturePen::DumpPenDef()
8485 : *
8486 : * Dump pen definition information.
8487 : **********************************************************************/
8488 0 : void ITABFeaturePen::DumpPenDef(FILE *fpOut /*=NULL*/)
8489 : {
8490 0 : if (fpOut == NULL)
8491 0 : fpOut = stdout;
8492 :
8493 0 : fprintf(fpOut, " m_nPenDefIndex = %d\n", m_nPenDefIndex);
8494 0 : fprintf(fpOut, " m_sPenDef.nRefCount = %d\n", m_sPenDef.nRefCount);
8495 0 : fprintf(fpOut, " m_sPenDef.nPixelWidth = %d\n", m_sPenDef.nPixelWidth);
8496 0 : fprintf(fpOut, " m_sPenDef.nLinePattern = %d\n", m_sPenDef.nLinePattern);
8497 0 : fprintf(fpOut, " m_sPenDef.nPointWidth = %d\n", m_sPenDef.nPointWidth);
8498 : fprintf(fpOut, " m_sPenDef.rgbColor = 0x%6.6x (%d)\n",
8499 0 : m_sPenDef.rgbColor, m_sPenDef.rgbColor);
8500 :
8501 0 : fflush(fpOut);
8502 0 : }
8503 :
8504 : /*=====================================================================
8505 : * class ITABFeatureBrush
8506 : *====================================================================*/
8507 :
8508 : /**********************************************************************
8509 : * ITABFeatureBrush::ITABFeatureBrush()
8510 : **********************************************************************/
8511 :
8512 100 : ITABFeatureBrush::ITABFeatureBrush()
8513 : {
8514 : static const TABBrushDef csDefaultBrush = MITAB_BRUSH_DEFAULT;
8515 :
8516 100 : m_nBrushDefIndex=-1;
8517 :
8518 : /* MI default is BRUSH(2,16777215,16777215) */
8519 100 : m_sBrushDef = csDefaultBrush;
8520 100 : }
8521 :
8522 :
8523 : /**********************************************************************
8524 : * ITABFeatureBrush::GetBrushStyleString()
8525 : *
8526 : * Return a Brush() string. All representations info for the Brush are here.
8527 : **********************************************************************/
8528 7 : const char *ITABFeatureBrush::GetBrushStyleString()
8529 : {
8530 7 : const char *pszStyle = NULL;
8531 7 : int nOGRStyle = 0;
8532 : char szPattern[20];
8533 :
8534 7 : szPattern[0] = '\0';
8535 :
8536 7 : if (m_sBrushDef.nFillPattern == 1)
8537 7 : nOGRStyle = 1;
8538 0 : else if (m_sBrushDef.nFillPattern == 3)
8539 0 : nOGRStyle = 2;
8540 0 : else if (m_sBrushDef.nFillPattern == 4)
8541 0 : nOGRStyle = 3;
8542 0 : else if (m_sBrushDef.nFillPattern == 5)
8543 0 : nOGRStyle = 5;
8544 0 : else if (m_sBrushDef.nFillPattern == 6)
8545 0 : nOGRStyle = 4;
8546 0 : else if (m_sBrushDef.nFillPattern == 7)
8547 0 : nOGRStyle = 6;
8548 0 : else if (m_sBrushDef.nFillPattern == 8)
8549 0 : nOGRStyle = 7;
8550 :
8551 :
8552 7 : if (GetBrushTransparent())
8553 : {
8554 : /* Omit BG Color for transparent brushes */
8555 : pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
8556 : m_sBrushDef.rgbFGColor,
8557 0 : m_sBrushDef.nFillPattern,nOGRStyle);
8558 : }
8559 : else
8560 : {
8561 : pszStyle =CPLSPrintf("BRUSH(fc:#%6.6x,bc:#%6.6x,id:\"mapinfo-brush-%d,ogr-brush-%d\")",
8562 : m_sBrushDef.rgbFGColor,
8563 : m_sBrushDef.rgbBGColor,
8564 7 : m_sBrushDef.nFillPattern,nOGRStyle);
8565 : }
8566 :
8567 7 : return pszStyle;
8568 :
8569 : }
8570 :
8571 :
8572 : /**********************************************************************
8573 : * ITABFeatureBrush::SetBrushFromStyleString()
8574 : *
8575 : * Set all Brush elements from a StyleString.
8576 : * Use StyleMgr to do so.
8577 : **********************************************************************/
8578 0 : void ITABFeatureBrush::SetBrushFromStyleString(const char *pszStyleString)
8579 : {
8580 : int numParts, i;
8581 : GBool bIsNull;
8582 :
8583 : const char *pszBrushId;
8584 : int nBrushId;
8585 :
8586 : const char *pszBrushColor;
8587 : int nBrushColor;
8588 :
8589 : // Use the Style Manager to retreive all the information we need.
8590 0 : OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
8591 : OGRStyleTool *poStylePart;
8592 :
8593 : // Init the StyleMgr with the StyleString.
8594 0 : poStyleMgr->InitStyleString(pszStyleString);
8595 :
8596 : // Retreive the Brush info.
8597 0 : numParts = poStyleMgr->GetPartCount();
8598 0 : for(i=0; i<numParts; i++)
8599 : {
8600 0 : poStylePart = poStyleMgr->GetPart(i);
8601 :
8602 0 : if(poStylePart->GetType() == OGRSTCBrush)
8603 : {
8604 0 : break;
8605 : }
8606 : }
8607 :
8608 : // If the no Brush found, do nothing.
8609 0 : if(i >= numParts)
8610 0 : return;
8611 :
8612 0 : OGRStyleBrush *poBrushStyle = (OGRStyleBrush*)poStylePart;
8613 :
8614 : // Set the Brush Id (FillPattern)
8615 0 : pszBrushId = poBrushStyle->Id(bIsNull);
8616 0 : if(bIsNull) pszBrushId = NULL;
8617 :
8618 0 : if(pszBrushId &&
8619 : (strstr(pszBrushId, "mapinfo-brush-") ||
8620 : strstr(pszBrushId, "ogr-brush-")) )
8621 : {
8622 0 : if(strstr(pszBrushId, "mapinfo-brush-"))
8623 : {
8624 0 : nBrushId = atoi(pszBrushId+14);
8625 0 : SetBrushPattern((GByte)nBrushId);
8626 : }
8627 0 : else if(strstr(pszBrushId, "ogr-brush-"))
8628 : {
8629 0 : nBrushId = atoi(pszBrushId+10);
8630 0 : if(nBrushId > 1)
8631 0 : nBrushId++;
8632 0 : SetBrushPattern((GByte)nBrushId);
8633 : }
8634 : }
8635 :
8636 : // Set the BackColor, if not set, then it's transparent
8637 0 : pszBrushColor = poBrushStyle->BackColor(bIsNull);
8638 0 : if(bIsNull) pszBrushColor = NULL;
8639 :
8640 0 : if(pszBrushColor)
8641 : {
8642 0 : if(pszBrushColor[0] == '#')
8643 0 : pszBrushColor++;
8644 0 : nBrushColor = strtol(pszBrushColor, NULL, 16);
8645 0 : SetBrushBGColor((GInt32)nBrushColor);
8646 : }
8647 : else
8648 : {
8649 0 : SetBrushTransparent(1);
8650 : }
8651 :
8652 : // Set the ForeColor
8653 0 : pszBrushColor = poBrushStyle->ForeColor(bIsNull);
8654 0 : if(bIsNull) pszBrushColor = NULL;
8655 :
8656 0 : if(pszBrushColor)
8657 : {
8658 0 : if(pszBrushColor[0] == '#')
8659 0 : pszBrushColor++;
8660 0 : nBrushColor = strtol(pszBrushColor, NULL, 16);
8661 0 : SetBrushFGColor((GInt32)nBrushColor);
8662 : }
8663 :
8664 0 : delete poStyleMgr;
8665 0 : delete poStylePart;
8666 :
8667 0 : return;
8668 : }
8669 :
8670 : /**********************************************************************
8671 : * ITABFeatureBrush::DumpBrushDef()
8672 : *
8673 : * Dump Brush definition information.
8674 : **********************************************************************/
8675 0 : void ITABFeatureBrush::DumpBrushDef(FILE *fpOut /*=NULL*/)
8676 : {
8677 0 : if (fpOut == NULL)
8678 0 : fpOut = stdout;
8679 :
8680 0 : fprintf(fpOut, " m_nBrushDefIndex = %d\n", m_nBrushDefIndex);
8681 0 : fprintf(fpOut, " m_sBrushDef.nRefCount = %d\n", m_sBrushDef.nRefCount);
8682 : fprintf(fpOut, " m_sBrushDef.nFillPattern = %d\n",
8683 0 : (int)m_sBrushDef.nFillPattern);
8684 : fprintf(fpOut, " m_sBrushDef.bTransparentFill = %d\n",
8685 0 : (int)m_sBrushDef.bTransparentFill);
8686 : fprintf(fpOut, " m_sBrushDef.rgbFGColor = 0x%6.6x (%d)\n",
8687 0 : m_sBrushDef.rgbFGColor, m_sBrushDef.rgbFGColor);
8688 : fprintf(fpOut, " m_sBrushDef.rgbBGColor = 0x%6.6x (%d)\n",
8689 0 : m_sBrushDef.rgbBGColor, m_sBrushDef.rgbBGColor);
8690 :
8691 0 : fflush(fpOut);
8692 0 : }
8693 :
8694 : /*=====================================================================
8695 : * class ITABFeatureFont
8696 : *====================================================================*/
8697 :
8698 : /**********************************************************************
8699 : * ITABFeatureFont::ITABFeatureFont()
8700 : **********************************************************************/
8701 :
8702 0 : ITABFeatureFont::ITABFeatureFont()
8703 : {
8704 : static const TABFontDef csDefaultFont = MITAB_FONT_DEFAULT;
8705 :
8706 0 : m_nFontDefIndex=-1;
8707 :
8708 : /* MI default is Font("Arial",0,0,0) */
8709 0 : m_sFontDef = csDefaultFont;
8710 0 : }
8711 :
8712 : /**********************************************************************
8713 : * ITABFeatureFont::SetFontName()
8714 : **********************************************************************/
8715 0 : void ITABFeatureFont::SetFontName(const char *pszName)
8716 : {
8717 0 : strncpy( m_sFontDef.szFontName, pszName, 32);
8718 0 : m_sFontDef.szFontName[32] = '\0';
8719 0 : }
8720 :
8721 : /**********************************************************************
8722 : * ITABFeatureFont::DumpFontDef()
8723 : *
8724 : * Dump Font definition information.
8725 : **********************************************************************/
8726 0 : void ITABFeatureFont::DumpFontDef(FILE *fpOut /*=NULL*/)
8727 : {
8728 0 : if (fpOut == NULL)
8729 0 : fpOut = stdout;
8730 :
8731 0 : fprintf(fpOut, " m_nFontDefIndex = %d\n", m_nFontDefIndex);
8732 0 : fprintf(fpOut, " m_sFontDef.nRefCount = %d\n", m_sFontDef.nRefCount);
8733 0 : fprintf(fpOut, " m_sFontDef.szFontName = '%s'\n", m_sFontDef.szFontName);
8734 :
8735 0 : fflush(fpOut);
8736 0 : }
8737 :
8738 :
8739 : /*=====================================================================
8740 : * class ITABFeatureSymbol
8741 : *====================================================================*/
8742 :
8743 : /**********************************************************************
8744 : * ITABFeatureSymbol::ITABFeatureSymbol()
8745 : **********************************************************************/
8746 :
8747 8 : ITABFeatureSymbol::ITABFeatureSymbol()
8748 : {
8749 : static const TABSymbolDef csDefaultSymbol = MITAB_SYMBOL_DEFAULT;
8750 :
8751 8 : m_nSymbolDefIndex=-1;
8752 :
8753 : /* MI default is Symbol(35,0,12) */
8754 8 : m_sSymbolDef = csDefaultSymbol;
8755 8 : }
8756 :
8757 : /**********************************************************************
8758 : * ITABFeatureSymbol::GetSymbolStyleString()
8759 : *
8760 : * Return a Symbol() string. All representations info for the Symbol are here.
8761 : **********************************************************************/
8762 0 : const char *ITABFeatureSymbol::GetSymbolStyleString(double dfAngle)
8763 : {
8764 0 : const char *pszStyle = NULL;
8765 0 : int nOGRStyle = 1;
8766 : char szPattern[20];
8767 0 : int nAngle = 0;
8768 :
8769 0 : szPattern[0] = '\0';
8770 :
8771 0 : if (m_sSymbolDef.nSymbolNo == 31)
8772 0 : nOGRStyle = 0;
8773 0 : else if (m_sSymbolDef.nSymbolNo == 32)
8774 0 : nOGRStyle = 6;
8775 0 : else if (m_sSymbolDef.nSymbolNo == 33)
8776 : {
8777 0 : nAngle = 45;
8778 0 : nOGRStyle = 6;
8779 : }
8780 0 : else if (m_sSymbolDef.nSymbolNo == 34)
8781 0 : nOGRStyle = 4;
8782 0 : else if (m_sSymbolDef.nSymbolNo == 35)
8783 0 : nOGRStyle = 10;
8784 0 : else if (m_sSymbolDef.nSymbolNo == 36)
8785 0 : nOGRStyle = 8;
8786 0 : else if (m_sSymbolDef.nSymbolNo == 37)
8787 : {
8788 0 : nAngle = 180;
8789 0 : nOGRStyle = 8;
8790 : }
8791 0 : else if (m_sSymbolDef.nSymbolNo == 38)
8792 0 : nOGRStyle = 5;
8793 0 : else if (m_sSymbolDef.nSymbolNo == 39)
8794 : {
8795 0 : nAngle = 45;
8796 0 : nOGRStyle = 5;
8797 : }
8798 0 : else if (m_sSymbolDef.nSymbolNo == 40)
8799 0 : nOGRStyle = 3;
8800 0 : else if (m_sSymbolDef.nSymbolNo == 41)
8801 0 : nOGRStyle = 9;
8802 0 : else if (m_sSymbolDef.nSymbolNo == 42)
8803 0 : nOGRStyle = 7;
8804 0 : else if (m_sSymbolDef.nSymbolNo == 43)
8805 : {
8806 0 : nAngle = 180;
8807 0 : nOGRStyle = 7;
8808 : }
8809 0 : else if (m_sSymbolDef.nSymbolNo == 44)
8810 0 : nOGRStyle = 6;
8811 0 : else if (m_sSymbolDef.nSymbolNo == 45)
8812 0 : nOGRStyle = 8;
8813 0 : else if (m_sSymbolDef.nSymbolNo == 46)
8814 0 : nOGRStyle = 4;
8815 0 : else if (m_sSymbolDef.nSymbolNo == 49)
8816 0 : nOGRStyle = 1;
8817 0 : else if (m_sSymbolDef.nSymbolNo == 50)
8818 0 : nOGRStyle = 2;
8819 :
8820 0 : nAngle += (int)dfAngle;
8821 :
8822 : pszStyle=CPLSPrintf("SYMBOL(a:%d,c:#%6.6x,s:%dpt,id:\"mapinfo-sym-%d,ogr-sym-%d\")",
8823 : nAngle,
8824 : m_sSymbolDef.rgbColor,
8825 : m_sSymbolDef.nPointSize,
8826 : m_sSymbolDef.nSymbolNo,
8827 0 : nOGRStyle);
8828 :
8829 0 : return pszStyle;
8830 :
8831 : }
8832 :
8833 : /**********************************************************************
8834 : * ITABFeatureSymbol::SetSymbolFromStyleString()
8835 : *
8836 : * Set all Symbol var from a StyleString. Use StyleMgr to do so.
8837 : **********************************************************************/
8838 0 : void ITABFeatureSymbol::SetSymbolFromStyleString(const char *pszStyleString)
8839 : {
8840 : int numParts, i;
8841 : GBool bIsNull;
8842 :
8843 : const char *pszSymbolId;
8844 : int nSymbolId;
8845 :
8846 : const char *pszSymbolColor;
8847 : int nSymbolColor;
8848 :
8849 : double dSymbolSize;
8850 :
8851 : // Use the Style Manager to retreive all the information we need.
8852 0 : OGRStyleMgr *poStyleMgr = new OGRStyleMgr(NULL);
8853 : OGRStyleTool *poStylePart;
8854 :
8855 : // Init the StyleMgr with the StyleString.
8856 0 : poStyleMgr->InitStyleString(pszStyleString);
8857 :
8858 : // Retreive the Symbol info.
8859 0 : numParts = poStyleMgr->GetPartCount();
8860 0 : for(i=0; i<numParts; i++)
8861 : {
8862 0 : poStylePart = poStyleMgr->GetPart(i);
8863 :
8864 0 : if(poStylePart->GetType() == OGRSTCSymbol)
8865 : {
8866 0 : break;
8867 : }
8868 : }
8869 :
8870 : // If the no Symbol found, do nothing.
8871 0 : if(i >= numParts)
8872 0 : return;
8873 :
8874 0 : OGRStyleSymbol *poSymbolStyle = (OGRStyleSymbol*)poStylePart;
8875 :
8876 : // With Symbol, we always want to output points
8877 : //
8878 : // It's very important to set the output unit of the feature.
8879 : // The default value is meter. If we don't do it all numerical values
8880 : // will be assumed to be converted from the input unit to meter when we
8881 : // will get them via GetParam...() functions.
8882 : // See OGRStyleTool::Parse() for more details.
8883 0 : poSymbolStyle->SetUnit(OGRSTUPoints, (72.0 * 39.37));
8884 :
8885 : // Set the Symbol Id (SymbolNo)
8886 0 : pszSymbolId = poSymbolStyle->Id(bIsNull);
8887 0 : if(bIsNull) pszSymbolId = NULL;
8888 :
8889 0 : if(pszSymbolId &&
8890 : (strstr(pszSymbolId, "mapinfo-sym-") ||
8891 : strstr(pszSymbolId, "ogr-sym-")) )
8892 : {
8893 0 : if(strstr(pszSymbolId, "mapinfo-sym-"))
8894 : {
8895 0 : nSymbolId = atoi(pszSymbolId+12);
8896 0 : SetSymbolNo((GByte)nSymbolId);
8897 : }
8898 0 : else if(strstr(pszSymbolId, "ogr-sym-"))
8899 : {
8900 0 : nSymbolId = atoi(pszSymbolId+8);
8901 :
8902 : // The OGR symbol is not the MapInfo one
8903 : // Here's some mapping
8904 0 : switch (nSymbolId)
8905 : {
8906 : case 0:
8907 0 : SetSymbolNo(31);
8908 0 : break;
8909 : case 1:
8910 0 : SetSymbolNo(49);
8911 0 : break;
8912 : case 2:
8913 0 : SetSymbolNo(50);
8914 0 : break;
8915 : case 3:
8916 0 : SetSymbolNo(40);
8917 0 : break;
8918 : case 4:
8919 0 : SetSymbolNo(34);
8920 0 : break;
8921 : case 5:
8922 0 : SetSymbolNo(38);
8923 0 : break;
8924 : case 6:
8925 0 : SetSymbolNo(32);
8926 0 : break;
8927 : case 7:
8928 0 : SetSymbolNo(42);
8929 0 : break;
8930 : case 8:
8931 0 : SetSymbolNo(36);
8932 0 : break;
8933 : case 9:
8934 0 : SetSymbolNo(41);
8935 0 : break;
8936 : case 10:
8937 0 : SetSymbolNo(35);
8938 : break;
8939 : }
8940 : }
8941 : }
8942 :
8943 : // Set SymbolSize
8944 0 : dSymbolSize = poSymbolStyle->Size(bIsNull);
8945 0 : if(dSymbolSize)
8946 : {
8947 0 : SetSymbolSize((GInt32)dSymbolSize);
8948 : }
8949 :
8950 : // Set Symbol Color
8951 0 : pszSymbolColor = poSymbolStyle->Color(bIsNull);
8952 0 : if(pszSymbolColor)
8953 : {
8954 0 : if(pszSymbolColor[0] == '#')
8955 0 : pszSymbolColor++;
8956 0 : nSymbolColor = strtol(pszSymbolColor, NULL, 16);
8957 0 : SetSymbolColor((GInt32)nSymbolColor);
8958 : }
8959 :
8960 0 : delete poStyleMgr;
8961 0 : delete poStylePart;
8962 :
8963 0 : return;
8964 : }
8965 :
8966 : /**********************************************************************
8967 : * ITABFeatureSymbol::DumpSymbolDef()
8968 : *
8969 : * Dump Symbol definition information.
8970 : **********************************************************************/
8971 0 : void ITABFeatureSymbol::DumpSymbolDef(FILE *fpOut /*=NULL*/)
8972 : {
8973 0 : if (fpOut == NULL)
8974 0 : fpOut = stdout;
8975 :
8976 0 : fprintf(fpOut, " m_nSymbolDefIndex = %d\n", m_nSymbolDefIndex);
8977 0 : fprintf(fpOut, " m_sSymbolDef.nRefCount = %d\n", m_sSymbolDef.nRefCount);
8978 0 : fprintf(fpOut, " m_sSymbolDef.nSymbolNo = %d\n", m_sSymbolDef.nSymbolNo);
8979 0 : fprintf(fpOut, " m_sSymbolDef.nPointSize = %d\n",m_sSymbolDef.nPointSize);
8980 : fprintf(fpOut, " m_sSymbolDef._unknown_ = %d\n",
8981 0 : (int)m_sSymbolDef._nUnknownValue_);
8982 : fprintf(fpOut, " m_sSymbolDef.rgbColor = 0x%6.6x (%d)\n",
8983 0 : m_sSymbolDef.rgbColor, m_sSymbolDef.rgbColor);
8984 :
8985 0 : fflush(fpOut);
8986 0 : }
|