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 4 : OGRFeature *OGRDXFLayer::TranslateHATCH()
52 :
53 : {
54 : char szLineBuf[257];
55 : int nCode;
56 4 : OGRFeature *poFeature = new OGRFeature( poFeatureDefn );
57 :
58 4 : CPLString osHatchPattern;
59 4 : int nFillFlag = 0;
60 4 : OGRGeometryCollection oGC;
61 :
62 40 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
63 : {
64 32 : switch( nCode )
65 : {
66 : case 70:
67 4 : nFillFlag = atoi(szLineBuf);
68 4 : break;
69 :
70 : case 2:
71 4 : osHatchPattern = szLineBuf;
72 4 : poFeature->SetField( "Text", osHatchPattern.c_str() );
73 4 : break;
74 :
75 : case 91:
76 : {
77 4 : int nBoundaryPathCount = atoi(szLineBuf);
78 : int iBoundary;
79 :
80 8 : for( iBoundary = 0; iBoundary < nBoundaryPathCount; iBoundary++ )
81 : {
82 4 : if (CollectBoundaryPath( &oGC ) != OGRERR_NONE)
83 0 : break;
84 : }
85 : }
86 4 : break;
87 :
88 : default:
89 20 : TranslateGenericProperty( poFeature, nCode, szLineBuf );
90 : break;
91 : }
92 : }
93 :
94 4 : if( nCode == 0 )
95 4 : poDS->UnreadValue();
96 :
97 : /* -------------------------------------------------------------------- */
98 : /* Try to turn the set of lines into something useful. */
99 : /* -------------------------------------------------------------------- */
100 : OGRErr eErr;
101 :
102 : OGRGeometryH hFinalGeom =
103 : OGRBuildPolygonFromEdges( (OGRGeometryH) &oGC,
104 4 : TRUE, TRUE, 0.0000001, &eErr );
105 :
106 4 : poFeature->SetGeometryDirectly( (OGRGeometry *) hFinalGeom );
107 :
108 : /* -------------------------------------------------------------------- */
109 : /* Work out the color for this feature. For now we just assume */
110 : /* solid fill. We cannot trivially translate the various sorts */
111 : /* of hatching. */
112 : /* -------------------------------------------------------------------- */
113 4 : CPLString osLayer = poFeature->GetFieldAsString("Layer");
114 :
115 4 : int nColor = 256;
116 :
117 4 : if( oStyleProperties.count("Color") > 0 )
118 0 : nColor = atoi(oStyleProperties["Color"]);
119 :
120 : // Use layer color?
121 4 : if( nColor < 1 || nColor > 255 )
122 : {
123 4 : const char *pszValue = poDS->LookupLayerProperty( osLayer, "Color" );
124 4 : if( pszValue != NULL )
125 4 : nColor = atoi(pszValue);
126 : }
127 :
128 : /* -------------------------------------------------------------------- */
129 : /* Setup the style string. */
130 : /* -------------------------------------------------------------------- */
131 4 : if( nColor >= 1 && nColor <= 255 )
132 : {
133 4 : CPLString osStyle;
134 4 : const unsigned char *pabyDXFColors = ACGetColorTable();
135 :
136 : osStyle.Printf( "BRUSH(fc:#%02x%02x%02x)",
137 4 : pabyDXFColors[nColor*3+0],
138 4 : pabyDXFColors[nColor*3+1],
139 12 : pabyDXFColors[nColor*3+2] );
140 :
141 4 : poFeature->SetStyleString( osStyle );
142 : }
143 :
144 4 : return poFeature;
145 : }
146 :
147 : /************************************************************************/
148 : /* CollectBoundaryPath() */
149 : /************************************************************************/
150 :
151 4 : OGRErr OGRDXFLayer::CollectBoundaryPath( OGRGeometryCollection *poGC )
152 :
153 : {
154 : int nCode;
155 : char szLineBuf[257];
156 :
157 : /* -------------------------------------------------------------------- */
158 : /* Read the boundary path type. */
159 : /* -------------------------------------------------------------------- */
160 4 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
161 4 : if( nCode != 92 )
162 0 : return OGRERR_FAILURE;
163 :
164 4 : int nBoundaryPathType = atoi(szLineBuf);
165 :
166 : /* ==================================================================== */
167 : /* Handle polyline loops. */
168 : /* ==================================================================== */
169 4 : if( nBoundaryPathType & 0x02 )
170 4 : return CollectPolylinePath( poGC );
171 :
172 : /* ==================================================================== */
173 : /* Handle non-polyline loops. */
174 : /* ==================================================================== */
175 :
176 : /* -------------------------------------------------------------------- */
177 : /* Read number of edges. */
178 : /* -------------------------------------------------------------------- */
179 0 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
180 0 : if( nCode != 93 )
181 0 : return OGRERR_FAILURE;
182 :
183 0 : int nEdgeCount = atoi(szLineBuf);
184 :
185 : /* -------------------------------------------------------------------- */
186 : /* Loop reading edges. */
187 : /* -------------------------------------------------------------------- */
188 : int iEdge;
189 :
190 0 : for( iEdge = 0; iEdge < nEdgeCount; iEdge++ )
191 : {
192 : /* -------------------------------------------------------------------- */
193 : /* Read the edge type. */
194 : /* -------------------------------------------------------------------- */
195 : #define ET_LINE 1
196 : #define ET_CIRCULAR_ARC 2
197 : #define ET_ELLIPTIC_ARC 3
198 : #define ET_SPLINE 4
199 :
200 0 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
201 0 : if( nCode != 72 )
202 0 : return OGRERR_FAILURE;
203 :
204 0 : int nEdgeType = atoi(szLineBuf);
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Process a line edge. */
208 : /* -------------------------------------------------------------------- */
209 0 : if( nEdgeType == ET_LINE )
210 : {
211 : double dfStartX;
212 : double dfStartY;
213 : double dfEndX;
214 : double dfEndY;
215 :
216 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 10 )
217 0 : dfStartX = atof(szLineBuf);
218 : else
219 0 : break;
220 :
221 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 20 )
222 0 : dfStartY = atof(szLineBuf);
223 : else
224 0 : break;
225 :
226 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 11 )
227 0 : dfEndX = atof(szLineBuf);
228 : else
229 0 : break;
230 :
231 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 21 )
232 0 : dfEndY = atof(szLineBuf);
233 : else
234 0 : break;
235 :
236 0 : OGRLineString *poLS = new OGRLineString();
237 :
238 0 : poLS->addPoint( dfStartX, dfStartY );
239 0 : poLS->addPoint( dfEndX, dfEndY );
240 :
241 0 : poGC->addGeometryDirectly( poLS );
242 : }
243 : /* -------------------------------------------------------------------- */
244 : /* Process a circular arc. */
245 : /* -------------------------------------------------------------------- */
246 0 : else if( nEdgeType == ET_CIRCULAR_ARC )
247 : {
248 : double dfCenterX;
249 : double dfCenterY;
250 : double dfRadius;
251 : double dfStartAngle;
252 : double dfEndAngle;
253 0 : int bCounterClockwise = FALSE;
254 :
255 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 10 )
256 0 : dfCenterX = atof(szLineBuf);
257 : else
258 0 : break;
259 :
260 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 20 )
261 0 : dfCenterY = atof(szLineBuf);
262 : else
263 0 : break;
264 :
265 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 40 )
266 0 : dfRadius = atof(szLineBuf);
267 : else
268 0 : break;
269 :
270 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 50 )
271 0 : dfStartAngle = -1 * atof(szLineBuf);
272 : else
273 0 : break;
274 :
275 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 51 )
276 0 : dfEndAngle = -1 * atof(szLineBuf);
277 : else
278 0 : break;
279 :
280 0 : if( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) == 73 )
281 0 : bCounterClockwise = atoi(szLineBuf);
282 0 : else if (nCode >= 0)
283 0 : poDS->UnreadValue();
284 :
285 0 : if( bCounterClockwise )
286 : {
287 0 : double dfTemp = dfStartAngle;
288 0 : dfStartAngle = dfEndAngle;
289 0 : dfEndAngle = dfTemp;
290 : }
291 :
292 0 : if( dfStartAngle > dfEndAngle )
293 0 : dfEndAngle += 360.0;
294 :
295 : OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
296 : dfCenterX, dfCenterY, 0.0,
297 : dfRadius, dfRadius, 0.0,
298 0 : dfStartAngle, dfEndAngle, 0.0 );
299 :
300 0 : poArc->flattenTo2D();
301 :
302 0 : poGC->addGeometryDirectly( poArc );
303 : }
304 :
305 : /* -------------------------------------------------------------------- */
306 : /* Process an elliptical arc. */
307 : /* -------------------------------------------------------------------- */
308 0 : else if( nEdgeType == ET_ELLIPTIC_ARC )
309 : {
310 : double dfCenterX;
311 : double dfCenterY;
312 : double dfMajorRadius, dfMinorRadius;
313 : double dfMajorX, dfMajorY;
314 : double dfStartAngle;
315 : double dfEndAngle;
316 : double dfRotation;
317 : double dfRatio;
318 0 : int bCounterClockwise = FALSE;
319 :
320 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 10 )
321 0 : dfCenterX = atof(szLineBuf);
322 : else
323 0 : break;
324 :
325 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 20 )
326 0 : dfCenterY = atof(szLineBuf);
327 : else
328 0 : break;
329 :
330 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 11 )
331 0 : dfMajorX = atof(szLineBuf);
332 : else
333 0 : break;
334 :
335 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 21 )
336 0 : dfMajorY = atof(szLineBuf);
337 : else
338 0 : break;
339 :
340 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 40 )
341 0 : dfRatio = atof(szLineBuf) / 100.0;
342 : else
343 0 : break;
344 :
345 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 50 )
346 0 : dfStartAngle = -1 * atof(szLineBuf);
347 : else
348 0 : break;
349 :
350 0 : if( poDS->ReadValue(szLineBuf,sizeof(szLineBuf)) == 51 )
351 0 : dfEndAngle = -1 * atof(szLineBuf);
352 : else
353 0 : break;
354 :
355 0 : if( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) == 73 )
356 0 : bCounterClockwise = atoi(szLineBuf);
357 0 : else if (nCode >= 0)
358 0 : poDS->UnreadValue();
359 :
360 0 : if( bCounterClockwise )
361 : {
362 0 : double dfTemp = dfStartAngle;
363 0 : dfStartAngle = dfEndAngle;
364 0 : dfEndAngle = dfTemp;
365 : }
366 :
367 0 : if( dfStartAngle > dfEndAngle )
368 0 : dfEndAngle += 360.0;
369 :
370 0 : dfMajorRadius = sqrt( dfMajorX * dfMajorX + dfMajorY * dfMajorY );
371 0 : dfMinorRadius = dfMajorRadius * dfRatio;
372 :
373 0 : dfRotation = -1 * atan2( dfMajorY, dfMajorX ) * 180 / PI;
374 :
375 : OGRGeometry *poArc = OGRGeometryFactory::approximateArcAngles(
376 : dfCenterX, dfCenterY, 0.0,
377 : dfMajorRadius, dfMinorRadius, dfRotation,
378 0 : dfStartAngle, dfEndAngle, 0.0 );
379 :
380 0 : poArc->flattenTo2D();
381 :
382 0 : poGC->addGeometryDirectly( poArc );
383 : }
384 : else
385 : {
386 : CPLDebug( "DXF", "Unsupported HATCH boundary line type:%d",
387 0 : nEdgeType );
388 0 : return OGRERR_UNSUPPORTED_OPERATION;
389 : }
390 : }
391 :
392 : /* -------------------------------------------------------------------- */
393 : /* Skip through source boundary objects if present. */
394 : /* -------------------------------------------------------------------- */
395 0 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
396 0 : if( nCode != 97 )
397 : {
398 0 : if (nCode < 0)
399 0 : return OGRERR_FAILURE;
400 0 : poDS->UnreadValue();
401 : }
402 : else
403 : {
404 0 : int iObj, nObjCount = atoi(szLineBuf);
405 :
406 0 : for( iObj = 0; iObj < nObjCount; iObj++ )
407 : {
408 0 : if (poDS->ReadValue( szLineBuf, sizeof(szLineBuf) ) < 0)
409 0 : return OGRERR_FAILURE;
410 : }
411 : }
412 :
413 0 : return OGRERR_NONE;
414 : }
415 :
416 : /************************************************************************/
417 : /* CollectPolylinePath() */
418 : /************************************************************************/
419 :
420 4 : OGRErr OGRDXFLayer::CollectPolylinePath( OGRGeometryCollection *poGC )
421 :
422 : {
423 : int nCode;
424 : char szLineBuf[257];
425 4 : DXFSmoothPolyline oSmoothPolyline;
426 4 : double dfBulge = 0.0;
427 4 : double dfX = 0.0, dfY = 0.0;
428 4 : int bHaveX = FALSE, bHaveY = FALSE;
429 4 : int bIsClosed = FALSE;
430 4 : int nVertexCount = -1;
431 4 : int bHaveBulges = FALSE;
432 :
433 : /* -------------------------------------------------------------------- */
434 : /* Read the boundary path type. */
435 : /* -------------------------------------------------------------------- */
436 52 : while( (nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf))) > 0 )
437 : {
438 44 : if( nVertexCount > 0 && (int) oSmoothPolyline.size() == nVertexCount )
439 0 : break;
440 :
441 44 : switch( nCode )
442 : {
443 : case 93:
444 4 : nVertexCount = atoi(szLineBuf);
445 4 : break;
446 :
447 : case 72:
448 4 : bHaveBulges = atoi(szLineBuf);
449 4 : break;
450 :
451 : case 73:
452 4 : bIsClosed = atoi(szLineBuf);
453 4 : break;
454 :
455 : case 10:
456 16 : if( bHaveX && bHaveY )
457 : {
458 0 : oSmoothPolyline.AddPoint(dfX, dfY, 0.0, dfBulge);
459 0 : dfBulge = 0.0;
460 0 : bHaveY = FALSE;
461 : }
462 16 : dfX = CPLAtof(szLineBuf);
463 16 : bHaveX = TRUE;
464 16 : break;
465 :
466 : case 20:
467 16 : if( bHaveX && bHaveY )
468 : {
469 0 : oSmoothPolyline.AddPoint( dfX, dfY, 0.0, dfBulge );
470 0 : dfBulge = 0.0;
471 0 : bHaveX = bHaveY = FALSE;
472 : }
473 16 : dfY = CPLAtof(szLineBuf);
474 16 : bHaveY = TRUE;
475 16 : if( bHaveX && bHaveY && !bHaveBulges )
476 : {
477 16 : oSmoothPolyline.AddPoint( dfX, dfY, 0.0, dfBulge );
478 16 : dfBulge = 0.0;
479 16 : bHaveX = bHaveY = FALSE;
480 : }
481 16 : break;
482 :
483 : case 42:
484 0 : dfBulge = CPLAtof(szLineBuf);
485 0 : if( bHaveX && bHaveY )
486 : {
487 0 : oSmoothPolyline.AddPoint( dfX, dfY, 0.0, dfBulge );
488 0 : dfBulge = 0.0;
489 0 : bHaveX = bHaveY = FALSE;
490 : }
491 : break;
492 :
493 : default:
494 : break;
495 : }
496 : }
497 :
498 4 : if( nCode != 10 && nCode != 20 && nCode != 42 && nCode >= 0)
499 4 : poDS->UnreadValue();
500 :
501 4 : if( bHaveX && bHaveY )
502 0 : oSmoothPolyline.AddPoint(dfX, dfY, 0.0, dfBulge);
503 :
504 4 : if( bIsClosed )
505 4 : oSmoothPolyline.Close();
506 :
507 4 : poGC->addGeometryDirectly( oSmoothPolyline.Tesselate() );
508 :
509 : /* -------------------------------------------------------------------- */
510 : /* Skip through source boundary objects if present. */
511 : /* -------------------------------------------------------------------- */
512 4 : nCode = poDS->ReadValue(szLineBuf,sizeof(szLineBuf));
513 4 : if( nCode != 97 )
514 : {
515 4 : if (nCode < 0)
516 0 : return OGRERR_FAILURE;
517 4 : poDS->UnreadValue();
518 : }
519 : else
520 : {
521 0 : int iObj, nObjCount = atoi(szLineBuf);
522 :
523 0 : for( iObj = 0; iObj < nObjCount; iObj++ )
524 : {
525 0 : if (poDS->ReadValue( szLineBuf, sizeof(szLineBuf) ) < 0)
526 0 : return OGRERR_FAILURE;
527 : }
528 : }
529 4 : return OGRERR_NONE;
530 : }
531 :
532 :
|