1 : /******************************************************************************
2 : * $Id: ogrdxflayer.cpp 25030 2012-10-02 22:08:36Z rouault $
3 : *
4 : * Project: DXF Translator
5 : * Purpose: Implements OGRDXFLayer class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2009, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "ogr_dxf.h"
31 : #include "cpl_conv.h"
32 : #include "ogrdxf_polyline_smooth.h"
33 :
34 : CPL_CVSID("$Id: ogrdxflayer.cpp 25030 2012-10-02 22:08:36Z rouault $");
35 :
36 : #ifndef PI
37 : #define PI 3.14159265358979323846
38 : #endif
39 :
40 : /************************************************************************/
41 : /* OGRDXFLayer() */
42 : /************************************************************************/
43 :
44 23 : OGRDXFLayer::OGRDXFLayer( OGRDXFDataSource *poDS )
45 :
46 : {
47 23 : this->poDS = poDS;
48 :
49 23 : iNextFID = 0;
50 :
51 23 : poFeatureDefn = new OGRFeatureDefn( "entities" );
52 23 : poFeatureDefn->Reference();
53 :
54 23 : poDS->AddStandardFields( poFeatureDefn );
55 :
56 23 : if( !poDS->InlineBlocks() )
57 : {
58 1 : OGRFieldDefn oScaleField( "BlockScale", OFTRealList );
59 1 : poFeatureDefn->AddFieldDefn( &oScaleField );
60 :
61 1 : OGRFieldDefn oBlockAngleField( "BlockAngle", OFTReal );
62 1 : poFeatureDefn->AddFieldDefn( &oBlockAngleField );
63 : }
64 23 : }
65 :
66 : /************************************************************************/
67 : /* ~OGRDXFLayer() */
68 : /************************************************************************/
69 :
70 23 : OGRDXFLayer::~OGRDXFLayer()
71 :
72 : {
73 23 : ClearPendingFeatures();
74 23 : if( m_nFeaturesRead > 0 && poFeatureDefn != NULL )
75 : {
76 : CPLDebug( "DXF", "%d features read on layer '%s'.",
77 : (int) m_nFeaturesRead,
78 19 : poFeatureDefn->GetName() );
79 : }
80 :
81 23 : if( poFeatureDefn )
82 23 : poFeatureDefn->Release();
83 23 : }
84 :
85 : /************************************************************************/
86 : /* ClearPendingFeatures() */
87 : /************************************************************************/
88 :
89 41 : void OGRDXFLayer::ClearPendingFeatures()
90 :
91 : {
92 82 : while( !apoPendingFeatures.empty() )
93 : {
94 0 : delete apoPendingFeatures.front();
95 0 : apoPendingFeatures.pop();
96 : }
97 41 : }
98 :
99 : /************************************************************************/
100 : /* ResetReading() */
101 : /************************************************************************/
102 :
103 18 : void OGRDXFLayer::ResetReading()
104 :
105 : {
106 18 : iNextFID = 0;
107 18 : ClearPendingFeatures();
108 18 : poDS->RestartEntities();
109 18 : }
110 :
111 : /************************************************************************/
112 : /* TranslateGenericProperty() */
113 : /* */
114 : /* Try and convert entity properties handled similarly for most */
115 : /* or all entity types. */
116 : /************************************************************************/
117 :
118 841 : void OGRDXFLayer::TranslateGenericProperty( OGRFeature *poFeature,
119 : int nCode, char *pszValue )
120 :
121 : {
122 841 : switch( nCode )
123 : {
124 : case 8:
125 103 : poFeature->SetField( "Layer", TextUnescape(pszValue) );
126 103 : break;
127 :
128 : case 100:
129 : {
130 216 : CPLString osSubClass = poFeature->GetFieldAsString("SubClasses");
131 216 : if( osSubClass.size() > 0 )
132 117 : osSubClass += ":";
133 216 : osSubClass += pszValue;
134 216 : poFeature->SetField( "SubClasses", osSubClass.c_str() );
135 : }
136 216 : break;
137 :
138 : case 62:
139 89 : oStyleProperties["Color"] = pszValue;
140 89 : break;
141 :
142 : case 6:
143 86 : poFeature->SetField( "Linetype", TextUnescape(pszValue) );
144 86 : break;
145 :
146 : case 370:
147 : case 39:
148 86 : oStyleProperties["LineWeight"] = pszValue;
149 86 : break;
150 :
151 : case 5:
152 99 : poFeature->SetField( "EntityHandle", pszValue );
153 99 : break;
154 :
155 : // Extended entity data
156 : case 1000:
157 : case 1002:
158 : case 1004:
159 : case 1005:
160 : case 1040:
161 : case 1041:
162 : case 1070:
163 : case 1071:
164 : {
165 0 : CPLString osAggregate = poFeature->GetFieldAsString("ExtendedEntity");
166 :
167 0 : if( osAggregate.size() > 0 )
168 0 : osAggregate += " ";
169 0 : osAggregate += pszValue;
170 :
171 0 : poFeature->SetField( "ExtendedEntity", osAggregate );
172 : }
173 0 : break;
174 :
175 : // OCS vector.
176 : case 210:
177 4 : oStyleProperties["210_N.dX"] = pszValue;
178 4 : break;
179 :
180 : case 220:
181 4 : oStyleProperties["220_N.dY"] = pszValue;
182 4 : break;
183 :
184 : case 230:
185 4 : oStyleProperties["230_N.dZ"] = pszValue;
186 : break;
187 :
188 :
189 : default:
190 : break;
191 : }
192 841 : }
193 :
194 : /************************************************************************/
195 : /* PrepareLineStyle() */
196 : /************************************************************************/
197 :
198 92 : void OGRDXFLayer::PrepareLineStyle( OGRFeature *poFeature )
199 :
200 : {
201 92 : CPLString osLayer = poFeature->GetFieldAsString("Layer");
202 :
203 : /* -------------------------------------------------------------------- */
204 : /* Is the layer disabled/hidden/frozen/off? */
205 : /* -------------------------------------------------------------------- */
206 : int bHidden =
207 92 : EQUAL(poDS->LookupLayerProperty( osLayer, "Hidden" ), "1");
208 :
209 : /* -------------------------------------------------------------------- */
210 : /* Work out the color for this feature. */
211 : /* -------------------------------------------------------------------- */
212 92 : int nColor = 256;
213 :
214 92 : if( oStyleProperties.count("Color") > 0 )
215 78 : nColor = atoi(oStyleProperties["Color"]);
216 :
217 : // Use layer color?
218 92 : if( nColor < 1 || nColor > 255 )
219 : {
220 87 : const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
221 87 : if( pszValue != NULL )
222 87 : nColor = atoi(pszValue);
223 : }
224 :
225 92 : if( nColor < 1 || nColor > 255 )
226 : return;
227 :
228 : /* -------------------------------------------------------------------- */
229 : /* Get line weight if available. */
230 : /* -------------------------------------------------------------------- */
231 84 : double dfWeight = 0.0;
232 :
233 84 : if( oStyleProperties.count("LineWeight") > 0 )
234 : {
235 75 : CPLString osWeight = oStyleProperties["LineWeight"];
236 :
237 75 : if( osWeight == "-1" )
238 70 : osWeight = poDS->LookupLayerProperty(osLayer,"LineWeight");
239 :
240 75 : dfWeight = CPLAtof(osWeight) / 100.0;
241 : }
242 :
243 : /* -------------------------------------------------------------------- */
244 : /* Do we have a dash/dot line style? */
245 : /* -------------------------------------------------------------------- */
246 : const char *pszPattern = poDS->LookupLineType(
247 84 : poFeature->GetFieldAsString("Linetype") );
248 :
249 : /* -------------------------------------------------------------------- */
250 : /* Format the style string. */
251 : /* -------------------------------------------------------------------- */
252 84 : CPLString osStyle;
253 84 : const unsigned char *pabyDXFColors = ACGetColorTable();
254 :
255 : osStyle.Printf( "PEN(c:#%02x%02x%02x",
256 84 : pabyDXFColors[nColor*3+0],
257 84 : pabyDXFColors[nColor*3+1],
258 252 : pabyDXFColors[nColor*3+2] );
259 :
260 84 : if( bHidden )
261 0 : osStyle += "00";
262 :
263 84 : if( dfWeight > 0.0 )
264 : {
265 : char szBuffer[64];
266 3 : snprintf(szBuffer, sizeof(szBuffer), "%.2g", dfWeight);
267 3 : char* pszComma = strchr(szBuffer, ',');
268 3 : if (pszComma)
269 0 : *pszComma = '.';
270 3 : osStyle += CPLString().Printf( ",w:%sg", szBuffer );
271 : }
272 :
273 84 : if( pszPattern )
274 : {
275 3 : osStyle += ",p:\"";
276 3 : osStyle += pszPattern;
277 3 : osStyle += "\"";
278 : }
279 :
280 84 : osStyle += ")";
281 :
282 84 : poFeature->SetStyleString( osStyle );
283 : }
284 :
285 : /************************************************************************/
286 : /* OCSTransformer */
287 : /************************************************************************/
288 :
289 : class OCSTransformer : public OGRCoordinateTransformation
290 4 : {
291 : private:
292 : double adfN[3];
293 : double adfAX[3];
294 : double adfAY[3];
295 :
296 : public:
297 4 : OCSTransformer( double adfN[3] ) {
298 : static const double dSmall = 1.0 / 64.0;
299 : static const double adfWZ[3] = {0, 0, 1};
300 : static const double adfWY[3] = {0, 1, 0};
301 :
302 4 : memcpy( this->adfN, adfN, sizeof(double)*3 );
303 :
304 7 : if ((ABS(adfN[0]) < dSmall) && (ABS(adfN[1]) < dSmall))
305 3 : CrossProduct(adfWY, adfN, adfAX);
306 : else
307 1 : CrossProduct(adfWZ, adfN, adfAX);
308 :
309 4 : Scale2Unit( adfAX );
310 4 : CrossProduct(adfN, adfAX, adfAY);
311 4 : Scale2Unit( adfAY );
312 4 : }
313 :
314 8 : void CrossProduct(const double *a, const double *b, double *vResult) {
315 8 : vResult[0] = a[1] * b[2] - a[2] * b[1];
316 8 : vResult[1] = a[2] * b[0] - a[0] * b[2];
317 8 : vResult[2] = a[0] * b[1] - a[1] * b[0];
318 8 : }
319 :
320 8 : void Scale2Unit(double* adfV) {
321 8 : double dfLen=sqrt(adfV[0]*adfV[0] + adfV[1]*adfV[1] + adfV[2]*adfV[2]);
322 8 : if (dfLen != 0)
323 : {
324 8 : adfV[0] /= dfLen;
325 8 : adfV[1] /= dfLen;
326 8 : adfV[2] /= dfLen;
327 : }
328 8 : }
329 0 : OGRSpatialReference *GetSourceCS() { return NULL; }
330 8 : OGRSpatialReference *GetTargetCS() { return NULL; }
331 0 : int Transform( int nCount,
332 : double *x, double *y, double *z )
333 0 : { return TransformEx( nCount, x, y, z, NULL ); }
334 :
335 5 : int TransformEx( int nCount,
336 : double *adfX, double *adfY, double *adfZ = NULL,
337 : int *pabSuccess = NULL )
338 : {
339 : int i;
340 26 : for( i = 0; i < nCount; i++ )
341 : {
342 21 : double x = adfX[i], y = adfY[i], z = adfZ[i];
343 :
344 21 : adfX[i] = x * adfAX[0] + y * adfAY[0] + z * adfN[0];
345 21 : adfY[i] = x * adfAX[1] + y * adfAY[1] + z * adfN[1];
346 21 : adfZ[i] = x * adfAX[2] + y * adfAY[2] + z * adfN[2];
347 :
348 21 : if( pabSuccess )
349 21 : pabSuccess[i] = TRUE;
350 : }
351 5 : return TRUE;
352 : }
353 : };
354 :
355 : /************************************************************************/
356 : /* ApplyOCSTransformer() */
357 : /* */
358 : /* Apply a transformation from OCS to world coordinates if an */
359 : /* OCS vector was found in the object. */
360 : /************************************************************************/
361 :
362 89 : void OGRDXFLayer::ApplyOCSTransformer( OGRGeometry *poGeometry )
363 :
364 : {
365 89 : if( oStyleProperties.count("210_N.dX") == 0
366 : || oStyleProperties.count("220_N.dY") == 0
367 : || oStyleProperties.count("230_N.dZ") == 0 )
368 85 : return;
369 :
370 4 : if( poGeometry == NULL )
371 0 : return;
372 :
373 : double adfN[3];
374 :
375 4 : adfN[0] = CPLAtof(oStyleProperties["210_N.dX"]);
376 8 : adfN[1] = CPLAtof(oStyleProperties["220_N.dY"]);
377 8 : adfN[2] = CPLAtof(oStyleProperties["230_N.dZ"]);
378 :
379 4 : OCSTransformer oTransformer( adfN );
380 :
381 8 : poGeometry->transform( &oTransformer );
382 : }
383 :
384 : /************************************************************************/
385 : /* TextUnescape() */
386 : /* */
387 : /* Unexcape DXF style escape sequences such as \P for newline */
388 : /* and \~ for space, and do the recoding to UTF8. */
389 : /************************************************************************/
390 :
391 198 : CPLString OGRDXFLayer::TextUnescape( const char *pszInput )
392 :
393 : {
394 198 : return ACTextUnescape( pszInput, poDS->GetEncoding() );
395 : }
396 :
397 : /************************************************************************/
398 : /* TranslateMTEXT() */
399 : /************************************************************************/
400 :
401 9 : OGRFeature *OGRDXFLayer::TranslateMTEXT()
402 :
403 : {
404 : char szLineBuf[257];
405 : int nCode;
406 9 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
407 9 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
408 9 : double dfAngle = 0.0;
409 9 : double dfHeight = 0.0;
410 9 : double dfXDirection = 0.0, dfYDirection = 0.0;
411 9 : int bHaveZ = FALSE;
412 9 : int nAttachmentPoint = -1;
413 9 : CPLString osText;
414 :
415 166 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
416 : {
417 148 : switch( nCode )
418 : {
419 : case 10:
420 9 : dfX = CPLAtof(szLineBuf);
421 9 : break;
422 :
423 : case 20:
424 9 : dfY = CPLAtof(szLineBuf);
425 9 : break;
426 :
427 : case 30:
428 6 : dfZ = CPLAtof(szLineBuf);
429 6 : bHaveZ = TRUE;
430 6 : break;
431 :
432 : case 40:
433 9 : dfHeight = CPLAtof(szLineBuf);
434 9 : break;
435 :
436 : case 71:
437 7 : nAttachmentPoint = atoi(szLineBuf);
438 7 : break;
439 :
440 : case 11:
441 0 : dfXDirection = CPLAtof(szLineBuf);
442 0 : break;
443 :
444 : case 21:
445 0 : dfYDirection = CPLAtof(szLineBuf);
446 0 : dfAngle = atan2( dfYDirection, dfXDirection ) * 180.0 / PI;
447 0 : break;
448 :
449 : case 1:
450 : case 3:
451 9 : if( osText != "" )
452 0 : osText += "\n";
453 9 : osText += TextUnescape(szLineBuf);
454 9 : break;
455 :
456 : case 50:
457 9 : dfAngle = CPLAtof(szLineBuf);
458 9 : break;
459 :
460 : default:
461 90 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
462 : break;
463 : }
464 : }
465 :
466 9 : if( nCode == 0 )
467 9 : poDS->UnreadValue();
468 :
469 : OGRPoint* poGeom;
470 9 : if( bHaveZ )
471 6 : poGeom = new OGRPoint( dfX, dfY, dfZ );
472 : else
473 3 : poGeom = new OGRPoint( dfX, dfY );
474 9 : ApplyOCSTransformer( poGeom );
475 9 : poFeature->SetGeometryDirectly( poGeom );
476 :
477 : /* -------------------------------------------------------------------- */
478 : /* Apply text after stripping off any extra terminating newline. */
479 : /* -------------------------------------------------------------------- */
480 9 : if( osText != "" && osText[osText.size()-1] == '\n' )
481 0 : osText.resize( osText.size() - 1 );
482 :
483 9 : poFeature->SetField( "Text", osText );
484 :
485 :
486 : /* -------------------------------------------------------------------- */
487 : /* We need to escape double quotes with backslashes before they */
488 : /* can be inserted in the style string. */
489 : /* -------------------------------------------------------------------- */
490 9 : if( strchr( osText, '"') != NULL )
491 : {
492 2 : CPLString osEscaped;
493 : size_t iC;
494 :
495 46 : for( iC = 0; iC < osText.size(); iC++ )
496 : {
497 44 : if( osText[iC] == '"' )
498 4 : osEscaped += "\\\"";
499 : else
500 40 : osEscaped += osText[iC];
501 : }
502 2 : osText = osEscaped;
503 : }
504 :
505 : /* -------------------------------------------------------------------- */
506 : /* Work out the color for this feature. */
507 : /* -------------------------------------------------------------------- */
508 9 : int nColor = 256;
509 :
510 9 : if( oStyleProperties.count("Color") > 0 )
511 9 : nColor = atoi(oStyleProperties["Color"]);
512 :
513 : // Use layer color?
514 9 : if( nColor < 1 || nColor > 255 )
515 : {
516 7 : CPLString osLayer = poFeature->GetFieldAsString("Layer");
517 7 : const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
518 7 : if( pszValue != NULL )
519 7 : nColor = atoi(pszValue);
520 : }
521 :
522 : /* -------------------------------------------------------------------- */
523 : /* Prepare style string. */
524 : /* -------------------------------------------------------------------- */
525 9 : CPLString osStyle;
526 : char szBuffer[64];
527 : char* pszComma;
528 :
529 9 : osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\"",osText.c_str());
530 :
531 9 : if( dfAngle != 0.0 )
532 : {
533 7 : snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
534 7 : pszComma = strchr(szBuffer, ',');
535 7 : if (pszComma)
536 0 : *pszComma = '.';
537 7 : osStyle += CPLString().Printf(",a:%s", szBuffer);
538 : }
539 :
540 9 : if( dfHeight != 0.0 )
541 : {
542 9 : snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
543 9 : pszComma = strchr(szBuffer, ',');
544 9 : if (pszComma)
545 0 : *pszComma = '.';
546 9 : osStyle += CPLString().Printf(",s:%sg", szBuffer);
547 : }
548 :
549 9 : if( nAttachmentPoint >= 0 && nAttachmentPoint <= 9 )
550 : {
551 : const static int anAttachmentMap[10] =
552 : { -1, 7, 8, 9, 4, 5, 6, 1, 2, 3 };
553 :
554 : osStyle +=
555 7 : CPLString().Printf(",p:%d", anAttachmentMap[nAttachmentPoint]);
556 : }
557 :
558 9 : if( nColor > 0 && nColor < 256 )
559 : {
560 9 : const unsigned char *pabyDXFColors = ACGetColorTable();
561 : osStyle +=
562 : CPLString().Printf( ",c:#%02x%02x%02x",
563 9 : pabyDXFColors[nColor*3+0],
564 9 : pabyDXFColors[nColor*3+1],
565 27 : pabyDXFColors[nColor*3+2] );
566 : }
567 :
568 9 : osStyle += ")";
569 :
570 9 : poFeature->SetStyleString( osStyle );
571 :
572 9 : return poFeature;
573 : }
574 :
575 : /************************************************************************/
576 : /* TranslateTEXT() */
577 : /************************************************************************/
578 :
579 0 : OGRFeature *OGRDXFLayer::TranslateTEXT()
580 :
581 : {
582 : char szLineBuf[257];
583 : int nCode;
584 0 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
585 0 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
586 0 : double dfAngle = 0.0;
587 0 : double dfHeight = 0.0;
588 0 : CPLString osText;
589 0 : int bHaveZ = FALSE;
590 :
591 0 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
592 : {
593 0 : switch( nCode )
594 : {
595 : case 10:
596 0 : dfX = CPLAtof(szLineBuf);
597 0 : break;
598 :
599 : case 20:
600 0 : dfY = CPLAtof(szLineBuf);
601 0 : break;
602 :
603 : case 30:
604 0 : dfZ = CPLAtof(szLineBuf);
605 0 : bHaveZ = TRUE;
606 0 : break;
607 :
608 : case 40:
609 0 : dfHeight = CPLAtof(szLineBuf);
610 0 : break;
611 :
612 : case 1:
613 : // case 3: // we used to capture prompt, but it should not be displayed as text.
614 0 : osText += szLineBuf;
615 0 : break;
616 :
617 : case 50:
618 0 : dfAngle = CPLAtof(szLineBuf);
619 0 : break;
620 :
621 : default:
622 0 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
623 : break;
624 : }
625 : }
626 :
627 0 : if( nCode == 0 )
628 0 : poDS->UnreadValue();
629 :
630 : OGRPoint* poGeom;
631 0 : if( bHaveZ )
632 0 : poGeom = new OGRPoint( dfX, dfY, dfZ );
633 : else
634 0 : poGeom = new OGRPoint( dfX, dfY );
635 0 : ApplyOCSTransformer( poGeom );
636 0 : poFeature->SetGeometryDirectly( poGeom );
637 :
638 : /* -------------------------------------------------------------------- */
639 : /* Translate text from Win-1252 to UTF8. We approximate this */
640 : /* by treating Win-1252 as Latin-1. */
641 : /* -------------------------------------------------------------------- */
642 0 : osText.Recode( poDS->GetEncoding(), CPL_ENC_UTF8 );
643 :
644 0 : poFeature->SetField( "Text", osText );
645 :
646 : /* -------------------------------------------------------------------- */
647 : /* We need to escape double quotes with backslashes before they */
648 : /* can be inserted in the style string. */
649 : /* -------------------------------------------------------------------- */
650 0 : if( strchr( osText, '"') != NULL )
651 : {
652 0 : CPLString osEscaped;
653 : size_t iC;
654 :
655 0 : for( iC = 0; iC < osText.size(); iC++ )
656 : {
657 0 : if( osText[iC] == '"' )
658 0 : osEscaped += "\\\"";
659 : else
660 0 : osEscaped += osText[iC];
661 : }
662 0 : osText = osEscaped;
663 : }
664 :
665 : /* -------------------------------------------------------------------- */
666 : /* Is the layer disabled/hidden/frozen/off? */
667 : /* -------------------------------------------------------------------- */
668 0 : CPLString osLayer = poFeature->GetFieldAsString("Layer");
669 :
670 : int bHidden =
671 0 : EQUAL(poDS->LookupLayerProperty( osLayer, "Hidden" ), "1");
672 :
673 : /* -------------------------------------------------------------------- */
674 : /* Work out the color for this feature. */
675 : /* -------------------------------------------------------------------- */
676 0 : int nColor = 256;
677 :
678 0 : if( oStyleProperties.count("Color") > 0 )
679 0 : nColor = atoi(oStyleProperties["Color"]);
680 :
681 : // Use layer color?
682 0 : if( nColor < 1 || nColor > 255 )
683 : {
684 0 : const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
685 0 : if( pszValue != NULL )
686 0 : nColor = atoi(pszValue);
687 : }
688 :
689 0 : if( nColor < 1 || nColor > 255 )
690 0 : nColor = 8;
691 :
692 : /* -------------------------------------------------------------------- */
693 : /* Prepare style string. */
694 : /* -------------------------------------------------------------------- */
695 0 : CPLString osStyle;
696 : char szBuffer[64];
697 : char* pszComma;
698 :
699 0 : osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\"",osText.c_str());
700 :
701 0 : if( dfAngle != 0.0 )
702 : {
703 0 : snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
704 0 : pszComma = strchr(szBuffer, ',');
705 0 : if (pszComma)
706 0 : *pszComma = '.';
707 0 : osStyle += CPLString().Printf(",a:%s", szBuffer);
708 : }
709 :
710 0 : if( dfHeight != 0.0 )
711 : {
712 0 : snprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
713 0 : pszComma = strchr(szBuffer, ',');
714 0 : if (pszComma)
715 0 : *pszComma = '.';
716 0 : osStyle += CPLString().Printf(",s:%sg", szBuffer);
717 : }
718 :
719 0 : const unsigned char *pabyDWGColors = ACGetColorTable();
720 :
721 : snprintf( szBuffer, sizeof(szBuffer), ",c:#%02x%02x%02x",
722 0 : pabyDWGColors[nColor*3+0],
723 0 : pabyDWGColors[nColor*3+1],
724 0 : pabyDWGColors[nColor*3+2] );
725 0 : osStyle += szBuffer;
726 :
727 0 : if( bHidden )
728 0 : osStyle += "00";
729 :
730 0 : osStyle += ")";
731 :
732 0 : poFeature->SetStyleString( osStyle );
733 :
734 0 : return poFeature;
735 : }
736 :
737 : /************************************************************************/
738 : /* TranslatePOINT() */
739 : /************************************************************************/
740 :
741 6 : OGRFeature *OGRDXFLayer::TranslatePOINT()
742 :
743 : {
744 : char szLineBuf[257];
745 : int nCode;
746 6 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
747 6 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
748 6 : int bHaveZ = FALSE;
749 :
750 56 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
751 : {
752 44 : switch( nCode )
753 : {
754 : case 10:
755 6 : dfX = CPLAtof(szLineBuf);
756 6 : break;
757 :
758 : case 20:
759 6 : dfY = CPLAtof(szLineBuf);
760 6 : break;
761 :
762 : case 30:
763 5 : dfZ = CPLAtof(szLineBuf);
764 5 : bHaveZ = TRUE;
765 5 : break;
766 :
767 : default:
768 27 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
769 : break;
770 : }
771 : }
772 :
773 : OGRPoint* poGeom;
774 6 : if( bHaveZ )
775 5 : poGeom = new OGRPoint( dfX, dfY, dfZ );
776 : else
777 1 : poGeom = new OGRPoint( dfX, dfY );
778 6 : ApplyOCSTransformer( poGeom );
779 6 : poFeature->SetGeometryDirectly( poGeom );
780 :
781 6 : if( nCode == 0 )
782 6 : poDS->UnreadValue();
783 :
784 : // Set style pen color
785 6 : PrepareLineStyle( poFeature );
786 :
787 6 : return poFeature;
788 : }
789 :
790 : /************************************************************************/
791 : /* TranslateLINE() */
792 : /************************************************************************/
793 :
794 49 : OGRFeature *OGRDXFLayer::TranslateLINE()
795 :
796 : {
797 : char szLineBuf[257];
798 : int nCode;
799 49 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
800 49 : double dfX1 = 0.0, dfY1 = 0.0, dfZ1 = 0.0;
801 49 : double dfX2 = 0.0, dfY2 = 0.0, dfZ2 = 0.0;
802 49 : int bHaveZ = FALSE;
803 :
804 : /* -------------------------------------------------------------------- */
805 : /* Process values. */
806 : /* -------------------------------------------------------------------- */
807 738 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
808 : {
809 640 : switch( nCode )
810 : {
811 : case 10:
812 49 : dfX1 = CPLAtof(szLineBuf);
813 49 : break;
814 :
815 : case 11:
816 49 : dfX2 = CPLAtof(szLineBuf);
817 49 : break;
818 :
819 : case 20:
820 49 : dfY1 = CPLAtof(szLineBuf);
821 49 : break;
822 :
823 : case 21:
824 49 : dfY2 = CPLAtof(szLineBuf);
825 49 : break;
826 :
827 : case 30:
828 49 : dfZ1 = CPLAtof(szLineBuf);
829 49 : bHaveZ = TRUE;
830 49 : break;
831 :
832 : case 31:
833 49 : dfZ2 = CPLAtof(szLineBuf);
834 49 : bHaveZ = TRUE;
835 49 : break;
836 :
837 : default:
838 346 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
839 : break;
840 : }
841 : }
842 :
843 49 : if( nCode == 0 )
844 49 : poDS->UnreadValue();
845 :
846 : /* -------------------------------------------------------------------- */
847 : /* Create geometry */
848 : /* -------------------------------------------------------------------- */
849 49 : OGRLineString *poLS = new OGRLineString();
850 49 : if( bHaveZ )
851 : {
852 49 : poLS->addPoint( dfX1, dfY1, dfZ1 );
853 49 : poLS->addPoint( dfX2, dfY2, dfZ2 );
854 : }
855 : else
856 : {
857 0 : poLS->addPoint( dfX1, dfY1 );
858 0 : poLS->addPoint( dfX2, dfY2 );
859 : }
860 :
861 49 : ApplyOCSTransformer( poLS );
862 49 : poFeature->SetGeometryDirectly( poLS );
863 :
864 49 : PrepareLineStyle( poFeature );
865 :
866 49 : return poFeature;
867 : }
868 :
869 : /************************************************************************/
870 : /* TranslateLWPOLYLINE() */
871 : /************************************************************************/
872 10 : OGRFeature *OGRDXFLayer::TranslateLWPOLYLINE()
873 :
874 : {
875 : // Collect vertices and attributes into a smooth polyline.
876 : // If there are no bulges, then we are a straight-line polyline.
877 : // Single-vertex polylines become points.
878 : // Group code 30 (vertex Z) is not part of this entity.
879 :
880 : char szLineBuf[257];
881 : int nCode;
882 10 : int nPolylineFlag = 0;
883 :
884 :
885 10 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
886 10 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
887 10 : int bHaveX = FALSE;
888 10 : int bHaveY = FALSE;
889 :
890 10 : int nNumVertices = 1; // use 1 based index
891 10 : int npolyarcVertexCount = 1;
892 10 : double dfBulge = 0.0;
893 10 : DXFSmoothPolyline smoothPolyline;
894 :
895 10 : smoothPolyline.setCoordinateDimension(2);
896 :
897 : /* -------------------------------------------------------------------- */
898 : /* Collect information from the LWPOLYLINE object itself. */
899 : /* -------------------------------------------------------------------- */
900 161 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
901 : {
902 141 : if(npolyarcVertexCount > nNumVertices)
903 : {
904 : CPLError( CE_Failure, CPLE_AppDefined,
905 0 : "Too many vertices found in LWPOLYLINE." );
906 0 : delete poFeature;
907 0 : return NULL;
908 : }
909 :
910 141 : switch( nCode )
911 : {
912 : case 38:
913 : // Constant elevation.
914 1 : dfZ = CPLAtof(szLineBuf);
915 1 : smoothPolyline.setCoordinateDimension(3);
916 1 : break;
917 :
918 : case 90:
919 10 : nNumVertices = atoi(szLineBuf);
920 10 : break;
921 :
922 : case 70:
923 10 : nPolylineFlag = atoi(szLineBuf);
924 10 : break;
925 :
926 : case 10:
927 27 : if( bHaveX && bHaveY )
928 : {
929 17 : smoothPolyline.AddPoint(dfX, dfY, dfZ, dfBulge);
930 17 : npolyarcVertexCount++;
931 17 : dfBulge = 0.0;
932 17 : bHaveY = FALSE;
933 : }
934 27 : dfX = CPLAtof(szLineBuf);
935 27 : bHaveX = TRUE;
936 27 : break;
937 :
938 : case 20:
939 27 : if( bHaveX && bHaveY )
940 : {
941 0 : smoothPolyline.AddPoint( dfX, dfY, dfZ, dfBulge );
942 0 : npolyarcVertexCount++;
943 0 : dfBulge = 0.0;
944 0 : bHaveX = FALSE;
945 : }
946 27 : dfY = CPLAtof(szLineBuf);
947 27 : bHaveY = TRUE;
948 27 : break;
949 :
950 : case 42:
951 4 : dfBulge = CPLAtof(szLineBuf);
952 4 : break;
953 :
954 :
955 : default:
956 62 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
957 : break;
958 : }
959 : }
960 :
961 10 : if( nCode == 0 )
962 10 : poDS->UnreadValue();
963 :
964 10 : if( bHaveX && bHaveY )
965 10 : smoothPolyline.AddPoint(dfX, dfY, dfZ, dfBulge);
966 :
967 :
968 10 : if(smoothPolyline.IsEmpty())
969 : {
970 0 : delete poFeature;
971 0 : return NULL;
972 : }
973 :
974 : /* -------------------------------------------------------------------- */
975 : /* Close polyline if necessary. */
976 : /* -------------------------------------------------------------------- */
977 10 : if(nPolylineFlag & 0x01)
978 1 : smoothPolyline.Close();
979 :
980 10 : OGRGeometry* poGeom = smoothPolyline.Tesselate();
981 10 : ApplyOCSTransformer( poGeom );
982 10 : poFeature->SetGeometryDirectly( poGeom );
983 :
984 10 : PrepareLineStyle( poFeature );
985 :
986 10 : return poFeature;
987 : }
988 :
989 :
990 : /************************************************************************/
991 : /* TranslatePOLYLINE() */
992 : /* */
993 : /* We also capture the following VERTEXes. */
994 : /************************************************************************/
995 :
996 1 : OGRFeature *OGRDXFLayer::TranslatePOLYLINE()
997 :
998 : {
999 : char szLineBuf[257];
1000 : int nCode;
1001 1 : int nPolylineFlag = 0;
1002 1 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1003 :
1004 : /* -------------------------------------------------------------------- */
1005 : /* Collect information from the POLYLINE object itself. */
1006 : /* -------------------------------------------------------------------- */
1007 8 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1008 : {
1009 6 : switch( nCode )
1010 : {
1011 : case 70:
1012 1 : nPolylineFlag = atoi(szLineBuf);
1013 1 : break;
1014 :
1015 : default:
1016 5 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
1017 : break;
1018 : }
1019 : }
1020 :
1021 : /* -------------------------------------------------------------------- */
1022 : /* Collect VERTEXes as a smooth polyline. */
1023 : /* -------------------------------------------------------------------- */
1024 1 : double dfX = 0.0, dfY = 0.0, dfZ = 0.0;
1025 1 : double dfBulge = 0.0;
1026 1 : DXFSmoothPolyline smoothPolyline;
1027 1 : int nVertexFlag = 0;
1028 :
1029 1 : smoothPolyline.setCoordinateDimension(2);
1030 :
1031 7 : while( nCode == 0 && !EQUAL(szLineBuf,"SEQEND") )
1032 : {
1033 : // Eat non-vertex objects.
1034 5 : if( !EQUAL(szLineBuf,"VERTEX") )
1035 : {
1036 0 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf)))>0 ) {}
1037 0 : continue;
1038 : }
1039 :
1040 : // process a Vertex
1041 39 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1042 : {
1043 29 : switch( nCode )
1044 : {
1045 : case 10:
1046 5 : dfX = CPLAtof(szLineBuf);
1047 5 : break;
1048 :
1049 : case 20:
1050 5 : dfY = CPLAtof(szLineBuf);
1051 5 : break;
1052 :
1053 : case 30:
1054 5 : dfZ = CPLAtof(szLineBuf);
1055 5 : smoothPolyline.setCoordinateDimension(3);
1056 5 : break;
1057 :
1058 : case 42:
1059 4 : dfBulge = CPLAtof(szLineBuf);
1060 4 : break;
1061 :
1062 : case 70:
1063 0 : nVertexFlag = atoi(szLineBuf);
1064 : break;
1065 :
1066 : default:
1067 : break;
1068 : }
1069 : }
1070 :
1071 : // Ignore Spline frame control points ( see #4683 )
1072 5 : if ((nVertexFlag & 16) == 0)
1073 5 : smoothPolyline.AddPoint( dfX, dfY, dfZ, dfBulge );
1074 5 : dfBulge = 0.0;
1075 : }
1076 :
1077 1 : if(smoothPolyline.IsEmpty())
1078 : {
1079 0 : delete poFeature;
1080 0 : return NULL;
1081 : }
1082 :
1083 : /* -------------------------------------------------------------------- */
1084 : /* Close polyline if necessary. */
1085 : /* -------------------------------------------------------------------- */
1086 1 : if(nPolylineFlag & 0x01)
1087 1 : smoothPolyline.Close();
1088 :
1089 1 : OGRGeometry* poGeom = smoothPolyline.Tesselate();
1090 1 : ApplyOCSTransformer( poGeom );
1091 1 : poFeature->SetGeometryDirectly( poGeom );
1092 :
1093 1 : PrepareLineStyle( poFeature );
1094 :
1095 1 : return poFeature;
1096 : }
1097 :
1098 : /************************************************************************/
1099 : /* TranslateCIRCLE() */
1100 : /************************************************************************/
1101 :
1102 1 : OGRFeature *OGRDXFLayer::TranslateCIRCLE()
1103 :
1104 : {
1105 : char szLineBuf[257];
1106 : int nCode;
1107 1 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1108 1 : double dfX1 = 0.0, dfY1 = 0.0, dfZ1 = 0.0, dfRadius = 0.0;
1109 1 : int bHaveZ = FALSE;
1110 :
1111 : /* -------------------------------------------------------------------- */
1112 : /* Process values. */
1113 : /* -------------------------------------------------------------------- */
1114 6 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1115 : {
1116 4 : switch( nCode )
1117 : {
1118 : case 10:
1119 1 : dfX1 = CPLAtof(szLineBuf);
1120 1 : break;
1121 :
1122 : case 20:
1123 1 : dfY1 = CPLAtof(szLineBuf);
1124 1 : break;
1125 :
1126 : case 30:
1127 1 : dfZ1 = CPLAtof(szLineBuf);
1128 1 : bHaveZ = TRUE;
1129 1 : break;
1130 :
1131 : case 40:
1132 1 : dfRadius = CPLAtof(szLineBuf);
1133 1 : break;
1134 :
1135 : default:
1136 0 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
1137 : break;
1138 : }
1139 : }
1140 :
1141 1 : if( nCode == 0 )
1142 1 : poDS->UnreadValue();
1143 :
1144 : /* -------------------------------------------------------------------- */
1145 : /* Create geometry */
1146 : /* -------------------------------------------------------------------- */
1147 : OGRGeometry *poCircle =
1148 : OGRGeometryFactory::approximateArcAngles( dfX1, dfY1, dfZ1,
1149 : dfRadius, dfRadius, 0.0,
1150 : 0.0, 360.0,
1151 1 : 0.0 );
1152 :
1153 1 : if( !bHaveZ )
1154 0 : poCircle->flattenTo2D();
1155 :
1156 1 : ApplyOCSTransformer( poCircle );
1157 1 : poFeature->SetGeometryDirectly( poCircle );
1158 1 : PrepareLineStyle( poFeature );
1159 :
1160 1 : return poFeature;
1161 : }
1162 :
1163 : /************************************************************************/
1164 : /* TranslateELLIPSE() */
1165 : /************************************************************************/
1166 :
1167 6 : OGRFeature *OGRDXFLayer::TranslateELLIPSE()
1168 :
1169 : {
1170 : char szLineBuf[257];
1171 : int nCode;
1172 6 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1173 6 : double dfX1 = 0.0, dfY1 = 0.0, dfZ1 = 0.0, dfRatio = 0.0;
1174 6 : double dfStartAngle = 0.0, dfEndAngle = 360.0;
1175 6 : double dfAxisX=0.0, dfAxisY=0.0, dfAxisZ=0.0;
1176 6 : int bHaveZ = FALSE;
1177 :
1178 : /* -------------------------------------------------------------------- */
1179 : /* Process values. */
1180 : /* -------------------------------------------------------------------- */
1181 108 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1182 : {
1183 96 : switch( nCode )
1184 : {
1185 : case 10:
1186 6 : dfX1 = CPLAtof(szLineBuf);
1187 6 : break;
1188 :
1189 : case 20:
1190 6 : dfY1 = CPLAtof(szLineBuf);
1191 6 : break;
1192 :
1193 : case 30:
1194 6 : dfZ1 = CPLAtof(szLineBuf);
1195 6 : bHaveZ = TRUE;
1196 6 : break;
1197 :
1198 : case 11:
1199 6 : dfAxisX = CPLAtof(szLineBuf);
1200 6 : break;
1201 :
1202 : case 21:
1203 6 : dfAxisY = CPLAtof(szLineBuf);
1204 6 : break;
1205 :
1206 : case 31:
1207 6 : dfAxisZ = CPLAtof(szLineBuf);
1208 6 : break;
1209 :
1210 : case 40:
1211 6 : dfRatio = CPLAtof(szLineBuf);
1212 6 : break;
1213 :
1214 : case 41:
1215 : // These *seem* to always be in radians regardless of $AUNITS
1216 6 : dfEndAngle = -1 * CPLAtof(szLineBuf) * 180.0 / PI;
1217 6 : break;
1218 :
1219 : case 42:
1220 : // These *seem* to always be in radians regardless of $AUNITS
1221 6 : dfStartAngle = -1 * CPLAtof(szLineBuf) * 180.0 / PI;
1222 6 : break;
1223 :
1224 : default:
1225 42 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
1226 : break;
1227 : }
1228 : }
1229 :
1230 6 : if( nCode == 0 )
1231 6 : poDS->UnreadValue();
1232 :
1233 : /* -------------------------------------------------------------------- */
1234 : /* Compute primary and secondary axis lengths, and the angle of */
1235 : /* rotation for the ellipse. */
1236 : /* -------------------------------------------------------------------- */
1237 : double dfPrimaryRadius, dfSecondaryRadius;
1238 : double dfRotation;
1239 :
1240 6 : if( dfStartAngle > dfEndAngle )
1241 0 : dfEndAngle += 360.0;
1242 :
1243 : dfPrimaryRadius = sqrt( dfAxisX * dfAxisX
1244 : + dfAxisY * dfAxisY
1245 6 : + dfAxisZ * dfAxisZ );
1246 :
1247 6 : dfSecondaryRadius = dfRatio * dfPrimaryRadius;
1248 :
1249 6 : dfRotation = -1 * atan2( dfAxisY, dfAxisX ) * 180 / PI;
1250 :
1251 : /* -------------------------------------------------------------------- */
1252 : /* Create geometry */
1253 : /* -------------------------------------------------------------------- */
1254 : OGRGeometry *poEllipse =
1255 : OGRGeometryFactory::approximateArcAngles( dfX1, dfY1, dfZ1,
1256 : dfPrimaryRadius,
1257 : dfSecondaryRadius,
1258 : dfRotation,
1259 : dfStartAngle, dfEndAngle,
1260 6 : 0.0 );
1261 :
1262 6 : if( !bHaveZ )
1263 0 : poEllipse->flattenTo2D();
1264 :
1265 6 : ApplyOCSTransformer( poEllipse );
1266 6 : poFeature->SetGeometryDirectly( poEllipse );
1267 :
1268 6 : PrepareLineStyle( poFeature );
1269 :
1270 6 : return poFeature;
1271 : }
1272 :
1273 : /************************************************************************/
1274 : /* TranslateARC() */
1275 : /************************************************************************/
1276 :
1277 3 : OGRFeature *OGRDXFLayer::TranslateARC()
1278 :
1279 : {
1280 : char szLineBuf[257];
1281 : int nCode;
1282 3 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1283 3 : double dfX1 = 0.0, dfY1 = 0.0, dfZ1 = 0.0, dfRadius = 0.0;
1284 3 : double dfStartAngle = 0.0, dfEndAngle = 360.0;
1285 3 : int bHaveZ = FALSE;
1286 :
1287 : /* -------------------------------------------------------------------- */
1288 : /* Process values. */
1289 : /* -------------------------------------------------------------------- */
1290 48 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1291 : {
1292 42 : switch( nCode )
1293 : {
1294 : case 10:
1295 3 : dfX1 = CPLAtof(szLineBuf);
1296 3 : break;
1297 :
1298 : case 20:
1299 3 : dfY1 = CPLAtof(szLineBuf);
1300 3 : break;
1301 :
1302 : case 30:
1303 3 : dfZ1 = CPLAtof(szLineBuf);
1304 3 : bHaveZ = TRUE;
1305 3 : break;
1306 :
1307 : case 40:
1308 3 : dfRadius = CPLAtof(szLineBuf);
1309 3 : break;
1310 :
1311 : case 50:
1312 : // This is apparently always degrees regardless of AUNITS
1313 3 : dfEndAngle = -1 * CPLAtof(szLineBuf);
1314 3 : break;
1315 :
1316 : case 51:
1317 : // This is apparently always degrees regardless of AUNITS
1318 3 : dfStartAngle = -1 * CPLAtof(szLineBuf);
1319 3 : break;
1320 :
1321 : default:
1322 24 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
1323 : break;
1324 : }
1325 : }
1326 :
1327 3 : if( nCode == 0 )
1328 3 : poDS->UnreadValue();
1329 :
1330 : /* -------------------------------------------------------------------- */
1331 : /* Create geometry */
1332 : /* -------------------------------------------------------------------- */
1333 3 : if( dfStartAngle > dfEndAngle )
1334 3 : dfEndAngle += 360.0;
1335 :
1336 : OGRGeometry *poArc =
1337 : OGRGeometryFactory::approximateArcAngles( dfX1, dfY1, dfZ1,
1338 : dfRadius, dfRadius, 0.0,
1339 : dfStartAngle, dfEndAngle,
1340 3 : 0.0 );
1341 3 : if( !bHaveZ )
1342 0 : poArc->flattenTo2D();
1343 :
1344 3 : ApplyOCSTransformer( poArc );
1345 3 : poFeature->SetGeometryDirectly( poArc );
1346 :
1347 3 : PrepareLineStyle( poFeature );
1348 :
1349 3 : return poFeature;
1350 : }
1351 :
1352 : /************************************************************************/
1353 : /* TranslateSPLINE() */
1354 : /************************************************************************/
1355 :
1356 : void rbspline(int npts,int k,int p1,double b[],double h[], double p[]);
1357 : void rbsplinu(int npts,int k,int p1,double b[],double h[], double p[]);
1358 :
1359 1 : OGRFeature *OGRDXFLayer::TranslateSPLINE()
1360 :
1361 : {
1362 : char szLineBuf[257];
1363 1 : int nCode, nDegree = -1, nFlags = -1, bClosed = FALSE, i;
1364 1 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1365 1 : std::vector<double> adfControlPoints;
1366 :
1367 1 : adfControlPoints.push_back(0.0);
1368 :
1369 : /* -------------------------------------------------------------------- */
1370 : /* Process values. */
1371 : /* -------------------------------------------------------------------- */
1372 50 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1373 : {
1374 48 : switch( nCode )
1375 : {
1376 : case 10:
1377 8 : adfControlPoints.push_back( CPLAtof(szLineBuf) );
1378 8 : break;
1379 :
1380 : case 20:
1381 8 : adfControlPoints.push_back( CPLAtof(szLineBuf) );
1382 8 : adfControlPoints.push_back( 0.0 );
1383 8 : break;
1384 :
1385 : case 70:
1386 1 : nFlags = atoi(szLineBuf);
1387 1 : if( nFlags & 1 )
1388 0 : bClosed = TRUE;
1389 1 : break;
1390 :
1391 : case 71:
1392 1 : nDegree = atoi(szLineBuf);
1393 1 : break;
1394 :
1395 : default:
1396 30 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
1397 : break;
1398 : }
1399 : }
1400 :
1401 1 : if( nCode == 0 )
1402 1 : poDS->UnreadValue();
1403 :
1404 1 : if( bClosed )
1405 : {
1406 0 : for( i = 0; i < nDegree; i++ )
1407 : {
1408 0 : adfControlPoints.push_back( adfControlPoints[i*3+1] );
1409 0 : adfControlPoints.push_back( adfControlPoints[i*3+2] );
1410 0 : adfControlPoints.push_back( adfControlPoints[i*3+3] );
1411 : }
1412 : }
1413 :
1414 : /* -------------------------------------------------------------------- */
1415 : /* Interpolate spline */
1416 : /* -------------------------------------------------------------------- */
1417 1 : int nControlPoints = adfControlPoints.size() / 3;
1418 1 : std::vector<double> h, p;
1419 :
1420 1 : h.push_back(1.0);
1421 9 : for( i = 0; i < nControlPoints; i++ )
1422 8 : h.push_back( 1.0 );
1423 :
1424 : // resolution:
1425 : //int p1 = getGraphicVariableInt("$SPLINESEGS", 8) * npts;
1426 1 : int p1 = nControlPoints * 8;
1427 :
1428 1 : p.push_back( 0.0 );
1429 193 : for( i = 0; i < 3*p1; i++ )
1430 192 : p.push_back( 0.0 );
1431 :
1432 1 : if( bClosed )
1433 : rbsplinu( nControlPoints, nDegree+1, p1, &(adfControlPoints[0]),
1434 0 : &(h[0]), &(p[0]) );
1435 : else
1436 : rbspline( nControlPoints, nDegree+1, p1, &(adfControlPoints[0]),
1437 1 : &(h[0]), &(p[0]) );
1438 :
1439 : /* -------------------------------------------------------------------- */
1440 : /* Turn into OGR geometry. */
1441 : /* -------------------------------------------------------------------- */
1442 1 : OGRLineString *poLS = new OGRLineString();
1443 :
1444 1 : poLS->setNumPoints( p1 );
1445 65 : for( i = 0; i < p1; i++ )
1446 64 : poLS->setPoint( i, p[i*3+1], p[i*3+2] );
1447 :
1448 1 : ApplyOCSTransformer( poLS );
1449 1 : poFeature->SetGeometryDirectly( poLS );
1450 :
1451 1 : PrepareLineStyle( poFeature );
1452 :
1453 1 : return poFeature;
1454 : }
1455 :
1456 : /************************************************************************/
1457 : /* GeometryInsertTransformer */
1458 : /************************************************************************/
1459 :
1460 : class GeometryInsertTransformer : public OGRCoordinateTransformation
1461 7 : {
1462 : public:
1463 7 : GeometryInsertTransformer() :
1464 : dfXOffset(0),dfYOffset(0),dfZOffset(0),
1465 : dfXScale(1.0),dfYScale(1.0),dfZScale(1.0),
1466 7 : dfAngle(0.0) {}
1467 :
1468 : double dfXOffset;
1469 : double dfYOffset;
1470 : double dfZOffset;
1471 : double dfXScale;
1472 : double dfYScale;
1473 : double dfZScale;
1474 : double dfAngle;
1475 :
1476 0 : OGRSpatialReference *GetSourceCS() { return NULL; }
1477 34 : OGRSpatialReference *GetTargetCS() { return NULL; }
1478 4 : int Transform( int nCount,
1479 : double *x, double *y, double *z )
1480 4 : { return TransformEx( nCount, x, y, z, NULL ); }
1481 :
1482 28 : int TransformEx( int nCount,
1483 : double *x, double *y, double *z = NULL,
1484 : int *pabSuccess = NULL )
1485 : {
1486 : int i;
1487 80 : for( i = 0; i < nCount; i++ )
1488 : {
1489 : double dfXNew, dfYNew;
1490 :
1491 52 : x[i] *= dfXScale;
1492 52 : y[i] *= dfYScale;
1493 52 : z[i] *= dfZScale;
1494 :
1495 52 : dfXNew = x[i] * cos(dfAngle) - y[i] * sin(dfAngle);
1496 52 : dfYNew = x[i] * sin(dfAngle) + y[i] * cos(dfAngle);
1497 :
1498 52 : x[i] = dfXNew;
1499 52 : y[i] = dfYNew;
1500 :
1501 52 : x[i] += dfXOffset;
1502 52 : y[i] += dfYOffset;
1503 52 : z[i] += dfZOffset;
1504 :
1505 52 : if( pabSuccess )
1506 48 : pabSuccess[i] = TRUE;
1507 : }
1508 28 : return TRUE;
1509 : }
1510 : };
1511 :
1512 : /************************************************************************/
1513 : /* TranslateINSERT() */
1514 : /************************************************************************/
1515 :
1516 7 : OGRFeature *OGRDXFLayer::TranslateINSERT()
1517 :
1518 : {
1519 : char szLineBuf[257];
1520 : int nCode;
1521 7 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1522 7 : GeometryInsertTransformer oTransformer;
1523 7 : CPLString osBlockName;
1524 7 : double dfAngle = 0.0;
1525 :
1526 : /* -------------------------------------------------------------------- */
1527 : /* Process values. */
1528 : /* -------------------------------------------------------------------- */
1529 85 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
1530 : {
1531 71 : switch( nCode )
1532 : {
1533 : case 10:
1534 7 : oTransformer.dfXOffset = CPLAtof(szLineBuf);
1535 7 : break;
1536 :
1537 : case 20:
1538 7 : oTransformer.dfYOffset = CPLAtof(szLineBuf);
1539 7 : break;
1540 :
1541 : case 30:
1542 3 : oTransformer.dfZOffset = CPLAtof(szLineBuf);
1543 3 : break;
1544 :
1545 : case 41:
1546 1 : oTransformer.dfXScale = CPLAtof(szLineBuf);
1547 1 : break;
1548 :
1549 : case 42:
1550 1 : oTransformer.dfYScale = CPLAtof(szLineBuf);
1551 1 : break;
1552 :
1553 : case 43:
1554 1 : oTransformer.dfZScale = CPLAtof(szLineBuf);
1555 1 : break;
1556 :
1557 : case 50:
1558 1 : dfAngle = CPLAtof(szLineBuf);
1559 : // We want to transform this to radians.
1560 : // It is apparently always in degrees regardless of $AUNITS
1561 1 : oTransformer.dfAngle = dfAngle * PI / 180.0;
1562 1 : break;
1563 :
1564 : case 2:
1565 7 : osBlockName = szLineBuf;
1566 7 : break;
1567 :
1568 : default:
1569 43 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
1570 : break;
1571 : }
1572 : }
1573 :
1574 7 : if( nCode == 0 )
1575 7 : poDS->UnreadValue();
1576 :
1577 : /* -------------------------------------------------------------------- */
1578 : /* In the case where we do not inlined blocks we just capture */
1579 : /* info on a point feature. */
1580 : /* -------------------------------------------------------------------- */
1581 7 : if( !poDS->InlineBlocks() )
1582 : {
1583 : // ApplyOCSTransformer( poGeom ); ?
1584 : poFeature->SetGeometryDirectly(
1585 : new OGRPoint( oTransformer.dfXOffset,
1586 : oTransformer.dfYOffset,
1587 1 : oTransformer.dfZOffset ) );
1588 :
1589 1 : poFeature->SetField( "BlockName", osBlockName );
1590 :
1591 1 : poFeature->SetField( "BlockAngle", dfAngle );
1592 1 : poFeature->SetField( "BlockScale", 3, &(oTransformer.dfXScale) );
1593 :
1594 1 : return poFeature;
1595 : }
1596 :
1597 : /* -------------------------------------------------------------------- */
1598 : /* Lookup the block. */
1599 : /* -------------------------------------------------------------------- */
1600 6 : DXFBlockDefinition *poBlock = poDS->LookupBlock( osBlockName );
1601 :
1602 6 : if( poBlock == NULL )
1603 : {
1604 0 : delete poFeature;
1605 0 : return NULL;
1606 : }
1607 :
1608 : /* -------------------------------------------------------------------- */
1609 : /* Transform the geometry. */
1610 : /* -------------------------------------------------------------------- */
1611 6 : if( poBlock->poGeometry != NULL )
1612 : {
1613 6 : OGRGeometry *poGeometry = poBlock->poGeometry->clone();
1614 :
1615 6 : poGeometry->transform( &oTransformer );
1616 :
1617 6 : poFeature->SetGeometryDirectly( poGeometry );
1618 : }
1619 :
1620 : /* -------------------------------------------------------------------- */
1621 : /* If we have complete features associated with the block, push */
1622 : /* them on the pending feature stack copying over key override */
1623 : /* information. */
1624 : /* */
1625 : /* Note that while we transform the geometry of the features we */
1626 : /* don't adjust subtle things like text angle. */
1627 : /* -------------------------------------------------------------------- */
1628 : unsigned int iSubFeat;
1629 :
1630 10 : for( iSubFeat = 0; iSubFeat < poBlock->apoFeatures.size(); iSubFeat++ )
1631 : {
1632 4 : OGRFeature *poSubFeature = poBlock->apoFeatures[iSubFeat]->Clone();
1633 4 : CPLString osCompEntityId;
1634 :
1635 4 : if( poSubFeature->GetGeometryRef() != NULL )
1636 4 : poSubFeature->GetGeometryRef()->transform( &oTransformer );
1637 :
1638 4 : ACAdjustText( dfAngle, oTransformer.dfXScale, poSubFeature );
1639 :
1640 : #ifdef notdef
1641 : osCompEntityId = poSubFeature->GetFieldAsString( "EntityHandle" );
1642 : osCompEntityId += ":";
1643 : #endif
1644 4 : osCompEntityId += poFeature->GetFieldAsString( "EntityHandle" );
1645 :
1646 4 : poSubFeature->SetField( "EntityHandle", osCompEntityId );
1647 :
1648 4 : apoPendingFeatures.push( poSubFeature );
1649 : }
1650 :
1651 : /* -------------------------------------------------------------------- */
1652 : /* Return the working feature if we had geometry, otherwise */
1653 : /* return NULL and let the machinery find the rest of the */
1654 : /* features in the pending feature stack. */
1655 : /* -------------------------------------------------------------------- */
1656 6 : if( poBlock->poGeometry == NULL )
1657 : {
1658 0 : delete poFeature;
1659 0 : return NULL;
1660 : }
1661 : else
1662 : {
1663 : // Set style pen color
1664 6 : PrepareLineStyle( poFeature );
1665 6 : return poFeature;
1666 0 : }
1667 : }
1668 :
1669 : /************************************************************************/
1670 : /* GetNextUnfilteredFeature() */
1671 : /************************************************************************/
1672 :
1673 129 : OGRFeature *OGRDXFLayer::GetNextUnfilteredFeature()
1674 :
1675 : {
1676 129 : OGRFeature *poFeature = NULL;
1677 :
1678 : /* -------------------------------------------------------------------- */
1679 : /* If we have pending features, return one of them. */
1680 : /* -------------------------------------------------------------------- */
1681 129 : if( !apoPendingFeatures.empty() )
1682 : {
1683 13 : poFeature = apoPendingFeatures.front();
1684 13 : apoPendingFeatures.pop();
1685 :
1686 13 : poFeature->SetFID( iNextFID++ );
1687 13 : return poFeature;
1688 : }
1689 :
1690 : /* -------------------------------------------------------------------- */
1691 : /* Read the entity type. */
1692 : /* -------------------------------------------------------------------- */
1693 : char szLineBuf[257];
1694 : int nCode;
1695 :
1696 337 : while( poFeature == NULL )
1697 : {
1698 : // read ahead to an entity.
1699 116 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 ) {}
1700 :
1701 116 : if( nCode == -1 )
1702 : {
1703 0 : CPLDebug( "DXF", "Unexpected end of data without ENDSEC." );
1704 0 : return NULL;
1705 : }
1706 :
1707 116 : if( EQUAL(szLineBuf,"ENDSEC") )
1708 : {
1709 : //CPLDebug( "DXF", "Clean end of features at ENDSEC." );
1710 1 : poDS->UnreadValue();
1711 1 : return NULL;
1712 : }
1713 :
1714 115 : if( EQUAL(szLineBuf,"ENDBLK") )
1715 : {
1716 : //CPLDebug( "DXF", "Clean end of block at ENDBLK." );
1717 10 : poDS->UnreadValue();
1718 10 : return NULL;
1719 : }
1720 :
1721 : /* -------------------------------------------------------------------- */
1722 : /* Handle the entity. */
1723 : /* -------------------------------------------------------------------- */
1724 105 : oStyleProperties.clear();
1725 :
1726 105 : if( EQUAL(szLineBuf,"POINT") )
1727 : {
1728 6 : poFeature = TranslatePOINT();
1729 : }
1730 99 : else if( EQUAL(szLineBuf,"MTEXT") )
1731 : {
1732 9 : poFeature = TranslateMTEXT();
1733 : }
1734 90 : else if( EQUAL(szLineBuf,"TEXT")
1735 : || EQUAL(szLineBuf,"ATTDEF") )
1736 : {
1737 0 : poFeature = TranslateTEXT();
1738 : }
1739 90 : else if( EQUAL(szLineBuf,"LINE") )
1740 : {
1741 49 : poFeature = TranslateLINE();
1742 : }
1743 41 : else if( EQUAL(szLineBuf,"POLYLINE") )
1744 : {
1745 1 : poFeature = TranslatePOLYLINE();
1746 : }
1747 40 : else if( EQUAL(szLineBuf,"LWPOLYLINE") )
1748 : {
1749 10 : poFeature = TranslateLWPOLYLINE();
1750 : }
1751 30 : else if( EQUAL(szLineBuf,"CIRCLE") )
1752 : {
1753 1 : poFeature = TranslateCIRCLE();
1754 : }
1755 29 : else if( EQUAL(szLineBuf,"ELLIPSE") )
1756 : {
1757 6 : poFeature = TranslateELLIPSE();
1758 : }
1759 23 : else if( EQUAL(szLineBuf,"ARC") )
1760 : {
1761 3 : poFeature = TranslateARC();
1762 : }
1763 20 : else if( EQUAL(szLineBuf,"SPLINE") )
1764 : {
1765 1 : poFeature = TranslateSPLINE();
1766 : }
1767 19 : else if( EQUAL(szLineBuf,"INSERT") )
1768 : {
1769 7 : poFeature = TranslateINSERT();
1770 : }
1771 12 : else if( EQUAL(szLineBuf,"DIMENSION") )
1772 : {
1773 9 : poFeature = TranslateDIMENSION();
1774 : }
1775 3 : else if( EQUAL(szLineBuf,"HATCH") )
1776 : {
1777 3 : poFeature = TranslateHATCH();
1778 : }
1779 : else
1780 : {
1781 0 : if( oIgnoredEntities.count(szLineBuf) == 0 )
1782 : {
1783 0 : oIgnoredEntities.insert( szLineBuf );
1784 : CPLDebug( "DWG", "Ignoring one or more of entity '%s'.",
1785 0 : szLineBuf );
1786 : }
1787 : }
1788 : }
1789 :
1790 : /* -------------------------------------------------------------------- */
1791 : /* Set FID. */
1792 : /* -------------------------------------------------------------------- */
1793 105 : poFeature->SetFID( iNextFID++ );
1794 105 : m_nFeaturesRead++;
1795 :
1796 105 : return poFeature;
1797 : }
1798 :
1799 : /************************************************************************/
1800 : /* GetNextFeature() */
1801 : /************************************************************************/
1802 :
1803 70 : OGRFeature *OGRDXFLayer::GetNextFeature()
1804 :
1805 : {
1806 0 : while( TRUE )
1807 : {
1808 70 : OGRFeature *poFeature = GetNextUnfilteredFeature();
1809 :
1810 70 : if( poFeature == NULL )
1811 1 : return NULL;
1812 :
1813 69 : if( (m_poFilterGeom == NULL
1814 : || FilterGeometry( poFeature->GetGeometryRef() ) )
1815 : && (m_poAttrQuery == NULL
1816 : || m_poAttrQuery->Evaluate( poFeature ) ) )
1817 : {
1818 69 : return poFeature;
1819 : }
1820 :
1821 0 : delete poFeature;
1822 : }
1823 : }
1824 :
1825 : /************************************************************************/
1826 : /* TestCapability() */
1827 : /************************************************************************/
1828 :
1829 0 : int OGRDXFLayer::TestCapability( const char * pszCap )
1830 :
1831 : {
1832 0 : if( EQUAL(pszCap,OLCStringsAsUTF8) )
1833 0 : return TRUE;
1834 : else
1835 0 : return FALSE;
1836 : }
1837 :
|