Files
wxWidgets/samples/opengl/penguin/dxfrenderer.cpp
Vadim Zeitlin 3f66f6a5b3 Remove all lines containing cvs/svn "$Id$" keyword.
This keyword is not expanded by Git which means it's not replaced with the
correct revision value in the releases made using git-based scripts and it's
confusing to have lines with unexpanded "$Id$" in the released files. As
expanding them with Git is not that simple (it could be done with git archive
and export-subst attribute) and there are not many benefits in having them in
the first place, just remove all these lines.

If nothing else, this will make an eventual transition to Git simpler.

Closes #14487.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74602 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2013-07-26 16:02:46 +00:00

694 lines
20 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: dxfrenderer.cpp
// Purpose: DXF reader and renderer
// Author: Sandro Sigala
// Modified by:
// Created: 2005-11-10
// 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 __DARWIN__
#include <OpenGL/glu.h>
#else
#include <GL/glu.h>
#endif
#include <sstream>
#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::compatibility_iterator node = m_layers.GetFirst(); node; node = node->GetNext())
{
DXFLayer *current = node->GetData();
delete current;
}
}
m_layers.Clear();
{
for (DXFEntityList::compatibility_iterator 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::compatibility_iterator 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;
}
// This method is used instead of numStr.ToDouble(d) because the latter
// (wxString::ToDouble()) takes the systems proper locale into account,
// whereas the implementation below works with the default locale.
// (Converting numbers that are formatted in the default locale can fail
// with system locales that use e.g. the comma as the decimal separator.)
static double ToDouble(const wxString& numStr)
{
double d;
std::string numStr_(numStr.c_str());
std::istringstream iss(numStr_);
iss >> d;
return d;
}
// 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)
{
const double d=ToDouble(line2);
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::compatibility_iterator 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::compatibility_iterator 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::compatibility_iterator 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();
}
}
}