LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/cad - ogrcadlayer.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 211 421 50.1 %
Date: 2024-11-21 22:18:42 Functions: 7 8 87.5 %

          Line data    Source code
       1             : /*******************************************************************************
       2             :  *  Project: OGR CAD Driver
       3             :  *  Purpose: Implements driver based on libopencad
       4             :  *  Author: Alexandr Borzykh, mush3d at gmail.com
       5             :  *  Author: Dmitry Baryshnikov, polimax@mail.ru
       6             :  *  Language: C++
       7             :  *******************************************************************************
       8             :  *  The MIT License (MIT)
       9             :  *
      10             :  *  Copyright (c) 2016 Alexandr Borzykh
      11             :  *  Copyright (c) 2016-2019, NextGIS <info@nextgis.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  *******************************************************************************/
      15             : #include "cpl_conv.h"
      16             : #include "ogr_cad.h"
      17             : 
      18             : #include <algorithm>
      19             : #include <iomanip>
      20             : #include <sstream>
      21             : 
      22             : #define FIELD_NAME_GEOMTYPE "cadgeom_type"
      23             : #define FIELD_NAME_THICKNESS "thickness"
      24             : #define FIELD_NAME_COLOR "color"
      25             : #define FIELD_NAME_EXT_DATA "extentity_data"
      26             : #define FIELD_NAME_TEXT "text"
      27             : 
      28             : constexpr double DEG2RAD = M_PI / 180.0;
      29             : constexpr double RAD2DEG = 1.0 / DEG2RAD;
      30             : 
      31          10 : OGRCADLayer::OGRCADLayer(GDALDataset *poDS, CADLayer &poCADLayer_,
      32          10 :                          OGRSpatialReference *poSR, int nEncoding)
      33             :     : m_poDS(poDS), poSpatialRef(poSR), poCADLayer(poCADLayer_),
      34          10 :       nDWGEncoding(nEncoding)
      35             : {
      36          10 :     nNextFID = 0;
      37             : 
      38          10 :     if (poSpatialRef)
      39          10 :         poSpatialRef->Reference();
      40          10 :     poFeatureDefn =
      41          10 :         new OGRFeatureDefn(CADRecode(poCADLayer_.getName(), nDWGEncoding));
      42             : 
      43             :     // Setting up layer geometry type
      44             :     OGRwkbGeometryType eGeomType;
      45          10 :     char dLineStringPresented = 0;
      46          10 :     char dCircularStringPresented = 0;
      47          10 :     char dPointPresented = 0;
      48          10 :     char dPolygonPresented = 0;
      49             :     std::vector<CADObject::ObjectType> aePresentedGeometryTypes =
      50          20 :         poCADLayer.getGeometryTypes();
      51          28 :     for (size_t i = 0; i < aePresentedGeometryTypes.size(); ++i)
      52             :     {
      53          18 :         switch (aePresentedGeometryTypes[i])
      54             :         {
      55          13 :             case CADObject::ATTDEF:
      56             :             case CADObject::TEXT:
      57             :             case CADObject::MTEXT:
      58             :             case CADObject::POINT:
      59          13 :                 dPointPresented = 1;
      60          13 :                 break;
      61           3 :             case CADObject::CIRCLE:
      62           3 :                 dCircularStringPresented = 1;
      63           3 :                 break;
      64           2 :             case CADObject::SPLINE:
      65             :             case CADObject::ELLIPSE:
      66             :             case CADObject::ARC:
      67             :             case CADObject::POLYLINE3D:
      68             :             case CADObject::POLYLINE2D:
      69             :             case CADObject::LWPOLYLINE:
      70             :             case CADObject::LINE:
      71           2 :                 dLineStringPresented = 1;
      72           2 :                 break;
      73           0 :             case CADObject::FACE3D:
      74             :             case CADObject::SOLID:
      75           0 :                 dPolygonPresented = 1;
      76           0 :                 break;
      77           0 :             default:
      78           0 :                 break;
      79             :         }
      80             :     }
      81             : 
      82          10 :     if ((dLineStringPresented + dCircularStringPresented + dPointPresented +
      83          10 :          dPolygonPresented) > 1)
      84             :     {
      85           0 :         eGeomType = wkbGeometryCollection;
      86             :     }
      87             :     else
      88             :     {
      89          10 :         if (dLineStringPresented)
      90             :         {
      91           2 :             eGeomType = wkbLineString;
      92             :         }
      93           8 :         else if (dCircularStringPresented)
      94             :         {
      95           3 :             eGeomType = wkbCircularString;
      96             :         }
      97           5 :         else if (dPointPresented)
      98             :         {
      99           5 :             eGeomType = wkbPoint;
     100             :         }
     101           0 :         else if (dPolygonPresented)
     102             :         {
     103           0 :             eGeomType = wkbPolygon;
     104             :         }
     105             :         else
     106             :         {
     107           0 :             eGeomType = wkbUnknown;
     108             :         }
     109             :     }
     110          10 :     poFeatureDefn->SetGeomType(eGeomType);
     111             : 
     112          20 :     OGRFieldDefn oClassField(FIELD_NAME_GEOMTYPE, OFTString);
     113          10 :     poFeatureDefn->AddFieldDefn(&oClassField);
     114             : 
     115          20 :     OGRFieldDefn oLinetypeField(FIELD_NAME_THICKNESS, OFTReal);
     116          10 :     poFeatureDefn->AddFieldDefn(&oLinetypeField);
     117             : 
     118          20 :     OGRFieldDefn oColorField(FIELD_NAME_COLOR, OFTString);
     119          10 :     poFeatureDefn->AddFieldDefn(&oColorField);
     120             : 
     121          20 :     OGRFieldDefn oExtendedField(FIELD_NAME_EXT_DATA, OFTString);
     122          10 :     poFeatureDefn->AddFieldDefn(&oExtendedField);
     123             : 
     124          20 :     OGRFieldDefn oTextField(FIELD_NAME_TEXT, OFTString);
     125          10 :     poFeatureDefn->AddFieldDefn(&oTextField);
     126             : 
     127          20 :     auto oAttrTags = poCADLayer.getAttributesTags();
     128          14 :     for (const std::string &osTag : oAttrTags)
     129             :     {
     130           4 :         auto ret = asFeaturesAttributes.insert(osTag);
     131           4 :         if (ret.second == true)
     132             :         {
     133           8 :             OGRFieldDefn oAttrField(osTag.c_str(), OFTString);
     134           4 :             poFeatureDefn->AddFieldDefn(&oAttrField);
     135             :         }
     136             :     }
     137             : 
     138             :     // Applying spatial ref info
     139          10 :     if (poFeatureDefn->GetGeomFieldCount() != 0)
     140          10 :         poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSpatialRef);
     141             : 
     142          10 :     SetDescription(poFeatureDefn->GetName());
     143          10 :     poFeatureDefn->Reference();
     144          10 : }
     145             : 
     146           7 : GIntBig OGRCADLayer::GetFeatureCount(int bForce)
     147             : {
     148           7 :     if (m_poFilterGeom != nullptr || m_poAttrQuery != nullptr)
     149           0 :         return OGRLayer::GetFeatureCount(bForce);
     150             : 
     151           7 :     return poCADLayer.getGeometryCount();
     152             : }
     153             : 
     154           0 : int OGRCADLayer::TestCapability(const char *pszCap)
     155             : {
     156           0 :     if (EQUAL(pszCap, OLCMeasuredGeometries))
     157           0 :         return true;
     158           0 :     if (EQUAL(pszCap, OLCZGeometries))
     159           0 :         return true;
     160           0 :     if (EQUAL(pszCap, OLCCurveGeometries))
     161           0 :         return true;
     162             : 
     163           0 :     return FALSE;
     164             : }
     165             : 
     166          20 : OGRCADLayer::~OGRCADLayer()
     167             : {
     168          10 :     if (poSpatialRef)
     169          10 :         poSpatialRef->Release();
     170          10 :     poFeatureDefn->Release();
     171          20 : }
     172             : 
     173           4 : void OGRCADLayer::ResetReading()
     174             : {
     175           4 :     nNextFID = 0;
     176           4 : }
     177             : 
     178          13 : OGRFeature *OGRCADLayer::GetNextFeature()
     179             : {
     180          13 :     OGRFeature *poFeature = GetFeature(nNextFID);
     181          13 :     ++nNextFID;
     182             : 
     183          13 :     if (poFeature == nullptr)
     184           0 :         return nullptr;
     185             : 
     186          26 :     if ((m_poFilterGeom == nullptr ||
     187          26 :          FilterGeometry(poFeature->GetGeometryRef())) &&
     188          13 :         (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
     189             :     {
     190          13 :         return poFeature;
     191             :     }
     192             : 
     193           0 :     return nullptr;
     194             : }
     195             : 
     196          13 : OGRFeature *OGRCADLayer::GetFeature(GIntBig nFID)
     197             : {
     198          13 :     if (poCADLayer.getGeometryCount() <= static_cast<size_t>(nFID) || nFID < 0)
     199             :     {
     200           0 :         return nullptr;
     201             :     }
     202             : 
     203          13 :     OGRFeature *poFeature = nullptr;
     204             :     CADGeometry *poCADGeometry =
     205          13 :         poCADLayer.getGeometry(static_cast<size_t>(nFID));
     206             : 
     207          26 :     if (nullptr == poCADGeometry ||
     208          13 :         GetLastErrorCode() != CADErrorCodes::SUCCESS)
     209             :     {
     210           0 :         CPLError(CE_Failure, CPLE_NotSupported,
     211             :                  "Failed to get geometry with ID = " CPL_FRMT_GIB
     212             :                  " from layer \"%s\". Libopencad errorcode: %d",
     213           0 :                  nFID, poCADLayer.getName().c_str(), GetLastErrorCode());
     214           0 :         return nullptr;
     215             :     }
     216             : 
     217          13 :     poFeature = new OGRFeature(poFeatureDefn);
     218          13 :     poFeature->SetFID(nFID);
     219          13 :     poFeature->SetField(FIELD_NAME_THICKNESS, poCADGeometry->getThickness());
     220             : 
     221          13 :     if (!poCADGeometry->getEED().empty())
     222             :     {
     223           6 :         std::vector<std::string> asGeometryEED = poCADGeometry->getEED();
     224           6 :         std::string sEEDAsOneString = "";
     225           3 :         for (std::vector<std::string>::const_iterator iter =
     226           3 :                  asGeometryEED.cbegin();
     227           9 :              iter != asGeometryEED.cend(); ++iter)
     228             :         {
     229           3 :             sEEDAsOneString += *iter;
     230           3 :             sEEDAsOneString += ' ';
     231             :         }
     232             : 
     233           3 :         poFeature->SetField(FIELD_NAME_EXT_DATA, sEEDAsOneString.c_str());
     234             :     }
     235             : 
     236          13 :     RGBColor stRGB = poCADGeometry->getColor();
     237          26 :     CPLString sHexColor;
     238          13 :     sHexColor.Printf("#%02X%02X%02X%02X", stRGB.R, stRGB.G, stRGB.B, 255);
     239          13 :     poFeature->SetField(FIELD_NAME_COLOR, sHexColor);
     240             : 
     241          26 :     CPLString sStyle;
     242          13 :     sStyle.Printf("PEN(c:%s,w:5px)", sHexColor.c_str());
     243          13 :     poFeature->SetStyleString(sStyle);
     244             : 
     245          26 :     std::vector<CADAttrib> oBlockAttrs = poCADGeometry->getBlockAttributes();
     246          13 :     for (const CADAttrib &oAttrib : oBlockAttrs)
     247             :     {
     248           0 :         CPLString osTag = oAttrib.getTag();
     249           0 :         auto featureAttrIt = asFeaturesAttributes.find(osTag);
     250           0 :         if (featureAttrIt != asFeaturesAttributes.end())
     251             :         {
     252           0 :             poFeature->SetField(*featureAttrIt, oAttrib.getTextValue().c_str());
     253             :         }
     254             :     }
     255             : 
     256          13 :     switch (poCADGeometry->getType())
     257             :     {
     258           1 :         case CADGeometry::POINT:
     259             :         {
     260           1 :             CADPoint3D *const poCADPoint = (CADPoint3D *)poCADGeometry;
     261           1 :             CADVector stPositionVector = poCADPoint->getPosition();
     262             : 
     263           1 :             poFeature->SetGeometryDirectly(
     264           1 :                 new OGRPoint(stPositionVector.getX(), stPositionVector.getY(),
     265           1 :                              stPositionVector.getZ()));
     266           1 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADPoint");
     267           1 :             break;
     268             :         }
     269             : 
     270           1 :         case CADGeometry::LINE:
     271             :         {
     272           1 :             CADLine *const poCADLine = (CADLine *)poCADGeometry;
     273           1 :             OGRLineString *poLS = new OGRLineString();
     274           2 :             poLS->addPoint(poCADLine->getStart().getPosition().getX(),
     275           2 :                            poCADLine->getStart().getPosition().getY(),
     276           2 :                            poCADLine->getStart().getPosition().getZ());
     277           2 :             poLS->addPoint(poCADLine->getEnd().getPosition().getX(),
     278           2 :                            poCADLine->getEnd().getPosition().getY(),
     279           2 :                            poCADLine->getEnd().getPosition().getZ());
     280             : 
     281           1 :             poFeature->SetGeometryDirectly(poLS);
     282           1 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADLine");
     283           1 :             break;
     284             :         }
     285             : 
     286           0 :         case CADGeometry::SOLID:
     287             :         {
     288           0 :             CADSolid *const poCADSolid = (CADSolid *)poCADGeometry;
     289           0 :             OGRPolygon *poPoly = new OGRPolygon();
     290           0 :             OGRLinearRing *poLR = new OGRLinearRing();
     291             : 
     292           0 :             std::vector<CADVector> astSolidCorners = poCADSolid->getCorners();
     293           0 :             for (size_t i = 0; i < astSolidCorners.size(); ++i)
     294             :             {
     295           0 :                 poLR->addPoint(astSolidCorners[i].getX(),
     296           0 :                                astSolidCorners[i].getY(),
     297           0 :                                astSolidCorners[i].getZ());
     298             :             }
     299           0 :             poPoly->addRingDirectly(poLR);
     300           0 :             poPoly->closeRings();
     301           0 :             poFeature->SetGeometryDirectly(poPoly);
     302             : 
     303           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADSolid");
     304           0 :             break;
     305             :         }
     306             : 
     307           3 :         case CADGeometry::CIRCLE:
     308             :         {
     309           3 :             CADCircle *poCADCircle = static_cast<CADCircle *>(poCADGeometry);
     310           3 :             OGRCircularString *poCircle = new OGRCircularString();
     311             : 
     312           3 :             CADVector stCircleCenter = poCADCircle->getPosition();
     313           6 :             OGRPoint oCirclePoint1;
     314           3 :             oCirclePoint1.setX(stCircleCenter.getX() -
     315           3 :                                poCADCircle->getRadius());
     316           3 :             oCirclePoint1.setY(stCircleCenter.getY());
     317           3 :             oCirclePoint1.setZ(stCircleCenter.getZ());
     318           3 :             poCircle->addPoint(&oCirclePoint1);
     319             : 
     320           6 :             OGRPoint oCirclePoint2;
     321           3 :             oCirclePoint2.setX(stCircleCenter.getX());
     322           3 :             oCirclePoint2.setY(stCircleCenter.getY() +
     323           3 :                                poCADCircle->getRadius());
     324           3 :             oCirclePoint2.setZ(stCircleCenter.getZ());
     325           3 :             poCircle->addPoint(&oCirclePoint2);
     326             : 
     327           6 :             OGRPoint oCirclePoint3;
     328           3 :             oCirclePoint3.setX(stCircleCenter.getX() +
     329           3 :                                poCADCircle->getRadius());
     330           3 :             oCirclePoint3.setY(stCircleCenter.getY());
     331           3 :             oCirclePoint3.setZ(stCircleCenter.getZ());
     332           3 :             poCircle->addPoint(&oCirclePoint3);
     333             : 
     334           6 :             OGRPoint oCirclePoint4;
     335           3 :             oCirclePoint4.setX(stCircleCenter.getX());
     336           3 :             oCirclePoint4.setY(stCircleCenter.getY() -
     337           3 :                                poCADCircle->getRadius());
     338           3 :             oCirclePoint4.setZ(stCircleCenter.getZ());
     339           3 :             poCircle->addPoint(&oCirclePoint4);
     340             : 
     341             :             // Close the circle
     342           3 :             poCircle->addPoint(&oCirclePoint1);
     343             : 
     344             :             /*NOTE: The alternative way:
     345             :                     OGRGeometry *poCircle =
     346             :                OGRGeometryFactory::approximateArcAngles(
     347             :                     poCADCircle->getPosition().getX(),
     348             :                     poCADCircle->getPosition().getY(),
     349             :                     poCADCircle->getPosition().getZ(),
     350             :                     poCADCircle->getRadius(), poCADCircle->getRadius(), 0.0,
     351             :                     0.0, 360.0,
     352             :                     0.0 );
     353             :             */
     354           3 :             poFeature->SetGeometryDirectly(poCircle);
     355             : 
     356           3 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADCircle");
     357           3 :             break;
     358             :         }
     359             : 
     360           0 :         case CADGeometry::ARC:
     361             :         {
     362           0 :             CADArc *poCADArc = static_cast<CADArc *>(poCADGeometry);
     363           0 :             OGRCircularString *poCircle = new OGRCircularString();
     364             : 
     365             :             // Need at least 3 points in arc
     366           0 :             double dfStartAngle = poCADArc->getStartingAngle() * RAD2DEG;
     367           0 :             double dfEndAngle = poCADArc->getEndingAngle() * RAD2DEG;
     368           0 :             double dfMidAngle = (dfEndAngle + dfStartAngle) / 2;
     369           0 :             CADVector stCircleCenter = poCADArc->getPosition();
     370             : 
     371           0 :             OGRPoint oCirclePoint;
     372           0 :             oCirclePoint.setX(stCircleCenter.getX() +
     373           0 :                               poCADArc->getRadius() * cos(dfStartAngle));
     374           0 :             oCirclePoint.setY(stCircleCenter.getY() +
     375           0 :                               poCADArc->getRadius() * sin(dfStartAngle));
     376           0 :             oCirclePoint.setZ(stCircleCenter.getZ());
     377           0 :             poCircle->addPoint(&oCirclePoint);
     378             : 
     379           0 :             oCirclePoint.setX(stCircleCenter.getX() +
     380           0 :                               poCADArc->getRadius() * cos(dfMidAngle));
     381           0 :             oCirclePoint.setY(stCircleCenter.getY() +
     382           0 :                               poCADArc->getRadius() * sin(dfMidAngle));
     383           0 :             oCirclePoint.setZ(stCircleCenter.getZ());
     384           0 :             poCircle->addPoint(&oCirclePoint);
     385             : 
     386           0 :             oCirclePoint.setX(stCircleCenter.getX() +
     387           0 :                               poCADArc->getRadius() * cos(dfEndAngle));
     388           0 :             oCirclePoint.setY(stCircleCenter.getY() +
     389           0 :                               poCADArc->getRadius() * sin(dfEndAngle));
     390           0 :             oCirclePoint.setZ(stCircleCenter.getZ());
     391           0 :             poCircle->addPoint(&oCirclePoint);
     392             : 
     393             :             /*NOTE: alternative way:
     394             :                 OGRGeometry * poArc = OGRGeometryFactory::approximateArcAngles(
     395             :                 poCADArc->getPosition().getX(),
     396             :                 poCADArc->getPosition().getY(),
     397             :                 poCADArc->getPosition().getZ(),
     398             :                 poCADArc->getRadius(), poCADArc->getRadius(), 0.0,
     399             :                 dfStartAngle,
     400             :                 dfStartAngle > dfEndAngle ?
     401             :                     ( dfEndAngle + 360.0f ) :
     402             :                     dfEndAngle,
     403             :                 0.0 );
     404             :             */
     405             : 
     406           0 :             poFeature->SetGeometryDirectly(poCircle);
     407           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADArc");
     408             : 
     409           0 :             break;
     410             :         }
     411             : 
     412           0 :         case CADGeometry::FACE3D:
     413             :         {
     414           0 :             CADFace3D *const poCADFace = (CADFace3D *)poCADGeometry;
     415           0 :             OGRPolygon *poPoly = new OGRPolygon();
     416           0 :             OGRLinearRing *poLR = new OGRLinearRing();
     417             : 
     418           0 :             for (size_t i = 0; i < 3; ++i)
     419             :             {
     420           0 :                 poLR->addPoint(poCADFace->getCorner(i).getX(),
     421           0 :                                poCADFace->getCorner(i).getY(),
     422           0 :                                poCADFace->getCorner(i).getZ());
     423             :             }
     424           0 :             if (!(poCADFace->getCorner(2) == poCADFace->getCorner(3)))
     425             :             {
     426           0 :                 poLR->addPoint(poCADFace->getCorner(3).getX(),
     427           0 :                                poCADFace->getCorner(3).getY(),
     428           0 :                                poCADFace->getCorner(3).getZ());
     429             :             }
     430           0 :             poPoly->addRingDirectly(poLR);
     431           0 :             poPoly->closeRings();
     432           0 :             poFeature->SetGeometryDirectly(poPoly);
     433             : 
     434           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADFace3D");
     435           0 :             break;
     436             :         }
     437             : 
     438           0 :         case CADGeometry::LWPOLYLINE:
     439             :         {
     440           0 :             CADLWPolyline *const poCADLWPolyline =
     441             :                 (CADLWPolyline *)poCADGeometry;
     442             : 
     443           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADLWPolyline");
     444             : 
     445             :             /*
     446             :              * Excessive check, like in DXF driver.
     447             :              * I tried to make a single-point polyline, but couldn't make it.
     448             :              * Probably this check should be removed.
     449             :              */
     450           0 :             if (poCADLWPolyline->getVertexCount() == 1)
     451             :             {
     452           0 :                 poFeature->SetGeometryDirectly(
     453           0 :                     new OGRPoint(poCADLWPolyline->getVertex(0).getX(),
     454           0 :                                  poCADLWPolyline->getVertex(0).getY(),
     455           0 :                                  poCADLWPolyline->getVertex(0).getZ()));
     456             : 
     457           0 :                 break;
     458             :             }
     459             : 
     460             :             /*
     461             :              * If polyline has no arcs, handle it in easy way.
     462             :              */
     463           0 :             OGRLineString *poLS = new OGRLineString();
     464             : 
     465           0 :             if (poCADLWPolyline->getBulges().empty())
     466             :             {
     467           0 :                 for (size_t i = 0; i < poCADLWPolyline->getVertexCount(); ++i)
     468             :                 {
     469           0 :                     CADVector stVertex = poCADLWPolyline->getVertex(i);
     470           0 :                     poLS->addPoint(stVertex.getX(), stVertex.getY(),
     471             :                                    stVertex.getZ());
     472             :                 }
     473             : 
     474           0 :                 poFeature->SetGeometryDirectly(poLS);
     475           0 :                 break;
     476             :             }
     477             : 
     478             :             /*
     479             :              * Last case - if polyline has mixed arcs and lines.
     480             :              */
     481           0 :             bool bLineStringStarted = false;
     482           0 :             std::vector<double> adfBulges = poCADLWPolyline->getBulges();
     483             :             const size_t nCount =
     484           0 :                 std::min(adfBulges.size(), poCADLWPolyline->getVertexCount());
     485             : 
     486           0 :             for (size_t iCurrentVertex = 0; iCurrentVertex + 1 < nCount;
     487             :                  iCurrentVertex++)
     488             :             {
     489             :                 CADVector stCurrentVertex =
     490           0 :                     poCADLWPolyline->getVertex(iCurrentVertex);
     491             :                 CADVector stNextVertex =
     492           0 :                     poCADLWPolyline->getVertex(iCurrentVertex + 1);
     493             : 
     494             :                 double dfLength =
     495           0 :                     sqrt(pow(stNextVertex.getX() - stCurrentVertex.getX(), 2) +
     496           0 :                          pow(stNextVertex.getY() - stCurrentVertex.getY(), 2));
     497             : 
     498             :                 /*
     499             :                  * Handling straight polyline segment.
     500             :                  */
     501           0 :                 if ((dfLength == 0) || (adfBulges[iCurrentVertex] == 0))
     502             :                 {
     503           0 :                     if (!bLineStringStarted)
     504             :                     {
     505           0 :                         poLS->addPoint(stCurrentVertex.getX(),
     506             :                                        stCurrentVertex.getY(),
     507             :                                        stCurrentVertex.getZ());
     508           0 :                         bLineStringStarted = true;
     509             :                     }
     510             : 
     511           0 :                     poLS->addPoint(stNextVertex.getX(), stNextVertex.getY(),
     512             :                                    stNextVertex.getZ());
     513             :                 }
     514             :                 else
     515             :                 {
     516           0 :                     double dfSegmentBulge = adfBulges[iCurrentVertex];
     517           0 :                     double dfH = (dfSegmentBulge * dfLength) / 2;
     518           0 :                     if (dfH == 0.0)
     519           0 :                         dfH = 1.0;  // just to avoid a division by zero
     520           0 :                     double dfRadius =
     521           0 :                         (dfH / 2) + (dfLength * dfLength / (8 * dfH));
     522           0 :                     double dfOgrArcRotation = 0,
     523           0 :                            dfOgrArcRadius = fabs(dfRadius);
     524             : 
     525             :                     /*
     526             :                      * Set arc's direction and keep bulge positive.
     527             :                      */
     528           0 :                     bool bClockwise = (dfSegmentBulge < 0);
     529           0 :                     if (bClockwise)
     530           0 :                         dfSegmentBulge *= -1;
     531             : 
     532             :                     /*
     533             :                      * Get arc's center point.
     534             :                      */
     535           0 :                     double dfSaggita = fabs(dfSegmentBulge * (dfLength / 2.0));
     536           0 :                     double dfApo = bClockwise ? -(dfOgrArcRadius - dfSaggita)
     537           0 :                                               : -(dfSaggita - dfOgrArcRadius);
     538             : 
     539           0 :                     CADVector stVertex;
     540           0 :                     stVertex.setX(stCurrentVertex.getX() - stNextVertex.getX());
     541           0 :                     stVertex.setY(stCurrentVertex.getY() - stNextVertex.getY());
     542           0 :                     stVertex.setZ(stCurrentVertex.getZ());
     543             : 
     544           0 :                     CADVector stMidPoint;
     545           0 :                     stMidPoint.setX(stNextVertex.getX() +
     546           0 :                                     0.5 * stVertex.getX());
     547           0 :                     stMidPoint.setY(stNextVertex.getY() +
     548           0 :                                     0.5 * stVertex.getY());
     549           0 :                     stMidPoint.setZ(stVertex.getZ());
     550             : 
     551           0 :                     CADVector stPperp;
     552           0 :                     stPperp.setX(stVertex.getY());
     553           0 :                     stPperp.setY(-stVertex.getX());
     554             :                     double dfStPperpLength =
     555           0 :                         sqrt(stPperp.getX() * stPperp.getX() +
     556           0 :                              stPperp.getY() * stPperp.getY());
     557             :                     // TODO: Check that length isnot 0
     558           0 :                     stPperp.setX(stPperp.getX() / dfStPperpLength);
     559           0 :                     stPperp.setY(stPperp.getY() / dfStPperpLength);
     560             : 
     561           0 :                     CADVector stOgrArcCenter;
     562           0 :                     stOgrArcCenter.setX(stMidPoint.getX() +
     563           0 :                                         (stPperp.getX() * dfApo));
     564           0 :                     stOgrArcCenter.setY(stMidPoint.getY() +
     565           0 :                                         (stPperp.getY() * dfApo));
     566             : 
     567             :                     /*
     568             :                      * Get the line's general vertical direction ( -1 = down, +1
     569             :                      * = up ).
     570             :                      */
     571             :                     double dfLineDir =
     572           0 :                         stNextVertex.getY() > stCurrentVertex.getY() ? 1.0f
     573           0 :                                                                      : -1.0f;
     574             : 
     575             :                     /*
     576             :                      * Get arc's starting angle.
     577             :                      */
     578             :                     double dfA =
     579           0 :                         atan2(
     580           0 :                             (stOgrArcCenter.getY() - stCurrentVertex.getY()),
     581           0 :                             (stOgrArcCenter.getX() - stCurrentVertex.getX())) *
     582           0 :                         RAD2DEG;
     583           0 :                     if (bClockwise && (dfLineDir == 1.0))
     584           0 :                         dfA += (dfLineDir * 180.0);
     585             : 
     586           0 :                     double dfOgrArcStartAngle =
     587           0 :                         dfA > 0.0 ? -(dfA - 180.0) : -(dfA + 180.0);
     588             : 
     589             :                     /*
     590             :                      * Get arc's ending angle.
     591             :                      */
     592           0 :                     dfA = atan2((stOgrArcCenter.getY() - stNextVertex.getY()),
     593           0 :                                 (stOgrArcCenter.getX() - stNextVertex.getX())) *
     594             :                           RAD2DEG;
     595           0 :                     if (bClockwise && (dfLineDir == 1.0))
     596           0 :                         dfA += (dfLineDir * 180.0);
     597             : 
     598           0 :                     double dfOgrArcEndAngle =
     599           0 :                         dfA > 0.0 ? -(dfA - 180.0) : -(dfA + 180.0);
     600             : 
     601           0 :                     if (!bClockwise && (dfOgrArcStartAngle < dfOgrArcEndAngle))
     602           0 :                         dfOgrArcEndAngle = -180.0 + (dfLineDir * dfA);
     603             : 
     604           0 :                     if (bClockwise && (dfOgrArcStartAngle > dfOgrArcEndAngle))
     605           0 :                         dfOgrArcEndAngle += 360.0;
     606             : 
     607             :                     /*
     608             :                      * Flip arc's rotation if necessary.
     609             :                      */
     610           0 :                     if (bClockwise && (dfLineDir == 1.0))
     611           0 :                         dfOgrArcRotation = dfLineDir * 180.0;
     612             : 
     613             :                     /*
     614             :                      * Tessellate the arc segment and append to the linestring.
     615             :                      */
     616             :                     OGRLineString *poArcpoLS = (OGRLineString *)
     617           0 :                         OGRGeometryFactory::approximateArcAngles(
     618             :                             stOgrArcCenter.getX(), stOgrArcCenter.getY(),
     619             :                             stOgrArcCenter.getZ(), dfOgrArcRadius,
     620             :                             dfOgrArcRadius, dfOgrArcRotation,
     621             :                             dfOgrArcStartAngle, dfOgrArcEndAngle, 0.0);
     622             : 
     623           0 :                     poLS->addSubLineString(poArcpoLS);
     624             : 
     625           0 :                     delete (poArcpoLS);
     626             :                 }
     627             :             }
     628             : 
     629           0 :             if (poCADLWPolyline->isClosed())
     630             :             {
     631           0 :                 poLS->addPoint(poCADLWPolyline->getVertex(0).getX(),
     632           0 :                                poCADLWPolyline->getVertex(0).getY(),
     633           0 :                                poCADLWPolyline->getVertex(0).getZ());
     634             :             }
     635             : 
     636           0 :             poFeature->SetGeometryDirectly(poLS);
     637           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADLWPolyline");
     638           0 :             break;
     639             :         }
     640             : 
     641             :         // TODO: Unsupported smooth lines
     642           0 :         case CADGeometry::POLYLINE3D:
     643             :         {
     644           0 :             CADPolyline3D *const poCADPolyline3D =
     645             :                 (CADPolyline3D *)poCADGeometry;
     646           0 :             OGRLineString *poLS = new OGRLineString();
     647             : 
     648           0 :             for (size_t i = 0; i < poCADPolyline3D->getVertexCount(); ++i)
     649             :             {
     650           0 :                 CADVector stVertex = poCADPolyline3D->getVertex(i);
     651             : 
     652           0 :                 poLS->addPoint(stVertex.getX(), stVertex.getY(),
     653             :                                stVertex.getZ());
     654             :             }
     655             : 
     656           0 :             poFeature->SetGeometryDirectly(poLS);
     657           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADPolyline3D");
     658           0 :             break;
     659             :         }
     660             : 
     661           4 :         case CADGeometry::TEXT:
     662             :         {
     663           4 :             CADText *const poCADText = (CADText *)poCADGeometry;
     664           4 :             OGRPoint *poPoint = new OGRPoint(poCADText->getPosition().getX(),
     665           4 :                                              poCADText->getPosition().getY(),
     666           4 :                                              poCADText->getPosition().getZ());
     667             :             CPLString sTextValue =
     668          12 :                 CADRecode(poCADText->getTextValue(), nDWGEncoding);
     669             : 
     670           4 :             poFeature->SetField(FIELD_NAME_TEXT, sTextValue);
     671           4 :             poFeature->SetGeometryDirectly(poPoint);
     672           4 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADText");
     673             : 
     674             :             sStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",c:%s)",
     675           4 :                           sTextValue.c_str(), sHexColor.c_str());
     676           4 :             poFeature->SetStyleString(sStyle);
     677           4 :             break;
     678             :         }
     679             : 
     680           2 :         case CADGeometry::MTEXT:
     681             :         {
     682           2 :             CADMText *const poCADMText = (CADMText *)poCADGeometry;
     683           2 :             OGRPoint *poPoint = new OGRPoint(poCADMText->getPosition().getX(),
     684           2 :                                              poCADMText->getPosition().getY(),
     685           2 :                                              poCADMText->getPosition().getZ());
     686             :             CPLString sTextValue =
     687           6 :                 CADRecode(poCADMText->getTextValue(), nDWGEncoding);
     688             : 
     689           2 :             poFeature->SetField(FIELD_NAME_TEXT, sTextValue);
     690           2 :             poFeature->SetGeometryDirectly(poPoint);
     691           2 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADMText");
     692             : 
     693             :             sStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",c:%s)",
     694           2 :                           sTextValue.c_str(), sHexColor.c_str());
     695           2 :             poFeature->SetStyleString(sStyle);
     696           2 :             break;
     697             :         }
     698             : 
     699           0 :         case CADGeometry::SPLINE:
     700             :         {
     701           0 :             CADSpline *const poCADSpline = (CADSpline *)poCADGeometry;
     702           0 :             OGRLineString *poLS = new OGRLineString();
     703             : 
     704             :             // TODO: Interpolate spline as points or curves
     705           0 :             for (size_t i = 0; i < poCADSpline->getControlPoints().size(); ++i)
     706             :             {
     707           0 :                 poLS->addPoint(poCADSpline->getControlPoints()[i].getX(),
     708           0 :                                poCADSpline->getControlPoints()[i].getY(),
     709           0 :                                poCADSpline->getControlPoints()[i].getZ());
     710             :             }
     711             : 
     712           0 :             poFeature->SetGeometryDirectly(poLS);
     713           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADSpline");
     714           0 :             break;
     715             :         }
     716             : 
     717           1 :         case CADGeometry::ELLIPSE:
     718             :         {
     719           1 :             CADEllipse *poCADEllipse = static_cast<CADEllipse *>(poCADGeometry);
     720             : 
     721             :             // FIXME: Start/end angles should be swapped to work exactly as DXF
     722             :             // driver. is it correct?
     723           1 :             double dfStartAngle = poCADEllipse->getStartingAngle() * RAD2DEG;
     724           1 :             double dfEndAngle = poCADEllipse->getEndingAngle() * RAD2DEG;
     725           1 :             if (dfStartAngle > dfEndAngle)
     726             :             {
     727           0 :                 dfEndAngle += 360.0;
     728             :             }
     729           1 :             double dfAxisRatio = poCADEllipse->getAxisRatio();
     730             : 
     731           1 :             CADVector stEllipseCenter = poCADEllipse->getPosition();
     732           1 :             CADVector vectSMAxis = poCADEllipse->getSMAxis();
     733             :             double dfPrimaryRadius, dfSecondaryRadius;
     734             :             double dfRotation;
     735           1 :             dfPrimaryRadius = sqrt(vectSMAxis.getX() * vectSMAxis.getX() +
     736           1 :                                    vectSMAxis.getY() * vectSMAxis.getY() +
     737           1 :                                    vectSMAxis.getZ() * vectSMAxis.getZ());
     738             : 
     739           1 :             dfSecondaryRadius = dfAxisRatio * dfPrimaryRadius;
     740             : 
     741           1 :             dfRotation =
     742           1 :                 -1 * atan2(vectSMAxis.getY(), vectSMAxis.getX()) * RAD2DEG;
     743             :             /* NOTE: alternative way:
     744             :             OGRCircularString * poEllipse = new OGRCircularString();
     745             :             OGRPoint  oEllipsePoint1;
     746             :             oEllipsePoint1.setX( stEllipseCenter.getX() - dfPrimaryRadius *
     747             :                                                             cos( dfRotation ) );
     748             :             oEllipsePoint1.setY( stEllipseCenter.getY() + dfPrimaryRadius *
     749             :                                                             sin( dfRotation ) );
     750             :             oEllipsePoint1.setZ( stEllipseCenter.getZ() );
     751             :             poEllipse->addPoint( &oEllipsePoint1 );
     752             : 
     753             :             OGRPoint  oEllipsePoint2;
     754             :             oEllipsePoint2.setX( stEllipseCenter.getX() + dfSecondaryRadius *
     755             :                                                             cos( dfRotation ) );
     756             :             oEllipsePoint2.setY( stEllipseCenter.getY() + dfSecondaryRadius *
     757             :                                                             sin( dfRotation ) );
     758             :             oEllipsePoint2.setZ( stEllipseCenter.getZ() );
     759             :             poEllipse->addPoint( &oEllipsePoint2 );
     760             : 
     761             :             OGRPoint  oEllipsePoint3;
     762             :             oEllipsePoint3.setX( stEllipseCenter.getX() + dfPrimaryRadius *
     763             :                                                             cos( dfRotation ) );
     764             :             oEllipsePoint3.setY( stEllipseCenter.getY() - dfPrimaryRadius *
     765             :                                                             sin( dfRotation ) );
     766             :             oEllipsePoint3.setZ( stEllipseCenter.getZ() );
     767             :             poEllipse->addPoint( &oEllipsePoint3 );
     768             : 
     769             :             OGRPoint  oEllipsePoint4;
     770             :             oEllipsePoint4.setX( stEllipseCenter.getX() - dfSecondaryRadius *
     771             :                                                             cos( dfRotation ) );
     772             :             oEllipsePoint4.setY( stEllipseCenter.getY() - dfSecondaryRadius *
     773             :                                                             sin( dfRotation ) );
     774             :             oEllipsePoint4.setZ( stEllipseCenter.getZ() );
     775             :             poEllipse->addPoint( &oEllipsePoint4 );
     776             : 
     777             :             // Close the ellipse
     778             :             poEllipse->addPoint( &oEllipsePoint1 );
     779             :             */
     780             : 
     781           1 :             CPLDebug("CAD",
     782             :                      "Position: %f, %f, %f, radius %f/%f, start angle: %f, end "
     783             :                      "angle: %f, rotation: %f",
     784             :                      stEllipseCenter.getX(), stEllipseCenter.getY(),
     785             :                      stEllipseCenter.getZ(), dfPrimaryRadius, dfSecondaryRadius,
     786             :                      dfStartAngle, dfEndAngle, dfRotation);
     787           1 :             OGRGeometry *poEllipse = OGRGeometryFactory::approximateArcAngles(
     788             :                 stEllipseCenter.getX(), stEllipseCenter.getY(),
     789             :                 stEllipseCenter.getZ(), dfPrimaryRadius, dfSecondaryRadius,
     790             :                 dfRotation, dfStartAngle, dfEndAngle, 0.0);
     791             : 
     792           1 :             poFeature->SetGeometryDirectly(poEllipse);
     793           1 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADEllipse");
     794           1 :             break;
     795             :         }
     796             : 
     797           1 :         case CADGeometry::ATTDEF:
     798             :         {
     799           1 :             CADAttdef *const poCADAttdef = (CADAttdef *)poCADGeometry;
     800           1 :             OGRPoint *poPoint = new OGRPoint(poCADAttdef->getPosition().getX(),
     801           1 :                                              poCADAttdef->getPosition().getY(),
     802           1 :                                              poCADAttdef->getPosition().getZ());
     803             :             CPLString sTextValue =
     804           3 :                 CADRecode(poCADAttdef->getTag(), nDWGEncoding);
     805             : 
     806           1 :             poFeature->SetField(FIELD_NAME_TEXT, sTextValue);
     807           1 :             poFeature->SetGeometryDirectly(poPoint);
     808           1 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADAttdef");
     809             : 
     810             :             sStyle.Printf("LABEL(f:\"Arial\",t:\"%s\",c:%s)",
     811           1 :                           sTextValue.c_str(), sHexColor.c_str());
     812           1 :             poFeature->SetStyleString(sStyle);
     813           1 :             break;
     814             :         }
     815             : 
     816           0 :         default:
     817             :         {
     818           0 :             CPLError(CE_Warning, CPLE_NotSupported,
     819             :                      "Unhandled feature. Skipping it.");
     820             : 
     821           0 :             poFeature->SetField(FIELD_NAME_GEOMTYPE, "CADUnknown");
     822           0 :             delete poCADGeometry;
     823           0 :             return poFeature;
     824             :         }
     825             :     }
     826             : 
     827          13 :     delete poCADGeometry;
     828          13 :     poFeature->GetGeometryRef()->assignSpatialReference(poSpatialRef);
     829          13 :     return poFeature;
     830             : }

Generated by: LCOV version 1.14