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