///////////////////////////////////////////////////////////////////////////// // Name: dxfrenderer.cpp // Purpose: DXF reader and renderer // Author: Sandro Sigala // Modified by: // Created: 2005-11-10 // RCS-ID: $Id$ // Copyright: (c) Sandro Sigala // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/wfstream.h" #include "wx/txtstrm.h" #if !wxUSE_GLCANVAS #error "OpenGL required: set wxUSE_GLCANVAS to 1 and rebuild the library" #endif #ifdef __WXMAC__ # ifdef __DARWIN__ # include # else # include # endif #else # include #endif #include "dxfrenderer.h" #include "wx/listimpl.cpp" WX_DEFINE_LIST(DXFEntityList) WX_DEFINE_LIST(DXFLayerList) // Conversion table from AutoCAD ACI colours to RGB values static const struct { unsigned char r, g, b; } aci_to_rgb[256] = { /* 0 */ 255, 255, 255, /* 1 */ 255, 0, 0, /* 2 */ 255, 255, 0, /* 3 */ 0, 255, 0, /* 4 */ 0, 255, 255, /* 5 */ 0, 0, 255, /* 6 */ 255, 0, 255, /* 7 */ 255, 255, 255, /* 8 */ 128, 128, 128, /* 9 */ 192, 192, 192, /* 10 */ 255, 0, 0, /* 11 */ 255, 127, 127, /* 12 */ 204, 0, 0, /* 13 */ 204, 102, 102, /* 14 */ 153, 0, 0, /* 15 */ 153, 76, 76, /* 16 */ 127, 0, 0, /* 17 */ 127, 63, 63, /* 18 */ 76, 0, 0, /* 19 */ 76, 38, 38, /* 20 */ 255, 63, 0, /* 21 */ 255, 159, 127, /* 22 */ 204, 51, 0, /* 23 */ 204, 127, 102, /* 24 */ 153, 38, 0, /* 25 */ 153, 95, 76, /* 26 */ 127, 31, 0, /* 27 */ 127, 79, 63, /* 28 */ 76, 19, 0, /* 29 */ 76, 47, 38, /* 30 */ 255, 127, 0, /* 31 */ 255, 191, 127, /* 32 */ 204, 102, 0, /* 33 */ 204, 153, 102, /* 34 */ 153, 76, 0, /* 35 */ 153, 114, 76, /* 36 */ 127, 63, 0, /* 37 */ 127, 95, 63, /* 38 */ 76, 38, 0, /* 39 */ 76, 57, 38, /* 40 */ 255, 191, 0, /* 41 */ 255, 223, 127, /* 42 */ 204, 153, 0, /* 43 */ 204, 178, 102, /* 44 */ 153, 114, 0, /* 45 */ 153, 133, 76, /* 46 */ 127, 95, 0, /* 47 */ 127, 111, 63, /* 48 */ 76, 57, 0, /* 49 */ 76, 66, 38, /* 50 */ 255, 255, 0, /* 51 */ 255, 255, 127, /* 52 */ 204, 204, 0, /* 53 */ 204, 204, 102, /* 54 */ 153, 153, 0, /* 55 */ 153, 153, 76, /* 56 */ 127, 127, 0, /* 57 */ 127, 127, 63, /* 58 */ 76, 76, 0, /* 59 */ 76, 76, 38, /* 60 */ 191, 255, 0, /* 61 */ 223, 255, 127, /* 62 */ 153, 204, 0, /* 63 */ 178, 204, 102, /* 64 */ 114, 153, 0, /* 65 */ 133, 153, 76, /* 66 */ 95, 127, 0, /* 67 */ 111, 127, 63, /* 68 */ 57, 76, 0, /* 69 */ 66, 76, 38, /* 70 */ 127, 255, 0, /* 71 */ 191, 255, 127, /* 72 */ 102, 204, 0, /* 73 */ 153, 204, 102, /* 74 */ 76, 153, 0, /* 75 */ 114, 153, 76, /* 76 */ 63, 127, 0, /* 77 */ 95, 127, 63, /* 78 */ 38, 76, 0, /* 79 */ 57, 76, 38, /* 80 */ 63, 255, 0, /* 81 */ 159, 255, 127, /* 82 */ 51, 204, 0, /* 83 */ 127, 204, 102, /* 84 */ 38, 153, 0, /* 85 */ 95, 153, 76, /* 86 */ 31, 127, 0, /* 87 */ 79, 127, 63, /* 88 */ 19, 76, 0, /* 89 */ 47, 76, 38, /* 90 */ 0, 255, 0, /* 91 */ 127, 255, 127, /* 92 */ 0, 204, 0, /* 93 */ 102, 204, 102, /* 94 */ 0, 153, 0, /* 95 */ 76, 153, 76, /* 96 */ 0, 127, 0, /* 97 */ 63, 127, 63, /* 98 */ 0, 76, 0, /* 99 */ 38, 76, 38, /* 100 */ 0, 255, 63, /* 101 */ 127, 255, 159, /* 102 */ 0, 204, 51, /* 103 */ 102, 204, 127, /* 104 */ 0, 153, 38, /* 105 */ 76, 153, 95, /* 106 */ 0, 127, 31, /* 107 */ 63, 127, 79, /* 108 */ 0, 76, 19, /* 109 */ 38, 76, 47, /* 110 */ 0, 255, 127, /* 111 */ 127, 255, 191, /* 112 */ 0, 204, 102, /* 113 */ 102, 204, 153, /* 114 */ 0, 153, 76, /* 115 */ 76, 153, 114, /* 116 */ 0, 127, 63, /* 117 */ 63, 127, 95, /* 118 */ 0, 76, 38, /* 119 */ 38, 76, 57, /* 120 */ 0, 255, 191, /* 121 */ 127, 255, 223, /* 122 */ 0, 204, 153, /* 123 */ 102, 204, 178, /* 124 */ 0, 153, 114, /* 125 */ 76, 153, 133, /* 126 */ 0, 127, 95, /* 127 */ 63, 127, 111, /* 128 */ 0, 76, 57, /* 129 */ 38, 76, 66, /* 130 */ 0, 255, 255, /* 131 */ 127, 255, 255, /* 132 */ 0, 204, 204, /* 133 */ 102, 204, 204, /* 134 */ 0, 153, 153, /* 135 */ 76, 153, 153, /* 136 */ 0, 127, 127, /* 137 */ 63, 127, 127, /* 138 */ 0, 76, 76, /* 139 */ 38, 76, 76, /* 140 */ 0, 191, 255, /* 141 */ 127, 223, 255, /* 142 */ 0, 153, 204, /* 143 */ 102, 178, 204, /* 144 */ 0, 114, 153, /* 145 */ 76, 133, 153, /* 146 */ 0, 95, 127, /* 147 */ 63, 111, 127, /* 148 */ 0, 57, 76, /* 149 */ 38, 66, 76, /* 150 */ 0, 127, 255, /* 151 */ 127, 191, 255, /* 152 */ 0, 102, 204, /* 153 */ 102, 153, 204, /* 154 */ 0, 76, 153, /* 155 */ 76, 114, 153, /* 156 */ 0, 63, 127, /* 157 */ 63, 95, 127, /* 158 */ 0, 38, 76, /* 159 */ 38, 57, 76, /* 160 */ 0, 63, 255, /* 161 */ 127, 159, 255, /* 162 */ 0, 51, 204, /* 163 */ 102, 127, 204, /* 164 */ 0, 38, 153, /* 165 */ 76, 95, 153, /* 166 */ 0, 31, 127, /* 167 */ 63, 79, 127, /* 168 */ 0, 19, 76, /* 169 */ 38, 47, 76, /* 170 */ 0, 0, 255, /* 171 */ 127, 127, 255, /* 172 */ 0, 0, 204, /* 173 */ 102, 102, 204, /* 174 */ 0, 0, 153, /* 175 */ 76, 76, 153, /* 176 */ 0, 0, 127, /* 177 */ 63, 63, 127, /* 178 */ 0, 0, 76, /* 179 */ 38, 38, 76, /* 180 */ 63, 0, 255, /* 181 */ 159, 127, 255, /* 182 */ 51, 0, 204, /* 183 */ 127, 102, 204, /* 184 */ 38, 0, 153, /* 185 */ 95, 76, 153, /* 186 */ 31, 0, 127, /* 187 */ 79, 63, 127, /* 188 */ 19, 0, 76, /* 189 */ 47, 38, 76, /* 190 */ 127, 0, 255, /* 191 */ 191, 127, 255, /* 192 */ 102, 0, 204, /* 193 */ 153, 102, 204, /* 194 */ 76, 0, 153, /* 195 */ 114, 76, 153, /* 196 */ 63, 0, 127, /* 197 */ 95, 63, 127, /* 198 */ 38, 0, 76, /* 199 */ 57, 38, 76, /* 200 */ 191, 0, 255, /* 201 */ 223, 127, 255, /* 202 */ 153, 0, 204, /* 203 */ 178, 102, 204, /* 204 */ 114, 0, 153, /* 205 */ 133, 76, 153, /* 206 */ 95, 0, 127, /* 207 */ 111, 63, 127, /* 208 */ 57, 0, 76, /* 209 */ 66, 38, 76, /* 210 */ 255, 0, 255, /* 211 */ 255, 127, 255, /* 212 */ 204, 0, 204, /* 213 */ 204, 102, 204, /* 214 */ 153, 0, 153, /* 215 */ 153, 76, 153, /* 216 */ 127, 0, 127, /* 217 */ 127, 63, 127, /* 218 */ 76, 0, 76, /* 219 */ 76, 38, 76, /* 220 */ 255, 0, 191, /* 221 */ 255, 127, 223, /* 222 */ 204, 0, 153, /* 223 */ 204, 102, 178, /* 224 */ 153, 0, 114, /* 225 */ 153, 76, 133, /* 226 */ 127, 0, 95, /* 227 */ 127, 63, 111, /* 228 */ 76, 0, 57, /* 229 */ 76, 38, 66, /* 230 */ 255, 0, 127, /* 231 */ 255, 127, 191, /* 232 */ 204, 0, 102, /* 233 */ 204, 102, 153, /* 234 */ 153, 0, 76, /* 235 */ 153, 76, 114, /* 236 */ 127, 0, 63, /* 237 */ 127, 63, 95, /* 238 */ 76, 0, 38, /* 239 */ 76, 38, 57, /* 240 */ 255, 0, 63, /* 241 */ 255, 127, 159, /* 242 */ 204, 0, 51, /* 243 */ 204, 102, 127, /* 244 */ 153, 0, 38, /* 245 */ 153, 76, 95, /* 246 */ 127, 0, 31, /* 247 */ 127, 63, 79, /* 248 */ 76, 0, 19, /* 249 */ 76, 38, 47, /* 250 */ 51, 51, 51, /* 251 */ 91, 91, 91, /* 252 */ 132, 132, 132, /* 253 */ 173, 173, 173, /* 254 */ 214, 214, 214, /* 255 */ 255, 255, 255, }; inline DXFVector Cross(const DXFVector& v1, const DXFVector& v2) { 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); } void DXFFace::CalculateNormal() { DXFVector v01, v02; v01.x = v0.x - v1.x; v01.y = v0.y - v1.y; v01.z = v0.z - v1.z; v02.x = v0.x - v2.x; v02.y = v0.y - v2.y; v02.z = v0.z - v2.z; n = Cross(v01, v02); float mod = sqrt(n.x*n.x + n.y*n.y + n.z*n.z); n.x /= mod; n.y /= mod; n.z /= mod; } // convert an AutoCAD ACI colour to wxWidgets RGB colour inline wxColour ACIColourToRGB(int col) { wxASSERT(col >= 0 && col <= 255); return wxColour(aci_to_rgb[col].r, aci_to_rgb[col].g, aci_to_rgb[col].b); } // DXFReader constructor DXFRenderer::DXFRenderer() { m_loaded = false; } // DXFReader destructor DXFRenderer::~DXFRenderer() { Clear(); } // deallocate all the dynamic data void DXFRenderer::Clear() { m_loaded = false; { for (DXFLayerList::Node *node = m_layers.GetFirst(); node; node = node->GetNext()) { DXFLayer *current = node->GetData(); delete current; } } m_layers.Clear(); { for (DXFEntityList::Node *node = m_entities.GetFirst(); node; node = node->GetNext()) { DXFEntity *current = node->GetData(); delete current; } m_entities.Clear(); } } int DXFRenderer::GetLayerColour(const wxString& layer) const { for (DXFLayerList::Node *node = m_layers.GetFirst(); node; node = node->GetNext()) { DXFLayer *current = node->GetData(); if (current->name == layer) return current->colour; } return 7; // white } // read two sequential lines inline void GetLines(wxTextInputStream& text, wxString& line1, wxString& line2) { line1 = text.ReadLine().Trim().Trim(false); line2 = text.ReadLine().Trim().Trim(false); } // parse header section: just skip everything bool DXFRenderer::ParseHeader(wxInputStream& stream) { wxTextInputStream text(stream); wxString line1, line2; while (stream.CanRead()) { GetLines(text, line1, line2); if (line1 == wxT("0") && line2 == wxT("ENDSEC")) return true; } return false; } // parse tables section: save layers name and colour bool DXFRenderer::ParseTables(wxInputStream& stream) { wxTextInputStream text(stream); wxString line1, line2; bool inlayer=false; DXFLayer layer; while (stream.CanRead()) { GetLines(text, line1, line2); if (line1 == wxT("0") && inlayer) { // flush layer if (!layer.name.IsEmpty() && layer.colour != -1) { DXFLayer *p = new DXFLayer; p->name = layer.name; p->colour = layer.colour; m_layers.Append(p); } layer = DXFLayer(); inlayer = false; } if (line1 == wxT("0") && line2 == wxT("ENDSEC")) return true; else if (line1 == wxT("0") && line2 == wxT("LAYER")) inlayer = true; else if (inlayer) { if (line1 == wxT("2")) // layer name layer.name = line2; else if (line1 == wxT("62")) // ACI colour { long l; line2.ToLong(&l); layer.colour = l; } } } return false; } // parse entities section: save 3DFACE and LINE entities bool DXFRenderer::ParseEntities(wxInputStream& stream) { wxTextInputStream text(stream); wxString line1, line2; int state = 0; // 0: none, 1: 3DFACE, 2: LINE DXFVector v[4]; int colour = -1; wxString layer; while (stream.CanRead()) { GetLines(text, line1, line2); if (line1 == wxT("0") && state > 0) { // flush entity if (state == 1) // 3DFACE { DXFFace *p = new DXFFace; p->v0 = v[0]; p->v1 = v[1]; p->v2 = v[2]; p->v3 = v[3]; p->CalculateNormal(); if (colour != -1) p->colour = colour; else p->colour = GetLayerColour(layer); m_entities.Append(p); colour = -1; layer = wxEmptyString; v[0] = v[1] = v[2] = v[3] = DXFVector(); state = 0; } else if (state == 2) // LINE { DXFLine *p = new DXFLine; p->v0 = v[0]; p->v1 = v[1]; if (colour != -1) p->colour = colour; else p->colour = GetLayerColour(layer); m_entities.Append(p); colour = -1; layer = wxEmptyString; v[0] = v[1] = v[2] = v[3] = DXFVector(); state = 0; } } if (line1 == wxT("0") && line2 == wxT("ENDSEC")) return true; else if (line1 == wxT("0") && line2 == wxT("3DFACE")) state = 1; else if (line1 == wxT("0") && line2 == wxT("LINE")) state = 2; else if (state > 0) { double d; line2.ToDouble(&d); if (line1 == wxT("10")) v[0].x = d; else if (line1 == wxT("20")) v[0].y = d; else if (line1 == wxT("30")) v[0].z = d; else if (line1 == wxT("11")) v[1].x = d; else if (line1 == wxT("21")) v[1].y = d; else if (line1 == wxT("31")) v[1].z = d; else if (line1 == wxT("12")) v[2].x = d; else if (line1 == wxT("22")) v[2].y = d; else if (line1 == wxT("32")) v[2].z = d; else if (line1 == wxT("13")) v[3].x = d; else if (line1 == wxT("23")) v[3].y = d; else if (line1 == wxT("33")) v[3].z = d; else if (line1 == wxT("8")) // layer layer = line2; else if (line1 == wxT("62")) // colour { long l; line2.ToLong(&l); colour = l; } } } return false; } // parse and load a DXF file // currently pretty limited, but knows enought do handle 3DFACEs and LINEs bool DXFRenderer::Load(wxInputStream& stream) { Clear(); wxTextInputStream text(stream); wxString line1, line2; while (stream.CanRead()) { GetLines(text, line1, line2); if (line1 == wxT("999")) // comment continue; else if (line1 == wxT("0") && line2 == wxT("SECTION")) { GetLines(text, line1, line2); if (line1 == wxT("2")) { if (line2 == wxT("HEADER")) { if (!ParseHeader(stream)) return false; } else if (line2 == wxT("TABLES")) { if (!ParseTables(stream)) return false; } else if (line2 == wxT("ENTITIES")) { if (!ParseEntities(stream)) return false; } } } } NormalizeEntities(); m_loaded = true; return true; } inline float mymin(float x, float y) { return x < y ? x : y; } inline float mymax(float x, float y) { return x > y ? x : y; } // Scale object boundings to [-5,5] void DXFRenderer::NormalizeEntities() { // calculate current min and max boundings of object DXFVector minv(10e20f, 10e20f, 10e20f); DXFVector maxv(-10e20f, -10e20f, -10e20f); for (DXFEntityList::Node *node = m_entities.GetFirst(); node; node = node->GetNext()) { DXFEntity *p = node->GetData(); if (p->type == DXFEntity::Line) { DXFLine *line = (DXFLine *)p; const DXFVector *v[2] = { &line->v0, &line->v1 }; for (int i = 0; i < 2; ++i) { minv.x = mymin(v[i]->x, minv.x); minv.y = mymin(v[i]->y, minv.y); minv.z = mymin(v[i]->z, minv.z); maxv.x = mymax(v[i]->x, maxv.x); maxv.y = mymax(v[i]->y, maxv.y); maxv.z = mymax(v[i]->z, maxv.z); } } else if (p->type == DXFEntity::Face) { DXFFace *face = (DXFFace *)p; const DXFVector *v[4] = { &face->v0, &face->v1, &face->v2, &face->v3 }; for (int i = 0; i < 4; ++i) { minv.x = mymin(v[i]->x, minv.x); minv.y = mymin(v[i]->y, minv.y); minv.z = mymin(v[i]->z, minv.z); maxv.x = mymax(v[i]->x, maxv.x); maxv.y = mymax(v[i]->y, maxv.y); maxv.z = mymax(v[i]->z, maxv.z); } } } // rescale object down to [-5,5] DXFVector span(maxv.x - minv.x, maxv.y - minv.y, maxv.z - minv.z); float factor = mymin(mymin(10.0f / span.x, 10.0f / span.y), 10.0f / span.z); for (DXFEntityList::Node *node2 = m_entities.GetFirst(); node2; node2 = node2->GetNext()) { DXFEntity *p = node2->GetData(); if (p->type == DXFEntity::Line) { DXFLine *line = (DXFLine *)p; DXFVector *v[2] = { &line->v0, &line->v1 }; for (int i = 0; i < 2; ++i) { v[i]->x -= minv.x + span.x/2; v[i]->x *= factor; v[i]->y -= minv.y + span.y/2; v[i]->y *= factor; v[i]->z -= minv.z + span.z/2; v[i]->z *= factor; } } else if (p->type == DXFEntity::Face) { DXFFace *face = (DXFFace *)p; DXFVector *v[4] = { &face->v0, &face->v1, &face->v2, &face->v3 }; for (int i = 0; i < 4; ++i) { v[i]->x -= minv.x + span.x/2; v[i]->x *= factor; v[i]->y -= minv.y + span.y/2; v[i]->y *= factor; v[i]->z -= minv.z + span.z/2; v[i]->z *= factor; } } } } // OpenGL renderer for DXF entities void DXFRenderer::Render() const { if (!m_loaded) return; for (DXFEntityList::Node *node = m_entities.GetFirst(); node; node = node->GetNext()) { DXFEntity *p = node->GetData(); wxColour c = ACIColourToRGB(p->colour); if (p->type == DXFEntity::Line) { DXFLine *line = (DXFLine *)p; glBegin(GL_LINES); glColor3f(c.Red()/255.0,c.Green()/255.0,c.Blue()/255.0); glVertex3f(line->v0.x, line->v0.y, line->v0.z); glVertex3f(line->v1.x, line->v1.y, line->v1.z); glEnd(); } else if (p->type == DXFEntity::Face) { DXFFace *face = (DXFFace *)p; glBegin(GL_TRIANGLES); glColor3f(c.Red()/255.0,c.Green()/255.0,c.Blue()/255.0); glNormal3f(face->n.x, face->n.y, face->n.z); glVertex3f(face->v0.x, face->v0.y, face->v0.z); glVertex3f(face->v1.x, face->v1.y, face->v1.z); glVertex3f(face->v2.x, face->v2.y, face->v2.z); glEnd(); } } }