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