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