1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dxfrenderer.cpp
3 // Purpose: DXF reader and renderer
4 // Author: Sandro Sigala
7 // Copyright: (c) Sandro Sigala
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
22 #include "wx/wfstream.h"
23 #include "wx/txtstrm.h"
26 #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library"
30 #include <OpenGL/glu.h>
37 #include "dxfrenderer.h"
39 #include "wx/listimpl.cpp"
40 WX_DEFINE_LIST(DXFEntityList
)
41 WX_DEFINE_LIST(DXFLayerList
)
43 // Conversion table from AutoCAD ACI colours to RGB values
44 static const struct { unsigned char r
, g
, b
; } aci_to_rgb
[256] = {
45 /* 0 */ {255, 255, 255},
47 /* 2 */ {255, 255, 0},
49 /* 4 */ { 0, 255, 255},
51 /* 6 */ {255, 0, 255},
52 /* 7 */ {255, 255, 255},
53 /* 8 */ {128, 128, 128},
54 /* 9 */ {192, 192, 192},
56 /* 11 */ {255, 127, 127},
58 /* 13 */ {204, 102, 102},
60 /* 15 */ {153, 76, 76},
62 /* 17 */ {127, 63, 63},
64 /* 19 */ { 76, 38, 38},
65 /* 20 */ {255, 63, 0},
66 /* 21 */ {255, 159, 127},
67 /* 22 */ {204, 51, 0},
68 /* 23 */ {204, 127, 102},
69 /* 24 */ {153, 38, 0},
70 /* 25 */ {153, 95, 76},
71 /* 26 */ {127, 31, 0},
72 /* 27 */ {127, 79, 63},
73 /* 28 */ { 76, 19, 0},
74 /* 29 */ { 76, 47, 38},
75 /* 30 */ {255, 127, 0},
76 /* 31 */ {255, 191, 127},
77 /* 32 */ {204, 102, 0},
78 /* 33 */ {204, 153, 102},
79 /* 34 */ {153, 76, 0},
80 /* 35 */ {153, 114, 76},
81 /* 36 */ {127, 63, 0},
82 /* 37 */ {127, 95, 63},
83 /* 38 */ { 76, 38, 0},
84 /* 39 */ { 76, 57, 38},
85 /* 40 */ {255, 191, 0},
86 /* 41 */ {255, 223, 127},
87 /* 42 */ {204, 153, 0},
88 /* 43 */ {204, 178, 102},
89 /* 44 */ {153, 114, 0},
90 /* 45 */ {153, 133, 76},
91 /* 46 */ {127, 95, 0},
92 /* 47 */ {127, 111, 63},
93 /* 48 */ { 76, 57, 0},
94 /* 49 */ { 76, 66, 38},
95 /* 50 */ {255, 255, 0},
96 /* 51 */ {255, 255, 127},
97 /* 52 */ {204, 204, 0},
98 /* 53 */ {204, 204, 102},
99 /* 54 */ {153, 153, 0},
100 /* 55 */ {153, 153, 76},
101 /* 56 */ {127, 127, 0},
102 /* 57 */ {127, 127, 63},
103 /* 58 */ { 76, 76, 0},
104 /* 59 */ { 76, 76, 38},
105 /* 60 */ {191, 255, 0},
106 /* 61 */ {223, 255, 127},
107 /* 62 */ {153, 204, 0},
108 /* 63 */ {178, 204, 102},
109 /* 64 */ {114, 153, 0},
110 /* 65 */ {133, 153, 76},
111 /* 66 */ { 95, 127, 0},
112 /* 67 */ {111, 127, 63},
113 /* 68 */ { 57, 76, 0},
114 /* 69 */ { 66, 76, 38},
115 /* 70 */ {127, 255, 0},
116 /* 71 */ {191, 255, 127},
117 /* 72 */ {102, 204, 0},
118 /* 73 */ {153, 204, 102},
119 /* 74 */ { 76, 153, 0},
120 /* 75 */ {114, 153, 76},
121 /* 76 */ { 63, 127, 0},
122 /* 77 */ { 95, 127, 63},
123 /* 78 */ { 38, 76, 0},
124 /* 79 */ { 57, 76, 38},
125 /* 80 */ { 63, 255, 0},
126 /* 81 */ {159, 255, 127},
127 /* 82 */ { 51, 204, 0},
128 /* 83 */ {127, 204, 102},
129 /* 84 */ { 38, 153, 0},
130 /* 85 */ { 95, 153, 76},
131 /* 86 */ { 31, 127, 0},
132 /* 87 */ { 79, 127, 63},
133 /* 88 */ { 19, 76, 0},
134 /* 89 */ { 47, 76, 38},
135 /* 90 */ { 0, 255, 0},
136 /* 91 */ {127, 255, 127},
137 /* 92 */ { 0, 204, 0},
138 /* 93 */ {102, 204, 102},
139 /* 94 */ { 0, 153, 0},
140 /* 95 */ { 76, 153, 76},
141 /* 96 */ { 0, 127, 0},
142 /* 97 */ { 63, 127, 63},
143 /* 98 */ { 0, 76, 0},
144 /* 99 */ { 38, 76, 38},
145 /* 100 */ { 0, 255, 63},
146 /* 101 */ {127, 255, 159},
147 /* 102 */ { 0, 204, 51},
148 /* 103 */ {102, 204, 127},
149 /* 104 */ { 0, 153, 38},
150 /* 105 */ { 76, 153, 95},
151 /* 106 */ { 0, 127, 31},
152 /* 107 */ { 63, 127, 79},
153 /* 108 */ { 0, 76, 19},
154 /* 109 */ { 38, 76, 47},
155 /* 110 */ { 0, 255, 127},
156 /* 111 */ {127, 255, 191},
157 /* 112 */ { 0, 204, 102},
158 /* 113 */ {102, 204, 153},
159 /* 114 */ { 0, 153, 76},
160 /* 115 */ { 76, 153, 114},
161 /* 116 */ { 0, 127, 63},
162 /* 117 */ { 63, 127, 95},
163 /* 118 */ { 0, 76, 38},
164 /* 119 */ { 38, 76, 57},
165 /* 120 */ { 0, 255, 191},
166 /* 121 */ {127, 255, 223},
167 /* 122 */ { 0, 204, 153},
168 /* 123 */ {102, 204, 178},
169 /* 124 */ { 0, 153, 114},
170 /* 125 */ { 76, 153, 133},
171 /* 126 */ { 0, 127, 95},
172 /* 127 */ { 63, 127, 111},
173 /* 128 */ { 0, 76, 57},
174 /* 129 */ { 38, 76, 66},
175 /* 130 */ { 0, 255, 255},
176 /* 131 */ {127, 255, 255},
177 /* 132 */ { 0, 204, 204},
178 /* 133 */ {102, 204, 204},
179 /* 134 */ { 0, 153, 153},
180 /* 135 */ { 76, 153, 153},
181 /* 136 */ { 0, 127, 127},
182 /* 137 */ { 63, 127, 127},
183 /* 138 */ { 0, 76, 76},
184 /* 139 */ { 38, 76, 76},
185 /* 140 */ { 0, 191, 255},
186 /* 141 */ {127, 223, 255},
187 /* 142 */ { 0, 153, 204},
188 /* 143 */ {102, 178, 204},
189 /* 144 */ { 0, 114, 153},
190 /* 145 */ { 76, 133, 153},
191 /* 146 */ { 0, 95, 127},
192 /* 147 */ { 63, 111, 127},
193 /* 148 */ { 0, 57, 76},
194 /* 149 */ { 38, 66, 76},
195 /* 150 */ { 0, 127, 255},
196 /* 151 */ {127, 191, 255},
197 /* 152 */ { 0, 102, 204},
198 /* 153 */ {102, 153, 204},
199 /* 154 */ { 0, 76, 153},
200 /* 155 */ { 76, 114, 153},
201 /* 156 */ { 0, 63, 127},
202 /* 157 */ { 63, 95, 127},
203 /* 158 */ { 0, 38, 76},
204 /* 159 */ { 38, 57, 76},
205 /* 160 */ { 0, 63, 255},
206 /* 161 */ {127, 159, 255},
207 /* 162 */ { 0, 51, 204},
208 /* 163 */ {102, 127, 204},
209 /* 164 */ { 0, 38, 153},
210 /* 165 */ { 76, 95, 153},
211 /* 166 */ { 0, 31, 127},
212 /* 167 */ { 63, 79, 127},
213 /* 168 */ { 0, 19, 76},
214 /* 169 */ { 38, 47, 76},
215 /* 170 */ { 0, 0, 255},
216 /* 171 */ {127, 127, 255},
217 /* 172 */ { 0, 0, 204},
218 /* 173 */ {102, 102, 204},
219 /* 174 */ { 0, 0, 153},
220 /* 175 */ { 76, 76, 153},
221 /* 176 */ { 0, 0, 127},
222 /* 177 */ { 63, 63, 127},
223 /* 178 */ { 0, 0, 76},
224 /* 179 */ { 38, 38, 76},
225 /* 180 */ { 63, 0, 255},
226 /* 181 */ {159, 127, 255},
227 /* 182 */ { 51, 0, 204},
228 /* 183 */ {127, 102, 204},
229 /* 184 */ { 38, 0, 153},
230 /* 185 */ { 95, 76, 153},
231 /* 186 */ { 31, 0, 127},
232 /* 187 */ { 79, 63, 127},
233 /* 188 */ { 19, 0, 76},
234 /* 189 */ { 47, 38, 76},
235 /* 190 */ {127, 0, 255},
236 /* 191 */ {191, 127, 255},
237 /* 192 */ {102, 0, 204},
238 /* 193 */ {153, 102, 204},
239 /* 194 */ { 76, 0, 153},
240 /* 195 */ {114, 76, 153},
241 /* 196 */ { 63, 0, 127},
242 /* 197 */ { 95, 63, 127},
243 /* 198 */ { 38, 0, 76},
244 /* 199 */ { 57, 38, 76},
245 /* 200 */ {191, 0, 255},
246 /* 201 */ {223, 127, 255},
247 /* 202 */ {153, 0, 204},
248 /* 203 */ {178, 102, 204},
249 /* 204 */ {114, 0, 153},
250 /* 205 */ {133, 76, 153},
251 /* 206 */ { 95, 0, 127},
252 /* 207 */ {111, 63, 127},
253 /* 208 */ { 57, 0, 76},
254 /* 209 */ { 66, 38, 76},
255 /* 210 */ {255, 0, 255},
256 /* 211 */ {255, 127, 255},
257 /* 212 */ {204, 0, 204},
258 /* 213 */ {204, 102, 204},
259 /* 214 */ {153, 0, 153},
260 /* 215 */ {153, 76, 153},
261 /* 216 */ {127, 0, 127},
262 /* 217 */ {127, 63, 127},
263 /* 218 */ { 76, 0, 76},
264 /* 219 */ { 76, 38, 76},
265 /* 220 */ {255, 0, 191},
266 /* 221 */ {255, 127, 223},
267 /* 222 */ {204, 0, 153},
268 /* 223 */ {204, 102, 178},
269 /* 224 */ {153, 0, 114},
270 /* 225 */ {153, 76, 133},
271 /* 226 */ {127, 0, 95},
272 /* 227 */ {127, 63, 111},
273 /* 228 */ { 76, 0, 57},
274 /* 229 */ { 76, 38, 66},
275 /* 230 */ {255, 0, 127},
276 /* 231 */ {255, 127, 191},
277 /* 232 */ {204, 0, 102},
278 /* 233 */ {204, 102, 153},
279 /* 234 */ {153, 0, 76},
280 /* 235 */ {153, 76, 114},
281 /* 236 */ {127, 0, 63},
282 /* 237 */ {127, 63, 95},
283 /* 238 */ { 76, 0, 38},
284 /* 239 */ { 76, 38, 57},
285 /* 240 */ {255, 0, 63},
286 /* 241 */ {255, 127, 159},
287 /* 242 */ {204, 0, 51},
288 /* 243 */ {204, 102, 127},
289 /* 244 */ {153, 0, 38},
290 /* 245 */ {153, 76, 95},
291 /* 246 */ {127, 0, 31},
292 /* 247 */ {127, 63, 79},
293 /* 248 */ { 76, 0, 19},
294 /* 249 */ { 76, 38, 47},
295 /* 250 */ { 51, 51, 51},
296 /* 251 */ { 91, 91, 91},
297 /* 252 */ {132, 132, 132},
298 /* 253 */ {173, 173, 173},
299 /* 254 */ {214, 214, 214},
300 /* 255 */ {255, 255, 255}
303 inline DXFVector
Cross(const DXFVector
& v1
, const DXFVector
& v2
)
305 return DXFVector(v1
.y
*v2
.z
- v1
.z
*v2
.y
, v1
.z
*v2
.x
- v1
.x
*v2
.z
, v1
.x
*v2
.y
- v1
.y
*v2
.x
);
308 void DXFFace::CalculateNormal()
318 float mod
= sqrt(n
.x
*n
.x
+ n
.y
*n
.y
+ n
.z
*n
.z
);
324 // convert an AutoCAD ACI colour to wxWidgets RGB colour
325 inline wxColour
ACIColourToRGB(int col
)
327 wxASSERT(col
>= 0 && col
<= 255);
328 return wxColour(aci_to_rgb
[col
].r
, aci_to_rgb
[col
].g
, aci_to_rgb
[col
].b
);
331 // DXFReader constructor
332 DXFRenderer::DXFRenderer()
337 // DXFReader destructor
338 DXFRenderer::~DXFRenderer()
343 // deallocate all the dynamic data
344 void DXFRenderer::Clear()
348 for (DXFLayerList::compatibility_iterator node
= m_layers
.GetFirst(); node
; node
= node
->GetNext())
350 DXFLayer
*current
= node
->GetData();
356 for (DXFEntityList::compatibility_iterator node
= m_entities
.GetFirst(); node
; node
= node
->GetNext())
358 DXFEntity
*current
= node
->GetData();
365 int DXFRenderer::GetLayerColour(const wxString
& layer
) const
367 for (DXFLayerList::compatibility_iterator node
= m_layers
.GetFirst(); node
; node
= node
->GetNext())
369 DXFLayer
*current
= node
->GetData();
370 if (current
->name
== layer
)
371 return current
->colour
;
376 // read two sequential lines
377 inline void GetLines(wxTextInputStream
& text
, wxString
& line1
, wxString
& line2
)
379 line1
= text
.ReadLine().Trim().Trim(false);
380 line2
= text
.ReadLine().Trim().Trim(false);
383 // parse header section: just skip everything
384 bool DXFRenderer::ParseHeader(wxInputStream
& stream
)
386 wxTextInputStream
text(stream
);
387 wxString line1
, line2
;
388 while (stream
.CanRead())
390 GetLines(text
, line1
, line2
);
391 if (line1
== wxT("0") && line2
== wxT("ENDSEC"))
397 // parse tables section: save layers name and colour
398 bool DXFRenderer::ParseTables(wxInputStream
& stream
)
400 wxTextInputStream
text(stream
);
401 wxString line1
, line2
;
404 while (stream
.CanRead())
406 GetLines(text
, line1
, line2
);
407 if (line1
== wxT("0") && inlayer
)
410 if (!layer
.name
.IsEmpty() && layer
.colour
!= -1)
412 DXFLayer
*p
= new DXFLayer
;
413 p
->name
= layer
.name
;
414 p
->colour
= layer
.colour
;
420 if (line1
== wxT("0") && line2
== wxT("ENDSEC"))
422 else if (line1
== wxT("0") && line2
== wxT("LAYER"))
426 if (line1
== wxT("2")) // layer name
428 else if (line1
== wxT("62")) // ACI colour
439 // This method is used instead of numStr.ToDouble(d) because the latter
440 // (wxString::ToDouble()) takes the systems proper locale into account,
441 // whereas the implementation below works with the default locale.
442 // (Converting numbers that are formatted in the default locale can fail
443 // with system locales that use e.g. the comma as the decimal separator.)
444 static double ToDouble(const wxString
& numStr
)
447 std::string
numStr_(numStr
.c_str());
448 std::istringstream
iss(numStr_
);
455 // parse entities section: save 3DFACE and LINE entities
456 bool DXFRenderer::ParseEntities(wxInputStream
& stream
)
458 wxTextInputStream
text(stream
);
459 wxString line1
, line2
;
460 int state
= 0; // 0: none, 1: 3DFACE, 2: LINE
464 while (stream
.CanRead())
466 GetLines(text
, line1
, line2
);
467 if (line1
== wxT("0") && state
> 0)
470 if (state
== 1) // 3DFACE
472 DXFFace
*p
= new DXFFace
;
477 p
->CalculateNormal();
481 p
->colour
= GetLayerColour(layer
);
482 m_entities
.Append(p
);
483 colour
= -1; layer
= wxEmptyString
;
484 v
[0] = v
[1] = v
[2] = v
[3] = DXFVector();
487 else if (state
== 2) // LINE
489 DXFLine
*p
= new DXFLine
;
495 p
->colour
= GetLayerColour(layer
);
496 m_entities
.Append(p
);
497 colour
= -1; layer
= wxEmptyString
;
498 v
[0] = v
[1] = v
[2] = v
[3] = DXFVector();
502 if (line1
== wxT("0") && line2
== wxT("ENDSEC"))
504 else if (line1
== wxT("0") && line2
== wxT("3DFACE"))
506 else if (line1
== wxT("0") && line2
== wxT("LINE"))
510 const double d
=ToDouble(line2
);
512 if (line1
== wxT("10"))
514 else if (line1
== wxT("20"))
516 else if (line1
== wxT("30"))
518 else if (line1
== wxT("11"))
520 else if (line1
== wxT("21"))
522 else if (line1
== wxT("31"))
524 else if (line1
== wxT("12"))
526 else if (line1
== wxT("22"))
528 else if (line1
== wxT("32"))
530 else if (line1
== wxT("13"))
532 else if (line1
== wxT("23"))
534 else if (line1
== wxT("33"))
536 else if (line1
== wxT("8")) // layer
538 else if (line1
== wxT("62")) // colour
549 // parse and load a DXF file
550 // currently pretty limited, but knows enought do handle 3DFACEs and LINEs
551 bool DXFRenderer::Load(wxInputStream
& stream
)
554 wxTextInputStream
text(stream
);
556 wxString line1
, line2
;
557 while (stream
.CanRead())
559 GetLines(text
, line1
, line2
);
560 if (line1
== wxT("999")) // comment
562 else if (line1
== wxT("0") && line2
== wxT("SECTION"))
564 GetLines(text
, line1
, line2
);
565 if (line1
== wxT("2"))
567 if (line2
== wxT("HEADER"))
569 if (!ParseHeader(stream
))
572 else if (line2
== wxT("TABLES"))
574 if (!ParseTables(stream
))
577 else if (line2
== wxT("ENTITIES"))
579 if (!ParseEntities(stream
))
591 inline float mymin(float x
, float y
) { return x
< y
? x
: y
; }
592 inline float mymax(float x
, float y
) { return x
> y
? x
: y
; }
594 // Scale object boundings to [-5,5]
595 void DXFRenderer::NormalizeEntities()
597 // calculate current min and max boundings of object
598 DXFVector
minv(10e20f
, 10e20f
, 10e20f
);
599 DXFVector
maxv(-10e20f
, -10e20f
, -10e20f
);
600 for (DXFEntityList::compatibility_iterator node
= m_entities
.GetFirst(); node
; node
= node
->GetNext())
602 DXFEntity
*p
= node
->GetData();
603 if (p
->type
== DXFEntity::Line
)
605 DXFLine
*line
= (DXFLine
*)p
;
606 const DXFVector
*v
[2] = { &line
->v0
, &line
->v1
};
607 for (int i
= 0; i
< 2; ++i
)
609 minv
.x
= mymin(v
[i
]->x
, minv
.x
);
610 minv
.y
= mymin(v
[i
]->y
, minv
.y
);
611 minv
.z
= mymin(v
[i
]->z
, minv
.z
);
612 maxv
.x
= mymax(v
[i
]->x
, maxv
.x
);
613 maxv
.y
= mymax(v
[i
]->y
, maxv
.y
);
614 maxv
.z
= mymax(v
[i
]->z
, maxv
.z
);
616 } else if (p
->type
== DXFEntity::Face
)
618 DXFFace
*face
= (DXFFace
*)p
;
619 const DXFVector
*v
[4] = { &face
->v0
, &face
->v1
, &face
->v2
, &face
->v3
};
620 for (int i
= 0; i
< 4; ++i
)
622 minv
.x
= mymin(v
[i
]->x
, minv
.x
);
623 minv
.y
= mymin(v
[i
]->y
, minv
.y
);
624 minv
.z
= mymin(v
[i
]->z
, minv
.z
);
625 maxv
.x
= mymax(v
[i
]->x
, maxv
.x
);
626 maxv
.y
= mymax(v
[i
]->y
, maxv
.y
);
627 maxv
.z
= mymax(v
[i
]->z
, maxv
.z
);
632 // rescale object down to [-5,5]
633 DXFVector
span(maxv
.x
- minv
.x
, maxv
.y
- minv
.y
, maxv
.z
- minv
.z
);
634 float factor
= mymin(mymin(10.0f
/ span
.x
, 10.0f
/ span
.y
), 10.0f
/ span
.z
);
635 for (DXFEntityList::compatibility_iterator node2
= m_entities
.GetFirst(); node2
; node2
= node2
->GetNext())
637 DXFEntity
*p
= node2
->GetData();
638 if (p
->type
== DXFEntity::Line
)
640 DXFLine
*line
= (DXFLine
*)p
;
641 DXFVector
*v
[2] = { &line
->v0
, &line
->v1
};
642 for (int i
= 0; i
< 2; ++i
)
644 v
[i
]->x
-= minv
.x
+ span
.x
/2; v
[i
]->x
*= factor
;
645 v
[i
]->y
-= minv
.y
+ span
.y
/2; v
[i
]->y
*= factor
;
646 v
[i
]->z
-= minv
.z
+ span
.z
/2; v
[i
]->z
*= factor
;
648 } else if (p
->type
== DXFEntity::Face
)
650 DXFFace
*face
= (DXFFace
*)p
;
651 DXFVector
*v
[4] = { &face
->v0
, &face
->v1
, &face
->v2
, &face
->v3
};
652 for (int i
= 0; i
< 4; ++i
)
654 v
[i
]->x
-= minv
.x
+ span
.x
/2; v
[i
]->x
*= factor
;
655 v
[i
]->y
-= minv
.y
+ span
.y
/2; v
[i
]->y
*= factor
;
656 v
[i
]->z
-= minv
.z
+ span
.z
/2; v
[i
]->z
*= factor
;
662 // OpenGL renderer for DXF entities
663 void DXFRenderer::Render() const
668 for (DXFEntityList::compatibility_iterator node
= m_entities
.GetFirst(); node
; node
= node
->GetNext())
670 DXFEntity
*p
= node
->GetData();
671 wxColour c
= ACIColourToRGB(p
->colour
);
672 if (p
->type
== DXFEntity::Line
)
674 DXFLine
*line
= (DXFLine
*)p
;
676 glColor3f(c
.Red()/255.0,c
.Green()/255.0,c
.Blue()/255.0);
677 glVertex3f(line
->v0
.x
, line
->v0
.y
, line
->v0
.z
);
678 glVertex3f(line
->v1
.x
, line
->v1
.y
, line
->v1
.z
);
681 else if (p
->type
== DXFEntity::Face
)
683 DXFFace
*face
= (DXFFace
*)p
;
684 glBegin(GL_TRIANGLES
);
685 glColor3f(c
.Red()/255.0,c
.Green()/255.0,c
.Blue()/255.0);
686 glNormal3f(face
->n
.x
, face
->n
.y
, face
->n
.z
);
687 glVertex3f(face
->v0
.x
, face
->v0
.y
, face
->v0
.z
);
688 glVertex3f(face
->v1
.x
, face
->v1
.y
, face
->v1
.z
);
689 glVertex3f(face
->v2
.x
, face
->v2
.y
, face
->v2
.z
);