1 : /******************************************************************************
2 : * $Id: ogrdxf_dimension.cpp 19643 2010-05-08 21:56:18Z rouault $
3 : *
4 : * Project: DXF Translator
5 : * Purpose: Implements translation support for HATCH elements as part
6 : * of the OGRDXFLayer class.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2010, Frank Warmerdam <warmerdam@pobox.com>
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "ogr_dxf.h"
32 : #include "cpl_conv.h"
33 : #include "ogr_api.h"
34 :
35 : #include "ogrdxf_polyline_smooth.h"
36 :
37 : CPL_CVSID("$Id: ogrdxf_dimension.cpp 19643 2010-05-08 21:56:18Z rouault $");
38 :
39 : #ifndef PI
40 : #define PI 3.14159265358979323846
41 : #endif
42 :
43 : /************************************************************************/
44 : /* TranslateHATCH() */
45 : /* */
46 : /* We mostly just try to convert hatch objects as polygons or */
47 : /* multipolygons representing the hatched area. It is hard to */
48 : /* preserve the actual details of the hatching. */
49 : /************************************************************************/
50 :
51 3 : OGRFeature *OGRDXFLayer::TranslateHATCH()
52 :
53 : {
54 : char szLineBuf[257];
55 : int nCode;
56 3 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
57 :
58 3 : CPLString osHatchPattern;
59 3 : int nFillFlag = 0;
60 3 : OGRGeometryCollection oGC;
61 :
62 58 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
63 : {
64 52 : switch( nCode )
65 : {
66 : case 70:
67 3 : nFillFlag = atoi(szLineBuf);
68 3 : break;
69 :
70 : case 2:
71 3 : osHatchPattern = szLineBuf;
72 3 : poFeature->SetField( "Text", osHatchPattern.c_str() );
73 3 : break;
74 :
75 : case 91:
76 : {
77 3 : int nBoundaryPathCount = atoi(szLineBuf);
78 : int iBoundary;
79 :
80 7 : for( iBoundary = 0; iBoundary < nBoundaryPathCount; iBoundary++ )
81 : {
82 4 : if (CollectBoundaryPath( &oGC ) != OGRERR_NONE)
83 0 : break;
84 : }
85 : }
86 3 : break;
87 :
88 : default:
89 43 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
90 : break;
91 : }
92 : }
93 :
94 3 : if( nCode == 0 )
95 3 : poDS->UnreadValue();
96 :
97 : /* -------------------------------------------------------------------- */
98 : /* Try to turn the set of lines into something useful. */
99 : /* -------------------------------------------------------------------- */
100 : OGRErr eErr;
101 :
102 : OGRGeometry* poFinalGeom = (OGRGeometry *)
103 : OGRBuildPolygonFromEdges( (OGRGeometryH) &oGC,
104 3 : TRUE, TRUE, 0.0000001, &eErr );
105 :
106 3 : ApplyOCSTransformer( poFinalGeom );
107 3 : poFeature->SetGeometryDirectly( poFinalGeom );
108 :
109 : /* -------------------------------------------------------------------- */
110 : /* Work out the color for this feature. For now we just assume */
111 : /* solid fill. We cannot trivially translate the various sorts */
112 : /* of hatching. */
113 : /* -------------------------------------------------------------------- */
114 3 : CPLString osLayer = poFeature->GetFieldAsString("Layer");
115 :
116 3 : int nColor = 256;
117 :
118 3 : if( oStyleProperties.count("Color") > 0 )
119 1 : nColor = atoi(oStyleProperties["Color"]);
120 :
121 : // Use layer color?
122 3 : if( nColor < 1 || nColor > 255 )
123 : {
124 2 : const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
125 2 : if( pszValue != NULL )
126 2 : nColor = atoi(pszValue);
127 : }
128 :
129 : /* -------------------------------------------------------------------- */
130 : /* Setup the style string. */
131 : /* -------------------------------------------------------------------- */
132 3 : if( nColor >= 1 && nColor <= 255 )
133 : {
134 3 : CPLString osStyle;
135 3 : const unsigned char *pabyDXFColors = ACGetColorTable();
136 :
137 : osStyle.Printf( "BRUSH(fc:#%02x%02x%02x)",
138 3 : pabyDXFColors[nColor*3+0],
139 3 : pabyDXFColors[nColor*3+1],
140 9 : pabyDXFColors[nColor*3+2] );
141 :
142 3 : poFeature->SetStyleString( osStyle );
143 : }
144 :
145 3 : return poFeature;
146 : }
147 :
148 : /************************************************************************/
149 : /* CollectBoundaryPath() */
150 : /************************************************************************/
151 :
152 4 : OGRErr OGRDXFLayer::CollectBoundaryPath( OGRGeometryCollection *poGC )
153 :
154 : {
155 : int nCode;
156 : char szLineBuf[257];
157 :
158 : /* -------------------------------------------------------------------- */
159 : /* Read the boundary path type. */
160 : /* -------------------------------------------------------------------- */
161 4 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
162 4 : if( nCode != 92 )
163 0 : return OGRERR_FAILURE;
164 :
165 4 : int nBoundaryPathType = atoi(szLineBuf);
166 :
167 : /* ==================================================================== */
168 : /* Handle polyline loops. */
169 : /* ==================================================================== */
170 4 : if( nBoundaryPathType & 0x02 )
171 4 : return CollectPolylinePath( poGC );
172 :
173 : /* ==================================================================== */
174 : /* Handle non-polyline loops. */
175 : /* ==================================================================== */
176 :
177 : /* -------------------------------------------------------------------- */
178 : /* Read number of edges. */
179 : /* -------------------------------------------------------------------- */
180 0 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
181 0 : if( nCode != 93 )
182 0 : return OGRERR_FAILURE;
183 :
184 0 : int nEdgeCount = atoi(szLineBuf);
185 :
186 : /* -------------------------------------------------------------------- */
187 : /* Loop reading edges. */
188 : /* -------------------------------------------------------------------- */
189 : int iEdge;
190 :
191 0 : for( iEdge = 0; iEdge < nEdgeCount; iEdge++ )
192 : {
193 : /* -------------------------------------------------------------------- */
194 : /* Read the edge type. */
195 : /* -------------------------------------------------------------------- */
196 : #define ET_LINE 1
197 : #define ET_CIRCULAR_ARC 2
198 : #define ET_ELLIPTIC_ARC 3
199 : #define ET_SPLINE 4
200 :
201 0 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
202 0 : if( nCode != 72 )
203 0 : return OGRERR_FAILURE;
204 :
205 0 : int nEdgeType = atoi(szLineBuf);
206 :
207 : /* -------------------------------------------------------------------- */
208 : /* Process a line edge. */
209 : /* -------------------------------------------------------------------- */
210 0 : if( nEdgeType == ET_LINE )
211 : {
212 : double dfStartX;
213 : double dfStartY;
214 : double dfEndX;
215 : double dfEndY;
216 :
217 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 10 )
218 0 : dfStartX = atof(szLineBuf);
219 : else
220 0 : break;
221 :
222 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 20 )
223 0 : dfStartY = atof(szLineBuf);
224 : else
225 0 : break;
226 :
227 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 11 )
228 0 : dfEndX = atof(szLineBuf);
229 : else
230 0 : break;
231 :
232 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 21 )
233 0 : dfEndY = atof(szLineBuf);
234 : else
235 0 : break;
236 :
237 0 : OGRLineString *poLS = new OGRLineString();
238 :
239 0 : poLS->addPoint( dfStartX, dfStartY );
240 0 : poLS->addPoint( dfEndX, dfEndY );
241 :
242 0 : poGC->addGeometryDirectly( poLS );
243 : }
244 : /* -------------------------------------------------------------------- */
245 : /* Process a circular arc. */
246 : /* -------------------------------------------------------------------- */
247 0 : else if( nEdgeType == ET_CIRCULAR_ARC )
248 : {
249 : double dfCenterX;
250 : double dfCenterY;
251 : double dfRadius;
252 : double dfStartAngle;
253 : double dfEndAngle;
254 0 : int bCounterClockwise = FALSE;
255 :
256 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 10 )
257 0 : dfCenterX = atof(szLineBuf);
258 : else
259 0 : break;
260 :
261 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 20 )
262 0 : dfCenterY = atof(szLineBuf);
263 : else
264 0 : break;
265 :
266 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 40 )
267 0 : dfRadius = atof(szLineBuf);
268 : else
269 0 : break;
270 :
271 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 50 )
272 0 : dfStartAngle = -1 * atof(szLineBuf);
273 : else
274 0 : break;
275 :
276 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 51 )
277 0 : dfEndAngle = -1 * atof(szLineBuf);
278 : else
279 0 : break;
280 :
281 0 : if( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) == 73 )
282 0 : bCounterClockwise = atoi(szLineBuf);
283 0 : else if (nCode >= 0)
284 0 : poDS->UnreadValue();
285 :
286 0 : if( bCounterClockwise )
287 : {
288 0 : double dfTemp = dfStartAngle;
289 0 : dfStartAngle = dfEndAngle;
290 0 : dfEndAngle = dfTemp;
291 : }
292 :
293 0 : if( dfStartAngle > dfEndAngle )
294 0 : dfEndAngle += 360.0;
295 :
296 : OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
297 : dfCenterX, dfCenterY, 0.0,
298 : dfRadius, dfRadius, 0.0,
299 0 : dfStartAngle, dfEndAngle, 0.0 );
300 :
301 0 : poArc->flattenTo2D();
302 :
303 0 : poGC->addGeometryDirectly( poArc );
304 : }
305 :
306 : /* -------------------------------------------------------------------- */
307 : /* Process an elliptical arc. */
308 : /* -------------------------------------------------------------------- */
309 0 : else if( nEdgeType == ET_ELLIPTIC_ARC )
310 : {
311 : double dfCenterX;
312 : double dfCenterY;
313 : double dfMajorRadius, dfMinorRadius;
314 : double dfMajorX, dfMajorY;
315 : double dfStartAngle;
316 : double dfEndAngle;
317 : double dfRotation;
318 : double dfRatio;
319 0 : int bCounterClockwise = FALSE;
320 :
321 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 10 )
322 0 : dfCenterX = atof(szLineBuf);
323 : else
324 0 : break;
325 :
326 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 20 )
327 0 : dfCenterY = atof(szLineBuf);
328 : else
329 0 : break;
330 :
331 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 11 )
332 0 : dfMajorX = atof(szLineBuf);
333 : else
334 0 : break;
335 :
336 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 21 )
337 0 : dfMajorY = atof(szLineBuf);
338 : else
339 0 : break;
340 :
341 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 40 )
342 0 : dfRatio = atof(szLineBuf) / 100.0;
343 : else
344 0 : break;
345 :
346 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 50 )
347 0 : dfStartAngle = -1 * atof(szLineBuf);
348 : else
349 0 : break;
350 :
351 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 51 )
352 0 : dfEndAngle = -1 * atof(szLineBuf);
353 : else
354 0 : break;
355 :
356 0 : if( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) == 73 )
357 0 : bCounterClockwise = atoi(szLineBuf);
358 0 : else if (nCode >= 0)
359 0 : poDS->UnreadValue();
360 :
361 0 : if( bCounterClockwise )
362 : {
363 0 : double dfTemp = dfStartAngle;
364 0 : dfStartAngle = dfEndAngle;
365 0 : dfEndAngle = dfTemp;
366 : }
367 :
368 0 : if( dfStartAngle > dfEndAngle )
369 0 : dfEndAngle += 360.0;
370 :
371 0 : dfMajorRadius = sqrt( dfMajorX * dfMajorX + dfMajorY * dfMajorY );
372 0 : dfMinorRadius = dfMajorRadius * dfRatio;
373 :
374 0 : dfRotation = -1 * atan2( dfMajorY, dfMajorX ) * 180 / PI;
375 :
376 : OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
377 : dfCenterX, dfCenterY, 0.0,
378 : dfMajorRadius, dfMinorRadius, dfRotation,
379 0 : dfStartAngle, dfEndAngle, 0.0 );
380 :
381 0 : poArc->flattenTo2D();
382 :
383 0 : poGC->addGeometryDirectly( poArc );
384 : }
385 : else
386 : {
387 : CPLDebug( "DXF", "Unsupported HATCH boundary line type:%d",
388 0 : nEdgeType );
389 0 : return OGRERR_UNSUPPORTED_OPERATION;
390 : }
391 : }
392 :
393 : /* -------------------------------------------------------------------- */
394 : /* Skip through source boundary objects if present. */
395 : /* -------------------------------------------------------------------- */
396 0 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
397 0 : if( nCode != 97 )
398 : {
399 0 : if (nCode < 0)
400 0 : return OGRERR_FAILURE;
401 0 : poDS->UnreadValue();
402 : }
403 : else
404 : {
405 0 : int iObj, nObjCount = atoi(szLineBuf);
406 :
407 0 : for( iObj = 0; iObj < nObjCount; iObj++ )
408 : {
409 0 : if (poDS->ReadValue( szLineBuf, sizeof(szLineBuf) ) < 0)
410 0 : return OGRERR_FAILURE;
411 : }
412 : }
413 :
414 0 : return OGRERR_NONE;
415 : }
416 :
417 : /************************************************************************/
418 : /* CollectPolylinePath() */
419 : /************************************************************************/
420 :
421 4 : OGRErr OGRDXFLayer::CollectPolylinePath( OGRGeometryCollection *poGC )
422 :
423 : {
424 : int nCode;
425 : char szLineBuf[257];
426 4 : DXFSmoothPolyline oSmoothPolyline;
427 4 : double dfBulge = 0.0;
428 4 : double dfX = 0.0, dfY = 0.0;
429 4 : int bHaveX = FALSE, bHaveY = FALSE;
430 4 : int bIsClosed = FALSE;
431 4 : int nVertexCount = -1;
432 4 : int bHaveBulges = FALSE;
433 :
434 : /* -------------------------------------------------------------------- */
435 : /* Read the boundary path type. */
436 : /* -------------------------------------------------------------------- */
437 56 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
438 : {
439 52 : if( nVertexCount > 0 && (int) oSmoothPolyline.size() == nVertexCount )
440 4 : break;
441 :
442 48 : switch( nCode )
443 : {
444 : case 93:
445 4 : nVertexCount = atoi(szLineBuf);
446 4 : break;
447 :
448 : case 72:
449 4 : bHaveBulges = atoi(szLineBuf);
450 4 : break;
451 :
452 : case 73:
453 4 : bIsClosed = atoi(szLineBuf);
454 4 : break;
455 :
456 : case 10:
457 18 : if( bHaveX && bHaveY )
458 : {
459 0 : oSmoothPolyline.AddPoint(dfX, dfY, 0.0, dfBulge);
460 0 : dfBulge = 0.0;
461 0 : bHaveY = FALSE;
462 : }
463 18 : dfX = CPLAtof(szLineBuf);
464 18 : bHaveX = TRUE;
465 18 : break;
466 :
467 : case 20:
468 18 : if( bHaveX && bHaveY )
469 : {
470 0 : oSmoothPolyline.AddPoint( dfX, dfY, 0.0, dfBulge );
471 0 : dfBulge = 0.0;
472 0 : bHaveX = bHaveY = FALSE;
473 : }
474 18 : dfY = CPLAtof(szLineBuf);
475 18 : bHaveY = TRUE;
476 18 : if( bHaveX && bHaveY && !bHaveBulges )
477 : {
478 18 : oSmoothPolyline.AddPoint( dfX, dfY, 0.0, dfBulge );
479 18 : dfBulge = 0.0;
480 18 : bHaveX = bHaveY = FALSE;
481 : }
482 18 : break;
483 :
484 : case 42:
485 0 : dfBulge = CPLAtof(szLineBuf);
486 0 : if( bHaveX && bHaveY )
487 : {
488 0 : oSmoothPolyline.AddPoint( dfX, dfY, 0.0, dfBulge );
489 0 : dfBulge = 0.0;
490 0 : bHaveX = bHaveY = FALSE;
491 : }
492 : break;
493 :
494 : default:
495 : break;
496 : }
497 : }
498 :
499 4 : if( nCode != 10 && nCode != 20 && nCode != 42 && nCode >= 0)
500 4 : poDS->UnreadValue();
501 :
502 4 : if( bHaveX && bHaveY )
503 0 : oSmoothPolyline.AddPoint(dfX, dfY, 0.0, dfBulge);
504 :
505 4 : if( bIsClosed )
506 4 : oSmoothPolyline.Close();
507 :
508 4 : poGC->addGeometryDirectly( oSmoothPolyline.Tesselate() );
509 :
510 : /* -------------------------------------------------------------------- */
511 : /* Skip through source boundary objects if present. */
512 : /* -------------------------------------------------------------------- */
513 4 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
514 4 : if( nCode != 97 )
515 : {
516 0 : if (nCode < 0)
517 0 : return OGRERR_FAILURE;
518 0 : poDS->UnreadValue();
519 : }
520 : else
521 : {
522 4 : int iObj, nObjCount = atoi(szLineBuf);
523 :
524 4 : for( iObj = 0; iObj < nObjCount; iObj++ )
525 : {
526 0 : if (poDS->ReadValue( szLineBuf, sizeof(szLineBuf) ) < 0)
527 0 : return OGRERR_FAILURE;
528 : }
529 : }
530 4 : return OGRERR_NONE;
531 : }
532 :
533 :
|