Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: DXF Translator
4 : * Purpose: Definition of classes for OGR .dxf driver.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2009, Frank Warmerdam
9 : * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
10 : * Copyright (c) 2017, Alan Thomas <alant@outlook.com.au>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #ifndef OGR_DXF_H_INCLUDED
16 : #define OGR_DXF_H_INCLUDED
17 :
18 : #include "ogrsf_frmts.h"
19 : #include "ogr_autocad_services.h"
20 : #include "cpl_conv.h"
21 : #include <array>
22 : #include <vector>
23 : #include <map>
24 : #include <optional>
25 : #include <set>
26 : #include <queue>
27 : #include <memory>
28 : #include <utility>
29 :
30 : class OGRDXFDataSource;
31 : class OGRDXFFeature;
32 :
33 : constexpr std::array<char, 22> AUTOCAD_BINARY_DXF_SIGNATURE = {
34 : 'A', 'u', 't', 'o', 'C', 'A', 'D', ' ', 'B', 'i', 'n',
35 : 'a', 'r', 'y', ' ', 'D', 'X', 'F', '\r', '\n', '\x1A', '\x00'};
36 :
37 : /************************************************************************/
38 : /* DXFBlockDefinition */
39 : /* */
40 : /* Container for info about a block. */
41 : /************************************************************************/
42 :
43 : class DXFBlockDefinition
44 : {
45 : public:
46 87 : DXFBlockDefinition()
47 87 : {
48 87 : }
49 :
50 : ~DXFBlockDefinition();
51 :
52 : std::vector<OGRDXFFeature *> apoFeatures;
53 : };
54 :
55 : /************************************************************************/
56 : /* OGRDXFFeatureQueue */
57 : /************************************************************************/
58 :
59 : class OGRDXFFeatureQueue
60 : {
61 : std::queue<OGRDXFFeature *> apoFeatures;
62 :
63 : public:
64 745 : OGRDXFFeatureQueue()
65 745 : {
66 745 : }
67 :
68 : void push(OGRDXFFeature *poFeature);
69 :
70 4383 : OGRDXFFeature *front() const
71 : {
72 4383 : return apoFeatures.front();
73 : }
74 :
75 : void pop();
76 :
77 10063 : bool empty() const
78 : {
79 10063 : return apoFeatures.empty();
80 : }
81 :
82 : size_t size() const
83 : {
84 : return apoFeatures.size();
85 : }
86 : };
87 :
88 : /************************************************************************/
89 : /* OGRDXFBlocksLayer */
90 : /************************************************************************/
91 :
92 : class OGRDXFBlocksLayer final : public OGRLayer
93 : {
94 : OGRDXFDataSource *poDS;
95 :
96 : OGRFeatureDefn *poFeatureDefn;
97 :
98 : GIntBig iNextFID;
99 :
100 : std::map<CPLString, DXFBlockDefinition>::iterator oIt;
101 : CPLString osBlockName;
102 :
103 : OGRDXFFeatureQueue apoPendingFeatures;
104 :
105 : public:
106 : explicit OGRDXFBlocksLayer(OGRDXFDataSource *poDS);
107 : ~OGRDXFBlocksLayer() override;
108 :
109 : void ResetReading() override;
110 : OGRFeature *GetNextFeature() override;
111 :
112 17 : const OGRFeatureDefn *GetLayerDefn() const override
113 : {
114 17 : return poFeatureDefn;
115 : }
116 :
117 : int TestCapability(const char *) const override;
118 :
119 : OGRDXFFeature *GetNextUnfilteredFeature();
120 : };
121 :
122 : /************************************************************************/
123 : /* OGRDXFInsertTransformer */
124 : /* */
125 : /* Stores the transformation needed to insert a block reference. */
126 : /************************************************************************/
127 :
128 : class OGRDXFInsertTransformer final : public OGRCoordinateTransformation
129 : {
130 : public:
131 441 : OGRDXFInsertTransformer() = default;
132 :
133 : double dfXOffset = 0.0;
134 : double dfYOffset = 0.0;
135 : double dfZOffset = 0.0;
136 : double dfXScale = 1.0;
137 : double dfYScale = 1.0;
138 : double dfZScale = 1.0;
139 : double dfAngle = 0.0;
140 :
141 2429 : OGRDXFInsertTransformer GetOffsetTransformer()
142 : {
143 2429 : OGRDXFInsertTransformer oResult;
144 2429 : oResult.dfXOffset = this->dfXOffset;
145 2429 : oResult.dfYOffset = this->dfYOffset;
146 2429 : oResult.dfZOffset = this->dfZOffset;
147 2429 : return oResult;
148 : }
149 :
150 2429 : OGRDXFInsertTransformer GetRotateScaleTransformer()
151 : {
152 2429 : OGRDXFInsertTransformer oResult;
153 2429 : oResult.dfXScale = this->dfXScale;
154 2429 : oResult.dfYScale = this->dfYScale;
155 2429 : oResult.dfZScale = this->dfZScale;
156 2429 : oResult.dfAngle = this->dfAngle;
157 2429 : return oResult;
158 : }
159 :
160 : OGRCoordinateTransformation *Clone() const override;
161 :
162 0 : const OGRSpatialReference *GetSourceCS() const override
163 : {
164 0 : return nullptr;
165 : }
166 :
167 6962 : const OGRSpatialReference *GetTargetCS() const override
168 : {
169 6962 : return nullptr;
170 : }
171 :
172 6815 : int Transform(size_t nCount, double *x, double *y, double *z,
173 : double * /* t */, int *pabSuccess) override
174 : {
175 29723 : for (size_t i = 0; i < nCount; i++)
176 : {
177 22908 : x[i] *= dfXScale;
178 22908 : y[i] *= dfYScale;
179 22908 : if (z)
180 22908 : z[i] *= dfZScale;
181 :
182 22908 : const double dfXNew = x[i] * cos(dfAngle) - y[i] * sin(dfAngle);
183 22908 : const double dfYNew = x[i] * sin(dfAngle) + y[i] * cos(dfAngle);
184 :
185 22908 : x[i] = dfXNew;
186 22908 : y[i] = dfYNew;
187 :
188 22908 : x[i] += dfXOffset;
189 22908 : y[i] += dfYOffset;
190 22908 : if (z)
191 22908 : z[i] += dfZOffset;
192 :
193 22908 : if (pabSuccess)
194 22908 : pabSuccess[i] = TRUE;
195 : }
196 6815 : return TRUE;
197 : }
198 :
199 0 : OGRCoordinateTransformation *GetInverse() const override
200 : {
201 0 : return nullptr;
202 : }
203 : };
204 :
205 : /************************************************************************/
206 : /* OGRDXFAffineTransform */
207 : /* */
208 : /* A simple 3D affine transform used to keep track of the */
209 : /* transformation to be applied to an ASM entity. */
210 : /************************************************************************/
211 :
212 : class OGRDXFAffineTransform
213 : {
214 : public:
215 2 : OGRDXFAffineTransform()
216 2 : : adfData{1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0}
217 : {
218 2 : }
219 :
220 : double adfData[12]; // Column-major: adfMatrix[5] is column 2, row 3
221 :
222 : // Last 3 elements are translation
223 :
224 : // Left composition (composes oOther o this), modifying this
225 6 : void ComposeWith(const OGRDXFInsertTransformer &oCT)
226 : {
227 : double adfNew[12];
228 :
229 6 : adfNew[0] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[0] -
230 6 : oCT.dfYScale * sin(oCT.dfAngle) * adfData[1];
231 6 : adfNew[1] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[0] +
232 6 : oCT.dfYScale * cos(oCT.dfAngle) * adfData[1];
233 6 : adfNew[2] = oCT.dfZScale * adfData[2];
234 :
235 6 : adfNew[3] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[3] -
236 6 : oCT.dfYScale * sin(oCT.dfAngle) * adfData[4];
237 6 : adfNew[4] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[3] +
238 6 : oCT.dfYScale * cos(oCT.dfAngle) * adfData[4];
239 6 : adfNew[5] = oCT.dfZScale * adfData[5];
240 :
241 6 : adfNew[6] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[6] -
242 6 : oCT.dfYScale * sin(oCT.dfAngle) * adfData[7];
243 6 : adfNew[7] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[6] +
244 6 : oCT.dfYScale * cos(oCT.dfAngle) * adfData[7];
245 6 : adfNew[8] = oCT.dfZScale * adfData[8];
246 :
247 6 : adfNew[9] = oCT.dfXScale * cos(oCT.dfAngle) * adfData[9] -
248 6 : oCT.dfYScale * sin(oCT.dfAngle) * adfData[10] +
249 6 : oCT.dfXOffset;
250 6 : adfNew[10] = oCT.dfXScale * sin(oCT.dfAngle) * adfData[9] +
251 6 : oCT.dfYScale * cos(oCT.dfAngle) * adfData[10] +
252 6 : oCT.dfYOffset;
253 6 : adfNew[11] = oCT.dfZScale * adfData[11] + oCT.dfZOffset;
254 :
255 6 : memcpy(adfData, adfNew, sizeof(adfNew));
256 6 : }
257 :
258 5 : void SetField(OGRFeature *poFeature, const char *pszFieldName) const
259 : {
260 5 : poFeature->SetField(pszFieldName, 12, adfData);
261 5 : }
262 : };
263 :
264 : /************************************************************************/
265 : /* OGRDXFOCSTransformer */
266 : /************************************************************************/
267 :
268 : class OGRDXFOCSTransformer final : public OGRCoordinateTransformation
269 : {
270 : private:
271 : double adfN[3];
272 : double adfAX[3];
273 : double adfAY[3];
274 :
275 : double dfDeterminant;
276 : double aadfInverse[4][4];
277 :
278 : public:
279 : explicit OGRDXFOCSTransformer(double adfNIn[3], bool bInverse = false);
280 :
281 0 : const OGRSpatialReference *GetSourceCS() const override
282 : {
283 0 : return nullptr;
284 : }
285 :
286 3994 : const OGRSpatialReference *GetTargetCS() const override
287 : {
288 3994 : return nullptr;
289 : }
290 :
291 : int Transform(size_t nCount, double *adfX, double *adfY, double *adfZ,
292 : double *adfT, int *pabSuccess) override;
293 :
294 : int InverseTransform(size_t nCount, double *adfX, double *adfY,
295 : double *adfZ);
296 :
297 : void ComposeOnto(OGRDXFAffineTransform &poCT) const;
298 :
299 0 : OGRCoordinateTransformation *Clone() const override
300 : {
301 0 : return new OGRDXFOCSTransformer(*this);
302 : }
303 :
304 0 : OGRCoordinateTransformation *GetInverse() const override
305 : {
306 0 : return nullptr;
307 : }
308 : };
309 :
310 : /************************************************************************/
311 : /* DXFTriple */
312 : /* */
313 : /* Represents a triple (X, Y, Z) used for various purposes in */
314 : /* DXF files. We do not use OGRPoint for this purpose, as the */
315 : /* triple does not always represent a point as such (for */
316 : /* example, it could contain a scale factor for each dimension). */
317 : /************************************************************************/
318 : struct DXFTriple
319 : {
320 : double dfX, dfY, dfZ;
321 :
322 27 : DXFTriple() : dfX(0.0), dfY(0.0), dfZ(0.0)
323 : {
324 27 : }
325 :
326 16151 : DXFTriple(double x, double y, double z) : dfX(x), dfY(y), dfZ(z)
327 : {
328 16151 : }
329 :
330 3842 : void ToArray(double adfOut[3]) const
331 : {
332 3842 : adfOut[0] = dfX;
333 3842 : adfOut[1] = dfY;
334 3842 : adfOut[2] = dfZ;
335 3842 : }
336 :
337 18 : DXFTriple &operator*=(const double dfValue)
338 : {
339 18 : dfX *= dfValue;
340 18 : dfY *= dfValue;
341 18 : dfZ *= dfValue;
342 18 : return *this;
343 : }
344 :
345 2 : DXFTriple &operator/=(const double dfValue)
346 : {
347 2 : dfX /= dfValue;
348 2 : dfY /= dfValue;
349 2 : dfZ /= dfValue;
350 2 : return *this;
351 : }
352 :
353 : bool operator==(const DXFTriple &oOther) const
354 : {
355 : return dfX == oOther.dfX && dfY == oOther.dfY && dfZ == oOther.dfZ;
356 : }
357 : };
358 :
359 : /************************************************************************/
360 : /* OGRDXFFeature */
361 : /* */
362 : /* Extends OGRFeature with some DXF-specific members. */
363 : /************************************************************************/
364 9088 : class OGRDXFFeature final : public OGRFeature
365 : {
366 : friend class OGRDXFLayer;
367 :
368 : protected:
369 : // The feature's Object Coordinate System (OCS) unit normal vector
370 : DXFTriple oOCS;
371 :
372 : // A list of properties that are used to construct the style string
373 : std::map<CPLString, CPLString> oStyleProperties;
374 :
375 : // Additional data for INSERT entities
376 : bool bIsBlockReference;
377 : CPLString osBlockName;
378 : double dfBlockAngle;
379 : DXFTriple oBlockScale;
380 :
381 : // Used for INSERT entities when DXF_INLINE_BLOCKS is false, to store
382 : // the OCS insertion point
383 : DXFTriple oOriginalCoords;
384 :
385 : // Used in 3D mode to store transformation parameters for ASM entities
386 : std::unique_ptr<OGRDXFAffineTransform> poASMTransform;
387 :
388 : // Additional data for ATTRIB and ATTDEF entities
389 : CPLString osAttributeTag;
390 :
391 : // Store ATTRIB entities associated with an INSERT, for use when
392 : // DXF_INLINE_BLOCKS is true and a block with attributes is INSERTed
393 : // in another block
394 : std::vector<std::unique_ptr<OGRDXFFeature>> apoAttribFeatures;
395 :
396 : public:
397 : explicit OGRDXFFeature(const OGRFeatureDefn *poFeatureDefn);
398 : ~OGRDXFFeature() override;
399 :
400 : OGRDXFFeature *CloneDXFFeature();
401 :
402 : DXFTriple GetOCS() const
403 : {
404 : return oOCS;
405 : }
406 :
407 3786 : bool IsBlockReference() const
408 : {
409 3786 : return bIsBlockReference;
410 : }
411 :
412 : CPLString GetBlockName() const
413 : {
414 : return osBlockName;
415 : }
416 :
417 : double GetBlockAngle() const
418 : {
419 : return dfBlockAngle;
420 : }
421 :
422 : DXFTriple GetBlockScale() const
423 : {
424 : return oBlockScale;
425 : }
426 :
427 806 : DXFTriple GetInsertOCSCoords() const
428 : {
429 806 : return oOriginalCoords;
430 : }
431 :
432 45 : CPLString GetAttributeTag() const
433 : {
434 45 : return osAttributeTag;
435 : }
436 :
437 : const std::vector<std::unique_ptr<OGRDXFFeature>> &GetAttribFeatures() const
438 : {
439 : return apoAttribFeatures;
440 : }
441 :
442 806 : void SetInsertOCSCoords(const DXFTriple &oTriple)
443 : {
444 806 : oOriginalCoords = oTriple;
445 806 : }
446 :
447 : void ApplyOCSTransformer(OGRGeometry *const poGeometry) const;
448 : void ApplyOCSTransformer(OGRDXFAffineTransform *const poCT) const;
449 : const CPLString GetColor(OGRDXFDataSource *const poDS,
450 : OGRDXFFeature *const poBlockFeature = nullptr);
451 : };
452 :
453 : /************************************************************************/
454 : /* OGRDXFLayer */
455 : /************************************************************************/
456 : class OGRDXFLayer final : public OGRLayer
457 : {
458 : friend class OGRDXFBlocksLayer;
459 :
460 : OGRDXFDataSource *poDS;
461 :
462 : OGRFeatureDefn *poFeatureDefn;
463 : GIntBig iNextFID;
464 :
465 : std::set<CPLString> oIgnoredEntities;
466 :
467 : OGRDXFFeatureQueue apoPendingFeatures;
468 :
469 : struct InsertState
470 : {
471 : OGRDXFInsertTransformer m_oTransformer{};
472 : CPLString m_osBlockName{};
473 : CPLStringList m_aosAttribs{};
474 : int m_nColumnCount = 0;
475 : int m_nRowCount = 0;
476 : int m_iCurCol = 0;
477 : int m_iCurRow = 0;
478 : double m_dfColumnSpacing = 0.0;
479 : double m_dfRowSpacing = 0.0;
480 : std::vector<std::unique_ptr<OGRDXFFeature>> m_apoAttribs{};
481 : std::unique_ptr<OGRDXFFeature> m_poTemplateFeature{};
482 : };
483 :
484 : InsertState m_oInsertState{};
485 :
486 : void ClearPendingFeatures();
487 :
488 : void TranslateGenericProperty(OGRDXFFeature *poFeature, int nCode,
489 : char *pszValue);
490 :
491 : void PrepareFeatureStyle(OGRDXFFeature *const poFeature,
492 : OGRDXFFeature *const poBlockFeature = nullptr);
493 : void PrepareBrushStyle(OGRDXFFeature *const poFeature,
494 : OGRDXFFeature *const poBlockFeature = nullptr);
495 : void PrepareLineStyle(OGRDXFFeature *const poFeature,
496 : OGRDXFFeature *const poBlockFeature = nullptr);
497 :
498 : OGRDXFFeature *TranslatePOINT();
499 : OGRDXFFeature *TranslateLINE();
500 : OGRDXFFeature *TranslatePOLYLINE();
501 : OGRDXFFeature *TranslateLWPOLYLINE();
502 : OGRDXFFeature *TranslateMLINE();
503 : OGRDXFFeature *TranslateCIRCLE();
504 : OGRDXFFeature *TranslateELLIPSE();
505 : OGRDXFFeature *TranslateARC();
506 : OGRDXFFeature *TranslateSPLINE();
507 : OGRDXFFeature *Translate3DFACE();
508 : bool TranslateINSERT();
509 : OGRDXFFeature *TranslateMTEXT();
510 : OGRDXFFeature *TranslateTEXT(const bool bIsAttribOrAttdef);
511 : OGRDXFFeature *TranslateDIMENSION();
512 : OGRDXFFeature *TranslateHATCH();
513 : OGRDXFFeature *TranslateSOLID();
514 : OGRDXFFeature *TranslateLEADER();
515 : OGRDXFFeature *TranslateMLEADER();
516 : OGRDXFFeature *TranslateWIPEOUT();
517 : OGRDXFFeature *TranslateASMEntity();
518 :
519 : static constexpr int FORTRAN_INDEXING = 1;
520 :
521 : bool GenerateINSERTFeatures();
522 : std::unique_ptr<OGRLineString>
523 : InsertSplineWithChecks(const int nDegree,
524 : std::vector<double> &adfControlPoints, bool bHasZ,
525 : int nControlPoints, std::vector<double> &adfKnots,
526 : int nKnots, std::vector<double> &adfWeights);
527 : static OGRGeometry *SimplifyBlockGeometry(OGRGeometryCollection *);
528 : OGRDXFFeature *InsertBlockInline(GUInt32 nInitialErrorCounter,
529 : const CPLString &osBlockName,
530 : OGRDXFInsertTransformer oTransformer,
531 : OGRDXFFeature *const poFeature,
532 : OGRDXFFeatureQueue &apoExtraFeatures,
533 : const bool bInlineNestedBlocks,
534 : const bool bMergeGeometry);
535 : static OGRDXFFeature *
536 : InsertBlockReference(const CPLString &osBlockName,
537 : const OGRDXFInsertTransformer &oTransformer,
538 : OGRDXFFeature *const poFeature);
539 : static void FormatDimension(CPLString &osText, const double dfValue,
540 : int nPrecision);
541 : void InsertArrowhead(OGRDXFFeature *const poFeature,
542 : const CPLString &osBlockName,
543 : OGRLineString *const poLine,
544 : const double dfArrowheadSize,
545 : const bool bReverse = false);
546 : OGRErr CollectBoundaryPath(OGRGeometryCollection *poGC,
547 : const double dfElevation);
548 : OGRErr CollectPolylinePath(OGRGeometryCollection *poGC,
549 : const double dfElevation);
550 :
551 : CPLString TextRecode(const char *);
552 : CPLString TextUnescape(const char *, bool);
553 :
554 : public:
555 : explicit OGRDXFLayer(OGRDXFDataSource *poDS);
556 : ~OGRDXFLayer() override;
557 :
558 : void ResetReading() override;
559 : OGRFeature *GetNextFeature() override;
560 :
561 406 : const OGRFeatureDefn *GetLayerDefn() const override
562 : {
563 406 : return poFeatureDefn;
564 : }
565 :
566 : int TestCapability(const char *) const override;
567 :
568 : GDALDataset *GetDataset() override;
569 :
570 : OGRDXFFeature *GetNextUnfilteredFeature();
571 : };
572 :
573 : /************************************************************************/
574 : /* OGRDXFReader */
575 : /* */
576 : /* A class for very low level DXF reading without interpretation. */
577 : /************************************************************************/
578 :
579 : #define DXF_READER_ERROR() \
580 : do \
581 : { \
582 : CPLError(CE_Failure, CPLE_AppDefined, \
583 : "%s, %d: error at line %d of %s", __FILE__, __LINE__, \
584 : GetLineNumber(), GetDescription()); \
585 : } while (0)
586 : #define DXF_LAYER_READER_ERROR() \
587 : do \
588 : { \
589 : CPLError(CE_Failure, CPLE_AppDefined, \
590 : "%s, %d: error at line %d of %s", __FILE__, __LINE__, \
591 : poDS->GetLineNumber(), poDS->GetDescription()); \
592 : } while (0)
593 :
594 426 : class OGRDXFReaderBase /* non final */
595 : {
596 : protected:
597 224 : OGRDXFReaderBase() = default;
598 :
599 : public:
600 : virtual ~OGRDXFReaderBase();
601 :
602 : void Initialize(VSILFILE *fp);
603 :
604 : VSILFILE *fp = nullptr;
605 :
606 : unsigned int nLastValueSize = 0;
607 : int nLineNumber = 0;
608 :
609 : virtual uint64_t GetCurrentFilePos() const = 0;
610 : virtual int ReadValue(char *pszValueBuffer, int nValueBufferSize = 81) = 0;
611 : virtual void UnreadValue() = 0;
612 : virtual void ResetReadPointer(uint64_t iNewOffset,
613 : int nNewLineNumber = 0) = 0;
614 : };
615 :
616 : class OGRDXFReaderASCII final : public OGRDXFReaderBase
617 : {
618 : int ReadValueRaw(char *pszValueBuffer, int nValueBufferSize);
619 : void LoadDiskChunk();
620 :
621 : unsigned int iSrcBufferOffset = 0;
622 : unsigned int nSrcBufferBytes = 0;
623 : uint64_t iSrcBufferFileOffset = 0;
624 : std::array<char, 1025> achSrcBuffer{};
625 :
626 : public:
627 219 : OGRDXFReaderASCII() = default;
628 :
629 339 : uint64_t GetCurrentFilePos() const override
630 : {
631 339 : return iSrcBufferFileOffset + iSrcBufferOffset;
632 : }
633 :
634 : int ReadValue(char *pszValueBuffer, int nValueBufferSize) override;
635 : void UnreadValue() override;
636 : void ResetReadPointer(uint64_t, int nNewLineNumber) override;
637 : };
638 :
639 : class OGRDXFReaderBinary final : public OGRDXFReaderBase
640 : {
641 : bool m_bIsR12 = false;
642 : uint64_t m_nPrevPos = static_cast<uint64_t>(-1);
643 :
644 : public:
645 5 : OGRDXFReaderBinary() = default;
646 :
647 10 : uint64_t GetCurrentFilePos() const override
648 : {
649 10 : return VSIFTellL(fp);
650 : }
651 :
652 : int ReadValue(char *pszValueBuffer, int nValueBufferSize) override;
653 : void UnreadValue() override;
654 : void ResetReadPointer(uint64_t, int nNewLineNumber) override;
655 : };
656 :
657 : /************************************************************************/
658 : /* OGRDXFFieldModes */
659 : /* */
660 : /* Represents which fields should be included in the data source. */
661 : /************************************************************************/
662 :
663 : enum OGRDXFFieldModes
664 : {
665 : ODFM_None = 0,
666 : ODFM_IncludeRawCodeValues = 0x1,
667 : ODFM_IncludeBlockFields = 0x2,
668 : ODFM_Include3DModeFields = 0x4
669 : };
670 :
671 : /************************************************************************/
672 : /* OGRDXFDataSource */
673 : /************************************************************************/
674 :
675 : class OGRDXFDataSource final : public GDALDataset
676 : {
677 : VSILFILE *fp;
678 :
679 : std::vector<OGRLayer *> apoLayers;
680 :
681 : uint64_t iEntitiesOffset;
682 : int iEntitiesLineNumber;
683 :
684 : std::map<CPLString, DXFBlockDefinition> oBlockMap;
685 : std::map<CPLString, CPLString> oBlockRecordHandles;
686 : std::map<CPLString, CPLString> oHeaderVariables;
687 :
688 : CPLString osEncoding;
689 :
690 : // indexed by layer name, then by property name.
691 : std::map<CPLString, std::map<CPLString, CPLString>> oLayerTable;
692 :
693 : // indexed by style name, then by property name.
694 : std::map<CPLString, std::map<CPLString, CPLString>> oTextStyleTable;
695 : std::map<CPLString, CPLString> oTextStyleHandles;
696 :
697 : // indexed by dimstyle name, then by DIM... variable name
698 : std::map<CPLString, std::map<CPLString, CPLString>> oDimStyleTable;
699 :
700 : std::map<CPLString, std::vector<double>> oLineTypeTable;
701 :
702 : bool bInlineBlocks;
703 : bool bMergeBlockGeometries;
704 : bool bTranslateEscapeSequences;
705 : bool bIncludeRawCodeValues;
706 : bool m_bClosedLineAsPolygon = false;
707 : double m_dfHatchTolerance = -1.0;
708 :
709 : bool b3DExtensibleMode;
710 : bool bHaveReadSolidData;
711 : std::map<CPLString, std::vector<GByte>> oSolidBinaryData;
712 :
713 : std::unique_ptr<OGRDXFReaderBase> poReader{};
714 :
715 : std::vector<CPLString> aosBlockInsertionStack;
716 :
717 : public:
718 : OGRDXFDataSource();
719 : ~OGRDXFDataSource() override;
720 :
721 : bool Open(const char *pszFilename, VSILFILE *fpIn, bool bHeaderOnly,
722 : CSLConstList papszOptionsIn);
723 :
724 613 : int GetLayerCount() const override
725 : {
726 613 : return static_cast<int>(apoLayers.size());
727 : }
728 :
729 : const OGRLayer *GetLayer(int) const override;
730 :
731 : int TestCapability(const char *) const override;
732 :
733 : // The following is only used by OGRDXFLayer
734 :
735 1528 : bool InlineBlocks() const
736 : {
737 1528 : return bInlineBlocks;
738 : }
739 :
740 141 : bool ShouldMergeBlockGeometries() const
741 : {
742 141 : return bMergeBlockGeometries;
743 : }
744 :
745 150 : bool ShouldTranslateEscapes() const
746 : {
747 150 : return bTranslateEscapeSequences;
748 : }
749 :
750 3179 : bool ShouldIncludeRawCodeValues() const
751 : {
752 3179 : return bIncludeRawCodeValues;
753 : }
754 :
755 247 : bool In3DExtensibleMode() const
756 : {
757 247 : return b3DExtensibleMode;
758 : }
759 :
760 27 : bool ClosedLineAsPolygon() const
761 : {
762 27 : return m_bClosedLineAsPolygon;
763 : }
764 :
765 45 : double HatchTolerance() const
766 : {
767 45 : return m_dfHatchTolerance;
768 : }
769 :
770 : static void AddStandardFields(OGRFeatureDefn *poDef, const int nFieldModes);
771 :
772 : // Implemented in ogrdxf_blockmap.cpp
773 : bool ReadBlocksSection();
774 : DXFBlockDefinition *LookupBlock(const char *pszName);
775 : CPLString GetBlockNameByRecordHandle(const char *pszID);
776 :
777 48 : std::map<CPLString, DXFBlockDefinition> &GetBlockMap()
778 : {
779 48 : return oBlockMap;
780 : }
781 :
782 : bool PushBlockInsertion(const CPLString &osBlockName);
783 :
784 424 : void PopBlockInsertion()
785 : {
786 424 : aosBlockInsertionStack.pop_back();
787 424 : }
788 :
789 : // Layer and other Table Handling (ogrdatasource.cpp)
790 : bool ReadTablesSection();
791 : bool ReadLayerDefinition();
792 : bool ReadLineTypeDefinition();
793 : bool ReadTextStyleDefinition();
794 : bool ReadDimStyleDefinition();
795 : std::optional<CPLString> LookupLayerProperty(const char *pszLayer,
796 : const char *pszProperty) const;
797 : const char *LookupTextStyleProperty(const char *pszTextStyle,
798 : const char *pszProperty,
799 : const char *pszDefault);
800 : bool LookupDimStyle(const char *pszDimstyle,
801 : std::map<CPLString, CPLString> &oDimStyleProperties);
802 :
803 4 : const std::map<CPLString, std::vector<double>> &GetLineTypeTable() const
804 : {
805 4 : return oLineTypeTable;
806 : }
807 :
808 : std::vector<double> LookupLineType(const char *pszName);
809 : bool TextStyleExists(const char *pszTextStyle);
810 : CPLString GetTextStyleNameByHandle(const char *pszID);
811 : static void PopulateDefaultDimStyleProperties(
812 : std::map<CPLString, CPLString> &oDimStyleProperties);
813 : size_t GetEntryFromAcDsDataSection(const char *pszEntityHandle,
814 : const GByte **pabyBuffer);
815 :
816 : // Header variables.
817 : bool ReadHeaderSection(CSLConstList papszOpenOptionsIn);
818 : const char *GetVariable(const char *pszName,
819 : const char *pszDefault = nullptr);
820 :
821 3363 : const char *GetEncoding()
822 : {
823 3363 : return osEncoding;
824 : }
825 :
826 : // reader related.
827 6 : int GetLineNumber() const
828 : {
829 6 : return poReader->nLineNumber;
830 : }
831 :
832 166607 : int ReadValue(char *pszValueBuffer, int nValueBufferSize = 81)
833 : {
834 166607 : return poReader->ReadValue(pszValueBuffer, nValueBufferSize);
835 : }
836 :
837 218 : void RestartEntities()
838 : {
839 218 : poReader->ResetReadPointer(iEntitiesOffset, iEntitiesLineNumber);
840 218 : }
841 :
842 2651 : void UnreadValue()
843 : {
844 2651 : poReader->UnreadValue();
845 2651 : }
846 :
847 66 : void ResetReadPointer(uint64_t iNewOffset)
848 : {
849 66 : poReader->ResetReadPointer(iNewOffset);
850 66 : }
851 : };
852 :
853 : /************************************************************************/
854 : /* OGRDXFWriterLayer */
855 : /************************************************************************/
856 :
857 : class OGRDXFWriterDS;
858 :
859 : class OGRDXFWriterLayer final : public OGRLayer
860 : {
861 : VSILFILE *fp;
862 : OGRFeatureDefn *poFeatureDefn;
863 :
864 : OGRDXFWriterDS *poDS;
865 :
866 : int WriteValue(int nCode, const char *pszValue);
867 : int WriteValue(int nCode, int nValue);
868 : int WriteValue(int nCode, double dfValue);
869 :
870 : static constexpr int PROP_RGBA_COLOR = -1;
871 :
872 : using CorePropertiesType = std::vector<std::pair<int, std::string>>;
873 :
874 : OGRErr WriteCore(OGRFeature *, const CorePropertiesType &oCoreProperties);
875 : OGRErr WritePOINT(OGRFeature *);
876 : OGRErr WriteTEXT(OGRFeature *);
877 : OGRErr WritePOLYLINE(OGRFeature *, const OGRGeometry * = nullptr);
878 : OGRErr WriteHATCH(OGRFeature *, OGRGeometry * = nullptr);
879 : OGRErr WriteINSERT(OGRFeature *);
880 :
881 : static CPLString TextEscape(const char *);
882 : static int ColorStringToDXFColor(const char *, bool &bPerfectMatch);
883 : static std::vector<double> PrepareLineTypeDefinition(OGRStylePen *);
884 : static std::map<CPLString, CPLString>
885 : PrepareTextStyleDefinition(OGRStyleLabel *);
886 :
887 : std::map<CPLString, std::vector<double>> oNewLineTypes;
888 : std::map<CPLString, std::map<CPLString, CPLString>> oNewTextStyles;
889 : int nNextAutoID;
890 : int bWriteHatch;
891 :
892 : public:
893 : OGRDXFWriterLayer(OGRDXFWriterDS *poDS, VSILFILE *fp);
894 : ~OGRDXFWriterLayer() override;
895 :
896 16 : void ResetReading() override
897 : {
898 16 : }
899 :
900 16 : OGRFeature *GetNextFeature() override
901 : {
902 16 : return nullptr;
903 : }
904 :
905 537 : const OGRFeatureDefn *GetLayerDefn() const override
906 : {
907 537 : return poFeatureDefn;
908 : }
909 :
910 : int TestCapability(const char *) const override;
911 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
912 : OGRErr CreateField(const OGRFieldDefn *poField,
913 : int bApproxOK = TRUE) override;
914 :
915 : GDALDataset *GetDataset() override;
916 :
917 : void ResetFP(VSILFILE *);
918 :
919 58 : std::map<CPLString, std::vector<double>> &GetNewLineTypeMap()
920 : {
921 58 : return oNewLineTypes;
922 : }
923 :
924 58 : std::map<CPLString, std::map<CPLString, CPLString>> &GetNewTextStyleMap()
925 : {
926 58 : return oNewTextStyles;
927 : }
928 : };
929 :
930 : /************************************************************************/
931 : /* OGRDXFBlocksWriterLayer */
932 : /************************************************************************/
933 :
934 : class OGRDXFBlocksWriterLayer final : public OGRLayer
935 : {
936 : OGRFeatureDefn *poFeatureDefn;
937 :
938 : public:
939 : explicit OGRDXFBlocksWriterLayer(OGRDXFWriterDS *poDS);
940 : ~OGRDXFBlocksWriterLayer() override;
941 :
942 0 : void ResetReading() override
943 : {
944 0 : }
945 :
946 0 : OGRFeature *GetNextFeature() override
947 : {
948 0 : return nullptr;
949 : }
950 :
951 10 : const OGRFeatureDefn *GetLayerDefn() const override
952 : {
953 10 : return poFeatureDefn;
954 : }
955 :
956 : int TestCapability(const char *) const override;
957 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
958 : OGRErr CreateField(const OGRFieldDefn *poField,
959 : int bApproxOK = TRUE) override;
960 :
961 : std::vector<OGRFeature *> apoBlocks;
962 : OGRFeature *FindBlock(const char *);
963 : };
964 :
965 : /************************************************************************/
966 : /* OGRDXFWriterDS */
967 : /************************************************************************/
968 :
969 : class OGRDXFWriterDS final : public GDALDataset
970 : {
971 : friend class OGRDXFWriterLayer;
972 :
973 : int nNextFID;
974 :
975 : OGRDXFWriterLayer *poLayer;
976 : OGRDXFBlocksWriterLayer *poBlocksLayer;
977 : VSILFILE *fp;
978 : CPLString osTrailerFile;
979 :
980 : CPLString osTempFilename;
981 : VSILFILE *fpTemp;
982 :
983 : CPLString osHeaderFile;
984 : OGRDXFDataSource oHeaderDS;
985 : char **papszLayersToCreate;
986 :
987 : vsi_l_offset nHANDSEEDOffset;
988 :
989 : std::vector<int> anDefaultLayerCode;
990 : std::vector<CPLString> aosDefaultLayerText;
991 :
992 : std::set<CPLString> aosUsedEntities;
993 : void ScanForEntities(const char *pszFilename, const char *pszTarget);
994 :
995 : bool WriteNewLineTypeRecords(VSILFILE *fp);
996 : bool WriteNewTextStyleRecords(VSILFILE *fp);
997 : bool WriteNewBlockRecords(VSILFILE *);
998 : bool WriteNewBlockDefinitions(VSILFILE *);
999 : bool WriteNewLayerDefinitions(VSILFILE *);
1000 : bool TransferUpdateHeader(VSILFILE *);
1001 : bool TransferUpdateTrailer(VSILFILE *);
1002 : bool FixupHANDSEED(VSILFILE *);
1003 :
1004 : OGREnvelope oGlobalEnvelope;
1005 :
1006 : bool m_bHeaderFileIsTemp = false;
1007 : bool m_bTrailerFileIsTemp = false;
1008 : OGRSpatialReference m_oSRS{};
1009 : std::string m_osINSUNITS = "AUTO";
1010 : std::string m_osMEASUREMENT = "HEADER_VALUE";
1011 :
1012 : public:
1013 : OGRDXFWriterDS();
1014 : ~OGRDXFWriterDS() override;
1015 :
1016 : int Open(const char *pszFilename, CSLConstList papszOptions);
1017 :
1018 : int GetLayerCount() const override;
1019 : const OGRLayer *GetLayer(int) const override;
1020 :
1021 : int TestCapability(const char *) const override;
1022 :
1023 : OGRLayer *ICreateLayer(const char *pszName,
1024 : const OGRGeomFieldDefn *poGeomFieldDefn,
1025 : CSLConstList papszOptions) override;
1026 :
1027 : bool CheckEntityID(const char *pszEntityID);
1028 : bool WriteEntityID(VSILFILE *fp, unsigned int &nAssignedFID,
1029 : GIntBig nPreferredFID = OGRNullFID);
1030 :
1031 : void UpdateExtent(OGREnvelope *psEnvelope);
1032 : };
1033 :
1034 : #endif /* ndef OGR_DXF_H_INCLUDED */
|