1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: OGR Driver for DGNv8
5 * Author: Even Rouault <even.rouault at spatialys.com>
6 *
7 ******************************************************************************
8 * Copyright (c) 2017, Even Rouault <even.rouault at spatialys.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_dgnv8.h"
30 #include "cpl_conv.h"
31 #include "ogr_featurestyle.h"
32 #include "ogr_api.h"
33
34 #include <math.h>
35 #include <algorithm>
36
37 /* -------------------------------------------------------------------- */
38 /* Line Styles */
39 /* -------------------------------------------------------------------- */
40 #define DGNS_SOLID 0
41 #define DGNS_DOTTED 1
42 #define DGNS_MEDIUM_DASH 2
43 #define DGNS_LONG_DASH 3
44 #define DGNS_DOT_DASH 4
45 #define DGNS_SHORT_DASH 5
46 #define DGNS_DASH_DOUBLE_DOT 6
47 #define DGNS_LONG_DASH_SHORT_DASH 7
48
49 constexpr double DEG_TO_RAD = M_PI / 180.0;
50 constexpr double RAD_TO_DEG = 180.0 / M_PI;
51 constexpr double CONTIGUITY_TOLERANCE = 1e10; // Arbitrary high value
52
53 CPL_CVSID("$Id: ogrdgnv8layer.cpp fa752ad6eabafaf630a704e1892a9d837d683cb3 2021-03-06 17:04:38 +0100 Even Rouault $")
54
ToUTF8(const OdString & str)55 static CPLString ToUTF8(const OdString& str)
56 {
57 return OGRDGNV8DataSource::ToUTF8(str);
58 }
59
60 /************************************************************************/
61 /* EscapeDoubleQuote() */
62 /************************************************************************/
63
EscapeDoubleQuote(const char * pszStr)64 static CPLString EscapeDoubleQuote(const char* pszStr)
65 {
66 if( strchr( pszStr, '"') != nullptr )
67 {
68 CPLString osEscaped;
69
70 for( size_t iC = 0; pszStr[iC] != '\0'; iC++ )
71 {
72 if( pszStr[iC] == '"' )
73 osEscaped += "\\\"";
74 else
75 osEscaped += pszStr[iC];
76 }
77 return osEscaped;
78 }
79 else
80 {
81 return pszStr;
82 }
83 }
84
85 /************************************************************************/
86 /* OGRDGNV8Layer() */
87 /************************************************************************/
88
OGRDGNV8Layer(OGRDGNV8DataSource * poDS,OdDgModelPtr pModel)89 OGRDGNV8Layer::OGRDGNV8Layer( OGRDGNV8DataSource* poDS,
90 OdDgModelPtr pModel ) :
91 m_poDS(poDS),
92 m_poFeatureDefn(nullptr),
93 m_pModel(pModel),
94 m_pIterator(static_cast<OdDgElementIterator*>(nullptr)),
95 m_nIdxInPendingFeatures(0)
96 {
97 const char* pszName;
98 if( pModel->getName().isEmpty() )
99 pszName = CPLSPrintf("Model #%d", pModel->getEntryId());
100 else
101 pszName = CPLSPrintf("%s", ToUTF8(pModel->getName()).c_str());
102 CPLDebug("DGNV8", "%s is %dd", pszName,
103 pModel->getModelIs3dFlag() ? 3 : 2);
104
105 /* -------------------------------------------------------------------- */
106 /* Create the feature definition. */
107 /* -------------------------------------------------------------------- */
108 m_poFeatureDefn = new OGRFeatureDefn( pszName );
109 SetDescription( m_poFeatureDefn->GetName() );
110 m_poFeatureDefn->Reference();
111
112 OGRFieldDefn oField( "", OFTInteger );
113
114 /* -------------------------------------------------------------------- */
115 /* Element type */
116 /* -------------------------------------------------------------------- */
117 oField.SetName( "Type" );
118 oField.SetType( OFTInteger );
119 oField.SetWidth( 2 );
120 oField.SetPrecision( 0 );
121 m_poFeatureDefn->AddFieldDefn( &oField );
122
123 /* -------------------------------------------------------------------- */
124 /* Level number. */
125 /* -------------------------------------------------------------------- */
126 oField.SetName( "Level" );
127 oField.SetType( OFTInteger );
128 oField.SetWidth( 2 );
129 oField.SetPrecision( 0 );
130 m_poFeatureDefn->AddFieldDefn( &oField );
131
132 /* -------------------------------------------------------------------- */
133 /* graphic group */
134 /* -------------------------------------------------------------------- */
135 oField.SetName( "GraphicGroup" );
136 oField.SetType( OFTInteger );
137 oField.SetWidth( 4 );
138 oField.SetPrecision( 0 );
139 m_poFeatureDefn->AddFieldDefn( &oField );
140
141 /* -------------------------------------------------------------------- */
142 /* ColorIndex */
143 /* -------------------------------------------------------------------- */
144 oField.SetName( "ColorIndex" );
145 oField.SetType( OFTInteger );
146 oField.SetWidth( 3 );
147 oField.SetPrecision( 0 );
148 m_poFeatureDefn->AddFieldDefn( &oField );
149
150 /* -------------------------------------------------------------------- */
151 /* Weight */
152 /* -------------------------------------------------------------------- */
153 oField.SetName( "Weight" );
154 oField.SetType( OFTInteger );
155 oField.SetWidth( 2 );
156 oField.SetPrecision( 0 );
157 m_poFeatureDefn->AddFieldDefn( &oField );
158
159 /* -------------------------------------------------------------------- */
160 /* Style */
161 /* -------------------------------------------------------------------- */
162 oField.SetName( "Style" );
163 oField.SetType( OFTInteger );
164 oField.SetWidth( 1 );
165 oField.SetPrecision( 0 );
166 m_poFeatureDefn->AddFieldDefn( &oField );
167
168 /* -------------------------------------------------------------------- */
169 /* Text */
170 /* -------------------------------------------------------------------- */
171 oField.SetName( "Text" );
172 oField.SetType( OFTString );
173 oField.SetWidth( 0 );
174 oField.SetPrecision( 0 );
175 m_poFeatureDefn->AddFieldDefn( &oField );
176
177 /* -------------------------------------------------------------------- */
178 /* ULink */
179 /* -------------------------------------------------------------------- */
180 oField.SetName( "ULink" );
181 oField.SetType( OFTString );
182 oField.SetSubType( OFSTJSON );
183 oField.SetWidth( 0 );
184 oField.SetPrecision( 0 );
185 m_poFeatureDefn->AddFieldDefn( &oField );
186
187 OGRDGNV8Layer::ResetReading();
188 }
189
190 /************************************************************************/
191 /* ~OGRDGNV8Layer() */
192 /************************************************************************/
193
~OGRDGNV8Layer()194 OGRDGNV8Layer::~OGRDGNV8Layer()
195
196 {
197 CleanPendingFeatures();
198 m_poFeatureDefn->Release();
199 }
200 /************************************************************************/
201 /* CleanPendingFeatures() */
202 /************************************************************************/
203
CleanPendingFeatures()204 void OGRDGNV8Layer::CleanPendingFeatures()
205
206 {
207 for( size_t i = m_nIdxInPendingFeatures;
208 i < m_aoPendingFeatures.size(); i++ )
209 {
210 delete m_aoPendingFeatures[i].first;
211 }
212 m_aoPendingFeatures.clear();
213 m_nIdxInPendingFeatures = 0;
214 }
215
216 /************************************************************************/
217 /* ResetReading() */
218 /************************************************************************/
219
ResetReading()220 void OGRDGNV8Layer::ResetReading()
221
222 {
223 if( m_pModel.get() )
224 {
225 m_pIterator = m_pModel->createGraphicsElementsIterator();
226 }
227 CleanPendingFeatures();
228 }
229
230 /************************************************************************/
231 /* CollectSubElements() */
232 /************************************************************************/
233
CollectSubElements(OdDgElementIteratorPtr iterator,int level)234 std::vector<tPairFeatureHoleFlag> OGRDGNV8Layer::CollectSubElements(
235 OdDgElementIteratorPtr iterator, int level )
236 {
237 std::vector<tPairFeatureHoleFlag> oVector;
238 #ifdef DEBUG_VERBOSE
239 CPLString osIndent;
240 for(int i=0;i<level;i++)
241 osIndent += " ";
242 int counter = 0;
243 #endif
244 for( ; !iterator->done(); iterator->step())
245 {
246 #ifdef DEBUG_VERBOSE
247 fprintf(stdout, "%sSub element %d:\n", osIndent.c_str(), counter );
248 counter ++;
249 #endif
250 OdRxObjectPtr object = iterator->item().openObject( OdDg::kForRead );
251 OdDgGraphicsElementPtr element = OdDgGraphicsElement::cast( object );
252 if (element.isNull())
253 continue;
254
255 std::vector<tPairFeatureHoleFlag> oSubVector =
256 ProcessElement(element, level + 1);
257 oVector.insert(oVector.end(), oSubVector.begin(), oSubVector.end());
258 }
259 return oVector;
260 }
261
262 /************************************************************************/
263 /* GetAnchorPosition() */
264 /************************************************************************/
265
GetAnchorPosition(OdDg::TextJustification value)266 static int GetAnchorPosition( OdDg::TextJustification value )
267 {
268 switch( value )
269 {
270 case OdDg::kLeftTop : return 7;
271 case OdDg::kLeftCenter : return 4;
272 case OdDg::kLeftBottom : return 10;
273 case OdDg::kLeftMarginTop : return 7;
274 case OdDg::kLeftMarginCenter : return 4;
275 case OdDg::kLeftMarginBottom : return 10;
276 case OdDg::kCenterTop : return 8;
277 case OdDg::kCenterCenter : return 5;
278 case OdDg::kCenterBottom : return 11;
279 case OdDg::kRightMarginTop : return 9;
280 case OdDg::kRightMarginCenter : return 6;
281 case OdDg::kRightMarginBottom : return 12;
282 case OdDg::kRightTop : return 9;
283 case OdDg::kRightCenter : return 6;
284 case OdDg::kRightBottom : return 12;
285 case OdDg::kLeftDescender : return 1;
286 case OdDg::kCenterDescender : return 2;
287 case OdDg::kRightDescender : return 3;
288 default : return 0;
289 }
290 }
291
292 /************************************************************************/
293 /* GetAnchorPosition() */
294 /************************************************************************/
295
GetAnchorPositionFromOGR(int value)296 static OdDg::TextJustification GetAnchorPositionFromOGR( int value )
297 {
298 switch( value )
299 {
300 case 1: return OdDg::kLeftDescender;
301 case 2: return OdDg::kCenterDescender;
302 case 3: return OdDg::kRightDescender;
303 case 4: return OdDg::kLeftCenter;
304 case 5: return OdDg::kCenterCenter;
305 case 6: return OdDg::kRightCenter;
306 case 7: return OdDg::kLeftTop;
307 case 8: return OdDg::kCenterTop;
308 case 9: return OdDg::kRightTop;
309 case 10: return OdDg::kLeftBottom;
310 case 11: return OdDg::kCenterBottom;
311 case 12: return OdDg::kRightBottom;
312 default: return OdDg::kLeftTop;
313 }
314 }
315
316 /************************************************************************/
317 /* AlmostEqual() */
318 /************************************************************************/
319
AlmostEqual(double dfA,double dfB)320 static bool AlmostEqual(double dfA, double dfB)
321 {
322 if( fabs(dfB) > 1e-7 )
323 return fabs((dfA - dfB) / dfB) < 1e-6;
324 else
325 return fabs(dfA) <= 1e-7;
326 }
327
328 /************************************************************************/
329 /* ProcessTextTraits */
330 /************************************************************************/
331
332 template<class TextPtr> struct ProcessTextTraits
333 {
334 };
335
336 template<> struct ProcessTextTraits<OdDgText2dPtr>
337 {
getRotationProcessTextTraits338 static double getRotation(OdDgText2dPtr text)
339 {
340 return text->getRotation();
341 }
342
setGeomProcessTextTraits343 static void setGeom(OGRFeature* poFeature, OdDgText2dPtr text)
344 {
345 OdGePoint2d point = text->getOrigin();
346 poFeature->SetGeometryDirectly(
347 new OGRPoint(point.x, point.y) );
348 }
349 };
350
351 template<> struct ProcessTextTraits<OdDgText3dPtr>
352 {
getRotationProcessTextTraits353 static double getRotation(OdDgText3dPtr /*text*/)
354 {
355 return 0.0;
356 }
357
setGeomProcessTextTraits358 static void setGeom(OGRFeature* poFeature, OdDgText3dPtr text)
359 {
360 OdGePoint3d point = text->getOrigin();
361 poFeature->SetGeometryDirectly(
362 new OGRPoint(point.x, point.y, point.z) );
363 }
364 };
365
366 /************************************************************************/
367 /* ProcessText() */
368 /************************************************************************/
369
370 template<class TextPtr >
ProcessText(OGRFeature * poFeature,const CPLString & osColor,TextPtr text)371 static void ProcessText(OGRFeature* poFeature,
372 const CPLString& osColor,
373 TextPtr text)
374 {
375 const OdString oText = text->getText();
376 poFeature->SetField( "Text", ToUTF8(oText).c_str());
377
378 CPLString osStyle;
379 osStyle.Printf("LABEL(t:\"%s\"",
380 EscapeDoubleQuote(ToUTF8(oText)).c_str());
381 osStyle += osColor;
382 osStyle += CPLSPrintf(",s:%fg", text->getHeightMultiplier());
383
384 // Gets Font name
385 OdDgFontTablePtr pFontTable = text->database()->getFontTable();
386 OdDgFontTableRecordPtr pFont =
387 pFontTable->getFont(text->getFontEntryId());
388 if (!pFont.isNull())
389 {
390 osStyle += CPLSPrintf(",f:\"%s\"",
391 EscapeDoubleQuote(ToUTF8(pFont->getName())).c_str() );
392 }
393 else
394 {
395 osStyle += CPLSPrintf(",f:MstnFont%u",
396 text->getFontEntryId() );
397 }
398
399 const int nAnchor = GetAnchorPosition(text->getJustification());
400 if( nAnchor > 0 )
401 osStyle += CPLSPrintf(",p:%d", nAnchor);
402
403 // Add the angle, if not horizontal
404 const double dfRotation =
405 ProcessTextTraits<TextPtr>::getRotation(text);
406 if( dfRotation != 0.0 )
407 osStyle += CPLSPrintf(",a:%d",
408 static_cast<int>(floor(dfRotation * RAD_TO_DEG +0.5)) );
409
410 osStyle += ")";
411 poFeature->SetStyleString(osStyle);
412 ProcessTextTraits<TextPtr>::setGeom( poFeature, text );
413 }
414
415 /************************************************************************/
416 /* ConsiderBrush() */
417 /************************************************************************/
418
ConsiderBrush(OdDgGraphicsElementPtr element,const CPLString & osStyle)419 static CPLString ConsiderBrush(OdDgGraphicsElementPtr element,
420 const CPLString& osStyle)
421 {
422 CPLString osNewStyle(osStyle);
423 OdRxObjectPtrArray linkages;
424 element->getLinkages(OdDgAttributeLinkage::kFillStyle, linkages);
425 if( linkages.length() >= 1 )
426 {
427 OdDgFillColorLinkagePtr fillColor =
428 OdDgFillColorLinkage::cast( linkages[0] );
429 if( !fillColor.isNull() )
430 {
431 const OdUInt32 uFillColorIdx = fillColor->getColorIndex();
432 if( OdDgColorTable::isCorrectIndex(
433 element->database(), uFillColorIdx ) )
434 {
435 ODCOLORREF color = OdDgColorTable::lookupRGB(
436 element->database(), uFillColorIdx );
437 const char* pszBrush = CPLSPrintf(
438 "BRUSH(fc:#%02x%02x%02x,id:\"ogr-brush-0\")",
439 ODGETRED(color),
440 ODGETGREEN(color),
441 ODGETBLUE(color));
442 const OdUInt32 uColorIndex = element->getColorIndex();
443 if( uFillColorIdx != uColorIndex )
444 {
445 osNewStyle = CPLString(pszBrush) + ";" + osNewStyle;
446 }
447 else
448 {
449 osNewStyle = pszBrush;
450 }
451 }
452 }
453 }
454 return osNewStyle;
455 }
456
457 /************************************************************************/
458 /* ProcessCurveTraits */
459 /************************************************************************/
460
461 template<class CurveElementPtr> struct ProcessCurveTraits
462 {
463 };
464
465 template<> struct ProcessCurveTraits<OdDgCurveElement2dPtr>
466 {
467 typedef OdDgCurve2d CurveType;
468 typedef OdDgArc2d ArcType;
469 typedef OdDgBSplineCurve2d BSplineType;
470 typedef OdDgEllipse2d EllipseType;
471 typedef OdGePoint2d PointType;
472
setPointProcessCurveTraits473 static void setPoint( OGRSimpleCurve* poSC, int i, OdGePoint2d point)
474 {
475 poSC->setPoint(i, point.x, point.y);
476 }
477 };
478
479 template<> struct ProcessCurveTraits<OdDgCurveElement3dPtr>
480 {
481 typedef OdDgCurve3d CurveType;
482 typedef OdDgArc3d ArcType;
483 typedef OdDgBSplineCurve3d BSplineType;
484 typedef OdDgEllipse3d EllipseType;
485 typedef OdGePoint3d PointType;
486
setPointProcessCurveTraits487 static void setPoint( OGRSimpleCurve* poSC, int i, OdGePoint3d point)
488 {
489 poSC->setPoint(i, point.x, point.y, point.z);
490 }
491 };
492
493 /************************************************************************/
494 /* ProcessCurve() */
495 /************************************************************************/
496
497 template<class CurveElementPtr>
ProcessCurve(OGRFeature * poFeature,const CPLString & osPen,CurveElementPtr curveElement)498 static void ProcessCurve(OGRFeature* poFeature, const CPLString& osPen,
499 CurveElementPtr curveElement)
500 {
501 typedef typename ProcessCurveTraits<CurveElementPtr>::CurveType CurveType;
502 typedef typename ProcessCurveTraits<CurveElementPtr>::ArcType ArcType;
503 typedef typename ProcessCurveTraits<CurveElementPtr>::BSplineType
504 BSplineType;
505 typedef typename ProcessCurveTraits<CurveElementPtr>::EllipseType
506 EllipseType;
507 typedef typename ProcessCurveTraits<CurveElementPtr>::PointType PointType;
508
509 OdSmartPtr<CurveType> curve = CurveType::cast( curveElement );
510 OdSmartPtr<ArcType> arc = ArcType::cast( curveElement );
511 OdSmartPtr<BSplineType> bspline = BSplineType::cast( curveElement );
512 OdSmartPtr<EllipseType> ellipse = EllipseType::cast( curveElement );
513
514 bool bIsCircular = false;
515 if( !ellipse.isNull() )
516 {
517 bIsCircular = AlmostEqual(ellipse->getPrimaryAxis(),
518 ellipse->getSecondaryAxis());
519 }
520 else if( !arc.isNull() )
521 {
522 bIsCircular = AlmostEqual(arc->getPrimaryAxis(),
523 arc->getSecondaryAxis());
524 }
525
526 double dfStartParam, dfEndParam;
527 OdResult eRes = curveElement->getStartParam(dfStartParam);
528 CPL_IGNORE_RET_VAL(eRes);
529 CPLAssert(eRes == eOk );
530 eRes = curveElement->getEndParam(dfEndParam);
531 CPL_IGNORE_RET_VAL(eRes);
532 CPLAssert(eRes == eOk );
533
534 CPLString osStyle(osPen);
535 bool bIsFilled = false;
536 if( !ellipse.isNull() )
537 {
538 osStyle = ConsiderBrush(curveElement, osPen);
539 bIsFilled = osStyle.find("BRUSH") == 0;
540 }
541
542 OGRSimpleCurve* poSC;
543 int nPoints;
544 if( !bspline.isNull() )
545 {
546 // 10 is somewhat arbitrary
547 nPoints = 10 * bspline->numControlPoints();
548 poSC = new OGRLineString();
549 }
550 else if( !curve.isNull() )
551 {
552 // 5 is what is used in DGN driver
553 nPoints = 5 * curve->getVerticesCount();
554 poSC = new OGRLineString();
555 }
556 else if( bIsCircular )
557 {
558 poSC = new OGRCircularString();
559 if( !ellipse.isNull() )
560 {
561 nPoints = 5;
562 }
563 else
564 {
565 nPoints = 3;
566 }
567 }
568 else
569 {
570 if( bIsFilled )
571 poSC = new OGRLinearRing();
572 else
573 poSC = new OGRLineString();
574 const double dfArcStepSize =
575 CPLAtofM(CPLGetConfigOption("OGR_ARC_STEPSIZE", "4"));
576 if( !ellipse.isNull() )
577 {
578 nPoints = std::max(2,
579 static_cast<int>(360 / dfArcStepSize));
580 }
581 else
582 {
583 nPoints = std::max(2,
584 static_cast<int>(arc->getSweepAngle() *
585 RAD_TO_DEG / dfArcStepSize) );
586 }
587 }
588
589 poSC->setNumPoints(nPoints);
590 for( int i = 0; i < nPoints; i++ )
591 {
592 PointType point;
593 double dfParam = dfStartParam + i *
594 (dfEndParam - dfStartParam) / (nPoints - 1);
595 eRes = curveElement->getPointAtParam(dfParam, point);
596 CPL_IGNORE_RET_VAL(eRes);
597 CPLAssert(eRes == eOk );
598 ProcessCurveTraits<CurveElementPtr>::setPoint(poSC, i, point);
599 }
600
601 if( bIsFilled )
602 {
603 if( bIsCircular )
604 {
605 OGRCurvePolygon* poCP = new OGRCurvePolygon();
606 poCP->addRingDirectly(poSC);
607 poFeature->SetGeometryDirectly( poCP );
608 }
609 else
610 {
611 OGRPolygon* poPoly = new OGRPolygon();
612 poPoly->addRingDirectly(poSC);
613 poFeature->SetGeometryDirectly( poPoly );
614 }
615 }
616 else
617 {
618 poFeature->SetGeometryDirectly( poSC );
619 }
620 poFeature->SetStyleString(osStyle);
621 }
622
623 /************************************************************************/
624 /* IsContiguous() */
625 /************************************************************************/
626
627 static
IsContiguous(const std::vector<tPairFeatureHoleFlag> & oVectorSubElts,bool & bHasCurves,bool & bIsClosed)628 bool IsContiguous( const std::vector<tPairFeatureHoleFlag>& oVectorSubElts,
629 bool& bHasCurves,
630 bool& bIsClosed )
631 {
632 bHasCurves = false;
633 bIsClosed = false;
634 OGRPoint oFirstPoint, oLastPoint;
635 bool bLastPointValid = false;
636 bool bIsContiguous = true;
637 for( size_t i = 0; i < oVectorSubElts.size(); i++ )
638 {
639 OGRGeometry* poGeom = oVectorSubElts[i].first->GetGeometryRef();
640 if( poGeom != nullptr )
641 {
642 OGRwkbGeometryType eType =
643 wkbFlatten(poGeom->getGeometryType());
644 if( eType == wkbCircularString )
645 {
646 bHasCurves = true;
647 }
648 if( bIsContiguous &&
649 (eType == wkbCircularString ||
650 eType == wkbLineString) )
651 {
652 OGRCurve* poCurve = poGeom->toCurve();
653 if( poCurve->getNumPoints() >= 2 )
654 {
655 OGRPoint oStartPoint;
656 poCurve->StartPoint( &oStartPoint );
657
658 if( bLastPointValid )
659 {
660 if( !AlmostEqual(oStartPoint.getX(),
661 oLastPoint.getX()) ||
662 !AlmostEqual(oStartPoint.getY(),
663 oLastPoint.getY()) ||
664 !AlmostEqual(oStartPoint.getZ(),
665 oLastPoint.getZ()) )
666 {
667 bIsContiguous = false;
668 break;
669 }
670 }
671 else
672 {
673 oFirstPoint = oStartPoint;
674 }
675 bLastPointValid = true;
676 poCurve->EndPoint( &oLastPoint );
677 }
678 else
679 {
680 bIsContiguous = false;
681 break;
682 }
683 }
684 else
685 {
686 bIsContiguous = false;
687 break;
688 }
689 }
690 }
691 if( bIsContiguous )
692 {
693 bIsClosed = bLastPointValid &&
694 AlmostEqual(oFirstPoint.getX(), oLastPoint.getX()) &&
695 AlmostEqual(oFirstPoint.getY(), oLastPoint.getY()) &&
696 AlmostEqual(oFirstPoint.getZ(), oLastPoint.getZ());
697 }
698 return bIsContiguous;
699 }
700
701 /************************************************************************/
702 /* ProcessElement() */
703 /************************************************************************/
704
ProcessElement(OdDgGraphicsElementPtr element,int level)705 std::vector<tPairFeatureHoleFlag> OGRDGNV8Layer::ProcessElement(
706 OdDgGraphicsElementPtr element,
707 int level)
708 {
709 std::vector<tPairFeatureHoleFlag> oVector;
710 #ifdef DEBUG_VERBOSE
711 CPLString osIndent;
712 for(int i=0;i<level;i++)
713 osIndent += " ";
714 #endif
715
716 bool bHoleFlag = false;
717 OGRFeature *poFeature = new OGRFeature( m_poFeatureDefn );
718
719 OdRxClass *poClass = element->isA();
720 const OdString osName = poClass->name();
721 const char *pszEntityClassName = static_cast<const char*>(osName);
722 poFeature->SetFID(
723 static_cast<GIntBig>(
724 static_cast<OdUInt64>(element->elementId().getHandle()) ) );
725 #ifdef DEBUG_VERBOSE
726 fprintf(stdout, "%s%s\n", osIndent.c_str(), pszEntityClassName);
727 fprintf(stdout, "%sID = %s\n",
728 osIndent.c_str(),
729 static_cast<const char*>(element->elementId().getHandle().ascii()) );
730 fprintf(stdout, "%sType = %d\n",
731 osIndent.c_str(), element->getElementType() );
732 #endif
733
734 poFeature->SetField("Type", element->getElementType() );
735 const int nLevel = static_cast<int>(element->getLevelEntryId());
736 poFeature->SetField("Level", nLevel );
737 poFeature->SetField("GraphicGroup",
738 static_cast<int>(element->getGraphicsGroupEntryId()) );
739 const OdUInt32 uColorIndex = element->getColorIndex();
740 CPLString osColor;
741 if( uColorIndex != OdDg::kColorByLevel &&
742 uColorIndex != OdDg::kColorByCell )
743 {
744 poFeature->SetField("ColorIndex",
745 static_cast<int>(uColorIndex));
746
747 const ODCOLORREF color = element->getColor();
748 osColor = CPLSPrintf(",c:#%02x%02x%02x",
749 ODGETRED(color),
750 ODGETGREEN(color),
751 ODGETBLUE(color));
752 }
753 const OdInt32 nLineStyle = element->getLineStyleEntryId();
754 if( nLineStyle != OdDg::kLineStyleByLevel &&
755 nLineStyle != OdDg::kLineStyleByCell )
756 {
757 poFeature->SetField("Style", nLineStyle);
758 }
759
760 const OdUInt32 uLineWeight = element->getLineWeight();
761 int nLineWeight = 0;
762 if( uLineWeight != OdDg::kLineWeightByLevel &&
763 uLineWeight != OdDg::kLineWeightByCell )
764 {
765 nLineWeight = static_cast<int>(uLineWeight);
766 poFeature->SetField("Weight", nLineWeight);
767 }
768
769 CPLJSONObject uLinkData;
770 CPLJSONArray previousValues;
771
772 OdRxObjectPtrArray linkages;
773 element->getLinkages(linkages);
774 if( linkages.size() > 0 )
775 {
776 for(unsigned i = 0; i < linkages.size(); ++i)
777 {
778 OdDgAttributeLinkagePtr pLinkage = linkages[i];
779 OdUInt16 primaryId = pLinkage->getPrimaryId();
780 CPLString primaryIdStr = CPLSPrintf("%d", primaryId );
781
782 OdBinaryData pabyData;
783 pLinkage->getData(pabyData);
784
785 previousValues = uLinkData.GetArray( primaryIdStr.c_str() );
786 if (!previousValues.IsValid() )
787 {
788 uLinkData.Add( primaryIdStr.c_str(), CPLJSONArray() );
789 previousValues = uLinkData.GetArray( primaryIdStr.c_str() );
790 }
791 CPLJSONObject theNewObject = CPLJSONObject();
792 GByte* pData = pabyData.asArrayPtr();
793 int nSize = pabyData.size();
794 theNewObject.Add( "size", nSize );
795 previousValues.Add( theNewObject );
796 switch( primaryId ) {
797 case OdDgAttributeLinkage::kFRAMME : // DB Linkage - FRAMME tag data signature
798 case OdDgAttributeLinkage::kBSI : // DB Linkage - secondary id link (BSI radix 50)
799 case OdDgAttributeLinkage::kXBASE : // DB Linkage - XBase (DBase)
800 case OdDgAttributeLinkage::kINFORMIX : // DB Linkage - Informix
801 case OdDgAttributeLinkage::kINGRES : // DB Linkage - INGRES
802 case OdDgAttributeLinkage::kSYBASE : // DB Linkage - Sybase
803 case OdDgAttributeLinkage::kODBC : // DB Linkage - ODBC
804 case OdDgAttributeLinkage::kOLEDB : // DB Linkage - OLEDB
805 case OdDgAttributeLinkage::kORACLE : // DB Linkage - Oracle
806 case OdDgAttributeLinkage::kRIS : // DB Linkage - RIS
807 {
808 OdDgDBLinkagePtr dbLinkage = OdDgDBLinkage::cast( pLinkage );
809 if( !dbLinkage.isNull() )
810 {
811 std::string namedType;
812
813 switch( dbLinkage->getDBType() )
814 {
815 case OdDgDBLinkage::kBSI:
816 namedType.assign("BSI");
817 break;
818 case OdDgDBLinkage::kFRAMME:
819 namedType.assign("FRAMME");
820 break;
821 case OdDgDBLinkage::kInformix:
822 namedType.assign("Informix");
823 break;
824 case OdDgDBLinkage::kIngres:
825 namedType.assign("Ingres");
826 break;
827 case OdDgDBLinkage::kODBC:
828 namedType.assign("ODBC");
829 break;
830 case OdDgDBLinkage::kOLEDB:
831 namedType.assign("OLE DB");
832 break;
833 case OdDgDBLinkage::kOracle:
834 namedType.assign("Oracle");
835 break;
836 case OdDgDBLinkage::kRIS:
837 namedType.assign("RIS");
838 break;
839 case OdDgDBLinkage::kSybase:
840 namedType.assign("Sybase");
841 break;
842 case OdDgDBLinkage::kXbase:
843 namedType.assign("xBase");
844 break;
845 default:
846 namedType.assign("Unknown");
847 break;
848 }
849
850 theNewObject.Add( "tableId", int( dbLinkage->getTableEntityId() ) );
851 theNewObject.Add( "MSLink", int( dbLinkage->getMSLink() ) );
852 theNewObject.Add( "type", namedType );
853 }
854 }
855 break;
856 case 0x1995: // 0x1995 (6549) IPCC/Portugal
857 {
858 theNewObject.Add( "domain", CPLSPrintf("0x%02x", pData[5] ) );
859 theNewObject.Add( "subdomain", CPLSPrintf("0x%02x", pData[4] ) );
860 theNewObject.Add( "family", CPLSPrintf("0x%02x", pData[7] ) );
861 theNewObject.Add( "object", CPLSPrintf("0x%02x", pData[6] ) );
862 theNewObject.Add( "key", CPLSPrintf("%02x%02x%02x%02x", pData[5], pData[4], pData[7], pData[6] ) );
863 theNewObject.Add( "type", "IPCC/Portugal" );
864 }
865 break;
866 case OdDgAttributeLinkage::kString: // 0x56d2 (22226):
867 {
868 OdDgStringLinkagePtr pStrLinkage = OdDgStringLinkage::cast( pLinkage );
869 if ( !pStrLinkage.isNull() )
870 {
871 theNewObject.Add( "string", ToUTF8(pStrLinkage->getString()).c_str() );
872 theNewObject.Add( "type", "string" );
873 }
874 }
875 break;
876 default:
877 {
878 CPLJSONArray rawWords;
879 for( int k=0; k < nSize-1; k+=2 )
880 {
881 rawWords.Add( CPLSPrintf("0x%02x%02x", pData[k+1], pData[k] ) );
882 }
883 theNewObject.Add( "raw", rawWords );
884 theNewObject.Add( "type", "unknown" );
885 }
886 break;
887 }
888
889 }
890
891 poFeature->SetField( "ULink", uLinkData.ToString().c_str() );
892
893 }
894
895 /* -------------------------------------------------------------------- */
896 /* Generate corresponding PEN style. */
897 /* -------------------------------------------------------------------- */
898 CPLString osPen;
899
900 if( nLineStyle == DGNS_SOLID )
901 osPen = "PEN(id:\"ogr-pen-0\"";
902 else if( nLineStyle == DGNS_DOTTED )
903 osPen = "PEN(id:\"ogr-pen-5\"";
904 else if( nLineStyle == DGNS_MEDIUM_DASH )
905 osPen = "PEN(id:\"ogr-pen-2\"";
906 else if( nLineStyle == DGNS_LONG_DASH )
907 osPen = "PEN(id:\"ogr-pen-4\"";
908 else if( nLineStyle == DGNS_DOT_DASH )
909 osPen = "PEN(id:\"ogr-pen-6\"";
910 else if( nLineStyle == DGNS_SHORT_DASH )
911 osPen = "PEN(id:\"ogr-pen-3\"";
912 else if( nLineStyle == DGNS_DASH_DOUBLE_DOT )
913 osPen = "PEN(id:\"ogr-pen-7\"";
914 else if( nLineStyle == DGNS_LONG_DASH_SHORT_DASH )
915 osPen = "PEN(p:\"10px 5px 4px 5px\"";
916 else
917 osPen = "PEN(id:\"ogr-pen-0\"";
918
919 osPen += osColor;
920
921 if( nLineWeight > 1 )
922 osPen += CPLSPrintf(",w:%dpx", nLineWeight );
923
924 osPen += ")";
925
926 if( EQUAL(pszEntityClassName, "OdDgCellHeader2d") ||
927 EQUAL(pszEntityClassName, "OdDgCellHeader3d") )
928 {
929 bool bDestroyFeature = true;
930 OdDgElementIteratorPtr iterator;
931 if( EQUAL(pszEntityClassName, "OdDgCellHeader2d") )
932 {
933 OdDgCellHeader2dPtr elementCell = OdDgCellHeader2d::cast( element );
934 CPLAssert( !elementCell.isNull() );
935 iterator = elementCell->createIterator();
936 }
937 else
938 {
939 OdDgCellHeader3dPtr elementCell = OdDgCellHeader3d::cast( element );
940 CPLAssert( !elementCell.isNull() );
941 iterator = elementCell->createIterator();
942 }
943 if( !iterator.isNull() )
944 {
945 oVector = CollectSubElements(iterator, level + 1 );
946 int nCountMain = 0;
947 bool bHasHole = false;
948 bool bHasCurve = false;
949 OGRGeometry* poExterior = nullptr;
950 for( size_t i = 0; i < oVector.size(); i++ )
951 {
952 OGRFeature* poFeat = oVector[i].first;
953 CPLAssert( poFeat );
954 OGRGeometry* poGeom = poFeat->GetGeometryRef();
955 if( poGeom == nullptr )
956 {
957 nCountMain = 0;
958 break;
959 }
960 const OGRwkbGeometryType eType =
961 wkbFlatten(poGeom->getGeometryType());
962 if( (eType == wkbPolygon || eType == wkbCurvePolygon) &&
963 poGeom->toCurvePolygon()->getNumInteriorRings() == 0 )
964 {
965 if( eType == wkbCurvePolygon )
966 bHasCurve = true;
967 if( oVector[i].second )
968 bHasHole = true;
969 else
970 {
971 poExterior = poGeom;
972 nCountMain ++;
973 }
974 }
975 else
976 {
977 nCountMain = 0;
978 break;
979 }
980 }
981 if( nCountMain == 1 && bHasHole )
982 {
983 bDestroyFeature = false;
984 OGRCurvePolygon* poCP;
985 if( bHasCurve )
986 poCP = new OGRCurvePolygon();
987 else
988 poCP = new OGRPolygon();
989 poCP->addRing(poExterior->toCurvePolygon()->getExteriorRingCurve() );
990 for( size_t i = 0; i < oVector.size(); i++ )
991 {
992 OGRFeature* poFeat = oVector[i].first;
993 OGRGeometry* poGeom = poFeat->GetGeometryRef();
994 if( poGeom != poExterior )
995 {
996 poCP->addRing(poGeom->toCurvePolygon()->
997 getExteriorRingCurve() );
998 }
999 delete poFeat;
1000 }
1001 oVector.clear();
1002 poFeature->SetGeometryDirectly(poCP);
1003 poFeature->SetStyleString( ConsiderBrush(element, osPen) );
1004 }
1005 }
1006 if( bDestroyFeature )
1007 {
1008 delete poFeature;
1009 poFeature = nullptr;
1010 }
1011 }
1012 else if( EQUAL(pszEntityClassName, "OdDgText2d") )
1013 {
1014 OdDgText2dPtr text = OdDgText2d::cast( element );
1015 CPLAssert( !text.isNull() );
1016 ProcessText(poFeature, osColor, text);
1017 }
1018 else if( EQUAL(pszEntityClassName, "OdDgText3d") )
1019 {
1020 OdDgText3dPtr text = OdDgText3d::cast( element );
1021 CPLAssert( !text.isNull() );
1022 ProcessText(poFeature, osColor, text);
1023 }
1024 else if( EQUAL(pszEntityClassName, "OdDgTextNode2d") ||
1025 EQUAL(pszEntityClassName, "OdDgTextNode3d") )
1026 {
1027 OdDgElementIteratorPtr iterator;
1028 if( EQUAL(pszEntityClassName, "OdDgTextNode2d") )
1029 {
1030 OdDgTextNode2dPtr textNode = OdDgTextNode2d::cast( element );
1031 CPLAssert( !textNode.isNull() );
1032 iterator = textNode->createIterator();
1033 }
1034 else
1035 {
1036 OdDgTextNode3dPtr textNode = OdDgTextNode3d::cast( element );
1037 CPLAssert( !textNode.isNull() );
1038 iterator = textNode->createIterator();
1039 }
1040 if( !iterator.isNull() )
1041 {
1042 oVector = CollectSubElements(iterator, level + 1 );
1043 }
1044 delete poFeature;
1045 poFeature = nullptr;
1046 }
1047 else if( EQUAL(pszEntityClassName, "OdDgLine2d") )
1048 {
1049 OdDgLine2dPtr line = OdDgLine2d::cast( element );
1050 CPLAssert( !line.isNull() );
1051 OdGePoint2d pointStart = line->getStartPoint( );
1052 OdGePoint2d pointEnd = line->getEndPoint( );
1053 if( pointStart == pointEnd )
1054 {
1055 poFeature->SetGeometryDirectly(
1056 new OGRPoint(pointStart.x, pointStart.y) );
1057 }
1058 else
1059 {
1060 OGRLineString* poLS = new OGRLineString();
1061 poLS->setNumPoints(2);
1062 poLS->setPoint(0, pointStart.x, pointStart.y);
1063 poLS->setPoint(1, pointEnd.x, pointEnd.y);
1064 poFeature->SetGeometryDirectly( poLS );
1065 poFeature->SetStyleString(osPen);
1066 }
1067 }
1068 else if( EQUAL(pszEntityClassName, "OdDgLine3d") )
1069 {
1070 OdDgLine3dPtr line = OdDgLine3d::cast( element );
1071 CPLAssert( !line.isNull() );
1072 OdGePoint3d pointStart = line->getStartPoint( );
1073 OdGePoint3d pointEnd = line->getEndPoint( );
1074 if( pointStart == pointEnd )
1075 {
1076 poFeature->SetGeometryDirectly(
1077 new OGRPoint(pointStart.x, pointStart.y, pointStart.z) );
1078 }
1079 else
1080 {
1081 OGRLineString* poLS = new OGRLineString();
1082 poLS->setNumPoints(2);
1083 poLS->setPoint(0, pointStart.x, pointStart.y, pointStart.z);
1084 poLS->setPoint(1, pointEnd.x, pointEnd.y, pointEnd.z);
1085 poFeature->SetGeometryDirectly( poLS );
1086 poFeature->SetStyleString(osPen);
1087 }
1088 }
1089 else if( EQUAL(pszEntityClassName, "OdDgLineString2d") )
1090 {
1091 OdDgLineString2dPtr line = OdDgLineString2d::cast( element );
1092 CPLAssert( !line.isNull() );
1093 const int nPoints = line->getVerticesCount();
1094
1095 OGRLineString* poLS = new OGRLineString();
1096 poLS->setNumPoints(nPoints);
1097 for( int i = 0; i < nPoints; i++ )
1098 {
1099 OdGePoint2d point = line->getVertexAt( i );
1100 poLS->setPoint(i, point.x, point.y);
1101 }
1102 poFeature->SetGeometryDirectly( poLS );
1103 poFeature->SetStyleString(osPen);
1104 }
1105 else if( EQUAL(pszEntityClassName, "OdDgLineString3d") )
1106 {
1107 OdDgLineString3dPtr line = OdDgLineString3d::cast( element );
1108 CPLAssert( !line.isNull() );
1109 const int nPoints = line->getVerticesCount();
1110
1111 OGRLineString* poLS = new OGRLineString();
1112 poLS->setNumPoints(nPoints);
1113 for( int i = 0; i < nPoints; i++ )
1114 {
1115 OdGePoint3d point = line->getVertexAt( i );
1116 poLS->setPoint(i, point.x, point.y, point.z);
1117 }
1118 poFeature->SetGeometryDirectly( poLS );
1119 poFeature->SetStyleString(osPen);
1120 }
1121 else if( EQUAL(pszEntityClassName, "OdDgPointString2d") )
1122 {
1123 OdDgPointString2dPtr string = OdDgPointString2d::cast( element );
1124 CPLAssert( !string.isNull() );
1125 const int nPoints = string->getVerticesCount();
1126
1127 // Not sure this is the right way to model this
1128 // We lose the rotation per vertex.
1129 OGRMultiPoint* poMP = new OGRMultiPoint();
1130 for( int i = 0; i < nPoints; i++ )
1131 {
1132 OdGePoint2d point = string->getVertexAt( i );
1133 poMP->addGeometryDirectly(new OGRPoint(point.x, point.y));
1134 }
1135 poFeature->SetGeometryDirectly( poMP );
1136 }
1137 else if( EQUAL(pszEntityClassName, "OdDgPointString3d") )
1138 {
1139 OdDgPointString3dPtr string = OdDgPointString3d::cast( element );
1140 CPLAssert( !string.isNull() );
1141 const int nPoints = string->getVerticesCount();
1142
1143 // Not sure this is the right way to model this
1144 // We lose the rotation per vertex.
1145 OGRMultiPoint* poMP = new OGRMultiPoint();
1146 for( int i = 0; i < nPoints; i++ )
1147 {
1148 OdGePoint3d point = string->getVertexAt( i );
1149 poMP->addGeometryDirectly(new OGRPoint(point.x, point.y, point.z));
1150 }
1151 poFeature->SetGeometryDirectly( poMP );
1152 }
1153 else if( EQUAL(pszEntityClassName, "OdDgMultiline") )
1154 {
1155 // This is a poor approximation since a multiline is a central line
1156 // with parallel lines.
1157 OdDgMultilinePtr line = OdDgMultiline::cast( element );
1158 CPLAssert( !line.isNull() );
1159 const int nPoints = static_cast<int>(line->getPointsCount());
1160
1161 OGRLineString* poLS = new OGRLineString();
1162 poLS->setNumPoints(nPoints);
1163 for( int i = 0; i < nPoints; i++ )
1164 {
1165 OdDgMultilinePoint point;
1166 OdGePoint3d point3d;
1167 line->getPoint( i, point );
1168 point.getPoint( point3d );
1169 poLS->setPoint(i, point3d.x, point3d.y, point3d.z);
1170 }
1171 poFeature->SetGeometryDirectly( poLS );
1172 poFeature->SetStyleString(osPen);
1173 }
1174 else if( EQUAL(pszEntityClassName, "OdDgArc2d") ||
1175 EQUAL(pszEntityClassName, "OdDgCurve2d") ||
1176 EQUAL(pszEntityClassName, "OdDgBSplineCurve2d") ||
1177 EQUAL(pszEntityClassName, "OdDgEllipse2d") )
1178 {
1179 OdDgCurveElement2dPtr curveElement =
1180 OdDgCurveElement2d::cast( element );
1181 CPLAssert( !curveElement.isNull() );
1182
1183 ProcessCurve(poFeature, osPen, curveElement);
1184 }
1185 else if( EQUAL(pszEntityClassName, "OdDgArc3d") ||
1186 EQUAL(pszEntityClassName, "OdDgCurve3d") ||
1187 EQUAL(pszEntityClassName, "OdDgBSplineCurve3d") ||
1188 EQUAL(pszEntityClassName, "OdDgEllipse3d") )
1189 {
1190 OdDgCurveElement3dPtr curveElement =
1191 OdDgCurveElement3d::cast( element );
1192 CPLAssert( !curveElement.isNull() );
1193
1194 ProcessCurve(poFeature, osPen, curveElement);
1195 }
1196 else if( EQUAL(pszEntityClassName, "OdDgShape2d") )
1197 {
1198 OdDgShape2dPtr shape = OdDgShape2d::cast( element );
1199 CPLAssert( !shape.isNull() );
1200 bHoleFlag = shape->getHoleFlag();
1201 const int nPoints = shape->getVerticesCount();
1202
1203 OGRLinearRing* poLS = new OGRLinearRing();
1204 poLS->setNumPoints(nPoints);
1205 for( int i = 0; i < nPoints; i++ )
1206 {
1207 OdGePoint2d point = shape->getVertexAt( i );
1208 poLS->setPoint(i, point.x, point.y);
1209 }
1210 OGRPolygon* poPoly = new OGRPolygon();
1211 poPoly->addRingDirectly(poLS);
1212 poFeature->SetGeometryDirectly( poPoly );
1213 poFeature->SetStyleString(ConsiderBrush(element, osPen));
1214 }
1215 else if( EQUAL(pszEntityClassName, "OdDgShape3d") )
1216 {
1217 OdDgShape3dPtr shape = OdDgShape3d::cast( element );
1218 CPLAssert( !shape.isNull() );
1219 bHoleFlag = shape->getHoleFlag();
1220 const int nPoints = shape->getVerticesCount();
1221
1222 OGRLinearRing* poLS = new OGRLinearRing();
1223 poLS->setNumPoints(nPoints);
1224 for( int i = 0; i < nPoints; i++ )
1225 {
1226 OdGePoint3d point = shape->getVertexAt( i );
1227 poLS->setPoint(i, point.x, point.y, point.z);
1228 }
1229 OGRPolygon* poPoly = new OGRPolygon();
1230 poPoly->addRingDirectly(poLS);
1231 poFeature->SetGeometryDirectly( poPoly );
1232 poFeature->SetStyleString(ConsiderBrush(element, osPen));
1233 }
1234 else if( EQUAL(pszEntityClassName, "OdDgComplexString") )
1235 {
1236 OdDgComplexStringPtr complex = OdDgComplexString::cast( element );
1237 CPLAssert( !complex.isNull() );
1238
1239 OdDgElementIteratorPtr iterator = complex->createIterator();
1240 if( !iterator.isNull() )
1241 {
1242 std::vector<tPairFeatureHoleFlag> oVectorSubElts =
1243 CollectSubElements(iterator, level + 1 );
1244
1245 // First pass to determine if we have non-linear pieces.
1246 bool bHasCurves = false;
1247 bool bIsClosed = false;
1248 bool bIsContiguous = IsContiguous(oVectorSubElts, bHasCurves, bIsClosed );
1249
1250 if( bIsContiguous && bHasCurves )
1251 {
1252 OGRCompoundCurve* poCC = new OGRCompoundCurve();
1253
1254 // Second pass to aggregate the geometries.
1255 for( size_t i = 0; i < oVectorSubElts.size(); i++ )
1256 {
1257 OGRGeometry* poGeom =
1258 oVectorSubElts[i].first->GetGeometryRef();
1259 if( poGeom != nullptr )
1260 {
1261 OGRwkbGeometryType eType =
1262 wkbFlatten(poGeom->getGeometryType());
1263 if( eType == wkbCircularString || eType == wkbLineString )
1264 {
1265 poCC->addCurve( poGeom->toCurve(),
1266 CONTIGUITY_TOLERANCE );
1267 }
1268 }
1269 delete oVectorSubElts[i].first;
1270 }
1271
1272 poFeature->SetGeometryDirectly( poCC );
1273 }
1274 else
1275 {
1276 OGRMultiCurve* poMC;
1277 if( bHasCurves )
1278 poMC = new OGRMultiCurve();
1279 else
1280 poMC = new OGRMultiLineString();
1281
1282 // Second pass to aggregate the geometries.
1283 for( size_t i = 0; i < oVectorSubElts.size(); i++ )
1284 {
1285 OGRGeometry* poGeom =
1286 oVectorSubElts[i].first->GetGeometryRef();
1287 if( poGeom != nullptr )
1288 {
1289 OGRwkbGeometryType eType =
1290 wkbFlatten(poGeom->getGeometryType());
1291 if( eType == wkbCircularString || eType == wkbLineString )
1292 {
1293 poMC->addGeometry( poGeom );
1294 }
1295 }
1296 delete oVectorSubElts[i].first;
1297 }
1298
1299 poFeature->SetGeometryDirectly( poMC );
1300 }
1301 poFeature->SetStyleString( osPen );
1302 }
1303 }
1304 else if( EQUAL(pszEntityClassName, "OdDgComplexShape") )
1305 {
1306 OdDgComplexCurvePtr complex = OdDgComplexCurve::cast( element );
1307 CPLAssert( !complex.isNull() );
1308
1309 OdDgComplexShapePtr complexShape = OdDgComplexShape::cast( element );
1310 CPLAssert( !complexShape.isNull() );
1311 bHoleFlag = complexShape->getHoleFlag();
1312
1313 OdDgElementIteratorPtr iterator = complex->createIterator();
1314 if( !iterator.isNull() )
1315 {
1316 std::vector<tPairFeatureHoleFlag> oVectorSubElts =
1317 CollectSubElements(iterator, level + 1 );
1318
1319 // First pass to determine if we have non-linear pieces.
1320 bool bHasCurves = false;
1321 bool bIsClosed = false;
1322 bool bIsContiguous = IsContiguous(oVectorSubElts, bHasCurves, bIsClosed );
1323
1324 if( bIsContiguous && bIsClosed )
1325 {
1326 OGRCurvePolygon* poCP;
1327 OGRCompoundCurve* poCC = nullptr;
1328 OGRLinearRing* poLR = nullptr;
1329
1330 if( bHasCurves )
1331 {
1332 poCP = new OGRCurvePolygon();
1333 poCC = new OGRCompoundCurve();
1334 }
1335 else
1336 {
1337 poCP = new OGRPolygon();
1338 poLR = new OGRLinearRing();
1339 }
1340
1341 // Second pass to aggregate the geometries.
1342 for( size_t i = 0; i < oVectorSubElts.size(); i++ )
1343 {
1344 OGRGeometry* poGeom =
1345 oVectorSubElts[i].first->GetGeometryRef();
1346 if( poGeom != nullptr )
1347 {
1348 OGRwkbGeometryType eType =
1349 wkbFlatten(poGeom->getGeometryType());
1350 if( poCC != nullptr )
1351 {
1352 poCC->addCurve( poGeom->toCurve(),
1353 CONTIGUITY_TOLERANCE );
1354 }
1355 else if( eType == wkbLineString )
1356 {
1357 poLR->addSubLineString(poGeom->toLineString(),
1358 poLR->getNumPoints() == 0 ? 0 : 1 );
1359 }
1360 }
1361 delete oVectorSubElts[i].first;
1362 }
1363
1364 poCP->addRingDirectly( ( bHasCurves ) ?
1365 poCC->toCurve() :
1366 poLR->toCurve() );
1367
1368 poFeature->SetGeometryDirectly( poCP );
1369 }
1370 else
1371 {
1372 OGRGeometryCollection oGC;
1373 for( size_t i = 0; i < oVectorSubElts.size(); i++ )
1374 {
1375 OGRGeometry* poGeom =
1376 oVectorSubElts[i].first->StealGeometry();
1377 if( poGeom != nullptr )
1378 {
1379 OGRwkbGeometryType eType =
1380 wkbFlatten(poGeom->getGeometryType());
1381 if( eType == wkbCircularString )
1382 {
1383 oGC.addGeometryDirectly(
1384 OGRGeometryFactory::forceToLineString(poGeom) );
1385 }
1386 else if( eType == wkbLineString )
1387 {
1388 oGC.addGeometryDirectly( poGeom );
1389 }
1390 else
1391 {
1392 delete poGeom;
1393 }
1394 }
1395 delete oVectorSubElts[i].first;
1396 }
1397
1398 // Try to assemble into polygon geometry.
1399 OGRGeometry* poGeom = reinterpret_cast<OGRGeometry *>(
1400 OGRBuildPolygonFromEdges(
1401 reinterpret_cast<OGRGeometryH>( &oGC ),
1402 TRUE, TRUE, CONTIGUITY_TOLERANCE, nullptr ) );
1403 poGeom->setCoordinateDimension( oGC.getCoordinateDimension() );
1404 poFeature->SetGeometryDirectly( poGeom );
1405
1406 }
1407 poFeature->SetStyleString( ConsiderBrush( element, osPen) );
1408 }
1409 }
1410 else if( EQUAL(pszEntityClassName, "OdDgSharedCellReference") )
1411 {
1412 OdDgSharedCellReferencePtr ref =
1413 OdDgSharedCellReference::cast( element );
1414 CPLAssert( !ref.isNull() );
1415 OdGePoint3d point = ref->getOrigin();
1416 poFeature->SetField( "Text",
1417 ToUTF8(ref->getDefinitionName()).c_str() );
1418 poFeature->SetGeometryDirectly(
1419 new OGRPoint(point.x, point.y, point.z) );
1420 }
1421 else
1422 {
1423 if( m_aoSetIgnoredFeatureClasses.find(pszEntityClassName) ==
1424 m_aoSetIgnoredFeatureClasses.end() )
1425 {
1426 m_aoSetIgnoredFeatureClasses.insert(pszEntityClassName);
1427 CPLDebug("DGNV8", "Unhandled class %s for, at least, "
1428 "feature " CPL_FRMT_GIB,
1429 pszEntityClassName, poFeature->GetFID());
1430 }
1431 }
1432
1433 if( poFeature != nullptr )
1434 oVector.push_back( tPairFeatureHoleFlag(poFeature, bHoleFlag) );
1435
1436 return oVector;
1437 }
1438
1439 /************************************************************************/
1440 /* GetNextUnfilteredFeature() */
1441 /************************************************************************/
1442
GetNextUnfilteredFeature()1443 OGRFeature *OGRDGNV8Layer::GetNextUnfilteredFeature()
1444
1445 {
1446 while( true )
1447 {
1448 if( m_nIdxInPendingFeatures < m_aoPendingFeatures.size() )
1449 {
1450 OGRFeature* poFeature =
1451 m_aoPendingFeatures[m_nIdxInPendingFeatures].first;
1452 m_aoPendingFeatures[m_nIdxInPendingFeatures].first = nullptr;
1453 m_nIdxInPendingFeatures ++;
1454 return poFeature;
1455 }
1456
1457 if( m_pIterator.isNull() )
1458 return nullptr;
1459
1460 while( true )
1461 {
1462 if( m_pIterator->done() )
1463 return nullptr;
1464 OdRxObjectPtr object = m_pIterator->item().openObject();
1465 m_pIterator->step();
1466 OdDgGraphicsElementPtr element =
1467 OdDgGraphicsElement::cast( object );
1468 if (element.isNull())
1469 continue;
1470
1471 m_aoPendingFeatures = ProcessElement(element);
1472 m_nIdxInPendingFeatures = 0;
1473
1474 break;
1475 }
1476 }
1477 }
1478
1479 /************************************************************************/
1480 /* GetNextFeature() */
1481 /************************************************************************/
1482
GetNextFeature()1483 OGRFeature *OGRDGNV8Layer::GetNextFeature()
1484
1485 {
1486 while( true )
1487 {
1488 OGRFeature* poFeature = GetNextUnfilteredFeature();
1489 if( poFeature == nullptr )
1490 break;
1491 if( poFeature->GetGeometryRef() == nullptr )
1492 {
1493 delete poFeature;
1494 continue;
1495 }
1496
1497 if( (m_poAttrQuery == nullptr
1498 || m_poAttrQuery->Evaluate( poFeature ))
1499 && FilterGeometry( poFeature->GetGeometryRef() ) )
1500 return poFeature;
1501
1502 delete poFeature;
1503 }
1504 return nullptr;
1505 }
1506
1507 /************************************************************************/
1508 /* GetFeatureInternal() */
1509 /************************************************************************/
1510
GetFeatureInternal(GIntBig nFID,OdDg::OpenMode openMode)1511 OdDgGraphicsElementPtr OGRDGNV8Layer::GetFeatureInternal(GIntBig nFID,
1512 OdDg::OpenMode openMode)
1513 {
1514 if( nFID < 0 )
1515 return OdDgGraphicsElementPtr();
1516 const OdDbHandle handle( static_cast<OdUInt64>(nFID) );
1517 const OdDgElementId id = m_pModel->database()->getElementId(handle);
1518 OdRxObjectPtr object = id.openObject(openMode);
1519 OdDgGraphicsElementPtr element = OdDgGraphicsElement::cast( object );
1520 if (element.isNull() || element->ownerId() != m_pModel->elementId() )
1521 return OdDgGraphicsElementPtr();
1522 return element;
1523 }
1524
1525 /************************************************************************/
1526 /* GetFeature() */
1527 /************************************************************************/
1528
GetFeature(GIntBig nFID)1529 OGRFeature *OGRDGNV8Layer::GetFeature(GIntBig nFID)
1530 {
1531 OdDgGraphicsElementPtr element = GetFeatureInternal(nFID, OdDg::kForRead);
1532 if( element.isNull() )
1533 return nullptr;
1534 std::vector<tPairFeatureHoleFlag> oVector = ProcessElement(element);
1535 // Only return a feature if and only if we have a single element
1536 if( oVector.empty() )
1537 return nullptr;
1538 if( oVector.size() > 1 )
1539 {
1540 for( size_t i = 0; i < oVector.size(); i++ )
1541 delete oVector[i].first;
1542 return nullptr;
1543 }
1544 return oVector[0].first;
1545 }
1546
1547 /************************************************************************/
1548 /* DeleteFeature() */
1549 /************************************************************************/
1550
DeleteFeature(GIntBig nFID)1551 OGRErr OGRDGNV8Layer::DeleteFeature(GIntBig nFID)
1552 {
1553 if( !m_poDS->GetUpdate() )
1554 {
1555 CPLError( CE_Failure, CPLE_AppDefined,
1556 "Attempt to delete feature on read-only DGN file." );
1557 return OGRERR_FAILURE;
1558 }
1559
1560 OdDgGraphicsElementPtr element = GetFeatureInternal(nFID,
1561 OdDg::kForWrite);
1562 if( element.isNull() )
1563 return OGRERR_FAILURE;
1564 try
1565 {
1566 element->erase(true);
1567 }
1568 catch (const OdError& e)
1569 {
1570 CPLError(CE_Failure, CPLE_AppDefined,
1571 "Teigha DGN error occurred: %s",
1572 ToUTF8(e.description()).c_str());
1573 return OGRERR_FAILURE;
1574 }
1575 catch (const std::exception &exc)
1576 {
1577 CPLError(CE_Failure, CPLE_AppDefined,
1578 "std::exception occurred: %s", exc.what());
1579 return OGRERR_FAILURE;
1580 }
1581 catch (...)
1582 {
1583 CPLError(CE_Failure, CPLE_AppDefined,
1584 "Unknown exception occurred");
1585 return OGRERR_FAILURE;
1586 }
1587 m_poDS->SetModified();
1588 return OGRERR_NONE;
1589 }
1590
1591
1592 /************************************************************************/
1593 /* GetExtent() */
1594 /************************************************************************/
1595
GetExtent(OGREnvelope * psExtent,int bForce)1596 OGRErr OGRDGNV8Layer::GetExtent( OGREnvelope *psExtent, int bForce )
1597 {
1598 OdDgModel::StorageUnitDescription description;
1599 m_pModel->getStorageUnit( description );
1600 OdDgElementIteratorPtr iterator =
1601 m_pModel->createGraphicsElementsIterator();
1602 bool bValid = false;
1603 while( true )
1604 {
1605 if( iterator.isNull() || iterator->done() )
1606 break;
1607 OdRxObjectPtr object = iterator->item().openObject();
1608 iterator->step();
1609 OdDgGraphicsElementPtr element = OdDgGraphicsElement::cast( object );
1610 if (element.isNull())
1611 continue;
1612 OdDgGraphicsElementPEPtr pElementPE =
1613 OdDgGraphicsElementPEPtr(OdRxObjectPtr(element));
1614 if( pElementPE.isNull() )
1615 continue;
1616 OdGeExtents3d savedExtent;
1617 if( pElementPE->getRange( element, savedExtent ) == eOk )
1618 {
1619 OdGePoint3d min = savedExtent.minPoint();
1620 OdGePoint3d max = savedExtent.maxPoint();
1621 if( !bValid )
1622 {
1623 psExtent->MinX = min.x / description.m_uorPerStorageUnit;
1624 psExtent->MinY = min.y / description.m_uorPerStorageUnit;
1625 psExtent->MaxX = max.x / description.m_uorPerStorageUnit;
1626 psExtent->MaxY = max.y / description.m_uorPerStorageUnit;
1627 bValid = true;
1628 }
1629 else
1630 {
1631 psExtent->MinX = std::min(psExtent->MinX,
1632 min.x / description.m_uorPerStorageUnit);
1633 psExtent->MinY = std::min(psExtent->MinY,
1634 min.y / description.m_uorPerStorageUnit);
1635 psExtent->MaxX = std::max(psExtent->MaxX,
1636 max.x / description.m_uorPerStorageUnit);
1637 psExtent->MaxY = std::max(psExtent->MaxY,
1638 max.y / description.m_uorPerStorageUnit);
1639 }
1640 }
1641 }
1642 if( bValid )
1643 return OGRERR_NONE;
1644 return OGRLayer::GetExtent(psExtent, bForce);
1645 }
1646
1647
1648 /************************************************************************/
1649 /* TestCapability() */
1650 /************************************************************************/
1651
TestCapability(const char * pszCap)1652 int OGRDGNV8Layer::TestCapability( const char * pszCap )
1653
1654 {
1655 if( EQUAL(pszCap,OLCRandomRead) )
1656 return TRUE;
1657 else if( EQUAL(pszCap,OLCStringsAsUTF8) )
1658 return TRUE;
1659 else if( EQUAL(pszCap,OLCSequentialWrite) ||
1660 EQUAL(pszCap,OLCDeleteFeature) )
1661 return m_poDS->GetUpdate();
1662 else if( EQUAL(pszCap,OLCCurveGeometries) )
1663 return TRUE;
1664
1665 return FALSE;
1666 }
1667
1668
1669 /************************************************************************/
1670 /* ICreateFeature() */
1671 /* */
1672 /* Create a new feature and write to file. */
1673 /************************************************************************/
1674
ICreateFeature(OGRFeature * poFeature)1675 OGRErr OGRDGNV8Layer::ICreateFeature( OGRFeature *poFeature )
1676
1677 {
1678 if( !m_poDS->GetUpdate() )
1679 {
1680 CPLError( CE_Failure, CPLE_AppDefined,
1681 "Attempt to create feature on read-only DGN file." );
1682 return OGRERR_FAILURE;
1683 }
1684
1685 if( poFeature->GetGeometryRef() == nullptr )
1686 {
1687 CPLError( CE_Failure, CPLE_AppDefined,
1688 "Features with empty, geometry collection geometries not "
1689 "supported in DGN format." );
1690 return OGRERR_FAILURE;
1691 }
1692
1693 try
1694 {
1695 OdDgGraphicsElementPtr element = CreateGraphicsElement(
1696 poFeature, poFeature->GetGeometryRef() );
1697 if( element.isNull() )
1698 return OGRERR_FAILURE;
1699 m_pModel->addElement(element);
1700 poFeature->SetFID(
1701 static_cast<GIntBig>(
1702 static_cast<OdUInt64>(element->elementId().getHandle()) ) );
1703 }
1704 catch (const OdError& e)
1705 {
1706 CPLError(CE_Failure, CPLE_AppDefined,
1707 "Teigha DGN error occurred: %s",
1708 ToUTF8(e.description()).c_str());
1709 return OGRERR_FAILURE;
1710 }
1711 catch (const std::exception &exc)
1712 {
1713 CPLError(CE_Failure, CPLE_AppDefined,
1714 "std::exception occurred: %s", exc.what());
1715 return OGRERR_FAILURE;
1716 }
1717 catch (...)
1718 {
1719 CPLError(CE_Failure, CPLE_AppDefined,
1720 "Unknown exception occurred");
1721 return OGRERR_FAILURE;
1722 }
1723
1724 m_poDS->SetModified();
1725 return OGRERR_NONE;
1726 }
1727
1728 /************************************************************************/
1729 /* GetTool() */
1730 /************************************************************************/
1731
GetTool(OGRFeature * poFeature,OGRSTClassId eClassId)1732 static OGRStyleTool* GetTool( OGRFeature* poFeature, OGRSTClassId eClassId )
1733 {
1734
1735 OGRStyleMgr oMgr;
1736 oMgr.InitFromFeature( poFeature );
1737 for( int i=0; i<oMgr.GetPartCount(); i++)
1738 {
1739 OGRStyleTool* poTool = oMgr.GetPart( i );
1740 if( poTool == nullptr || poTool->GetType() != eClassId)
1741 {
1742 delete poTool;
1743 }
1744 else
1745 {
1746 return poTool;
1747 }
1748 }
1749 return nullptr;
1750 }
1751
1752 /************************************************************************/
1753 /* TranslateLabel() */
1754 /************************************************************************/
1755
TranslateLabel(OGRFeature * poFeature,OGRPoint * poPoint)1756 OdDgGraphicsElementPtr OGRDGNV8Layer::TranslateLabel(
1757 OGRFeature *poFeature, OGRPoint *poPoint )
1758
1759 {
1760 const char *pszText = poFeature->GetFieldAsString( "Text" );
1761
1762 OGRStyleLabel *poLabel = static_cast<OGRStyleLabel*>(
1763 GetTool(poFeature, OGRSTCLabel));
1764
1765 OdDgText2dPtr text = OdDgText2d::createObject();
1766 OdGePoint2d point;
1767 point.x = poPoint->getX();
1768 point.y = poPoint->getY();
1769 text->setOrigin(point);
1770
1771 double dfHeightMultiplier = 1.0;
1772 if( poLabel != nullptr )
1773 {
1774 GBool bDefault;
1775
1776 if( poLabel->TextString(bDefault) != nullptr && !bDefault )
1777 pszText = poLabel->TextString(bDefault);
1778
1779 const double dfRotation = poLabel->Angle(bDefault);
1780 text->setRotation(dfRotation * DEG_TO_RAD);
1781
1782 poLabel->SetUnit(OGRSTUMM);
1783 double dfVal = poLabel->Size( bDefault );
1784 if( !bDefault )
1785 dfHeightMultiplier = dfVal/1000.0;
1786
1787 /* get font id */
1788 const char *pszFontName = poLabel->FontName( bDefault );
1789 if( !bDefault && pszFontName != nullptr )
1790 {
1791 OdDgFontTablePtr pFontTable =
1792 m_pModel->database()->getFontTable(OdDg::kForRead);
1793 OdDgElementId idFont = pFontTable->getAt(
1794 OGRDGNV8DataSource::FromUTF8(pszFontName) );
1795 if( !idFont.isNull() )
1796 {
1797 OdDgFontTableRecordPtr pFont =
1798 idFont.openObject(OdDg::kForRead);
1799 OdUInt32 uFontEntryId = pFont->getNumber();
1800 text->setFontEntryId(uFontEntryId);
1801 }
1802 }
1803
1804 int nAnchor = poLabel->Anchor(bDefault);
1805 if( !bDefault )
1806 text->setJustification( GetAnchorPositionFromOGR( nAnchor ) );
1807 }
1808
1809 text->setHeightMultiplier( dfHeightMultiplier );
1810 text->setLengthMultiplier( text->getHeightMultiplier() ); // FIXME ??
1811 text->setText( OGRDGNV8DataSource::FromUTF8(pszText) );
1812
1813 if( poLabel )
1814 delete poLabel;
1815 return text;
1816 }
1817
1818 /************************************************************************/
1819 /* GetColorFromString() */
1820 /************************************************************************/
1821
GetColorFromString(const char * pszColor)1822 int OGRDGNV8Layer::GetColorFromString(const char* pszColor)
1823 {
1824 unsigned int nRed = 0;
1825 unsigned int nGreen = 0;
1826 unsigned int nBlue = 0;
1827 const int nCount =
1828 sscanf(pszColor, "#%2x%2x%2x", &nRed, &nGreen, &nBlue);
1829 if( nCount == 3 )
1830 {
1831 OdUInt32 nIdx = OdDgColorTable::getColorIndexByRGB(
1832 m_poDS->GetDb(), ODRGB( nRed, nGreen ,nBlue ) );
1833 return static_cast<int>(nIdx);
1834 }
1835 else
1836 {
1837 return -1;
1838 }
1839 }
1840
1841 /************************************************************************/
1842 /* AttachFillLinkage() */
1843 /************************************************************************/
1844
AttachFillLinkage(OGRFeature * poFeature,OdDgGraphicsElementPtr element)1845 void OGRDGNV8Layer::AttachFillLinkage( OGRFeature* poFeature,
1846 OdDgGraphicsElementPtr element )
1847 {
1848 const char* pszStyle = poFeature->GetStyleString();
1849 if( pszStyle != nullptr && strstr(pszStyle, "BRUSH") != nullptr )
1850 {
1851 OGRStyleBrush* poBrush = static_cast<OGRStyleBrush*>(
1852 GetTool(poFeature, OGRSTCBrush));
1853 if( poBrush != nullptr )
1854 {
1855 GBool bDefault;
1856 const char* pszColor = poBrush->ForeColor(bDefault);
1857 if( pszColor && !bDefault )
1858 {
1859 const int nIdx = GetColorFromString(pszColor);
1860 if( nIdx >= 0 )
1861 {
1862 OdDgFillColorLinkagePtr fillColor =
1863 OdDgFillColorLinkage::createObject();
1864 fillColor->setColorIndex( nIdx );
1865 element->addLinkage( fillColor->getPrimaryId(),
1866 fillColor.get() );
1867 }
1868 }
1869
1870 delete poBrush;
1871 }
1872 }
1873 }
1874
1875 /************************************************************************/
1876 /* AttachCommonAttributes() */
1877 /************************************************************************/
1878
AttachCommonAttributes(OGRFeature * poFeature,OdDgGraphicsElementPtr element)1879 void OGRDGNV8Layer::AttachCommonAttributes( OGRFeature *poFeature,
1880 OdDgGraphicsElementPtr element )
1881 {
1882 const int nLevel = poFeature->GetFieldAsInteger( "Level" );
1883 const int nGraphicGroup = poFeature->GetFieldAsInteger( "GraphicGroup" );
1884 const int nWeight = poFeature->GetFieldAsInteger( "Weight" );
1885 const int nStyle = poFeature->GetFieldAsInteger( "Style" );
1886
1887 element->setLevelEntryId(nLevel);
1888 element->setGraphicsGroupEntryId(nGraphicGroup);
1889
1890 const int nColorIndexField = poFeature->GetFieldIndex("ColorIndex");
1891 if( poFeature->IsFieldSetAndNotNull(nColorIndexField) )
1892 {
1893 const int nColor = poFeature->GetFieldAsInteger(nColorIndexField);
1894 element->setColorIndex(nColor);
1895 }
1896 else
1897 {
1898 const char* pszStyle = poFeature->GetStyleString();
1899 if( pszStyle != nullptr && strstr(pszStyle, "PEN") != nullptr )
1900 {
1901 OGRStylePen* poPen = static_cast<OGRStylePen*>(
1902 GetTool(poFeature, OGRSTCPen));
1903 if( poPen != nullptr )
1904 {
1905 GBool bDefault;
1906 const char* pszColor = poPen->Color(bDefault);
1907 if( pszColor && !bDefault )
1908 {
1909 const int nIdx = GetColorFromString(pszColor);
1910 if( nIdx >= 0 )
1911 {
1912 element->setColorIndex(nIdx);
1913 }
1914 }
1915 delete poPen;
1916 }
1917 }
1918 else if( pszStyle != nullptr && strstr(pszStyle, "LABEL") != nullptr )
1919 {
1920 OGRStyleLabel *poLabel = static_cast<OGRStyleLabel*>(
1921 GetTool(poFeature, OGRSTCLabel));
1922 if( poLabel != nullptr )
1923 {
1924 GBool bDefault;
1925 const char* pszColor = poLabel->ForeColor(bDefault);
1926 if( pszColor && !bDefault )
1927 {
1928 const int nIdx = GetColorFromString(pszColor);
1929 if( nIdx >= 0 )
1930 {
1931 element->setColorIndex(nIdx);
1932 }
1933 }
1934
1935 delete poLabel;
1936 }
1937 }
1938 }
1939
1940 element->setLineStyleEntryId(nStyle);
1941 element->setLineWeight(nWeight);
1942 }
1943
1944 /************************************************************************/
1945 /* AddToComplexCurve() */
1946 /************************************************************************/
1947
AddToComplexCurve(OGRFeature * poFeature,OGRCircularString * poCS,OdDgComplexCurvePtr complexCurve)1948 void OGRDGNV8Layer::AddToComplexCurve( OGRFeature* poFeature,
1949 OGRCircularString* poCS,
1950 OdDgComplexCurvePtr complexCurve )
1951 {
1952 for( int i = 0; i + 2 < poCS->getNumPoints(); i+= 2 )
1953 {
1954 double R, cx, cy;
1955 double alpha0, alpha1, alpha2;
1956 if( OGRGeometryFactory::GetCurveParameters(
1957 poCS->getX(i),
1958 poCS->getY(i),
1959 poCS->getX(i+1),
1960 poCS->getY(i+1),
1961 poCS->getX(i+2),
1962 poCS->getY(i+2),
1963 R, cx, cy, alpha0, alpha1, alpha2) )
1964 {
1965 OdDgArc2dPtr arc = OdDgArc2d::createObject();
1966 arc->setPrimaryAxis(R);
1967 arc->setSecondaryAxis(R);
1968 OdGePoint2d point;
1969 point.x = cx;
1970 point.y = cy;
1971 arc->setOrigin(point);
1972 arc->setStartAngle(alpha0); // already in radians
1973 arc->setSweepAngle(alpha2 - alpha0);
1974 AttachCommonAttributes(poFeature, arc);
1975 complexCurve->add(arc);
1976 }
1977 }
1978 }
1979
1980 /************************************************************************/
1981 /* AddToComplexCurve() */
1982 /************************************************************************/
1983
AddToComplexCurve(OGRFeature * poFeature,OGRCompoundCurve * poCC,OdDgComplexCurvePtr complexCurve)1984 void OGRDGNV8Layer::AddToComplexCurve( OGRFeature* poFeature,
1985 OGRCompoundCurve* poCC,
1986 OdDgComplexCurvePtr complexCurve )
1987 {
1988 for( int iCurve = 0; iCurve < poCC->getNumCurves(); ++iCurve )
1989 {
1990 OGRCurve* poCurve = poCC->getCurve(iCurve);
1991 OGRwkbGeometryType eType = wkbFlatten(poCurve->getGeometryType());
1992 if( eType == wkbLineString || OGR_GT_HasZ(eType) )
1993 {
1994 complexCurve->add( CreateGraphicsElement(poFeature, poCurve) );
1995 }
1996 else if( eType == wkbCircularString )
1997 {
1998 OGRCircularString* poCS = poCurve->toCircularString();
1999 AddToComplexCurve(poFeature, poCS, complexCurve);
2000 }
2001 else
2002 {
2003 CPLAssert(false);
2004 }
2005 }
2006 }
2007
2008 /************************************************************************/
2009 /* CreateShapeFromLS() */
2010 /************************************************************************/
2011
2012 static
CreateShapeFromLS(OGRLineString * poLS,bool bHbit=false)2013 OdDgGraphicsElementPtr CreateShapeFromLS( OGRLineString* poLS,
2014 bool bHbit = false )
2015 {
2016 if( OGR_GT_HasZ(poLS->getGeometryType()) )
2017 {
2018 OdDgShape3dPtr shape = OdDgShape3d::createObject();
2019 for( int i = 0; i < poLS->getNumPoints(); i++ )
2020 {
2021 OGRPoint ogrPoint;
2022 OdGePoint3d point;
2023 poLS->getPoint(i, &ogrPoint);
2024 point.x = ogrPoint.getX();
2025 point.y = ogrPoint.getY();
2026 point.z = ogrPoint.getZ();
2027 shape->addVertex(point);
2028 }
2029 shape->setHbitFlag(bHbit);
2030 return shape;
2031 }
2032 else
2033 {
2034 OdDgShape2dPtr shape = OdDgShape2d::createObject();
2035 for( int i = 0; i < poLS->getNumPoints(); i++ )
2036 {
2037 OGRPoint ogrPoint;
2038 OdGePoint2d point;
2039 poLS->getPoint(i, &ogrPoint);
2040 point.x = ogrPoint.getX();
2041 point.y = ogrPoint.getY();
2042 shape->addVertex(point);
2043 }
2044 shape->setHbitFlag(bHbit);
2045 return shape;
2046 }
2047 }
2048
2049 /************************************************************************/
2050 /* CreateShape() */
2051 /************************************************************************/
2052
CreateShape(OGRFeature * poFeature,OGRCurve * poCurve,bool bIsHole)2053 OdDgGraphicsElementPtr OGRDGNV8Layer::CreateShape( OGRFeature* poFeature,
2054 OGRCurve* poCurve,
2055 bool bIsHole )
2056 {
2057 OdDgGraphicsElementPtr element;
2058 OGRwkbGeometryType eType = wkbFlatten(poCurve->getGeometryType());
2059 if( eType == wkbLineString )
2060 {
2061 OGRLineString* poLS = poCurve->toLineString();
2062 element = CreateShapeFromLS(poLS, bIsHole);
2063 }
2064 else if( eType == wkbCircularString )
2065 {
2066 OdDgComplexShapePtr complexShape = OdDgComplexShape::createObject();
2067 complexShape->setHbitFlag(bIsHole);
2068 OGRCircularString* poCS = poCurve->toCircularString();
2069 AddToComplexCurve(poFeature, poCS, complexShape);
2070 element = complexShape;
2071 }
2072 else if( eType == wkbCompoundCurve )
2073 {
2074 OdDgComplexShapePtr complexShape = OdDgComplexShape::createObject();
2075 complexShape->setHbitFlag(bIsHole);
2076 OGRCompoundCurve* poCC = poCurve->toCompoundCurve();
2077 AddToComplexCurve( poFeature, poCC, complexShape );
2078 element = complexShape;
2079 }
2080
2081 if( !bIsHole )
2082 AttachFillLinkage( poFeature, element );
2083
2084 return element;
2085 }
2086
2087 /************************************************************************/
2088 /* IsFullCircle() */
2089 /************************************************************************/
2090
IsFullCircle(OGRCircularString * poCS,double & cx,double & cy,double & R)2091 static bool IsFullCircle( OGRCircularString* poCS,
2092 double& cx, double& cy,
2093 double& R )
2094 {
2095 if( poCS->getNumPoints() == 3 && poCS->get_IsClosed() )
2096 {
2097 const double x0 = poCS->getX(0);
2098 const double y0 = poCS->getY(0);
2099 const double x1 = poCS->getX(1);
2100 const double y1 = poCS->getY(1);
2101 cx = (x0 + x1) / 2;
2102 cy = (y0 + y1) / 2;
2103 R = sqrt((x1 - cx) * (x1 - cx) + (y1 - cy) * (y1 - cy));
2104 return true;
2105 }
2106 // Full circle defined by 2 arcs?
2107 else if( poCS->getNumPoints() == 5 && poCS->get_IsClosed() )
2108 {
2109 double R_1 = 0.0;
2110 double cx_1 = 0.0;
2111 double cy_1 = 0.0;
2112 double alpha0_1 = 0.0;
2113 double alpha1_1 = 0.0;
2114 double alpha2_1 = 0.0;
2115 double R_2 = 0.0;
2116 double cx_2 = 0.0;
2117 double cy_2 = 0.0;
2118 double alpha0_2 = 0.0;
2119 double alpha1_2 = 0.0;
2120 double alpha2_2 = 0.0;
2121 if( OGRGeometryFactory::GetCurveParameters(
2122 poCS->getX(0), poCS->getY(0),
2123 poCS->getX(1), poCS->getY(1),
2124 poCS->getX(2), poCS->getY(2),
2125 R_1, cx_1, cy_1, alpha0_1, alpha1_1, alpha2_1) &&
2126 OGRGeometryFactory::GetCurveParameters(
2127 poCS->getX(2), poCS->getY(2),
2128 poCS->getX(3), poCS->getY(3),
2129 poCS->getX(4), poCS->getY(4),
2130 R_2, cx_2, cy_2, alpha0_2, alpha1_2, alpha2_2) &&
2131 AlmostEqual(R_1,R_2) &&
2132 AlmostEqual(cx_1,cx_2) &&
2133 AlmostEqual(cy_1,cy_2) &&
2134 (alpha2_1 - alpha0_1) * (alpha2_2 - alpha0_2) > 0 )
2135 {
2136 cx = cx_1;
2137 cy = cy_1;
2138 R = R_1;
2139 return true;
2140 }
2141 }
2142 return false;
2143 }
2144
2145 /************************************************************************/
2146 /* CreateGraphicsElement() */
2147 /* */
2148 /* Create an element or element group from a given geometry and */
2149 /* the given feature. This method recurses to handle */
2150 /* collections as essentially independent features. */
2151 /************************************************************************/
2152
CreateGraphicsElement(OGRFeature * poFeature,OGRGeometry * poGeom)2153 OdDgGraphicsElementPtr OGRDGNV8Layer::CreateGraphicsElement(
2154 OGRFeature *poFeature,
2155 OGRGeometry *poGeom)
2156
2157 {
2158 const OGRwkbGeometryType eType = poGeom->getGeometryType();
2159 const OGRwkbGeometryType eFType = wkbFlatten(eType);
2160
2161 const int nType = poFeature->GetFieldAsInteger( "Type" );
2162
2163 OdDgGraphicsElementPtr element;
2164
2165 if( eFType == wkbPoint )
2166 {
2167 OGRPoint *poPoint = poGeom->toPoint();
2168 const char *pszText = poFeature->GetFieldAsString("Text");
2169 const char *pszStyle = poFeature->GetStyleString();
2170
2171 if( (pszText == nullptr || pszText[0] == 0)
2172 && (pszStyle == nullptr || strstr(pszStyle,"LABEL") == nullptr) )
2173 {
2174 if( OGR_GT_HasZ(eType) )
2175 {
2176 OdDgLine3dPtr line = OdDgLine3d::createObject();
2177 element = line;
2178 OdGePoint3d point;
2179 point.x = poPoint->getX();
2180 point.y = poPoint->getY();
2181 point.z = poPoint->getZ();
2182 line->setStartPoint(point);
2183 line->setEndPoint(point);
2184 }
2185 else
2186 {
2187 OdDgLine2dPtr line = OdDgLine2d::createObject();
2188 element = line;
2189 OdGePoint2d point;
2190 point.x = poPoint->getX();
2191 point.y = poPoint->getY();
2192 line->setStartPoint(point);
2193 line->setEndPoint(point);
2194 }
2195 }
2196 else
2197 {
2198 element = TranslateLabel( poFeature, poPoint );
2199 }
2200 }
2201 else if( eFType == wkbLineString )
2202 {
2203 OGRLineString* poLS = poGeom->toLineString();
2204 if( poLS->getNumPoints() == 2 &&
2205 (nType == 0 || nType == OdDgElement::kTypeLine) )
2206 {
2207 if( OGR_GT_HasZ(eType) )
2208 {
2209 OdDgLine3dPtr line = OdDgLine3d::createObject();
2210 element = line;
2211 OGRPoint ogrPoint;
2212 OdGePoint3d point;
2213 poLS->getPoint(0, &ogrPoint);
2214 point.x = ogrPoint.getX();
2215 point.y = ogrPoint.getY();
2216 point.z = ogrPoint.getZ();
2217 line->setStartPoint(point);
2218 poLS->getPoint(1, &ogrPoint);
2219 point.x = ogrPoint.getX();
2220 point.y = ogrPoint.getY();
2221 point.z = ogrPoint.getZ();
2222 line->setEndPoint(point);
2223 }
2224 else
2225 {
2226 OdDgLine2dPtr line = OdDgLine2d::createObject();
2227 element = line;
2228 OGRPoint ogrPoint;
2229 OdGePoint2d point;
2230 poLS->getPoint(0, &ogrPoint);
2231 point.x = ogrPoint.getX();
2232 point.y = ogrPoint.getY();
2233 line->setStartPoint(point);
2234 poLS->getPoint(1, &ogrPoint);
2235 point.x = ogrPoint.getX();
2236 point.y = ogrPoint.getY();
2237 line->setEndPoint(point);
2238 }
2239 }
2240 else
2241 {
2242 if( OGR_GT_HasZ(eType) )
2243 {
2244 OdDgLineString3dPtr line = OdDgLineString3d::createObject();
2245 element = line;
2246 for( int i = 0; i < poLS->getNumPoints(); i++ )
2247 {
2248 OGRPoint ogrPoint;
2249 OdGePoint3d point;
2250 poLS->getPoint(i, &ogrPoint);
2251 point.x = ogrPoint.getX();
2252 point.y = ogrPoint.getY();
2253 point.z = ogrPoint.getZ();
2254 line->addVertex(point);
2255 }
2256 }
2257 else
2258 {
2259 OdDgLineString2dPtr line = OdDgLineString2d::createObject();
2260 element = line;
2261 for( int i = 0; i < poLS->getNumPoints(); i++ )
2262 {
2263 OGRPoint ogrPoint;
2264 OdGePoint2d point;
2265 poLS->getPoint(i, &ogrPoint);
2266 point.x = ogrPoint.getX();
2267 point.y = ogrPoint.getY();
2268 line->addVertex(point);
2269 }
2270 }
2271 }
2272 }
2273 else if( eFType == wkbCircularString )
2274 {
2275 OGRCircularString* poCS = poGeom->toCircularString();
2276 double R, cx, cy;
2277 if( IsFullCircle(poCS, cx, cy, R) && !OGR_GT_HasZ(eType) )
2278 {
2279 OdDgEllipse2dPtr ellipse = OdDgEllipse2d::createObject();
2280 element = ellipse;
2281 ellipse->setPrimaryAxis(R);
2282 ellipse->setSecondaryAxis(R);
2283 OdGePoint2d point;
2284 point.x = cx;
2285 point.y = cy;
2286 ellipse->setOrigin(point);
2287 }
2288 else if( poCS->getNumPoints() == 3 && !OGR_GT_HasZ(eType) )
2289 {
2290 double alpha0, alpha1, alpha2;
2291 if( OGRGeometryFactory::GetCurveParameters(
2292 poCS->getX(0),
2293 poCS->getY(0),
2294 poCS->getX(1),
2295 poCS->getY(1),
2296 poCS->getX(2),
2297 poCS->getY(2),
2298 R, cx, cy, alpha0, alpha1, alpha2) )
2299 {
2300 OdDgArc2dPtr arc = OdDgArc2d::createObject();
2301 element = arc;
2302 arc->setPrimaryAxis(R);
2303 arc->setSecondaryAxis(R);
2304 OdGePoint2d point;
2305 point.x = cx;
2306 point.y = cy;
2307 arc->setOrigin(point);
2308 arc->setStartAngle(alpha0); // already in radians
2309 arc->setSweepAngle(alpha2 - alpha0);
2310 }
2311 }
2312 else if( !OGR_GT_HasZ(eType) )
2313 {
2314 OdDgComplexCurvePtr complexCurve =
2315 OdDgComplexString::createObject();
2316 element = complexCurve;
2317 AddToComplexCurve(poFeature, poCS, complexCurve);
2318 }
2319
2320 if( element.isNull() )
2321 {
2322 OGRGeometry* poLS =
2323 OGRGeometryFactory::forceToLineString( poGeom->clone() );
2324 element = CreateGraphicsElement(poFeature, poLS);
2325 delete poLS;
2326 return element;
2327 }
2328 }
2329 else if( eFType == wkbCompoundCurve )
2330 {
2331 OGRCompoundCurve* poCC = poGeom->toCompoundCurve();
2332 OdDgComplexCurvePtr complexCurve = OdDgComplexString::createObject();
2333 element = complexCurve;
2334 AddToComplexCurve( poFeature, poCC, complexCurve );
2335 }
2336 else if( eFType == wkbCurvePolygon || eFType == wkbPolygon )
2337 {
2338 OGRCurvePolygon* poPoly = poGeom->toCurvePolygon();
2339 if( poPoly->getNumInteriorRings() == 0 &&
2340 poPoly->getExteriorRingCurve() == nullptr )
2341 {
2342 if( OGR_GT_HasZ(eType) )
2343 {
2344 element = OdDgShape3d::createObject();
2345 }
2346 else
2347 {
2348 element = OdDgShape2d::createObject();
2349 }
2350 }
2351 else if( poPoly->getNumInteriorRings() == 0 )
2352 {
2353 element = CreateShape(poFeature, poPoly->getExteriorRingCurve());
2354 }
2355 else
2356 {
2357 if( OGR_GT_HasZ(eType) )
2358 {
2359 OdDgCellHeader3dPtr pCell = OdDgCellHeader3d::createObject();
2360 element = pCell;
2361 for( int iRing = -1;
2362 iRing < poPoly->getNumInteriorRings(); iRing++ )
2363 {
2364 OGRCurve* poCurve = (iRing < 0 ) ?
2365 poPoly->getExteriorRingCurve() :
2366 poPoly->getInteriorRingCurve(iRing);
2367
2368 OdDgGraphicsElementPtr shape = CreateShape(
2369 poFeature, poCurve, iRing >= 0);
2370 AttachCommonAttributes(poFeature, shape);
2371 pCell->add(shape);
2372 }
2373 }
2374 else
2375 {
2376 OdDgCellHeader2dPtr pCell = OdDgCellHeader2d::createObject();
2377 element = pCell;
2378 for( int iRing = -1;
2379 iRing < poPoly->getNumInteriorRings(); iRing++ )
2380 {
2381 OGRCurve* poCurve = (iRing < 0 ) ?
2382 poPoly->getExteriorRingCurve() :
2383 poPoly->getInteriorRingCurve(iRing);
2384
2385 OdDgGraphicsElementPtr shape = CreateShape(
2386 poFeature, poCurve, iRing >= 0);
2387 AttachCommonAttributes(poFeature, shape);
2388 pCell->add(shape);
2389 }
2390 }
2391 AttachFillLinkage( poFeature, element );
2392 }
2393 }
2394 else if( OGR_GT_IsSubClassOf( eFType, wkbGeometryCollection ) )
2395 {
2396 OGRGeometryCollection* poGC = poGeom->toGeometryCollection();
2397 OdDgCellHeader2dPtr pCell = OdDgCellHeader2d::createObject();
2398 element = pCell;
2399 if( !pCell.isNull() )
2400 {
2401 for( auto&& poMember: poGC )
2402 {
2403 pCell->add(CreateGraphicsElement( poFeature, poMember ));
2404 }
2405 }
2406 }
2407 else
2408 {
2409 CPLError( CE_Failure, CPLE_AppDefined,
2410 "Unsupported geometry type (%s) for DGN.",
2411 OGRGeometryTypeToName( eType ) );
2412 }
2413
2414 if( !element.isNull() )
2415 AttachCommonAttributes(poFeature, element);
2416
2417 return element;
2418 }
2419