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: 88 93 94.6 %
Date: 2024-05-04 12:52:34 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             :  * Permission is hereby granted, free of charge, to any person obtaining a
      13             :  * copy of this software and associated documentation files (the "Software"),
      14             :  * to deal in the Software without restriction, including without limitation
      15             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      16             :  * and/or sell copies of the Software, and to permit persons to whom the
      17             :  * Software is furnished to do so, subject to the following conditions:
      18             :  *
      19             :  * The above copyright notice and this permission notice shall be included
      20             :  * in all copies or substantial portions of the Software.
      21             :  *
      22             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      23             :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      24             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      25             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      26             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      27             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      28             :  * DEALINGS IN THE SOFTWARE.
      29             :  ****************************************************************************/
      30             : 
      31             : #include "stdlib.h"
      32             : #include "math.h"
      33             : #include "ogrdxf_polyline_smooth.h"
      34             : 
      35             : /************************************************************************/
      36             : /*                Local helper functions                                */
      37             : /************************************************************************/
      38             : 
      39          12 : static double GetRadius(double bulge, double length)
      40             : {
      41          12 :     const double h = (bulge * length) / 2;
      42          12 :     return (h / 2) + (length * length / (8 * h));
      43             : }
      44             : 
      45         212 : static double GetLength(const DXFSmoothPolylineVertex &start,
      46             :                         const DXFSmoothPolylineVertex &end)
      47             : {
      48         212 :     return sqrt(pow(end.x - start.x, 2) + pow(end.y - start.y, 2));
      49             : }
      50             : 
      51          24 : static double GetAngle(const DXFSmoothPolylineVertex &start,
      52             :                        const DXFSmoothPolylineVertex &end)
      53             : {
      54          24 :     return atan2((start.y - end.y), (start.x - end.x)) * 180.0 / M_PI;
      55             : }
      56             : 
      57          24 : static double GetOGRangle(double angle)
      58             : {
      59          24 :     return angle > 0.0 ? -(angle - 180.0) : -(angle + 180.0);
      60             : }
      61             : 
      62             : /************************************************************************/
      63             : /*                DXFSmoothPolyline::Tessellate()                        */
      64             : /************************************************************************/
      65             : 
      66          70 : OGRGeometry *DXFSmoothPolyline::Tessellate() const
      67             : {
      68          70 :     assert(!m_vertices.empty());
      69             : 
      70             :     /* -------------------------------------------------------------------- */
      71             :     /*      If polyline is one vertex, convert it to a point                */
      72             :     /* -------------------------------------------------------------------- */
      73             : 
      74          70 :     if (m_vertices.size() == 1)
      75             :     {
      76             :         OGRPoint *poPt =
      77           0 :             new OGRPoint(m_vertices[0].x, m_vertices[0].y, m_vertices[0].z);
      78           0 :         if (m_vertices[0].z == 0 || m_dim == 2)
      79           0 :             poPt->flattenTo2D();
      80           0 :         return poPt;
      81             :     }
      82             : 
      83             :     /* -------------------------------------------------------------------- */
      84             :     /*      Otherwise, presume a line string                                */
      85             :     /* -------------------------------------------------------------------- */
      86             : 
      87          70 :     OGRLineString *poLS = new OGRLineString;
      88             : 
      89          70 :     m_blinestringstarted = false;
      90             : 
      91             :     std::vector<DXFSmoothPolylineVertex>::const_iterator oIter =
      92          70 :         m_vertices.begin();
      93             :     std::vector<DXFSmoothPolylineVertex>::const_iterator oEndIter =
      94          70 :         m_vertices.end();
      95             : 
      96          70 :     --oEndIter;
      97             : 
      98          70 :     DXFSmoothPolylineVertex begin = *oIter;
      99             : 
     100         282 :     while (oIter != oEndIter)
     101             :     {
     102         212 :         ++oIter;
     103         212 :         DXFSmoothPolylineVertex end = *oIter;
     104             : 
     105         212 :         const double len = GetLength(begin, end);
     106             : 
     107             :         // Don't bother handling bulge for non-constant Z
     108         212 :         if (len == 0 || begin.bulge == 0 || begin.z != end.z)
     109             :         {
     110         200 :             EmitLine(begin, end, poLS);
     111             :         }
     112             :         else
     113             :         {
     114          12 :             const double radius = GetRadius(begin.bulge, len);
     115          12 :             EmitArc(begin, end, radius, len, begin.bulge, poLS, begin.z);
     116             :         }
     117             : 
     118             :         // Move to next vertex
     119         212 :         begin = end;
     120             :     }
     121             : 
     122             :     /* -------------------------------------------------------------------- */
     123             :     /*      Flatten to 2D if necessary                                      */
     124             :     /* -------------------------------------------------------------------- */
     125             : 
     126          70 :     if (m_dim == 2)
     127          44 :         poLS->flattenTo2D();
     128             : 
     129             : /* -------------------------------------------------------------------- */
     130             : /*      If polyline is closed, convert linestring to a linear ring      */
     131             : /*                                                                      */
     132             : /*      Actually, on review I'm not convinced this is a good idea.      */
     133             : /*      Note that most (all) "filled polygons" are expressed with       */
     134             : /*      hatches which are now handled fairly well and they tend to      */
     135             : /*      echo linear polylines.                                          */
     136             : /* -------------------------------------------------------------------- */
     137             : #ifdef notdef
     138             :     if (m_bClosed)
     139             :     {
     140             :         OGRLinearRing *poLR = new OGRLinearRing();
     141             :         poLR->addSubLineString(poLS, 0);
     142             :         delete poLS;
     143             : 
     144             :         // Wrap as polygon.
     145             :         OGRPolygon *poPoly = new OGRPolygon();
     146             :         poPoly->addRingDirectly(poLR);
     147             : 
     148             :         return poPoly;
     149             :     }
     150             : #endif
     151             : 
     152          70 :     return poLS;
     153             : }
     154             : 
     155             : /************************************************************************/
     156             : /*                DXFSmoothPolyline::EmitArc()                        */
     157             : /************************************************************************/
     158             : 
     159          12 : void DXFSmoothPolyline::EmitArc(const DXFSmoothPolylineVertex &start,
     160             :                                 const DXFSmoothPolylineVertex &end,
     161             :                                 double radius, double len, double bulge,
     162             :                                 OGRLineString *poLS, double dfZ) const
     163             : {
     164          12 :     assert(poLS);
     165             : 
     166          12 :     double ogrArcRotation = 0.0;
     167          12 :     const double ogrArcRadius = fabs(radius);
     168             : 
     169             :     /* -------------------------------------------------------------------- */
     170             :     /*      Set arc's direction and keep bulge positive                     */
     171             :     /* -------------------------------------------------------------------- */
     172             : 
     173          12 :     const bool bClockwise = (bulge < 0);
     174             : 
     175          12 :     if (bClockwise)
     176           6 :         bulge *= -1;
     177             : 
     178             :     /* -------------------------------------------------------------------- */
     179             :     /*      Get arc's center point                                          */
     180             :     /* -------------------------------------------------------------------- */
     181             : 
     182          12 :     const double saggita = fabs(bulge * (len / 2.0));
     183          12 :     const double apo =
     184          12 :         bClockwise ? -(ogrArcRadius - saggita) : -(saggita - ogrArcRadius);
     185             : 
     186          12 :     DXFSmoothPolylineVertex v;
     187          12 :     v.x = start.x - end.x;
     188          12 :     v.y = start.y - end.y;
     189             : 
     190             : #ifdef notdef
     191             :     const bool bMathissue = (v.x == 0.0 || v.y == 0.0);
     192             : #endif
     193             : 
     194          12 :     DXFSmoothPolylineVertex midpoint;
     195          12 :     midpoint.x = end.x + 0.5 * v.x;
     196          12 :     midpoint.y = end.y + 0.5 * v.y;
     197             : 
     198          12 :     DXFSmoothPolylineVertex pperp;
     199          12 :     pperp.x = v.y;
     200          12 :     pperp.y = -v.x;
     201          12 :     pperp.normalize();
     202             : 
     203          12 :     DXFSmoothPolylineVertex ogrArcCenter;
     204          12 :     ogrArcCenter.x = midpoint.x + (pperp.x * apo);
     205          12 :     ogrArcCenter.y = midpoint.y + (pperp.y * apo);
     206             : 
     207             :     /* -------------------------------------------------------------------- */
     208             :     /*      Get the line's general vertical direction (-1 = down, +1 = up)  */
     209             :     /* -------------------------------------------------------------------- */
     210             : 
     211          12 :     const double linedir = end.y > start.y ? 1.0 : -1.0;
     212             : 
     213             :     /* -------------------------------------------------------------------- */
     214             :     /*      Get arc's starting angle.                                       */
     215             :     /* -------------------------------------------------------------------- */
     216             : 
     217          12 :     double a = GetAngle(ogrArcCenter, start);
     218             : 
     219          12 :     if (bClockwise && (linedir == 1.0))
     220           3 :         a += (linedir * 180.0);
     221             : 
     222          12 :     double ogrArcStartAngle = GetOGRangle(a);
     223             : 
     224             :     /* -------------------------------------------------------------------- */
     225             :     /*      Get arc's ending angle.                                         */
     226             :     /* -------------------------------------------------------------------- */
     227             : 
     228          12 :     a = GetAngle(ogrArcCenter, end);
     229             : 
     230          12 :     if (bClockwise && (linedir == 1.0))
     231           3 :         a += (linedir * 180.0);
     232             : 
     233          12 :     double ogrArcEndAngle = GetOGRangle(a);
     234             : 
     235          12 :     if (!bClockwise && (ogrArcStartAngle < ogrArcEndAngle))
     236           2 :         ogrArcEndAngle = -180.0 + (linedir * a);
     237             : 
     238          12 :     if (bClockwise && (ogrArcStartAngle > ogrArcEndAngle))
     239           0 :         ogrArcEndAngle += 360.0;
     240             : 
     241             :     /* -------------------------------------------------------------------- */
     242             :     /*      Flip arc's rotation if necessary.                               */
     243             :     /* -------------------------------------------------------------------- */
     244             : 
     245          12 :     if (bClockwise && (linedir == 1.0))
     246           3 :         ogrArcRotation = linedir * 180.0;
     247             : 
     248             :     /* -------------------------------------------------------------------- */
     249             :     /*      Tessellate the arc segment and append to the linestring.        */
     250             :     /* -------------------------------------------------------------------- */
     251             : 
     252          12 :     if (fabs(ogrArcEndAngle - ogrArcStartAngle) <= 361.0)
     253             :     {
     254             :         OGRLineString *poArcpoLS =
     255             :             OGRGeometryFactory::approximateArcAngles(
     256             :                 ogrArcCenter.x, ogrArcCenter.y, dfZ, ogrArcRadius, ogrArcRadius,
     257             :                 ogrArcRotation, ogrArcStartAngle, ogrArcEndAngle, 0.0,
     258          12 :                 m_bUseMaxGapWhenTessellatingArcs)
     259          12 :                 ->toLineString();
     260             : 
     261          12 :         poLS->addSubLineString(poArcpoLS);
     262             : 
     263          12 :         delete poArcpoLS;
     264             :     }
     265             :     else
     266             :     {
     267             :         // TODO: emit error ?
     268             :     }
     269          12 : }
     270             : 
     271             : /************************************************************************/
     272             : /*                   DXFSmoothPolyline::EmitLine()                      */
     273             : /************************************************************************/
     274             : 
     275         200 : void DXFSmoothPolyline::EmitLine(const DXFSmoothPolylineVertex &start,
     276             :                                  const DXFSmoothPolylineVertex &end,
     277             :                                  OGRLineString *poLS) const
     278             : {
     279         200 :     assert(poLS);
     280             : 
     281         200 :     if (!m_blinestringstarted)
     282             :     {
     283          70 :         poLS->addPoint(start.x, start.y, start.z);
     284          70 :         m_blinestringstarted = true;
     285             :     }
     286             : 
     287         200 :     poLS->addPoint(end.x, end.y, end.z);
     288         200 : }
     289             : 
     290             : /************************************************************************/
     291             : /*                DXFSmoothPolyline::Close()                            */
     292             : /************************************************************************/
     293             : 
     294          41 : void DXFSmoothPolyline::Close()
     295             : {
     296          41 :     assert(!m_bClosed);
     297             : 
     298          41 :     if (m_vertices.size() >= 2)
     299             :     {
     300             :         const bool bVisuallyClosed =
     301          41 :             (m_vertices.back().shares_2D_pos(m_vertices[0]));
     302             : 
     303          41 :         if (!bVisuallyClosed)
     304             :         {
     305          33 :             m_vertices.push_back(m_vertices[0]);
     306             :         }
     307          41 :         m_bClosed = true;
     308             :     }
     309          41 : }

Generated by: LCOV version 1.14