1 /******************************************************************************
2 *
3 * Project: DWG Translator
4 * Purpose: Implements OGRDWGLayer class.
5 * Author: Frank Warmerdam, warmerdam@pobox.com
6 *
7 ******************************************************************************
8 * Copyright (c) 2011, Frank Warmerdam <warmerdam@pobox.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 #include "ogr_dwg.h"
30 #include "cpl_conv.h"
31
32 #include "ogrdxf_polyline_smooth.h"
33
34 CPL_CVSID("$Id: ogrdwglayer.cpp 95708c896583cc143c2ab314321aeb37483faed0 2021-08-19 20:35:04 +0800 GISerliang $")
35
36 /************************************************************************/
37 /* OGRDWGLayer() */
38 /************************************************************************/
39
OGRDWGLayer(OGRDWGDataSource * poDSIn)40 OGRDWGLayer::OGRDWGLayer( OGRDWGDataSource *poDSIn )
41
42 {
43 this->poDS = poDSIn;
44
45 iNextFID = 0;
46
47 poFeatureDefn = new OGRFeatureDefn( "entities" );
48 SetDescription( poFeatureDefn->GetName() );
49 poFeatureDefn->Reference();
50
51 poDS->AddStandardFields( poFeatureDefn );
52
53 if( !poDS->InlineBlocks() )
54 {
55 OGRFieldDefn oScaleField( "BlockScale", OFTRealList );
56 poFeatureDefn->AddFieldDefn( &oScaleField );
57
58 OGRFieldDefn oBlockAngleField( "BlockAngle", OFTReal );
59 poFeatureDefn->AddFieldDefn( &oBlockAngleField );
60 }
61
62 /* -------------------------------------------------------------------- */
63 /* Find the *Paper_Space block, which seems to contain all the */
64 /* regular entities. */
65 /* -------------------------------------------------------------------- */
66 OdDbBlockTablePtr pTable = poDS->GetDB()->getBlockTableId().safeOpenObject();
67 OdDbSymbolTableIteratorPtr pBlkIter = pTable->newIterator();
68
69 for (pBlkIter->start(); ! pBlkIter->done(); pBlkIter->step())
70 {
71 m_poBlock = pBlkIter->getRecordId().safeOpenObject();
72
73 if( EQUAL(m_poBlock->getName(),"*Model_Space") )
74 break;
75 else
76 m_poBlock = nullptr;
77 }
78
79 OGRDWGLayer::ResetReading();
80 }
81
82 /************************************************************************/
83 /* ~OGRDWGLayer() */
84 /************************************************************************/
85
~OGRDWGLayer()86 OGRDWGLayer::~OGRDWGLayer()
87
88 {
89 ClearPendingFeatures();
90 if( m_nFeaturesRead > 0 && poFeatureDefn != nullptr )
91 {
92 CPLDebug( "DWG", "%d features read on layer '%s'.",
93 (int) m_nFeaturesRead,
94 poFeatureDefn->GetName() );
95 }
96
97 if( poFeatureDefn )
98 poFeatureDefn->Release();
99 }
100
101 /************************************************************************/
102 /* TextUnescape() */
103 /************************************************************************/
104
TextUnescape(OdString oString,bool bIsMText)105 CPLString OGRDWGLayer::TextUnescape( OdString oString, bool bIsMText )
106
107 {
108 return ACTextUnescape( (const char *) oString, poDS->GetEncoding(), bIsMText );
109 }
110
111 /************************************************************************/
112 /* SetBlockTable() */
113 /* */
114 /* Set what block table to read features from. This layer */
115 /* object is used to read blocks features as well as generic */
116 /* entities. */
117 /************************************************************************/
118
SetBlockTable(OdDbBlockTableRecordPtr poNewBlock)119 void OGRDWGLayer::SetBlockTable( OdDbBlockTableRecordPtr poNewBlock )
120
121 {
122 m_poBlock = poNewBlock;
123
124 ResetReading();
125 }
126
127 /************************************************************************/
128 /* ClearPendingFeatures() */
129 /************************************************************************/
130
ClearPendingFeatures()131 void OGRDWGLayer::ClearPendingFeatures()
132
133 {
134 while( !apoPendingFeatures.empty() )
135 {
136 delete apoPendingFeatures.front();
137 apoPendingFeatures.pop();
138 }
139 }
140
141 /************************************************************************/
142 /* ResetReading() */
143 /************************************************************************/
144
ResetReading()145 void OGRDWGLayer::ResetReading()
146
147 {
148 iNextFID = 0;
149 ClearPendingFeatures();
150
151 if( !m_poBlock.isNull() )
152 poEntIter = m_poBlock->newIterator();
153 }
154
155 /************************************************************************/
156 /* TranslateGenericProperties() */
157 /* */
158 /* Try and convert entity properties handled similarly for most */
159 /* or all entity types */
160 /************************************************************************/
161
TranslateGenericProperties(OGRFeature * poFeature,OdDbEntityPtr poEntity)162 void OGRDWGLayer::TranslateGenericProperties( OGRFeature *poFeature,
163 OdDbEntityPtr poEntity )
164
165 {
166 poFeature->SetField( "Layer", TextUnescape(poEntity->layer(), false) );
167 poFeature->SetField( "Linetype", TextUnescape(poEntity->layer(), false) );
168
169 CPLString osValue;
170 osValue.Printf( "%d", (int) poEntity->lineWeight() );
171 oStyleProperties["LineWeight"] = osValue;
172
173 OdDbHandle oHandle = poEntity->getDbHandle();
174 poFeature->SetField( "EntityHandle", (const char *) oHandle.ascii() );
175
176 if( poEntity->colorIndex() != 256 )
177 {
178 osValue.Printf( "%d", poEntity->colorIndex() );
179 oStyleProperties["Color"] = osValue.c_str();
180 }
181
182 /* -------------------------------------------------------------------- */
183 /* Collect the subclasses. */
184 /* -------------------------------------------------------------------- */
185 CPLString osSubClasses;
186 OdRxClass *poClass = poEntity->isA();
187
188 while( poClass != nullptr )
189 {
190 if( !osSubClasses.empty() )
191 osSubClasses = ":" + osSubClasses;
192
193 osSubClasses = ((const char *) poClass->name()) + osSubClasses;
194 if( EQUAL(poClass->name(),"AcDbEntity") )
195 break;
196
197 poClass = poClass->myParent();
198 }
199
200 poFeature->SetField( "SubClasses", osSubClasses.c_str() );
201
202 /* -------------------------------------------------------------------- */
203 /* Collect Xdata. */
204 /* -------------------------------------------------------------------- */
205 OdResBufPtr poResBufBase = poEntity->xData();
206 OdResBuf *poResBuf = poResBufBase;
207 CPLString osFullXData;
208
209 for ( ; poResBuf != nullptr; poResBuf = poResBuf->next() )
210 {
211 CPLString osXDataItem;
212
213 switch (OdDxfCode::_getType(poResBuf->restype()))
214 {
215 case OdDxfCode::Name:
216 case OdDxfCode::String:
217 case OdDxfCode::LayerName:
218 osXDataItem = (const char *) poResBuf->getString();
219 break;
220
221 case OdDxfCode::Bool:
222 if( poResBuf->getBool() )
223 osXDataItem = "true";
224 else
225 osXDataItem = "false";
226 break;
227
228 case OdDxfCode::Integer8:
229 osXDataItem.Printf( "%d", (int) poResBuf->getInt8() );
230 break;
231
232 case OdDxfCode::Integer16:
233 osXDataItem.Printf( "%d", (int) poResBuf->getInt16() );
234 break;
235
236 case OdDxfCode::Integer32:
237 osXDataItem.Printf( "%d", (int) poResBuf->getInt32() );
238 break;
239
240 case OdDxfCode::Double:
241 case OdDxfCode::Angle:
242 osXDataItem.Printf( "%g", poResBuf->getDouble() );
243 break;
244
245 case OdDxfCode::Point:
246 {
247 OdGePoint3d oPoint = poResBuf->getPoint3d();
248 osXDataItem.Printf( "(%g,%g,%g)", oPoint.x, oPoint.y, oPoint.z );
249 }
250 break;
251
252 case OdDxfCode::BinaryChunk:
253 {
254 OdBinaryData oBinData = poResBuf->getBinaryChunk();
255 char *pszAsHex = CPLBinaryToHex( oBinData.size(),
256 (GByte*) oBinData.asArrayPtr() );
257 osXDataItem = pszAsHex;
258 CPLFree( pszAsHex );
259 }
260 break;
261
262 case OdDxfCode::ObjectId:
263 case OdDxfCode::SoftPointerId:
264 case OdDxfCode::HardPointerId:
265 case OdDxfCode::SoftOwnershipId:
266 case OdDxfCode::HardOwnershipId:
267 case OdDxfCode::Handle:
268 osXDataItem = (const char *) poResBuf->getHandle().ascii();
269 break;
270
271 default:
272 break;
273 }
274
275 if( !osFullXData.empty() )
276 osFullXData += " ";
277 osFullXData += (const char *) osXDataItem;
278 }
279
280 poFeature->SetField( "ExtendedEntity", osFullXData );
281
282 #ifdef notdef
283 // OCS vector.
284 case 210:
285 oStyleProperties["210_N.dX"] = pszValue;
286 break;
287
288 case 220:
289 oStyleProperties["220_N.dY"] = pszValue;
290 break;
291
292 case 230:
293 oStyleProperties["230_N.dZ"] = pszValue;
294 break;
295
296 default:
297 break;
298 }
299 #endif
300 }
301
302 /************************************************************************/
303 /* PrepareLineStyle() */
304 /************************************************************************/
305
306 void OGRDWGLayer::PrepareLineStyle( OGRFeature *poFeature )
307
308 {
309 CPLString osLayer = poFeature->GetFieldAsString("Layer");
310
311 /* -------------------------------------------------------------------- */
312 /* Is the layer disabled/hidden/frozen/off? */
313 /* -------------------------------------------------------------------- */
314 int bHidden =
315 EQUAL(poDS->LookupLayerProperty( osLayer, "Hidden" ), "1");
316
317 /* -------------------------------------------------------------------- */
318 /* Work out the color for this feature. */
319 /* -------------------------------------------------------------------- */
320 int nColor = 256;
321
322 if( oStyleProperties.count("Color") > 0 )
323 nColor = atoi(oStyleProperties["Color"]);
324
325 // Use layer color?
326 if( nColor < 1 || nColor > 255 )
327 {
328 const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
329 if( pszValue != nullptr )
330 nColor = atoi(pszValue);
331 }
332
333 if( nColor < 1 || nColor > 255 )
334 return;
335
336 /* -------------------------------------------------------------------- */
337 /* Get line weight if available. */
338 /* -------------------------------------------------------------------- */
339 double dfWeight = 0.0;
340
341 if( oStyleProperties.count("LineWeight") > 0 )
342 {
343 CPLString osWeight = oStyleProperties["LineWeight"];
344
345 if( osWeight == "-1" )
346 osWeight = poDS->LookupLayerProperty(osLayer,"LineWeight");
347
348 dfWeight = CPLAtof(osWeight) / 100.0;
349 }
350
351 /* -------------------------------------------------------------------- */
352 /* Do we have a dash/dot line style? */
353 /* -------------------------------------------------------------------- */
354 const char *pszPattern = poDS->LookupLineType(
355 poFeature->GetFieldAsString("Linetype") );
356
357 /* -------------------------------------------------------------------- */
358 /* Format the style string. */
359 /* -------------------------------------------------------------------- */
360 CPLString osStyle;
361 const unsigned char *pabyDWGColors = ACGetColorTable();
362
363 osStyle.Printf( "PEN(c:#%02x%02x%02x",
364 pabyDWGColors[nColor*3+0],
365 pabyDWGColors[nColor*3+1],
366 pabyDWGColors[nColor*3+2] );
367
368 if( bHidden )
369 osStyle += "00";
370
371 if( dfWeight > 0.0 )
372 {
373 char szBuffer[64];
374 CPLsnprintf(szBuffer, sizeof(szBuffer), "%.2g", dfWeight);
375 char* pszComma = strchr(szBuffer, ',');
376 if (pszComma)
377 *pszComma = '.';
378 osStyle += CPLString().Printf( ",w:%sg", szBuffer );
379 }
380
381 if( pszPattern )
382 {
383 osStyle += ",p:\"";
384 osStyle += pszPattern;
385 osStyle += "\"";
386 }
387
388 osStyle += ")";
389
390 poFeature->SetStyleString( osStyle );
391 }
392
393 /************************************************************************/
394 /* TranslateMTEXT() */
395 /************************************************************************/
396
397 OGRFeature *OGRDWGLayer::TranslateMTEXT( OdDbEntityPtr poEntity )
398
399 {
400 OdDbMTextPtr poMTE = OdDbMText::cast( poEntity );
401 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
402
403 TranslateGenericProperties( poFeature, poEntity );
404
405 /* -------------------------------------------------------------------- */
406 /* Set the location. */
407 /* -------------------------------------------------------------------- */
408 OdGePoint3d oLocation = poMTE->location();
409
410 poFeature->SetGeometryDirectly(
411 new OGRPoint( oLocation.x, oLocation.y, oLocation.z ) );
412
413 /* -------------------------------------------------------------------- */
414 /* Apply text after stripping off any extra terminating newline. */
415 /* -------------------------------------------------------------------- */
416 CPLString osText = TextUnescape( poMTE->contents(), true );
417
418 if( !osText.empty() && osText.back() == '\n' )
419 osText.resize( osText.size() - 1 );
420
421 poFeature->SetField( "Text", osText );
422
423 /* -------------------------------------------------------------------- */
424 /* We need to escape double quotes with backslashes before they */
425 /* can be inserted in the style string. */
426 /* -------------------------------------------------------------------- */
427 if( strchr( osText, '"') != nullptr )
428 {
429 CPLString osEscaped;
430 size_t iC;
431
432 for( iC = 0; iC < osText.size(); iC++ )
433 {
434 if( osText[iC] == '"' )
435 osEscaped += "\\\"";
436 else
437 osEscaped += osText[iC];
438 }
439 osText = osEscaped;
440 }
441
442 /* -------------------------------------------------------------------- */
443 /* Work out the color for this feature. */
444 /* -------------------------------------------------------------------- */
445 int nColor = 256;
446
447 if( oStyleProperties.count("Color") > 0 )
448 nColor = atoi(oStyleProperties["Color"]);
449
450 // Use layer color?
451 if( nColor < 1 || nColor > 255 )
452 {
453 CPLString osLayer = poFeature->GetFieldAsString("Layer");
454 const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
455 if( pszValue != nullptr )
456 nColor = atoi(pszValue);
457 }
458
459 /* -------------------------------------------------------------------- */
460 /* Prepare style string. */
461 /* -------------------------------------------------------------------- */
462 double dfAngle = poMTE->rotation() * 180 / M_PI;
463 double dfHeight = poMTE->textHeight();
464 int nAttachmentPoint = (int) poMTE->attachment();
465
466 CPLString osStyle;
467 char szBuffer[64];
468 char* pszComma = nullptr;
469
470 osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\"",osText.c_str());
471
472 if( dfAngle != 0.0 )
473 {
474 CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
475 pszComma = strchr(szBuffer, ',');
476 if (pszComma)
477 *pszComma = '.';
478 osStyle += CPLString().Printf(",a:%s", szBuffer);
479 }
480
481 if( dfHeight != 0.0 )
482 {
483 CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
484 pszComma = strchr(szBuffer, ',');
485 if (pszComma)
486 *pszComma = '.';
487 osStyle += CPLString().Printf(",s:%sg", szBuffer);
488 }
489
490 if( nAttachmentPoint >= 0 && nAttachmentPoint <= 9 )
491 {
492 const static int anAttachmentMap[10] =
493 { -1, 7, 8, 9, 4, 5, 6, 1, 2, 3 };
494
495 osStyle +=
496 CPLString().Printf(",p:%d", anAttachmentMap[nAttachmentPoint]);
497 }
498
499 if( nColor > 0 && nColor < 256 )
500 {
501 const unsigned char *pabyDWGColors = ACGetColorTable();
502 osStyle +=
503 CPLString().Printf( ",c:#%02x%02x%02x",
504 pabyDWGColors[nColor*3+0],
505 pabyDWGColors[nColor*3+1],
506 pabyDWGColors[nColor*3+2] );
507 }
508
509 osStyle += ")";
510
511 poFeature->SetStyleString( osStyle );
512
513 return poFeature;
514 }
515
516 /************************************************************************/
517 /* TranslateTEXT() */
518 /************************************************************************/
519
520 OGRFeature *OGRDWGLayer::TranslateTEXT( OdDbEntityPtr poEntity )
521
522 {
523 OdDbTextPtr poText = OdDbText::cast( poEntity );
524 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
525
526 TranslateGenericProperties( poFeature, poEntity );
527
528 /* -------------------------------------------------------------------- */
529 /* Set the location. */
530 /* -------------------------------------------------------------------- */
531 OdGePoint3d oLocation = poText->position();
532
533 poFeature->SetGeometryDirectly(
534 new OGRPoint( oLocation.x, oLocation.y, oLocation.z ) );
535
536 /* -------------------------------------------------------------------- */
537 /* Apply text after stripping off any extra terminating newline. */
538 /* -------------------------------------------------------------------- */
539 CPLString osText = TextUnescape( poText->textString(), false );
540
541 if( !osText.empty() && osText.back() == '\n' )
542 osText.resize( osText.size() - 1 );
543
544 poFeature->SetField( "Text", osText );
545
546 /* -------------------------------------------------------------------- */
547 /* We need to escape double quotes with backslashes before they */
548 /* can be inserted in the style string. */
549 /* -------------------------------------------------------------------- */
550 if( strchr( osText, '"') != nullptr )
551 {
552 CPLString osEscaped;
553 size_t iC;
554
555 for( iC = 0; iC < osText.size(); iC++ )
556 {
557 if( osText[iC] == '"' )
558 osEscaped += "\\\"";
559 else
560 osEscaped += osText[iC];
561 }
562 osText = osEscaped;
563 }
564
565 /* -------------------------------------------------------------------- */
566 /* Is the layer disabled/hidden/frozen/off? */
567 /* -------------------------------------------------------------------- */
568 CPLString osLayer = poFeature->GetFieldAsString("Layer");
569
570 int bHidden =
571 EQUAL(poDS->LookupLayerProperty( osLayer, "Hidden" ), "1");
572
573 /* -------------------------------------------------------------------- */
574 /* Work out the color for this feature. */
575 /* -------------------------------------------------------------------- */
576 int nColor = 256;
577
578 if( oStyleProperties.count("Color") > 0 )
579 nColor = atoi(oStyleProperties["Color"]);
580
581 // Use layer color?
582 if( nColor < 1 || nColor > 255 )
583 {
584 const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
585 if( pszValue != nullptr )
586 nColor = atoi(pszValue);
587 }
588
589 if( nColor < 1 || nColor > 255 )
590 nColor = 8;
591
592 /* -------------------------------------------------------------------- */
593 /* Prepare style string. */
594 /* -------------------------------------------------------------------- */
595 double dfAngle = poText->rotation() * 180 / M_PI;
596 double dfHeight = poText->height();
597
598 CPLString osStyle;
599 char szBuffer[64];
600 char* pszComma = nullptr;
601
602 osStyle.Printf("LABEL(f:\"Arial\",t:\"%s\"",osText.c_str());
603
604 if( dfAngle != 0.0 )
605 {
606 CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfAngle);
607 pszComma = strchr(szBuffer, ',');
608 if (pszComma)
609 *pszComma = '.';
610 osStyle += CPLString().Printf(",a:%s", szBuffer);
611 }
612
613 if( dfHeight != 0.0 )
614 {
615 CPLsnprintf(szBuffer, sizeof(szBuffer), "%.3g", dfHeight);
616 pszComma = strchr(szBuffer, ',');
617 if (pszComma)
618 *pszComma = '.';
619 osStyle += CPLString().Printf(",s:%sg", szBuffer);
620 }
621
622 const unsigned char *pabyDWGColors = ACGetColorTable();
623
624 snprintf( szBuffer, sizeof(szBuffer), ",c:#%02x%02x%02x",
625 pabyDWGColors[nColor*3+0],
626 pabyDWGColors[nColor*3+1],
627 pabyDWGColors[nColor*3+2] );
628 osStyle += szBuffer;
629
630 if( bHidden )
631 osStyle += "00";
632
633 osStyle += ")";
634
635 poFeature->SetStyleString( osStyle );
636
637 return poFeature;
638 }
639
640 /************************************************************************/
641 /* TranslatePOINT() */
642 /************************************************************************/
643
644 OGRFeature *OGRDWGLayer::TranslatePOINT( OdDbEntityPtr poEntity )
645
646 {
647 OdDbPointPtr poPE = OdDbPoint::cast( poEntity );
648 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
649
650 TranslateGenericProperties( poFeature, poEntity );
651
652 OdGePoint3d oPoint = poPE->position();
653
654 poFeature->SetGeometryDirectly( new OGRPoint( oPoint.x, oPoint.y, oPoint.z ) );
655
656 return poFeature;
657 }
658
659 /************************************************************************/
660 /* TranslateLWPOLYLINE() */
661 /************************************************************************/
662
663 OGRFeature *OGRDWGLayer::TranslateLWPOLYLINE( OdDbEntityPtr poEntity )
664
665 {
666 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
667 OdDbPolylinePtr poPL = OdDbPolyline::cast( poEntity );
668
669 TranslateGenericProperties( poFeature, poEntity );
670
671 /* -------------------------------------------------------------------- */
672 /* Collect polyline details. */
673 /* -------------------------------------------------------------------- */
674 DXFSmoothPolyline oSmoothPolyline;
675
676 for (unsigned int i = 0; i < poPL->numVerts(); i++)
677 {
678 OdGePoint3d oPoint;
679 poPL->getPointAt( i, oPoint );
680
681 oSmoothPolyline.AddPoint( oPoint.x, oPoint.y, 0.0,
682 poPL->getBulgeAt( i ) );
683 }
684
685 if(oSmoothPolyline.IsEmpty())
686 {
687 delete poFeature;
688 return nullptr;
689 }
690
691 if( poPL->isClosed() )
692 oSmoothPolyline.Close();
693
694 poFeature->SetGeometryDirectly(
695 oSmoothPolyline.Tessellate() );
696
697 PrepareLineStyle( poFeature );
698
699 return poFeature;
700 }
701
702 /************************************************************************/
703 /* Translate2DPOLYLINE() */
704 /************************************************************************/
705
706 OGRFeature *OGRDWGLayer::Translate2DPOLYLINE( OdDbEntityPtr poEntity )
707
708 {
709 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
710 OdDb2dPolylinePtr poPL = OdDb2dPolyline::cast( poEntity );
711
712 TranslateGenericProperties( poFeature, poEntity );
713
714 /* -------------------------------------------------------------------- */
715 /* Create a polyline geometry from the vertices. */
716 /* -------------------------------------------------------------------- */
717 OGRLineString *poLS = new OGRLineString();
718 OdDbObjectIteratorPtr poIter = poPL->vertexIterator();
719
720 while( !poIter->done() )
721 {
722 OdDb2dVertexPtr poVertex = poIter->entity();
723 OdGePoint3d oPoint = poPL->vertexPosition( *poVertex );
724 poLS->addPoint( oPoint.x, oPoint.y, oPoint.z );
725 poIter->step();
726 }
727
728 if (poPL->isClosed() && !poLS->IsEmpty())
729 {
730 poLS->addPoint(poLS->getX(0), poLS->getY(0), poLS->getZ(0));
731 }
732
733 poFeature->SetGeometryDirectly( poLS );
734
735 PrepareLineStyle( poFeature );
736
737 return poFeature;
738 }
739
740 /************************************************************************/
741 /* Translate3DPOLYLINE() */
742 /************************************************************************/
743
744 OGRFeature *OGRDWGLayer::Translate3DPOLYLINE( OdDbEntityPtr poEntity )
745
746 {
747 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
748 OdDb3dPolylinePtr poPL = OdDb3dPolyline::cast( poEntity );
749
750 TranslateGenericProperties( poFeature, poEntity );
751
752 /* -------------------------------------------------------------------- */
753 /* Create a polyline geometry from the vertices. */
754 /* -------------------------------------------------------------------- */
755 OGRLineString *poLS = new OGRLineString();
756 OdDbObjectIteratorPtr poIter = poPL->vertexIterator();
757
758 while( !poIter->done() )
759 {
760 OdDb3dPolylineVertexPtr poVertex = poIter->entity();
761 OdGePoint3d oPoint = poVertex->position();
762 poLS->addPoint( oPoint.x, oPoint.y, oPoint.z );
763 poIter->step();
764 }
765
766 if (poPL->isClosed() && !poLS->IsEmpty())
767 {
768 poLS->addPoint(poLS->getX(0), poLS->getY(0), poLS->getZ(0));
769 }
770
771 poFeature->SetGeometryDirectly( poLS );
772
773 PrepareLineStyle( poFeature );
774
775 return poFeature;
776 }
777
778 /************************************************************************/
779 /* TranslateLINE() */
780 /************************************************************************/
781
782 OGRFeature *OGRDWGLayer::TranslateLINE( OdDbEntityPtr poEntity )
783
784 {
785 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
786 OdDbLinePtr poPL = OdDbLine::cast( poEntity );
787
788 TranslateGenericProperties( poFeature, poEntity );
789
790 /* -------------------------------------------------------------------- */
791 /* Create a polyline geometry from the vertices. */
792 /* -------------------------------------------------------------------- */
793 OGRLineString *poLS = new OGRLineString();
794 OdGePoint3d oPoint;
795
796 poPL->getStartPoint( oPoint );
797 poLS->addPoint( oPoint.x, oPoint.y, oPoint.z );
798
799 poPL->getEndPoint( oPoint );
800 poLS->addPoint( oPoint.x, oPoint.y, oPoint.z );
801
802 poFeature->SetGeometryDirectly( poLS );
803
804 PrepareLineStyle( poFeature );
805
806 return poFeature;
807 }
808
809 /************************************************************************/
810 /* TranslateCIRCLE() */
811 /************************************************************************/
812
813 OGRFeature *OGRDWGLayer::TranslateCIRCLE( OdDbEntityPtr poEntity )
814
815 {
816 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
817 OdDbCirclePtr poC = OdDbCircle::cast( poEntity );
818
819 TranslateGenericProperties( poFeature, poEntity );
820
821 /* -------------------------------------------------------------------- */
822 /* Get geometry information. */
823 /* -------------------------------------------------------------------- */
824 OdGePoint3d oCenter = poC->center();
825 double dfRadius = poC->radius();
826
827 /* -------------------------------------------------------------------- */
828 /* Create geometry */
829 /* -------------------------------------------------------------------- */
830 OGRGeometry *poCircle =
831 OGRGeometryFactory::approximateArcAngles(
832 oCenter.x, oCenter.y, oCenter.z,
833 dfRadius, dfRadius, 0.0, 0.0, 360.0, 0.0 );
834
835 poFeature->SetGeometryDirectly( poCircle );
836 PrepareLineStyle( poFeature );
837
838 return poFeature;
839 }
840
841 /************************************************************************/
842 /* AngleCorrect() */
843 /* */
844 /* Convert from a "true" angle on the ellipse as returned by */
845 /* the DWG API to an angle of rotation on the ellipse as if the */
846 /* ellipse were actually circular. */
847 /************************************************************************/
848
849 double OGRDWGLayer::AngleCorrect( double dfTrueAngle, double dfRatio )
850
851 {
852 double dfRotAngle;
853 double dfDeltaX, dfDeltaY;
854
855 dfTrueAngle *= (M_PI / 180); // convert to radians.
856
857 dfDeltaX = cos(dfTrueAngle);
858 dfDeltaY = sin(dfTrueAngle);
859
860 dfRotAngle = atan2( dfDeltaY, dfDeltaX * dfRatio);
861
862 dfRotAngle *= (180 / M_PI); // convert to degrees.
863
864 if( dfTrueAngle < 0 && dfRotAngle > 0 )
865 dfRotAngle -= 360.0;
866
867 if( dfTrueAngle > 360 && dfRotAngle < 360 )
868 dfRotAngle += 360.0;
869
870 return dfRotAngle;
871 }
872
873 /************************************************************************/
874 /* TranslateELLIPSE() */
875 /************************************************************************/
876
877 OGRFeature *OGRDWGLayer::TranslateELLIPSE( OdDbEntityPtr poEntity )
878
879 {
880 OdDbEllipsePtr poEE = OdDbEllipse::cast( poEntity );
881 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
882
883 TranslateGenericProperties( poFeature, poEntity );
884
885 /* -------------------------------------------------------------------- */
886 /* Get some details. */
887 /* -------------------------------------------------------------------- */
888 double dfStartAngle, dfEndAngle, dfRatio;
889 OdGePoint3d oCenter;
890 OdGeVector3d oMajorAxis, oUnitNormal;
891
892 // note we reverse start and end angles to account for ogr orientation.
893 poEE->get( oCenter, oUnitNormal, oMajorAxis,
894 dfRatio, dfEndAngle, dfStartAngle );
895
896 dfStartAngle = -1 * dfStartAngle * 180 / M_PI;
897 dfEndAngle = -1 * dfEndAngle * 180 / M_PI;
898
899 /* -------------------------------------------------------------------- */
900 /* The DWG SDK expresses the angles as the angle to a real */
901 /* point on the ellipse while DXF and the OGR "arc angles" API */
902 /* work in terms of an angle of rotation on the ellipse as if */
903 /* the ellipse were actually circular. So we need to "correct" */
904 /* for the ratio. */
905 /* -------------------------------------------------------------------- */
906 dfStartAngle = AngleCorrect( dfStartAngle, dfRatio );
907 dfEndAngle = AngleCorrect( dfEndAngle, dfRatio );
908
909 if( dfStartAngle > dfEndAngle )
910 dfEndAngle += 360.0;
911
912 /* -------------------------------------------------------------------- */
913 /* Compute primary and secondary axis lengths, and the angle of */
914 /* rotation for the ellipse. */
915 /* -------------------------------------------------------------------- */
916 double dfPrimaryRadius, dfSecondaryRadius;
917 double dfRotation;
918
919 dfPrimaryRadius = sqrt( oMajorAxis.x * oMajorAxis.x
920 + oMajorAxis.y * oMajorAxis.y
921 + oMajorAxis.z * oMajorAxis.z );
922
923 dfSecondaryRadius = dfRatio * dfPrimaryRadius;
924
925 dfRotation = -1 * atan2( oMajorAxis.y, oMajorAxis.x ) * 180 / M_PI;
926
927 /* -------------------------------------------------------------------- */
928 /* Create geometry */
929 /* -------------------------------------------------------------------- */
930 OGRGeometry *poEllipse =
931 OGRGeometryFactory::approximateArcAngles(
932 oCenter.x, oCenter.y, oCenter.z,
933 dfPrimaryRadius, dfSecondaryRadius, dfRotation,
934 dfStartAngle, dfEndAngle, 0.0 );
935
936 poFeature->SetGeometryDirectly( poEllipse );
937
938 PrepareLineStyle( poFeature );
939
940 return poFeature;
941 }
942
943 /************************************************************************/
944 /* TranslateARC() */
945 /************************************************************************/
946
947 OGRFeature *OGRDWGLayer::TranslateARC( OdDbEntityPtr poEntity )
948
949 {
950 OdDbArcPtr poAE = OdDbArc::cast( poEntity );
951 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
952
953 TranslateGenericProperties( poFeature, poEntity );
954
955 /* -------------------------------------------------------------------- */
956 /* Collect parameters. */
957 /* -------------------------------------------------------------------- */
958 double dfEndAngle = -1 * poAE->startAngle() * 180 / M_PI;
959 double dfStartAngle = -1 * poAE->endAngle() * 180 / M_PI;
960 double dfRadius = poAE->radius();
961 OdGePoint3d oCenter = poAE->center();
962
963 /* -------------------------------------------------------------------- */
964 /* Create geometry */
965 /* -------------------------------------------------------------------- */
966 if( dfStartAngle > dfEndAngle )
967 dfEndAngle += 360.0;
968
969 OGRGeometry *poArc =
970 OGRGeometryFactory::approximateArcAngles(
971 oCenter.x, oCenter.y, oCenter.z,
972 dfRadius, dfRadius, 0.0, dfStartAngle, dfEndAngle, 0.0 );
973
974 poFeature->SetGeometryDirectly( poArc );
975
976 PrepareLineStyle( poFeature );
977
978 return poFeature;
979 }
980
981 /************************************************************************/
982 /* TranslateSPLINE() */
983 /************************************************************************/
984
985 void rbspline(int npts,int k,int p1,double b[],double h[], double p[]);
986 void rbsplinu(int npts,int k,int p1,double b[],double h[], double p[]);
987
988 OGRFeature *OGRDWGLayer::TranslateSPLINE( OdDbEntityPtr poEntity )
989
990 {
991 OdDbSplinePtr poSpline = OdDbSpline::cast( poEntity );
992 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
993 std::vector<double> adfControlPoints;
994 int nDegree, i;
995
996 TranslateGenericProperties( poFeature, poEntity );
997
998 nDegree = poSpline->degree();
999
1000 /* -------------------------------------------------------------------- */
1001 /* Collect the control points in our vector. */
1002 /* -------------------------------------------------------------------- */
1003 int nControlPoints = poSpline->numControlPoints();
1004
1005 adfControlPoints.push_back( 0.0 ); // some sort of control info.
1006
1007 for( i = 0; i < nControlPoints; i++ )
1008 {
1009 OdGePoint3d oCP;
1010
1011 poSpline->getControlPointAt( i, oCP );
1012
1013 adfControlPoints.push_back( oCP.x );
1014 adfControlPoints.push_back( oCP.y );
1015 adfControlPoints.push_back( 0.0 );
1016 }
1017
1018 /* -------------------------------------------------------------------- */
1019 /* Process values. */
1020 /* -------------------------------------------------------------------- */
1021 if( poSpline->isClosed() )
1022 {
1023 for( i = 0; i < nDegree; i++ )
1024 {
1025 adfControlPoints.push_back( adfControlPoints[i*3+1] );
1026 adfControlPoints.push_back( adfControlPoints[i*3+2] );
1027 adfControlPoints.push_back( adfControlPoints[i*3+3] );
1028 }
1029 }
1030
1031 /* -------------------------------------------------------------------- */
1032 /* Interpolate spline */
1033 /* -------------------------------------------------------------------- */
1034 std::vector<double> h, p;
1035
1036 h.push_back(1.0);
1037 for( i = 0; i < nControlPoints; i++ )
1038 h.push_back( 1.0 );
1039
1040 // resolution:
1041 //int p1 = getGraphicVariableInt("$SPLINESEGS", 8) * npts;
1042 int p1 = nControlPoints * 8;
1043
1044 p.push_back( 0.0 );
1045 for( i = 0; i < 3*p1; i++ )
1046 p.push_back( 0.0 );
1047
1048 if( poSpline->isClosed() )
1049 rbsplinu( nControlPoints, nDegree+1, p1, &(adfControlPoints[0]),
1050 &(h[0]), &(p[0]) );
1051 else
1052 rbspline( nControlPoints, nDegree+1, p1, &(adfControlPoints[0]),
1053 &(h[0]), &(p[0]) );
1054
1055 /* -------------------------------------------------------------------- */
1056 /* Turn into OGR geometry. */
1057 /* -------------------------------------------------------------------- */
1058 OGRLineString *poLS = new OGRLineString();
1059
1060 poLS->setNumPoints( p1 );
1061 for( i = 0; i < p1; i++ )
1062 poLS->setPoint( i, p[i*3+1], p[i*3+2] );
1063
1064 poFeature->SetGeometryDirectly( poLS );
1065
1066 PrepareLineStyle( poFeature );
1067
1068 return poFeature;
1069 }
1070
1071 /************************************************************************/
1072 /* GeometryInsertTransformer */
1073 /************************************************************************/
1074
1075 class GeometryInsertTransformer : public OGRCoordinateTransformation
1076 {
1077 public:
1078 GeometryInsertTransformer() :
1079 dfXOffset(0),dfYOffset(0),dfZOffset(0),
1080 dfXScale(1.0),dfYScale(1.0),dfZScale(1.0),
1081 dfAngle(0.0) {}
1082
1083 double dfXOffset;
1084 double dfYOffset;
1085 double dfZOffset;
1086 double dfXScale;
1087 double dfYScale;
1088 double dfZScale;
1089 double dfAngle;
1090
1091 OGRSpatialReference *GetSourceCS() override { return nullptr; }
1092 OGRSpatialReference *GetTargetCS() override { return nullptr; }
1093
1094 OGRCoordinateTransformation* Clone() const override { return new GeometryInsertTransformer(*this); }
1095
1096 virtual OGRCoordinateTransformation* GetInverse() const override { return nullptr; }
1097
1098 int Transform( int nCount,
1099 double *x, double *y, double *z = nullptr,
1100 double * /*t*/ = nullptr,
1101 int *pabSuccess = nullptr ) override
1102 {
1103 int i;
1104 for( i = 0; i < nCount; i++ )
1105 {
1106 double dfXNew, dfYNew;
1107
1108 x[i] *= dfXScale;
1109 y[i] *= dfYScale;
1110 if( z )
1111 z[i] *= dfZScale;
1112
1113 dfXNew = x[i] * cos(dfAngle) - y[i] * sin(dfAngle);
1114 dfYNew = x[i] * sin(dfAngle) + y[i] * cos(dfAngle);
1115
1116 x[i] = dfXNew;
1117 y[i] = dfYNew;
1118
1119 x[i] += dfXOffset;
1120 y[i] += dfYOffset;
1121 if( z )
1122 z[i] += dfZOffset;
1123
1124 if( pabSuccess )
1125 pabSuccess[i] = TRUE;
1126 }
1127 return TRUE;
1128 }
1129 };
1130
1131 /************************************************************************/
1132 /* TranslateINSERT() */
1133 /************************************************************************/
1134
1135 OGRFeature *OGRDWGLayer::TranslateINSERT( OdDbEntityPtr poEntity )
1136
1137 {
1138 OdDbBlockReferencePtr poRef = OdDbBlockReference::cast( poEntity );
1139 OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
1140
1141 TranslateGenericProperties( poFeature, poEntity );
1142
1143 /* -------------------------------------------------------------------- */
1144 /* Collect parameters from the object. */
1145 /* -------------------------------------------------------------------- */
1146 GeometryInsertTransformer oTransformer;
1147 CPLString osBlockName;
1148 double dfAngle = poRef->rotation() * 180 / M_PI;
1149 OdGePoint3d oPosition = poRef->position();
1150 OdGeScale3d oScale = poRef->scaleFactors();
1151
1152 oTransformer.dfXOffset = oPosition.x;
1153 oTransformer.dfYOffset = oPosition.y;
1154 oTransformer.dfZOffset = oPosition.z;
1155
1156 oTransformer.dfXScale = oScale.sx;
1157 oTransformer.dfYScale = oScale.sy;
1158 oTransformer.dfZScale = oScale.sz;
1159
1160 oTransformer.dfAngle = poRef->rotation();
1161
1162 OdDbBlockTableRecordPtr poBlockRec = poRef->blockTableRecord().openObject();
1163 if (poBlockRec.get())
1164 osBlockName = (const char *) poBlockRec->getName();
1165
1166 /* -------------------------------------------------------------------- */
1167 /* In the case where we do not inlined blocks we just capture */
1168 /* info on a point feature. */
1169 /* -------------------------------------------------------------------- */
1170 if( !poDS->InlineBlocks() )
1171 {
1172 poFeature->SetGeometryDirectly(
1173 new OGRPoint( oTransformer.dfXOffset,
1174 oTransformer.dfYOffset,
1175 oTransformer.dfZOffset ) );
1176
1177 poFeature->SetField( "BlockName", osBlockName );
1178
1179 poFeature->SetField( "BlockAngle", dfAngle );
1180 poFeature->SetField( "BlockScale", 3, &(oTransformer.dfXScale) );
1181
1182 return poFeature;
1183 }
1184
1185 /* -------------------------------------------------------------------- */
1186 /* Lookup the block. */
1187 /* -------------------------------------------------------------------- */
1188 DWGBlockDefinition *poBlock = poDS->LookupBlock( osBlockName );
1189
1190 if( poBlock == nullptr )
1191 {
1192 delete poFeature;
1193 return nullptr;
1194 }
1195
1196 /* -------------------------------------------------------------------- */
1197 /* Transform the geometry. */
1198 /* -------------------------------------------------------------------- */
1199 if( poBlock->poGeometry != nullptr )
1200 {
1201 OGRGeometry *poGeometry = poBlock->poGeometry->clone();
1202
1203 poGeometry->transform( &oTransformer );
1204
1205 poFeature->SetGeometryDirectly( poGeometry );
1206 }
1207
1208 /* -------------------------------------------------------------------- */
1209 /* If we have complete features associated with the block, push */
1210 /* them on the pending feature stack copying over key override */
1211 /* information. */
1212 /* */
1213 /* Note that while we transform the geometry of the features we */
1214 /* don't adjust subtle things like text angle. */
1215 /* -------------------------------------------------------------------- */
1216 unsigned int iSubFeat;
1217
1218 for( iSubFeat = 0; iSubFeat < poBlock->apoFeatures.size(); iSubFeat++ )
1219 {
1220 OGRFeature *poSubFeature = poBlock->apoFeatures[iSubFeat]->Clone();
1221 CPLString osCompEntityId;
1222
1223 if( poSubFeature->GetGeometryRef() != nullptr )
1224 poSubFeature->GetGeometryRef()->transform( &oTransformer );
1225
1226 ACAdjustText( dfAngle, oScale.sx, oScale.sy, poSubFeature );
1227
1228 #ifdef notdef
1229 osCompEntityId = poSubFeature->GetFieldAsString( "EntityHandle" );
1230 osCompEntityId += ":";
1231 #endif
1232 osCompEntityId += poFeature->GetFieldAsString( "EntityHandle" );
1233
1234 poSubFeature->SetField( "EntityHandle", osCompEntityId );
1235
1236 apoPendingFeatures.push( poSubFeature );
1237 }
1238
1239 /* -------------------------------------------------------------------- */
1240 /* If we have attributes, insert them on the stack at this */
1241 /* point too. */
1242 /* -------------------------------------------------------------------- */
1243 OdDbObjectIteratorPtr pIter = poRef->attributeIterator();
1244 for (; !pIter->done(); pIter->step())
1245 {
1246 OdDbAttributePtr pAttr = pIter->entity();
1247 if (!pAttr.isNull())
1248 {
1249 oStyleProperties.clear();
1250
1251 OGRFeature *poAttrFeat = TranslateTEXT( pAttr );
1252
1253 if( poAttrFeat )
1254 apoPendingFeatures.push( poAttrFeat );
1255 }
1256 }
1257
1258 /* -------------------------------------------------------------------- */
1259 /* Return the working feature if we had geometry, otherwise */
1260 /* return NULL and let the machinery find the rest of the */
1261 /* features in the pending feature stack. */
1262 /* -------------------------------------------------------------------- */
1263 if( poBlock->poGeometry == nullptr )
1264 {
1265 delete poFeature;
1266 return nullptr;
1267 }
1268 else
1269 {
1270 return poFeature;
1271 }
1272 }
1273
1274 /************************************************************************/
1275 /* GetNextUnfilteredFeature() */
1276 /************************************************************************/
1277
1278 OGRFeature *OGRDWGLayer::GetNextUnfilteredFeature()
1279
1280 {
1281 OGRFeature *poFeature = nullptr;
1282
1283 /* -------------------------------------------------------------------- */
1284 /* If we have pending features, return one of them. */
1285 /* -------------------------------------------------------------------- */
1286 if( !apoPendingFeatures.empty() )
1287 {
1288 poFeature = apoPendingFeatures.front();
1289 apoPendingFeatures.pop();
1290
1291 poFeature->SetFID( iNextFID++ );
1292 return poFeature;
1293 }
1294
1295 /* -------------------------------------------------------------------- */
1296 /* Fetch the next entity. */
1297 /* -------------------------------------------------------------------- */
1298 while( poFeature == nullptr && !poEntIter->done() )
1299 {
1300
1301 OdDbObjectId oId = poEntIter->objectId();
1302 OdDbEntityPtr poEntity = OdDbEntity::cast( oId.openObject() );
1303
1304 if (poEntity.isNull())
1305 return nullptr;
1306
1307 /* -------------------------------------------------------------------- */
1308 /* What is the class name for this entity? */
1309 /* -------------------------------------------------------------------- */
1310 OdRxClass *poClass = poEntity->isA();
1311 const OdString osName = poClass->name();
1312 const char *pszEntityClassName = (const char *) osName;
1313
1314 /* -------------------------------------------------------------------- */
1315 /* Handle the entity. */
1316 /* -------------------------------------------------------------------- */
1317 oStyleProperties.clear();
1318
1319 if( EQUAL(pszEntityClassName,"AcDbPoint") )
1320 {
1321 poFeature = TranslatePOINT( poEntity );
1322 }
1323 else if( EQUAL(pszEntityClassName,"AcDbLine") )
1324 {
1325 poFeature = TranslateLINE( poEntity );
1326 }
1327 else if( EQUAL(pszEntityClassName,"AcDbPolyline") )
1328 {
1329 poFeature = TranslateLWPOLYLINE( poEntity );
1330 }
1331 else if( EQUAL(pszEntityClassName,"AcDb2dPolyline") )
1332 {
1333 poFeature = Translate2DPOLYLINE( poEntity );
1334 }
1335 else if( EQUAL(pszEntityClassName,"AcDb3dPolyline") )
1336 {
1337 poFeature = Translate3DPOLYLINE( poEntity );
1338 }
1339 else if( EQUAL(pszEntityClassName,"AcDbEllipse") )
1340 {
1341 poFeature = TranslateELLIPSE( poEntity );
1342 }
1343 else if( EQUAL(pszEntityClassName,"AcDbArc") )
1344 {
1345 poFeature = TranslateARC( poEntity );
1346 }
1347 else if( EQUAL(pszEntityClassName,"AcDbMText") )
1348 {
1349 poFeature = TranslateMTEXT( poEntity );
1350 }
1351 else if( EQUAL(pszEntityClassName,"AcDbText")
1352 || EQUAL(pszEntityClassName,"AcDbAttributeDefinition") )
1353 {
1354 poFeature = TranslateTEXT( poEntity );
1355 }
1356 else if( EQUAL(pszEntityClassName,"AcDbAlignedDimension")
1357 || EQUAL(pszEntityClassName,"AcDbRotatedDimension") )
1358 {
1359 poFeature = TranslateDIMENSION( poEntity );
1360 }
1361 else if( EQUAL(pszEntityClassName,"AcDbCircle") )
1362 {
1363 poFeature = TranslateCIRCLE( poEntity );
1364 }
1365 else if( EQUAL(pszEntityClassName,"AcDbSpline") )
1366 {
1367 poFeature = TranslateSPLINE( poEntity );
1368 }
1369 else if( EQUAL(pszEntityClassName,"AcDbHatch") )
1370 {
1371 poFeature = TranslateHATCH( poEntity );
1372 }
1373 else if( EQUAL(pszEntityClassName,"AcDbBlockReference") )
1374 {
1375 poFeature = TranslateINSERT( poEntity );
1376 if( poFeature == nullptr && !apoPendingFeatures.empty() )
1377 {
1378 poFeature = apoPendingFeatures.front();
1379 apoPendingFeatures.pop();
1380 }
1381 }
1382 else
1383 {
1384 if( oIgnoredEntities.count(pszEntityClassName) == 0 )
1385 {
1386 oIgnoredEntities.insert( pszEntityClassName );
1387 CPLDebug( "DWG", "Ignoring one or more of entity '%s'.",
1388 pszEntityClassName );
1389 }
1390 }
1391
1392 poEntIter->step();
1393 }
1394
1395 /* -------------------------------------------------------------------- */
1396 /* Set FID. */
1397 /* -------------------------------------------------------------------- */
1398 if( poFeature != nullptr )
1399 {
1400 poFeature->SetFID( iNextFID++ );
1401 m_nFeaturesRead++;
1402 }
1403
1404 return poFeature;
1405 }
1406
1407 /************************************************************************/
1408 /* GetNextFeature() */
1409 /************************************************************************/
1410
1411 OGRFeature *OGRDWGLayer::GetNextFeature()
1412
1413 {
1414 while( true )
1415 {
1416 OGRFeature *poFeature = GetNextUnfilteredFeature();
1417
1418 if( poFeature == nullptr )
1419 return nullptr;
1420
1421 if( (m_poFilterGeom == nullptr
1422 || FilterGeometry( poFeature->GetGeometryRef() ) )
1423 && (m_poAttrQuery == nullptr
1424 || m_poAttrQuery->Evaluate( poFeature ) ) )
1425 {
1426 return poFeature;
1427 }
1428
1429 delete poFeature;
1430 }
1431 }
1432
1433 /************************************************************************/
1434 /* TestCapability() */
1435 /************************************************************************/
1436
1437 int OGRDWGLayer::TestCapability( const char * pszCap )
1438
1439 {
1440 if( EQUAL(pszCap,OLCStringsAsUTF8) )
1441 return TRUE;
1442 else
1443 return FALSE;
1444 }
1445