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 : }
|