Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: DXF Translator
4 : * Purpose: Implements translation support for HATCH elements as part
5 : * of the OGRDXFLayer class.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
10 : * Copyright (c) 2011-2013, Even Rouault <even dot rouault at spatialys.com>
11 : * Copyright (c) 2017, Alan Thomas <alant@outlook.com.au>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 :
16 : #include "ogr_dxf.h"
17 : #include "cpl_conv.h"
18 : #include "ogr_api.h"
19 :
20 : #include <algorithm>
21 : #include <cmath>
22 : #include "ogrdxf_polyline_smooth.h"
23 :
24 : /************************************************************************/
25 : /* TranslateHATCH() */
26 : /* */
27 : /* We mostly just try to convert hatch objects as polygons or */
28 : /* multipolygons representing the hatched area. It is hard to */
29 : /* preserve the actual details of the hatching. */
30 : /************************************************************************/
31 :
32 45 : OGRDXFFeature *OGRDXFLayer::TranslateHATCH()
33 :
34 : {
35 : char szLineBuf[257];
36 45 : int nCode = 0;
37 45 : OGRDXFFeature *poFeature = new OGRDXFFeature(poFeatureDefn);
38 :
39 45 : double dfElevation = 0.0; // Z value to be used for EVERY point
40 90 : OGRGeometryCollection oGC;
41 90 : std::string osExtendedData;
42 :
43 1453 : while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
44 : {
45 1408 : switch (nCode)
46 : {
47 45 : case 30:
48 : // Constant elevation.
49 45 : dfElevation = CPLAtof(szLineBuf);
50 45 : break;
51 :
52 45 : case 70:
53 : {
54 45 : const int nFillFlag = atoi(szLineBuf);
55 90 : poFeature->oStyleProperties["FillFlag"] =
56 135 : nFillFlag ? "Filled" : "Pattern";
57 45 : break;
58 : }
59 :
60 43 : case 2: // Hatch pattern name
61 43 : poFeature->SetField("Text", szLineBuf);
62 43 : break;
63 :
64 45 : case 91:
65 : {
66 45 : int nBoundaryPathCount = atoi(szLineBuf);
67 :
68 103 : for (int iBoundary = 0; iBoundary < nBoundaryPathCount;
69 : iBoundary++)
70 : {
71 58 : if (CollectBoundaryPath(&oGC, dfElevation) != OGRERR_NONE)
72 0 : break;
73 : }
74 : }
75 45 : break;
76 :
77 23 : case 52:
78 : {
79 23 : poFeature->oStyleProperties["HatchPatternRotation"] = szLineBuf;
80 23 : break;
81 : }
82 :
83 23 : case 41:
84 : {
85 23 : poFeature->oStyleProperties["HatchPatternScale"] = szLineBuf;
86 23 : break;
87 : }
88 :
89 25 : case 1001:
90 : {
91 25 : osExtendedData = szLineBuf;
92 25 : break;
93 : }
94 :
95 14 : case 1071:
96 : {
97 14 : if (osExtendedData == "HATCHBACKGROUNDCOLOR")
98 28 : poFeature->oStyleProperties["HatchBackgroundColor"] =
99 42 : szLineBuf;
100 14 : break;
101 : }
102 :
103 1145 : default:
104 1145 : TranslateGenericProperty(poFeature, nCode, szLineBuf);
105 1145 : break;
106 : }
107 : }
108 45 : if (nCode < 0)
109 : {
110 0 : DXF_LAYER_READER_ERROR();
111 0 : delete poFeature;
112 0 : return nullptr;
113 : }
114 :
115 45 : if (nCode == 0)
116 45 : poDS->UnreadValue();
117 :
118 : /* -------------------------------------------------------------------- */
119 : /* Obtain a tolerance value used when building the polygon. */
120 : /* -------------------------------------------------------------------- */
121 45 : double dfTolerance = poDS->HatchTolerance();
122 45 : if (dfTolerance < 0)
123 : {
124 : // If the configuration variable isn't set, compute the bounding box
125 : // and work out a tolerance from that
126 45 : OGREnvelope oEnvelope;
127 45 : oGC.getEnvelope(&oEnvelope);
128 90 : dfTolerance = std::max(oEnvelope.MaxX - oEnvelope.MinX,
129 45 : oEnvelope.MaxY - oEnvelope.MinY) *
130 : 1e-7;
131 : }
132 :
133 : /* -------------------------------------------------------------------- */
134 : /* Try to turn the set of lines into something useful. */
135 : /* -------------------------------------------------------------------- */
136 : OGRErr eErr;
137 :
138 : auto poFinalGeom = std::unique_ptr<OGRGeometry>(
139 : OGRGeometry::FromHandle(OGRBuildPolygonFromEdges(
140 45 : OGRGeometry::ToHandle(&oGC), TRUE, TRUE, dfTolerance, &eErr)));
141 45 : if (eErr != OGRERR_NONE)
142 : {
143 0 : auto poMLS = std::make_unique<OGRMultiLineString>();
144 0 : for (int i = 0; i < oGC.getNumGeometries(); i++)
145 0 : poMLS->addGeometry(oGC.getGeometryRef(i));
146 0 : poFinalGeom = std::move(poMLS);
147 : }
148 :
149 45 : poFeature->ApplyOCSTransformer(poFinalGeom.get());
150 45 : poFeature->SetGeometry(std::move(poFinalGeom));
151 :
152 45 : PrepareBrushStyle(poFeature);
153 :
154 45 : return poFeature;
155 : }
156 :
157 : /************************************************************************/
158 : /* CollectBoundaryPath() */
159 : /************************************************************************/
160 :
161 58 : OGRErr OGRDXFLayer::CollectBoundaryPath(OGRGeometryCollection *poGC,
162 : const double dfElevation)
163 :
164 : {
165 : char szLineBuf[257];
166 :
167 : /* -------------------------------------------------------------------- */
168 : /* Read the boundary path type. */
169 : /* -------------------------------------------------------------------- */
170 58 : int nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
171 58 : if (nCode != 92)
172 : {
173 0 : DXF_LAYER_READER_ERROR();
174 0 : return OGRERR_FAILURE;
175 : }
176 :
177 58 : const int nBoundaryPathType = atoi(szLineBuf);
178 :
179 : /* ==================================================================== */
180 : /* Handle polyline loops. */
181 : /* ==================================================================== */
182 58 : if (nBoundaryPathType & 0x02)
183 39 : return CollectPolylinePath(poGC, dfElevation);
184 :
185 : /* ==================================================================== */
186 : /* Handle non-polyline loops. */
187 : /* ==================================================================== */
188 :
189 : /* -------------------------------------------------------------------- */
190 : /* Read number of edges. */
191 : /* -------------------------------------------------------------------- */
192 19 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
193 19 : if (nCode != 93)
194 : {
195 0 : DXF_LAYER_READER_ERROR();
196 0 : return OGRERR_FAILURE;
197 : }
198 :
199 19 : const int nEdgeCount = atoi(szLineBuf);
200 :
201 : /* -------------------------------------------------------------------- */
202 : /* Loop reading edges. */
203 : /* -------------------------------------------------------------------- */
204 84 : for (int iEdge = 0; iEdge < nEdgeCount; iEdge++)
205 : {
206 : /* --------------------------------------------------------------------
207 : */
208 : /* Read the edge type. */
209 : /* --------------------------------------------------------------------
210 : */
211 65 : const int ET_LINE = 1;
212 65 : const int ET_CIRCULAR_ARC = 2;
213 65 : const int ET_ELLIPTIC_ARC = 3;
214 65 : const int ET_SPLINE = 4;
215 :
216 65 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
217 65 : if (nCode != 72)
218 : {
219 0 : DXF_LAYER_READER_ERROR();
220 0 : return OGRERR_FAILURE;
221 : }
222 :
223 65 : int nEdgeType = atoi(szLineBuf);
224 :
225 : /* --------------------------------------------------------------------
226 : */
227 : /* Process a line edge. */
228 : /* --------------------------------------------------------------------
229 : */
230 65 : if (nEdgeType == ET_LINE)
231 : {
232 45 : double dfStartX = 0.0;
233 :
234 45 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
235 45 : dfStartX = CPLAtof(szLineBuf);
236 : else
237 0 : break;
238 :
239 45 : double dfStartY = 0.0;
240 :
241 45 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
242 45 : dfStartY = CPLAtof(szLineBuf);
243 : else
244 0 : break;
245 :
246 45 : double dfEndX = 0.0;
247 :
248 45 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
249 45 : dfEndX = CPLAtof(szLineBuf);
250 : else
251 0 : break;
252 :
253 45 : double dfEndY = 0.0;
254 :
255 45 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
256 45 : dfEndY = CPLAtof(szLineBuf);
257 : else
258 0 : break;
259 :
260 45 : OGRLineString *poLS = new OGRLineString();
261 :
262 45 : poLS->addPoint(dfStartX, dfStartY, dfElevation);
263 45 : poLS->addPoint(dfEndX, dfEndY, dfElevation);
264 :
265 45 : poGC->addGeometryDirectly(poLS);
266 : }
267 : /* --------------------------------------------------------------------
268 : */
269 : /* Process a circular arc. */
270 : /* --------------------------------------------------------------------
271 : */
272 20 : else if (nEdgeType == ET_CIRCULAR_ARC)
273 : {
274 12 : double dfCenterX = 0.0;
275 :
276 12 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
277 12 : dfCenterX = CPLAtof(szLineBuf);
278 : else
279 0 : break;
280 :
281 12 : double dfCenterY = 0.0;
282 :
283 12 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
284 12 : dfCenterY = CPLAtof(szLineBuf);
285 : else
286 0 : break;
287 :
288 12 : double dfRadius = 0.0;
289 :
290 12 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
291 12 : dfRadius = CPLAtof(szLineBuf);
292 : else
293 0 : break;
294 :
295 12 : double dfStartAngle = 0.0;
296 :
297 12 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
298 12 : dfStartAngle = CPLAtof(szLineBuf);
299 : else
300 0 : break;
301 :
302 12 : double dfEndAngle = 0.0;
303 :
304 12 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
305 12 : dfEndAngle = CPLAtof(szLineBuf);
306 : else
307 0 : break;
308 :
309 12 : bool bCounterClockwise = false;
310 :
311 12 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
312 12 : bCounterClockwise = atoi(szLineBuf) != 0;
313 0 : else if (nCode >= 0)
314 0 : poDS->UnreadValue();
315 : else
316 0 : break;
317 :
318 12 : if (dfStartAngle > dfEndAngle)
319 4 : dfEndAngle += 360.0;
320 12 : if (bCounterClockwise)
321 : {
322 8 : dfStartAngle *= -1;
323 8 : dfEndAngle *= -1;
324 : }
325 :
326 12 : if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
327 : {
328 12 : OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
329 : dfCenterX, dfCenterY, dfElevation, dfRadius, dfRadius, 0.0,
330 12 : dfStartAngle, dfEndAngle, 0.0, poDS->InlineBlocks());
331 :
332 : // If the input was 2D, we assume we want to keep it that way
333 12 : if (dfElevation == 0.0)
334 8 : poArc->flattenTo2D();
335 :
336 12 : poGC->addGeometryDirectly(poArc);
337 : }
338 : else
339 : {
340 : // TODO: emit error ?
341 : }
342 : }
343 :
344 : /* --------------------------------------------------------------------
345 : */
346 : /* Process an elliptical arc. */
347 : /* --------------------------------------------------------------------
348 : */
349 8 : else if (nEdgeType == ET_ELLIPTIC_ARC)
350 : {
351 6 : double dfCenterX = 0.0;
352 :
353 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 10)
354 6 : dfCenterX = CPLAtof(szLineBuf);
355 : else
356 0 : break;
357 :
358 6 : double dfCenterY = 0.0;
359 :
360 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 20)
361 6 : dfCenterY = CPLAtof(szLineBuf);
362 : else
363 0 : break;
364 :
365 6 : double dfMajorX = 0.0;
366 :
367 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 11)
368 6 : dfMajorX = CPLAtof(szLineBuf);
369 : else
370 0 : break;
371 :
372 6 : double dfMajorY = 0.0;
373 :
374 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 21)
375 6 : dfMajorY = CPLAtof(szLineBuf);
376 : else
377 0 : break;
378 :
379 6 : double dfRatio = 0.0;
380 :
381 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 40)
382 6 : dfRatio = CPLAtof(szLineBuf);
383 6 : if (dfRatio == 0.0)
384 0 : break;
385 :
386 6 : double dfStartAngle = 0.0;
387 :
388 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 50)
389 6 : dfStartAngle = CPLAtof(szLineBuf);
390 : else
391 0 : break;
392 :
393 6 : double dfEndAngle = 0.0;
394 :
395 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 51)
396 6 : dfEndAngle = CPLAtof(szLineBuf);
397 : else
398 0 : break;
399 :
400 6 : bool bCounterClockwise = false;
401 :
402 6 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 73)
403 6 : bCounterClockwise = atoi(szLineBuf) != 0;
404 0 : else if (nCode >= 0)
405 0 : poDS->UnreadValue();
406 : else
407 0 : break;
408 :
409 6 : if (dfStartAngle > dfEndAngle)
410 0 : dfEndAngle += 360.0;
411 6 : if (bCounterClockwise)
412 : {
413 5 : dfStartAngle *= -1;
414 5 : dfEndAngle *= -1;
415 : }
416 :
417 : const double dfMajorRadius =
418 6 : sqrt(dfMajorX * dfMajorX + dfMajorY * dfMajorY);
419 6 : const double dfMinorRadius = dfMajorRadius * dfRatio;
420 :
421 : const double dfRotation =
422 6 : -1 * atan2(dfMajorY, dfMajorX) * 180 / M_PI;
423 :
424 : // The start and end angles are stored as circular angles. However,
425 : // approximateArcAngles is expecting elliptical angles (what AutoCAD
426 : // calls "parameters"), so let's transform them.
427 6 : dfStartAngle =
428 6 : 180.0 * round(dfStartAngle / 180) +
429 6 : (fabs(fmod(dfStartAngle, 180)) == 90
430 4 : ? (std::signbit(dfStartAngle) ? 180 : -180)
431 : : 0) +
432 6 : atan((1.0 / dfRatio) * tan(dfStartAngle * M_PI / 180)) * 180 /
433 : M_PI;
434 6 : dfEndAngle = 180.0 * round(dfEndAngle / 180) +
435 6 : (fabs(fmod(dfEndAngle, 180)) == 90
436 1 : ? (std::signbit(dfEndAngle) ? 180 : -180)
437 : : 0) +
438 6 : atan((1.0 / dfRatio) * tan(dfEndAngle * M_PI / 180)) *
439 6 : 180 / M_PI;
440 :
441 6 : if (fabs(dfEndAngle - dfStartAngle) <= 361.0)
442 : {
443 6 : OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
444 : dfCenterX, dfCenterY, dfElevation, dfMajorRadius,
445 : dfMinorRadius, dfRotation, dfStartAngle, dfEndAngle, 0.0,
446 6 : poDS->InlineBlocks());
447 :
448 : // If the input was 2D, we assume we want to keep it that way
449 6 : if (dfElevation == 0.0)
450 2 : poArc->flattenTo2D();
451 :
452 6 : poGC->addGeometryDirectly(poArc);
453 : }
454 : else
455 : {
456 : // TODO: emit error ?
457 : }
458 : }
459 :
460 : /* --------------------------------------------------------------------
461 : */
462 : /* Process an elliptical arc. */
463 : /* --------------------------------------------------------------------
464 : */
465 2 : else if (nEdgeType == ET_SPLINE)
466 : {
467 2 : int nDegree = 3;
468 :
469 2 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 94)
470 2 : nDegree = atoi(szLineBuf);
471 : else
472 0 : break;
473 :
474 : // Skip a few things we don't care about
475 2 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 73)
476 0 : break;
477 2 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) != 74)
478 0 : break;
479 :
480 2 : int nKnots = 0;
481 :
482 2 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 95)
483 2 : nKnots = atoi(szLineBuf);
484 : else
485 0 : break;
486 :
487 2 : int nControlPoints = 0;
488 :
489 2 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) == 96)
490 2 : nControlPoints = atoi(szLineBuf);
491 : else
492 0 : break;
493 :
494 2 : std::vector<double> adfKnots(FORTRAN_INDEXING, 0.0);
495 :
496 2 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
497 2 : if (nCode != 40)
498 0 : break;
499 :
500 23 : while (nCode == 40)
501 : {
502 21 : adfKnots.push_back(CPLAtof(szLineBuf));
503 21 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
504 : }
505 :
506 2 : std::vector<double> adfControlPoints(FORTRAN_INDEXING, 0.0);
507 2 : std::vector<double> adfWeights(FORTRAN_INDEXING, 0.0);
508 :
509 2 : if (nCode != 10)
510 0 : break;
511 :
512 15 : while (nCode == 10)
513 : {
514 13 : adfControlPoints.push_back(CPLAtof(szLineBuf));
515 :
516 13 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
517 : 20)
518 : {
519 13 : adfControlPoints.push_back(CPLAtof(szLineBuf));
520 : }
521 : else
522 0 : break;
523 :
524 13 : adfControlPoints.push_back(0.0); // Z coordinate
525 :
526 : // 42 (weights) are optional
527 13 : if ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) ==
528 : 42)
529 : {
530 7 : adfWeights.push_back(CPLAtof(szLineBuf));
531 7 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
532 : }
533 : }
534 :
535 : // Skip past the number of fit points
536 2 : if (nCode != 97)
537 0 : break;
538 :
539 : // Eat the rest of this section, if present, until the next
540 : // boundary segment (72) or the conclusion of the boundary data (97)
541 2 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
542 14 : while (nCode > 0 && nCode != 72 && nCode != 97)
543 12 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
544 2 : if (nCode > 0)
545 2 : poDS->UnreadValue();
546 :
547 : auto poLS =
548 : InsertSplineWithChecks(nDegree, adfControlPoints,
549 : /* bHaZ = */ false, nControlPoints,
550 2 : adfKnots, nKnots, adfWeights);
551 :
552 2 : if (!poLS)
553 : {
554 0 : DXF_LAYER_READER_ERROR();
555 0 : return OGRERR_FAILURE;
556 : }
557 :
558 2 : poGC->addGeometryDirectly(poLS.release());
559 : }
560 :
561 : else
562 : {
563 0 : CPLDebug("DXF", "Unsupported HATCH boundary line type:%d",
564 : nEdgeType);
565 0 : return OGRERR_UNSUPPORTED_OPERATION;
566 : }
567 : }
568 :
569 19 : if (nCode < 0)
570 : {
571 0 : DXF_LAYER_READER_ERROR();
572 0 : return OGRERR_FAILURE;
573 : }
574 :
575 : /* -------------------------------------------------------------------- */
576 : /* Skip through source boundary objects if present. */
577 : /* -------------------------------------------------------------------- */
578 19 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
579 19 : if (nCode != 97)
580 : {
581 0 : if (nCode < 0)
582 0 : return OGRERR_FAILURE;
583 0 : poDS->UnreadValue();
584 : }
585 : else
586 : {
587 19 : int iObj, nObjCount = atoi(szLineBuf);
588 :
589 21 : for (iObj = 0; iObj < nObjCount; iObj++)
590 : {
591 2 : if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
592 0 : return OGRERR_FAILURE;
593 : }
594 : }
595 :
596 19 : return OGRERR_NONE;
597 : }
598 :
599 : /************************************************************************/
600 : /* CollectPolylinePath() */
601 : /************************************************************************/
602 :
603 39 : OGRErr OGRDXFLayer::CollectPolylinePath(OGRGeometryCollection *poGC,
604 : const double dfElevation)
605 :
606 : {
607 39 : int nCode = 0;
608 : char szLineBuf[257];
609 78 : DXFSmoothPolyline oSmoothPolyline;
610 39 : double dfBulge = 0.0;
611 39 : double dfX = 0.0;
612 39 : double dfY = 0.0;
613 39 : bool bHaveX = false;
614 39 : bool bHaveY = false;
615 39 : bool bIsClosed = false;
616 39 : int nVertexCount = -1;
617 39 : bool bHaveBulges = false;
618 :
619 39 : if (dfElevation != 0)
620 1 : oSmoothPolyline.setCoordinateDimension(3);
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* Read the boundary path type. */
624 : /* -------------------------------------------------------------------- */
625 516 : while ((nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf))) > 0)
626 : {
627 516 : if (nVertexCount > 0 && (int)oSmoothPolyline.size() == nVertexCount)
628 39 : break;
629 :
630 477 : switch (nCode)
631 : {
632 39 : case 93:
633 39 : nVertexCount = atoi(szLineBuf);
634 39 : break;
635 :
636 39 : case 72:
637 39 : bHaveBulges = CPL_TO_BOOL(atoi(szLineBuf));
638 39 : break;
639 :
640 39 : case 73:
641 39 : bIsClosed = CPL_TO_BOOL(atoi(szLineBuf));
642 39 : break;
643 :
644 180 : case 10:
645 180 : if (bHaveX && bHaveY)
646 : {
647 0 : oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
648 0 : dfBulge = 0.0;
649 0 : bHaveY = false;
650 : }
651 180 : dfX = CPLAtof(szLineBuf);
652 180 : bHaveX = true;
653 180 : break;
654 :
655 180 : case 20:
656 180 : if (bHaveX && bHaveY)
657 : {
658 0 : oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
659 0 : dfBulge = 0.0;
660 0 : bHaveX = false;
661 : }
662 180 : dfY = CPLAtof(szLineBuf);
663 180 : bHaveY = true;
664 180 : if (bHaveX /* && bHaveY */ && !bHaveBulges)
665 : {
666 180 : oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
667 180 : dfBulge = 0.0;
668 180 : bHaveX = false;
669 180 : bHaveY = false;
670 : }
671 180 : break;
672 :
673 0 : case 42:
674 0 : dfBulge = CPLAtof(szLineBuf);
675 0 : if (bHaveX && bHaveY)
676 : {
677 0 : oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
678 0 : dfBulge = 0.0;
679 0 : bHaveX = false;
680 0 : bHaveY = false;
681 : }
682 0 : break;
683 :
684 0 : default:
685 0 : break;
686 : }
687 : }
688 39 : if (nCode < 0)
689 : {
690 0 : DXF_LAYER_READER_ERROR();
691 0 : return OGRERR_FAILURE;
692 : }
693 :
694 39 : if (nCode != 10 && nCode != 20 && nCode != 42)
695 39 : poDS->UnreadValue();
696 :
697 39 : if (bHaveX && bHaveY)
698 0 : oSmoothPolyline.AddPoint(dfX, dfY, dfElevation, dfBulge);
699 :
700 39 : if (bIsClosed)
701 39 : oSmoothPolyline.Close();
702 :
703 39 : if (oSmoothPolyline.IsEmpty())
704 : {
705 0 : return OGRERR_FAILURE;
706 : }
707 :
708 : // Only process polylines with at least 2 vertices
709 39 : if (nVertexCount >= 2)
710 : {
711 39 : oSmoothPolyline.SetUseMaxGapWhenTessellatingArcs(poDS->InlineBlocks());
712 39 : poGC->addGeometryDirectly(oSmoothPolyline.Tessellate(false));
713 : }
714 :
715 : /* -------------------------------------------------------------------- */
716 : /* Skip through source boundary objects if present. */
717 : /* -------------------------------------------------------------------- */
718 39 : nCode = poDS->ReadValue(szLineBuf, sizeof(szLineBuf));
719 39 : if (nCode != 97)
720 : {
721 0 : if (nCode < 0)
722 0 : return OGRERR_FAILURE;
723 0 : poDS->UnreadValue();
724 : }
725 : else
726 : {
727 39 : int iObj, nObjCount = atoi(szLineBuf);
728 :
729 39 : for (iObj = 0; iObj < nObjCount; iObj++)
730 : {
731 0 : if (poDS->ReadValue(szLineBuf, sizeof(szLineBuf)) < 0)
732 0 : return OGRERR_FAILURE;
733 : }
734 : }
735 39 : return OGRERR_NONE;
736 : }
|