LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxf_polyline_smooth.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 95 100 95.0 %
Date: 2024-11-21 22:18:42 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  * File:   ogrdxf_polyline_smooth.cpp
       3             :  *
       4             :  * Project:  Interpolation support for smooth POLYLINE and LWPOLYLINE entities.
       5             :  * Purpose:  Implementation of classes for OGR .dxf driver.
       6             :  * Author:   TJ Snider, timsn@thtree.com
       7             :  *           Ray Gardener, Daylon Graphics Ltd.
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 2010 Daylon Graphics Ltd.
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "stdlib.h"
      16             : #include "math.h"
      17             : #include "ogrdxf_polyline_smooth.h"
      18             : 
      19             : /************************************************************************/
      20             : /*                Local helper functions                                */
      21             : /************************************************************************/
      22             : 
      23          18 : static double GetRadius(double bulge, double length)
      24             : {
      25          18 :     const double h = (bulge * length) / 2;
      26          18 :     return (h / 2) + (length * length / (8 * h));
      27             : }
      28             : 
      29         228 : static double GetLength(const DXFSmoothPolylineVertex &start,
      30             :                         const DXFSmoothPolylineVertex &end)
      31             : {
      32         228 :     return sqrt(pow(end.x - start.x, 2) + pow(end.y - start.y, 2));
      33             : }
      34             : 
      35          36 : static double GetAngle(const DXFSmoothPolylineVertex &start,
      36             :                        const DXFSmoothPolylineVertex &end)
      37             : {
      38          36 :     return atan2((start.y - end.y), (start.x - end.x)) * 180.0 / M_PI;
      39             : }
      40             : 
      41          36 : static double GetOGRangle(double angle)
      42             : {
      43          36 :     return angle > 0.0 ? -(angle - 180.0) : -(angle + 180.0);
      44             : }
      45             : 
      46             : /************************************************************************/
      47             : /*                DXFSmoothPolyline::Tessellate()                        */
      48             : /************************************************************************/
      49             : 
      50          72 : OGRGeometry *DXFSmoothPolyline::Tessellate(bool bAsPolygon) const
      51             : {
      52          72 :     assert(!m_vertices.empty());
      53             : 
      54             :     /* -------------------------------------------------------------------- */
      55             :     /*      If polyline is one vertex, convert it to a point                */
      56             :     /* -------------------------------------------------------------------- */
      57             : 
      58          72 :     if (m_vertices.size() == 1)
      59             :     {
      60             :         OGRPoint *poPt =
      61           0 :             new OGRPoint(m_vertices[0].x, m_vertices[0].y, m_vertices[0].z);
      62           0 :         if (m_vertices[0].z == 0 || m_dim == 2)
      63           0 :             poPt->flattenTo2D();
      64           0 :         return poPt;
      65             :     }
      66             : 
      67             :     /* -------------------------------------------------------------------- */
      68             :     /*      Otherwise, presume a line string                                */
      69             :     /* -------------------------------------------------------------------- */
      70             : 
      71          72 :     OGRLinearRing *poLR = m_bClosed && bAsPolygon ? new OGRLinearRing : nullptr;
      72          72 :     OGRLineString *poLS = poLR ? poLR : new OGRLineString;
      73             : 
      74          72 :     m_blinestringstarted = false;
      75             : 
      76             :     std::vector<DXFSmoothPolylineVertex>::const_iterator oIter =
      77          72 :         m_vertices.begin();
      78             :     std::vector<DXFSmoothPolylineVertex>::const_iterator oEndIter =
      79          72 :         m_vertices.end();
      80             : 
      81          72 :     --oEndIter;
      82             : 
      83          72 :     DXFSmoothPolylineVertex begin = *oIter;
      84             : 
      85         300 :     while (oIter != oEndIter)
      86             :     {
      87         228 :         ++oIter;
      88         228 :         DXFSmoothPolylineVertex end = *oIter;
      89             : 
      90         228 :         const double len = GetLength(begin, end);
      91             : 
      92             :         // Don't bother handling bulge for non-constant Z
      93         228 :         if (len == 0 || begin.bulge == 0 || begin.z != end.z)
      94             :         {
      95         210 :             EmitLine(begin, end, poLS);
      96             :         }
      97             :         else
      98             :         {
      99          18 :             const double radius = GetRadius(begin.bulge, len);
     100          18 :             EmitArc(begin, end, radius, len, begin.bulge, poLS, begin.z);
     101             :         }
     102             : 
     103             :         // Move to next vertex
     104         228 :         begin = end;
     105             :     }
     106             : 
     107             :     /* -------------------------------------------------------------------- */
     108             :     /*      Flatten to 2D if necessary                                      */
     109             :     /* -------------------------------------------------------------------- */
     110             : 
     111          72 :     if (m_dim == 2)
     112          46 :         poLS->flattenTo2D();
     113             : 
     114          72 :     if (poLR)
     115             :     {
     116             :         // Wrap as polygon.
     117           1 :         OGRPolygon *poPoly = new OGRPolygon();
     118           1 :         poPoly->addRingDirectly(poLR);
     119             : 
     120           1 :         return poPoly;
     121             :     }
     122             : 
     123          71 :     return poLS;
     124             : }
     125             : 
     126             : /************************************************************************/
     127             : /*                DXFSmoothPolyline::EmitArc()                        */
     128             : /************************************************************************/
     129             : 
     130          18 : void DXFSmoothPolyline::EmitArc(const DXFSmoothPolylineVertex &start,
     131             :                                 const DXFSmoothPolylineVertex &end,
     132             :                                 double radius, double len, double bulge,
     133             :                                 OGRLineString *poLS, double dfZ) const
     134             : {
     135          18 :     assert(poLS);
     136             : 
     137          18 :     double ogrArcRotation = 0.0;
     138          18 :     const double ogrArcRadius = fabs(radius);
     139             : 
     140             :     /* -------------------------------------------------------------------- */
     141             :     /*      Set arc's direction and keep bulge positive                     */
     142             :     /* -------------------------------------------------------------------- */
     143             : 
     144          18 :     const bool bClockwise = (bulge < 0);
     145             : 
     146          18 :     if (bClockwise)
     147           6 :         bulge *= -1;
     148             : 
     149             :     /* -------------------------------------------------------------------- */
     150             :     /*      Get arc's center point                                          */
     151             :     /* -------------------------------------------------------------------- */
     152             : 
     153          18 :     const double saggita = fabs(bulge * (len / 2.0));
     154          18 :     const double apo =
     155          18 :         bClockwise ? -(ogrArcRadius - saggita) : -(saggita - ogrArcRadius);
     156             : 
     157          18 :     DXFSmoothPolylineVertex v;
     158          18 :     v.x = start.x - end.x;
     159          18 :     v.y = start.y - end.y;
     160             : 
     161             : #ifdef notdef
     162             :     const bool bMathissue = (v.x == 0.0 || v.y == 0.0);
     163             : #endif
     164             : 
     165          18 :     DXFSmoothPolylineVertex midpoint;
     166          18 :     midpoint.x = end.x + 0.5 * v.x;
     167          18 :     midpoint.y = end.y + 0.5 * v.y;
     168             : 
     169          18 :     DXFSmoothPolylineVertex pperp;
     170          18 :     pperp.x = v.y;
     171          18 :     pperp.y = -v.x;
     172          18 :     pperp.normalize();
     173             : 
     174          18 :     DXFSmoothPolylineVertex ogrArcCenter;
     175          18 :     ogrArcCenter.x = midpoint.x + (pperp.x * apo);
     176          18 :     ogrArcCenter.y = midpoint.y + (pperp.y * apo);
     177             : 
     178             :     /* -------------------------------------------------------------------- */
     179             :     /*      Get the line's general vertical direction (-1 = down, +1 = up)  */
     180             :     /* -------------------------------------------------------------------- */
     181             : 
     182          18 :     const double linedir = end.y > start.y ? 1.0 : -1.0;
     183             : 
     184             :     /* -------------------------------------------------------------------- */
     185             :     /*      Get arc's starting angle.                                       */
     186             :     /* -------------------------------------------------------------------- */
     187             : 
     188          18 :     double a = GetAngle(ogrArcCenter, start);
     189             : 
     190          18 :     if (bClockwise && (linedir == 1.0))
     191           3 :         a += (linedir * 180.0);
     192             : 
     193          18 :     double ogrArcStartAngle = GetOGRangle(a);
     194             : 
     195             :     /* -------------------------------------------------------------------- */
     196             :     /*      Get arc's ending angle.                                         */
     197             :     /* -------------------------------------------------------------------- */
     198             : 
     199          18 :     a = GetAngle(ogrArcCenter, end);
     200             : 
     201          18 :     if (bClockwise && (linedir == 1.0))
     202           3 :         a += (linedir * 180.0);
     203             : 
     204          18 :     double ogrArcEndAngle = GetOGRangle(a);
     205             : 
     206          18 :     if (!bClockwise && (ogrArcStartAngle < ogrArcEndAngle))
     207           2 :         ogrArcEndAngle = -180.0 + (linedir * a);
     208             : 
     209          18 :     if (bClockwise && (ogrArcStartAngle > ogrArcEndAngle))
     210           0 :         ogrArcEndAngle += 360.0;
     211             : 
     212             :     /* -------------------------------------------------------------------- */
     213             :     /*      Flip arc's rotation if necessary.                               */
     214             :     /* -------------------------------------------------------------------- */
     215             : 
     216          18 :     if (bClockwise && (linedir == 1.0))
     217           3 :         ogrArcRotation = linedir * 180.0;
     218             : 
     219             :     /* -------------------------------------------------------------------- */
     220             :     /*      Tessellate the arc segment and append to the linestring.        */
     221             :     /* -------------------------------------------------------------------- */
     222             : 
     223          18 :     if (fabs(ogrArcEndAngle - ogrArcStartAngle) <= 361.0)
     224             :     {
     225             :         auto poArc = std::unique_ptr<OGRLineString>(
     226             :             OGRGeometryFactory::approximateArcAngles(
     227             :                 ogrArcCenter.x, ogrArcCenter.y, dfZ, ogrArcRadius, ogrArcRadius,
     228             :                 ogrArcRotation, ogrArcStartAngle, ogrArcEndAngle, 0.0,
     229          18 :                 m_bUseMaxGapWhenTessellatingArcs)
     230          36 :                 ->toLineString());
     231             : 
     232             :         // Make sure extremities exactly match input start and end point.
     233             :         // This is in particular important if the polyline is closed.
     234          18 :         if (poArc->getNumPoints() >= 2)
     235             :         {
     236          18 :             poArc->setPoint(0, start.x, start.y);
     237          18 :             poArc->setPoint(poArc->getNumPoints() - 1, end.x, end.y);
     238             :         }
     239             : 
     240          18 :         poLS->addSubLineString(poArc.get());
     241             :     }
     242             :     else
     243             :     {
     244             :         // TODO: emit error ?
     245             :     }
     246          18 : }
     247             : 
     248             : /************************************************************************/
     249             : /*                   DXFSmoothPolyline::EmitLine()                      */
     250             : /************************************************************************/
     251             : 
     252         210 : void DXFSmoothPolyline::EmitLine(const DXFSmoothPolylineVertex &start,
     253             :                                  const DXFSmoothPolylineVertex &end,
     254             :                                  OGRLineString *poLS) const
     255             : {
     256         210 :     assert(poLS);
     257             : 
     258         210 :     if (!m_blinestringstarted)
     259             :     {
     260          72 :         poLS->addPoint(start.x, start.y, start.z);
     261          72 :         m_blinestringstarted = true;
     262             :     }
     263             : 
     264         210 :     poLS->addPoint(end.x, end.y, end.z);
     265         210 : }
     266             : 
     267             : /************************************************************************/
     268             : /*                DXFSmoothPolyline::Close()                            */
     269             : /************************************************************************/
     270             : 
     271          43 : void DXFSmoothPolyline::Close()
     272             : {
     273          43 :     assert(!m_bClosed);
     274             : 
     275          43 :     if (m_vertices.size() >= 2)
     276             :     {
     277             :         const bool bVisuallyClosed =
     278          43 :             (m_vertices.back().shares_2D_pos(m_vertices[0]));
     279             : 
     280          43 :         if (!bVisuallyClosed)
     281             :         {
     282          35 :             m_vertices.push_back(m_vertices[0]);
     283             :         }
     284          43 :         m_bClosed = true;
     285             :     }
     286          43 : }

Generated by: LCOV version 1.14