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