LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/dxf - ogrdxf_feature.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 112 124 90.3 %
Date: 2024-05-04 12:52:34 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  DXF Translator
       4             :  * Purpose:  Provides additional functionality for DXF features
       5             :  * Author:   Alan Thomas, alant@outlook.com.au
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2017, Alan Thomas <alant@outlook.com.au>
       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_dxf.h"
      30             : #include "cpl_string.h"
      31             : 
      32             : /************************************************************************/
      33             : /*                            OGRDXFFeature()                           */
      34             : /************************************************************************/
      35             : 
      36        3325 : OGRDXFFeature::OGRDXFFeature(OGRFeatureDefn *poFeatureDefn)
      37             :     : OGRFeature(poFeatureDefn), oOCS(0.0, 0.0, 1.0), bIsBlockReference(false),
      38             :       dfBlockAngle(0.0), oBlockScale(1.0, 1.0, 1.0),
      39        3325 :       oOriginalCoords(0.0, 0.0, 0.0)
      40             : {
      41        3325 : }
      42             : 
      43             : /************************************************************************/
      44             : /*                          CloneDXFFeature()                           */
      45             : /*                                                                      */
      46             : /*      Replacement for OGRFeature::Clone() for DXF features.           */
      47             : /************************************************************************/
      48             : 
      49        2612 : OGRDXFFeature *OGRDXFFeature::CloneDXFFeature()
      50             : {
      51        2612 :     OGRDXFFeature *poNew = new OGRDXFFeature(GetDefnRef());
      52        2612 :     if (poNew == nullptr)
      53           0 :         return nullptr;
      54             : 
      55        2612 :     if (!CopySelfTo(poNew))
      56             :     {
      57           0 :         delete poNew;
      58           0 :         return nullptr;
      59             :     }
      60             : 
      61        2612 :     poNew->oOCS = oOCS;
      62        2612 :     poNew->bIsBlockReference = bIsBlockReference;
      63        2612 :     poNew->osBlockName = osBlockName;
      64        2612 :     poNew->dfBlockAngle = dfBlockAngle;
      65        2612 :     poNew->oBlockScale = oBlockScale;
      66        2612 :     poNew->oOriginalCoords = oOriginalCoords;
      67        2612 :     poNew->osAttributeTag = osAttributeTag;
      68        2612 :     poNew->oStyleProperties = oStyleProperties;
      69             : 
      70        2612 :     if (poASMTransform)
      71             :     {
      72           2 :         poNew->poASMTransform = std::unique_ptr<OGRDXFAffineTransform>(
      73           2 :             new OGRDXFAffineTransform(*poASMTransform));
      74             :     }
      75             : 
      76           2 :     for (const std::unique_ptr<OGRDXFFeature> &poAttribFeature :
      77        2614 :          apoAttribFeatures)
      78             :     {
      79             :         poNew->apoAttribFeatures.emplace_back(
      80           2 :             poAttribFeature->CloneDXFFeature());
      81             :     }
      82             : 
      83        2612 :     return poNew;
      84             : }
      85             : 
      86             : /************************************************************************/
      87             : /*                        ApplyOCSTransformer()                         */
      88             : /*                                                                      */
      89             : /*      Applies the OCS transformation stored in this feature to        */
      90             : /*      the specified geometry.                                         */
      91             : /************************************************************************/
      92             : 
      93        1878 : void OGRDXFFeature::ApplyOCSTransformer(OGRGeometry *const poGeometry) const
      94             : {
      95        1878 :     if (poGeometry == nullptr)
      96           0 :         return;
      97             : 
      98             :     double adfN[3];
      99        1878 :     oOCS.ToArray(adfN);
     100             : 
     101        3756 :     OGRDXFOCSTransformer oTransformer(adfN);
     102             : 
     103             :     // Promote to 3D, in case the OCS transformation introduces a
     104             :     // third dimension to the geometry.
     105        1878 :     const bool bInitially2D = !poGeometry->Is3D();
     106        1878 :     if (bInitially2D)
     107         185 :         poGeometry->set3D(TRUE);
     108             : 
     109        1878 :     poGeometry->transform(&oTransformer);
     110             : 
     111             :     // If the geometry was 2D to begin with, and is still 2D after the
     112             :     // OCS transformation, flatten it back to 2D.
     113        1878 :     if (bInitially2D)
     114             :     {
     115         185 :         OGREnvelope3D oEnvelope;
     116         185 :         poGeometry->getEnvelope(&oEnvelope);
     117         185 :         if (oEnvelope.MaxZ == 0.0 && oEnvelope.MinZ == 0.0)
     118         168 :             poGeometry->flattenTo2D();
     119             :     }
     120             : }
     121             : 
     122             : /************************************************************************/
     123             : /*                        ApplyOCSTransformer()                         */
     124             : /************************************************************************/
     125             : 
     126           3 : void OGRDXFFeature::ApplyOCSTransformer(OGRDXFAffineTransform *const poCT) const
     127             : {
     128           3 :     if (!poCT)
     129           0 :         return;
     130             : 
     131             :     double adfN[3];
     132           3 :     oOCS.ToArray(adfN);
     133             : 
     134           6 :     OGRDXFOCSTransformer oTransformer(adfN);
     135             : 
     136           3 :     oTransformer.ComposeOnto(*poCT);
     137             : }
     138             : 
     139             : /************************************************************************/
     140             : /*                              GetColor()                              */
     141             : /*                                                                      */
     142             : /*      Gets the hex color string for this feature, using the given     */
     143             : /*      data source to fetch layer properties.                          */
     144             : /*                                                                      */
     145             : /*      For usage info about poBlockFeature, see                        */
     146             : /*      OGRDXFLayer::PrepareFeatureStyle.                               */
     147             : /************************************************************************/
     148             : 
     149             : const CPLString
     150        1234 : OGRDXFFeature::GetColor(OGRDXFDataSource *const poDS,
     151             :                         OGRDXFFeature *const poBlockFeature /* = NULL */)
     152             : {
     153        2468 :     CPLString osLayer = GetFieldAsString("Layer");
     154             : 
     155             :     /* -------------------------------------------------------------------- */
     156             :     /*      Is the layer or object hidden/off (1) or frozen (2)?            */
     157             :     /* -------------------------------------------------------------------- */
     158             : 
     159        1234 :     int iHidden = 0;
     160             : 
     161        2944 :     if (oStyleProperties.count("Hidden") > 0 ||
     162         952 :         (poBlockFeature &&
     163        1710 :          poBlockFeature->oStyleProperties.count("Hidden") > 0))
     164             :     {
     165             :         // Hidden objects should never be shown no matter what happens,
     166             :         // so they can be treated as if they are on a frozen layer
     167          97 :         iHidden = 2;
     168             :     }
     169             :     else
     170             :     {
     171        1137 :         const char *pszHidden = poDS->LookupLayerProperty(osLayer, "Hidden");
     172        1137 :         if (pszHidden)
     173        1137 :             iHidden = atoi(pszHidden);
     174             : 
     175             :         // Is the block feature on a frozen layer? If so, hide this feature
     176        1137 :         if (!iHidden && poBlockFeature)
     177             :         {
     178             :             const CPLString osBlockLayer =
     179         840 :                 poBlockFeature->GetFieldAsString("Layer");
     180             :             const char *pszBlockHidden =
     181         420 :                 poDS->LookupLayerProperty(osBlockLayer, "Hidden");
     182         420 :             if (pszBlockHidden && atoi(pszBlockHidden) == 2)
     183          16 :                 iHidden = 2;
     184             :         }
     185             :     }
     186             : 
     187             :     // If this feature is on a frozen layer, make the object totally
     188             :     // hidden so it won't reappear if we regenerate the style string again
     189             :     // during block insertion
     190        1234 :     if (iHidden == 2)
     191         129 :         oStyleProperties["Hidden"] = "1";
     192             : 
     193             :     // Helpful constants
     194        1234 :     const int C_BYLAYER = 256;
     195        1234 :     const int C_BYBLOCK = 0;
     196        1234 :     const int C_TRUECOLOR = -100;  // not used in DXF - for our purposes only
     197             : 
     198             :     /* -------------------------------------------------------------------- */
     199             :     /*      MULTILEADER entities store colors by directly outputting        */
     200             :     /*      the AcCmEntityColor struct as a 32-bit integer.                 */
     201             :     /* -------------------------------------------------------------------- */
     202             : 
     203        1234 :     int nColor = C_BYLAYER;
     204        1234 :     unsigned int nTrueColor = 0;
     205             : 
     206        1234 :     if (oStyleProperties.count("TrueColor") > 0)
     207             :     {
     208          11 :         nTrueColor = atoi(oStyleProperties["TrueColor"]);
     209          11 :         nColor = C_TRUECOLOR;
     210             :     }
     211        1223 :     else if (oStyleProperties.count("Color") > 0)
     212             :     {
     213         754 :         nColor = atoi(oStyleProperties["Color"]);
     214             :     }
     215             : 
     216        1234 :     const unsigned char byColorMethod = (nColor & 0xFF000000) >> 24;
     217        1234 :     switch (byColorMethod)
     218             :     {
     219             :         // ByLayer
     220           0 :         case 0xC0:
     221           0 :             nColor = C_BYLAYER;
     222           0 :             break;
     223             : 
     224             :         // ByBlock
     225          16 :         case 0xC1:
     226          16 :             nColor = C_BYBLOCK;
     227          16 :             break;
     228             : 
     229             :         // RGB true color
     230           0 :         case 0xC2:
     231           0 :             nTrueColor = nColor & 0xFFFFFF;
     232           0 :             nColor = C_TRUECOLOR;
     233           0 :             break;
     234             : 
     235             :         // Indexed color
     236           2 :         case 0xC3:
     237           2 :             nColor &= 0xFF;
     238           2 :             break;
     239             :     }
     240             : 
     241             :     /* -------------------------------------------------------------------- */
     242             :     /*      Work out the indexed color for this feature.                    */
     243             :     /* -------------------------------------------------------------------- */
     244             : 
     245             :     // Use ByBlock color?
     246        1234 :     if (nColor == C_BYBLOCK && poBlockFeature)
     247             :     {
     248         199 :         if (poBlockFeature->oStyleProperties.count("TrueColor") > 0)
     249             :         {
     250             :             // Inherit true color from the owning block
     251           3 :             nTrueColor = atoi(poBlockFeature->oStyleProperties["TrueColor"]);
     252           3 :             nColor = C_TRUECOLOR;
     253             : 
     254             :             // Use the inherited color if we regenerate the style string
     255             :             // again during block insertion
     256           6 :             oStyleProperties["TrueColor"] =
     257           9 :                 poBlockFeature->oStyleProperties["TrueColor"];
     258             :         }
     259         196 :         else if (poBlockFeature->oStyleProperties.count("Color") > 0)
     260             :         {
     261             :             // Inherit color from the owning block
     262         150 :             nColor = atoi(poBlockFeature->oStyleProperties["Color"]);
     263             : 
     264             :             // Use the inherited color if we regenerate the style string
     265             :             // again during block insertion
     266         300 :             oStyleProperties["Color"] =
     267         450 :                 poBlockFeature->oStyleProperties["Color"];
     268             :         }
     269             :         else
     270             :         {
     271             :             // If the owning block has no explicit color, assume ByLayer
     272          46 :             nColor = C_BYLAYER;
     273             :         }
     274             :     }
     275             : 
     276             :     // Use layer color?
     277        1234 :     if (nColor == C_BYLAYER)
     278             :     {
     279         718 :         if (poBlockFeature)
     280             :         {
     281             :             // Use the block feature's layer instead
     282         173 :             osLayer = poBlockFeature->GetFieldAsString("Layer");
     283             :         }
     284             : 
     285             :         const char *pszTrueColor =
     286         718 :             poDS->LookupLayerProperty(osLayer, "TrueColor");
     287         718 :         if (pszTrueColor != nullptr && *pszTrueColor)
     288             :         {
     289           1 :             nTrueColor = atoi(pszTrueColor);
     290           1 :             nColor = C_TRUECOLOR;
     291             : 
     292           1 :             if (poBlockFeature)
     293             :             {
     294             :                 // Use the inherited color if we regenerate the style string
     295             :                 // again during block insertion
     296           1 :                 oStyleProperties["TrueColor"] = pszTrueColor;
     297             :             }
     298             :         }
     299             :         else
     300             :         {
     301         717 :             const char *pszColor = poDS->LookupLayerProperty(osLayer, "Color");
     302         717 :             if (pszColor != nullptr)
     303             :             {
     304         717 :                 nColor = atoi(pszColor);
     305             : 
     306         717 :                 if (poBlockFeature)
     307             :                 {
     308             :                     // Use the inherited color if we regenerate the style string
     309             :                     // again during block insertion
     310         172 :                     oStyleProperties["Color"] = pszColor;
     311             :                 }
     312             :             }
     313             :         }
     314             :     }
     315             : 
     316             :     // If no color is available, use the default black/white color
     317        1234 :     if (nColor != C_TRUECOLOR && (nColor < 1 || nColor > 255))
     318         227 :         nColor = 7;
     319             : 
     320             :     /* -------------------------------------------------------------------- */
     321             :     /*      Translate the DWG/DXF color index to a hex color string.        */
     322             :     /* -------------------------------------------------------------------- */
     323             : 
     324        1234 :     CPLString osResult;
     325             : 
     326        1234 :     if (nColor == C_TRUECOLOR)
     327             :     {
     328          15 :         osResult.Printf("#%06x", nTrueColor);
     329             :     }
     330             :     else
     331             :     {
     332        1219 :         const unsigned char *pabyDXFColors = ACGetColorTable();
     333             : 
     334        1219 :         osResult.Printf("#%02x%02x%02x", pabyDXFColors[nColor * 3 + 0],
     335        1219 :                         pabyDXFColors[nColor * 3 + 1],
     336        1219 :                         pabyDXFColors[nColor * 3 + 2]);
     337             :     }
     338             : 
     339        1234 :     if (iHidden)
     340         177 :         osResult += "00";
     341             : 
     342        2468 :     return osResult;
     343             : }

Generated by: LCOV version 1.14