// dxf.cpp
// Copyright (c) 2009, Dan Heeks
// This program is released under the BSD license. See the file COPYING for details.

#include "dxf.h"

#include <wx/regex.h>

using namespace std;
static const double Pi = 3.14159265358979323846264338327950288419716939937511;

CDxfWrite::CDxfWrite(const char* filepath)
{
	// start the file
	m_fail = false;
#ifdef __WXMSW__
	m_ofs = new ofstream(filepath, ios::out);
#else
	m_ofs = new ofstream(filepath, ios::out);
#endif
	if(!(*m_ofs)){
		m_fail = true;
		return;
	}
	m_ofs->imbue(std::locale("C"));

	// start
	(*m_ofs) << 0          << endl;
	(*m_ofs) << "SECTION"  << endl;
	(*m_ofs) << 2          << endl;
	(*m_ofs) << "ENTITIES" << endl;
}

CDxfWrite::~CDxfWrite()
{
	// end
	(*m_ofs) << 0          << endl;
	(*m_ofs) << "ENDSEC"   << endl;
	(*m_ofs) << 0          << endl;
	(*m_ofs) << "EOF";

	delete m_ofs;
}

void CDxfWrite::WriteExtrusion(double thickness, const double* extru)
{
	if (thickness == 0.0)return;
	if (extru == NULL)return;

	(*m_ofs) << 39 << endl;	// thickness
	(*m_ofs) << thickness << endl;
	(*m_ofs) << 210 << endl;	// extrusion_vector
	(*m_ofs) << extru[0] << endl;
	(*m_ofs) << 220 << endl;	// extrusion_vector
	(*m_ofs) << extru[1] << endl;
	(*m_ofs) << 230 << endl;	// extrusion_vector
	(*m_ofs) << extru[2] << endl;
}

void CDxfWrite::WriteLine(const double* s, const double* e, const char* layer_name, double thickness, const double* extru)
{
	(*m_ofs) << 0			<< endl;
	(*m_ofs) << "LINE"		<< endl;
	(*m_ofs) << 8			<< endl;	// Group code for layer name
	(*m_ofs) << layer_name	<< endl;	// Layer number
	(*m_ofs) << 10			<< endl;	// Start point of line
	(*m_ofs) << s[0]		<< endl;	// X in WCS coordinates
	(*m_ofs) << 20			<< endl;
	(*m_ofs) << s[1]		<< endl;	// Y in WCS coordinates
	(*m_ofs) << 30			<< endl;
	(*m_ofs) << s[2]		<< endl;	// Z in WCS coordinates
	(*m_ofs) << 11			<< endl;	// End point of line
	(*m_ofs) << e[0]		<< endl;	// X in WCS coordinates
	(*m_ofs) << 21			<< endl;
	(*m_ofs) << e[1]		<< endl;	// Y in WCS coordinates
	(*m_ofs) << 31			<< endl;
	(*m_ofs) << e[2]		<< endl;	// Z in WCS coordinates

	WriteExtrusion(thickness, extru);
}

void CDxfWrite::WritePoint(const double* s, const char* layer_name)
{
	(*m_ofs) << 0			<< endl;
	(*m_ofs) << "POINT"		<< endl;
	(*m_ofs) << 8			<< endl;	// Group code for layer name
	(*m_ofs) << layer_name	<< endl;	// Layer number
	(*m_ofs) << 10			<< endl;	// Start point of line
	(*m_ofs) << s[0]		<< endl;	// X in WCS coordinates
	(*m_ofs) << 20			<< endl;
	(*m_ofs) << s[1]		<< endl;	// Y in WCS coordinates
	(*m_ofs) << 30			<< endl;
	(*m_ofs) << s[2]		<< endl;	// Z in WCS coordinates
}

void CDxfWrite::WriteArc(const double* s, const double* e, const double* c, bool dir, const char* layer_name, double thickness, const double* extru)
{
	double ax = s[0] - c[0];
	double ay = s[1] - c[1];
	double bx = e[0] - c[0];
	double by = e[1] - c[1];

	double start_angle = atan2(ay, ax) * 180/Pi;
	double end_angle = atan2(by, bx) * 180/Pi;
	double radius = sqrt(ax*ax + ay*ay);
	if(!dir){
		double temp = start_angle;
		start_angle = end_angle;
		end_angle = temp;
	}
	(*m_ofs) << 0			<< endl;
	(*m_ofs) << "ARC"		<< endl;
	(*m_ofs) << 8			<< endl;	// Group code for layer name
	(*m_ofs) << layer_name	<< endl;	// Layer number
	(*m_ofs) << 10			<< endl;	// Centre X
	(*m_ofs) << c[0]		<< endl;	// X in WCS coordinates
	(*m_ofs) << 20			<< endl;
	(*m_ofs) << c[1]		<< endl;	// Y in WCS coordinates
	(*m_ofs) << 30			<< endl;
	(*m_ofs) << c[2]		<< endl;	// Z in WCS coordinates
	(*m_ofs) << 40			<< endl;	//
	(*m_ofs) << radius		<< endl;	// Radius
	(*m_ofs) << 50			<< endl;
	(*m_ofs) << start_angle	<< endl;	// Start angle
	(*m_ofs) << 51			<< endl;
	(*m_ofs) << end_angle	<< endl;	// End angle

	WriteExtrusion(thickness, extru);
}

void CDxfWrite::WriteCircle(const double* c, double radius, const char* layer_name, double thickness, const double* extru)
{
	(*m_ofs) << 0			<< endl;
	(*m_ofs) << "CIRCLE"		<< endl;
	(*m_ofs) << 8			<< endl;	// Group code for layer name
	(*m_ofs) << layer_name	<< endl;	// Layer number
	(*m_ofs) << 10			<< endl;	// Centre X
	(*m_ofs) << c[0]		<< endl;	// X in WCS coordinates
	(*m_ofs) << 20			<< endl;
	(*m_ofs) << c[1]		<< endl;	// Y in WCS coordinates
	(*m_ofs) << 30			<< endl;
	(*m_ofs) << c[2]		<< endl;	// Z in WCS coordinates
	(*m_ofs) << 40			<< endl;	//
	(*m_ofs) << radius		<< endl;	// Radius

	WriteExtrusion(thickness, extru);
}

void CDxfWrite::WriteEllipse(const double* c, double major_radius, double minor_radius, double rotation, double start_angle, double end_angle, bool dir, const char* layer_name, double thickness, const double* extru)
{
	double m[3];
	m[2]=0;
	m[0] = major_radius * sin(rotation);
	m[1] = major_radius * cos(rotation);

	double ratio = minor_radius/major_radius;

	if(!dir){
		double temp = start_angle;
		start_angle = end_angle;
		end_angle = temp;
	}
	(*m_ofs) << 0			<< endl;
	(*m_ofs) << "ELLIPSE"		<< endl;
	(*m_ofs) << 8			<< endl;	// Group code for layer name
	(*m_ofs) << layer_name	<< endl;	// Layer number
	(*m_ofs) << 10			<< endl;	// Centre X
	(*m_ofs) << c[0]		<< endl;	// X in WCS coordinates
	(*m_ofs) << 20			<< endl;
	(*m_ofs) << c[1]		<< endl;	// Y in WCS coordinates
	(*m_ofs) << 30			<< endl;
	(*m_ofs) << c[2]		<< endl;	// Z in WCS coordinates
	(*m_ofs) << 40			<< endl;	//
	(*m_ofs) << ratio		<< endl;	// Ratio
	(*m_ofs) << 11			<< endl;	//
	(*m_ofs) << m[0]		<< endl;	// Major X
	(*m_ofs) << 21			<< endl;
	(*m_ofs) << m[1]		<< endl;	// Major Y
	(*m_ofs) << 31			<< endl;
	(*m_ofs) << m[2]		<< endl;	// Major Z
	(*m_ofs) << 41		<< endl;
	(*m_ofs) << start_angle	<< endl;	// Start angle
	(*m_ofs) << 42		<< endl;
	(*m_ofs) << end_angle	<< endl;	// End angle

	WriteExtrusion(thickness, extru);
}

CDxfRead::CDxfRead(const char* filepath)
{
	// start the file
	memset( m_unused_line, '\0', sizeof(m_unused_line) );
	m_fail = false;
	m_aci = 0;
	m_eUnits = eMillimeters;
	m_measurement_inch = false;
	strcpy(m_layer_name, "0");	// Default layer name
	m_ignore_errors = true;
#ifdef STORE_LINE_NUMBERS
	m_line_number = 0;
#endif
	m_ifs = new ifstream(filepath);
	if(!(*m_ifs)){
		m_fail = true;
		wprintf(wxT("DXF file didn't load\n"));
		return;
	}
	m_ifs->imbue(std::locale("C"));
}

CDxfRead::~CDxfRead()
{
	delete m_ifs;
}

double CDxfRead::mm( double value ) const
{
	if(m_measurement_inch)
	{
		value *= 0.0393700787401575;
	}

	switch(m_eUnits)
	{
		case eUnspecified:	return(value * 1.0);	// We don't know any better.
		case eInches:		return(value * 25.4);
		case eFeet:		return(value * 25.4 * 12);
		case eMiles:		return(value *  1609344.0);
		case eMillimeters:	return(value * 1.0);
		case eCentimeters:	return(value * 10.0);
		case eMeters:		return(value * 1000.0);
		case eKilometers:	return(value * 1000000.0);
		case eMicroinches:	return(value * 25.4 / 1000.0);
		case eMils:		return(value * 25.4 / 1000.0);
		case eYards:		return(value * 3 * 12 * 25.4);
		case eAngstroms:	return(value * 0.0000001);
		case eNanometers:	return(value * 0.000001);
		case eMicrons:		return(value * 0.001);
		case eDecimeters:	return(value * 100.0);
		case eDekameters:	return(value * 10000.0);
		case eHectometers:	return(value * 100000.0);
		case eGigameters:	return(value * 1000000000000.0);
		case eAstronomicalUnits: return(value * 149597870690000.0);
		case eLightYears:	return(value * 9454254955500000000.0);
		case eParsecs:		return(value * 30856774879000000000.0);
		default:		return(value * 1.0);	// We don't know any better.
	} // End switch
} // End mm() method

bool CDxfRead::ReadLine()
{
	double s[3] = {0, 0, 0};
	double e[3] = {0, 0, 0};
	bool hidden = false;
	
	ResetExtrusionAndThickness();

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
			wprintf(wxT("CDxfRead::ReadLine() Failed to read integer from '%s'\n"), m_str );
			return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with line
				DerefACI();
				OnReadLine(s, e, hidden);
				hidden = false;
				return true;

			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 6: // line style name follows
				get_line();
				if(m_str[0] == 'h' || m_str[0] == 'H')hidden = true;
				break;

			case 10:
				// start x
				get_line();
				ss.str(m_str); ss >> s[0]; s[0] = mm(s[0]); if(ss.fail()) return false;
				break;
			case 20:
				// start y
				get_line();
				ss.str(m_str); ss >> s[1]; s[1] = mm(s[1]); if(ss.fail()) return false;
				break;
			case 30:
				// start z
				get_line();
				ss.str(m_str); ss >> s[2]; s[2] = mm(s[2]); if(ss.fail()) return false;
				break;
			case 11:
				// end x
				get_line();
				ss.str(m_str); ss >> e[0]; e[0] = mm(e[0]); if(ss.fail()) return false;
				break;
			case 21:
				// end y
				get_line();
				ss.str(m_str); ss >> e[1]; e[1] = mm(e[1]); if(ss.fail()) return false;
				break;
			case 31:
				// end z
				get_line();
				ss.str(m_str); ss >> e[2]; e[2] = mm(e[2]); if(ss.fail()) return false;
				break;
	        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;
			case 100:
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	try {
	    DerefACI();
	    OnReadLine(s, e, false);
	}
	catch(...)
	{
		if (! IgnoreErrors()) throw;	// Re-throw the exception.
	}

	return false;
}

bool CDxfRead::ReadPoint()
{
	double s[3] = {0, 0, 0};

	ResetExtrusionAndThickness();

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadPoint() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with line
			        DerefACI();
				OnReadPoint(s);
				return true;

			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 10:
				// start x
				get_line();
				ss.str(m_str); ss >> s[0]; s[0] = mm(s[0]); if(ss.fail()) return false;
				break;
			case 20:
				// start y
				get_line();
				ss.str(m_str); ss >> s[1]; s[1] = mm(s[1]); if(ss.fail()) return false;
				break;
			case 30:
				// start z
				get_line();
				ss.str(m_str); ss >> s[2]; s[2] = mm(s[2]); if(ss.fail()) return false;
				break;

		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;

			case 100:
				// skip the next line
				get_line();
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}

	}

	try {
	    DerefACI();
	    OnReadPoint(s);
	}
	catch(...)
	{
		if (! IgnoreErrors()) throw;	// Re-throw the exception.
	}

	return false;
}

bool CDxfRead::ReadArc()
{
	double start_angle = 0.0;// in degrees
	double end_angle = 0.0;
	double radius = 0.0;
	double c[3]; // centre
	bool hidden = false;

	ResetExtrusionAndThickness();

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadArc() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with arc
			        DerefACI();
			        OnReadArc(start_angle, end_angle, radius, c, hidden);
					hidden = false;
			        return true;

			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 6: // line style name follows
				get_line();
				if(m_str[0] == 'h' || m_str[0] == 'H')hidden = true;
				break;

			case 10:
				// centre x
				get_line();
				ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false;
				break;
			case 20:
				// centre y
				get_line();
				ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false;
				break;
			case 30:
				// centre z
				get_line();
				ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false;
				break;
			case 40:
				// radius
				get_line();
				ss.str(m_str); ss >> radius; radius = mm(radius); if(ss.fail()) return false;
				break;
			case 50:
				// start angle
				get_line();
				ss.str(m_str); ss >> start_angle; if(ss.fail()) return false;
				break;
			case 51:
				// end angle
				get_line();
				ss.str(m_str); ss >> end_angle; if(ss.fail()) return false;
				break;
		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;



			case 100:
                // skip the next line
				get_line();
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;

			default:
				// skip the next line
				get_line();
				break;
		}
	}
	DerefACI();
	OnReadArc(start_angle, end_angle, radius, c, false);
	return false;
}

bool CDxfRead::ReadSpline()
{
	struct SplineData sd;
	sd.norm[0] = 0;
	sd.norm[1] = 0;
	sd.norm[2] = 1;
	sd.degree = 0;
	sd.knots = 0;
	sd.flag = 0;
	sd.control_points = 0;
	sd.fit_points = 0;

	double temp_double;

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadSpline() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with Spline
			        DerefACI();
				OnReadSpline(sd);
				return true;
			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;
		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;
			case 210:
				// normal x
				get_line();
				ss.str(m_str); ss >> sd.norm[0]; if(ss.fail()) return false;
				break;
			case 220:
				// normal y
				get_line();
				ss.str(m_str); ss >> sd.norm[1]; if(ss.fail()) return false;
				break;
			case 230:
				// normal z
				get_line();
				ss.str(m_str); ss >> sd.norm[2]; if(ss.fail()) return false;
				break;
			case 70:
				// flag
				get_line();
				ss.str(m_str); ss >> sd.flag; if(ss.fail()) return false;
				break;
			case 71:
				// degree
				get_line();
				ss.str(m_str); ss >> sd.degree; if(ss.fail()) return false;
				break;
			case 72:
				// knots
				get_line();
				ss.str(m_str); ss >> sd.knots; if(ss.fail()) return false;
				break;
			case 73:
				// control points
				get_line();
				ss.str(m_str); ss >> sd.control_points; if(ss.fail()) return false;
				break;
			case 74:
				// fit points
				get_line();
				ss.str(m_str); ss >> sd.fit_points; if(ss.fail()) return false;
				break;
			case 12:
				// starttan x
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.starttanx.push_back(temp_double);
				break;
			case 22:
				// starttan y
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.starttany.push_back(temp_double);
				break;
			case 32:
				// starttan z
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.starttanz.push_back(temp_double);
				break;
			case 13:
				// endtan x
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.endtanx.push_back(temp_double);
				break;
			case 23:
				// endtan y
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.endtany.push_back(temp_double);
				break;
			case 33:
				// endtan z
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.endtanz.push_back(temp_double);
				break;
			case 40:
				// knot
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.knot.push_back(temp_double);
				break;
			case 41:
				// weight
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.weight.push_back(temp_double);
				break;
			case 10:
				// control x
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.controlx.push_back(temp_double);
				break;
			case 20:
				// control y
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.controly.push_back(temp_double);
				break;
			case 30:
				// control z
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.controlz.push_back(temp_double);
				break;
			case 11:
				// fit x
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.fitx.push_back(temp_double);
				break;
			case 21:
				// fit y
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.fity.push_back(temp_double);
				break;
			case 31:
				// fit z
				get_line();
				ss.str(m_str); ss >> temp_double; temp_double = mm(temp_double); if(ss.fail()) return false;
				sd.fitz.push_back(temp_double);
				break;
			case 42:
			case 43:
			case 44:
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	DerefACI();
	OnReadSpline(sd);
	return false;
}


bool CDxfRead::ReadCircle()
{
	double radius = 0.0;
	double c[3]; // centre
	bool hidden = false;

	ResetExtrusionAndThickness();

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
			wprintf(wxT("CDxfRead::ReadCircle() Failed to read integer from '%s'\n"), m_str);
			return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with Circle
			    DerefACI();
				OnReadCircle(c, radius, hidden);
				hidden = false;
				return true;

			case 6: // line style name follows
				get_line();
				if(m_str[0] == 'h' || m_str[0] == 'H')hidden = true;
				break;

			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 10:
				// centre x
				get_line();
				ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false;
				break;
			case 20:
				// centre y
				get_line();
				ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false;
				break;
			case 30:
				// centre z
				get_line();
				ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false;
				break;
			case 40:
				// radius
				get_line();
				ss.str(m_str); ss >> radius; radius = mm(radius); if(ss.fail()) return false;
				break;
		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;

			case 100:
				// skip the next line
				get_line();
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	DerefACI();
	OnReadCircle(c, radius, false);
	return false;
}

bool CDxfRead::ReadText()
{
	double c[3]; // coordinate
	double height = 0.03082;
	int hj = 0;
	int vj = 0;
	double scale_x = 1.0;

	ResetExtrusionAndThickness();

	memset( c, 0, sizeof(c) );

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadText() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				return false;
			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 10:
				// centre x
				get_line();
				ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false;
				break;
			case 20:
				// centre y
				get_line();
				ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false;
				break;
			case 30:
				// centre z
				get_line();
				ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false;
				break;
		        case 40:
				// text height
				get_line();
				ss.str(m_str); ss >> height; height = mm(height); if(ss.fail()) return false;
				break;
		        case 41:
				// text relative x scale
				get_line();
				ss.str(m_str); ss >> scale_x; if(ss.fail()) return false;
				break;
                       case 1:
				// text
				get_line();
				DerefACI();
				OnReadText(c, height * 25.4 / 72.0, m_str, hj, vj);
				return(true);

		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;

		        case 72:
				// horizontal justification
				get_line();
				ss.str(m_str); ss >> hj; if(ss.fail()) return false;
				break;

		        case 73:
				// horizontal justification
				get_line();
				ss.str(m_str); ss >> vj; if(ss.fail()) return false;
				break;

			case 100:
				// skip the next line
				get_line();
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	return false;
}


bool CDxfRead::ReadMText()
{
	double c[3]; // coordinate
	double height = 0.03082;
	int hj = 0;
	int vj = 0;

	ResetExtrusionAndThickness();

	memset( c, 0, sizeof(c) );

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadText() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				return false;
			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 10:
				// centre x
				get_line();
				ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false;
				break;
			case 20:
				// centre y
				get_line();
				ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false;
				break;
			case 30:
				// centre z
				get_line();
				ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false;
				break;
	        case 40:
	        case 43:
				// text height
				get_line();
				ss.str(m_str); ss >> height; height = mm(height); if(ss.fail()) return false;
				break;
            case 1:
				// text
				get_line();
				DerefACI();
				OnReadText(c, height * 25.4 / 72.0, m_str, hj, vj);
				return(true);

	        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;

	        case 71:
				//Attachment point:
				//1 = Top left; 2 = Top center; 3 = Top right;
				//4 = Middle left; 5 = Middle center; 6 = Middle right
				//7 = Bottom left; 8 = Bottom center; 9 = Bottom right
				get_line();
				ss.str(m_str); ss >> hj; if(ss.fail()) return false;
				switch(hj)
				{
				case 1:
					hj = 0;
					vj = 3;
					break;
				case 2:
					hj = 1;
					vj = 3;
					break;
				case 3:
					hj = 2;
					vj = 3;
					break;
				case 4:
					hj = 0;
					vj = 2;
					break;
				case 5:
					hj = 1;
					vj = 2;
					break;
				case 6:
					hj = 2;
					vj = 2;
					break;
				case 7:
					hj = 0;
					vj = 1;
					break;
				case 8:
					hj = 1;
					vj = 1;
					break;
				case 9:
					hj = 2;
					vj = 1;
					break;
				}
				break;

	        case 72:
				// drawing direction
				get_line(); // to do
				//ss.str(m_str); ss >> vj; if(ss.fail()) return false;
				break;

			case 100:
				// skip the next line
				get_line();
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	return false;
}


bool CDxfRead::ReadRText()
{
	double c[3]; // coordinate
	double height = 0.03082;
	int hj = 0;
	int vj = 0;

	ResetExtrusionAndThickness();

	memset(c, 0, sizeof(c));

	while (!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if (sscanf(m_str, "%d", &n) != 1)
		{
			wprintf(wxT("CDxfRead::ReadText() Failed to read integer from '%s'\n"), m_str);
			return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch (n){
		case 0:
			return false;
		case 8: // Layer name follows
			get_line();
			strcpy(m_layer_name, m_str);
			break;

		case 10:
			// centre x
			get_line();
			ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if (ss.fail()) return false;
			break;
		case 20:
			// centre y
			get_line();
			ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if (ss.fail()) return false;
			break;
		case 30:
			// centre z
			get_line();
			ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if (ss.fail()) return false;
			break;
		case 40:
		case 43:
			// text height
			get_line();
			ss.str(m_str); ss >> height; height = mm(height); if (ss.fail()) return false;
			break;
		case 1:
			// text
			get_line();
			DerefACI();
			OnReadText(c, height * 25.4 / 72.0, m_str, hj, vj);
			return(true);

		case 62:
			// color index
			get_line();
			ss.str(m_str); ss >> m_aci; if (ss.fail()) return false;
			break;

		case 71:
			//Attachment point:
			//1 = Top left; 2 = Top center; 3 = Top right;
			//4 = Middle left; 5 = Middle center; 6 = Middle right
			//7 = Bottom left; 8 = Bottom center; 9 = Bottom right
			get_line();
			ss.str(m_str); ss >> hj; if (ss.fail()) return false;
			switch (hj)
			{
			case 1:
				hj = 0;
				vj = 3;
				break;
			case 2:
				hj = 1;
				vj = 3;
				break;
			case 3:
				hj = 2;
				vj = 3;
				break;
			case 4:
				hj = 0;
				vj = 2;
				break;
			case 5:
				hj = 1;
				vj = 2;
				break;
			case 6:
				hj = 2;
				vj = 2;
				break;
			case 7:
				hj = 0;
				vj = 1;
				break;
			case 8:
				hj = 1;
				vj = 1;
				break;
			case 9:
				hj = 2;
				vj = 1;
				break;
			}
			break;

		case 72:
			// drawing direction
			get_line(); // to do
			//ss.str(m_str); ss >> vj; if(ss.fail()) return false;
			break;

		case 100:
			// skip the next line
			get_line();
			break;
		case 39:
		case 210:
		case 220:
		case 230:
			if (!ReadExtrusionOrThickness(n))
				return false;
			break;
		default:
			// skip the next line
			get_line();
			break;
		}
	}

	return false;
}

bool CDxfRead::ReadEllipse()
{
	double c[3]; // centre
	double m[3]; //major axis point
	double ratio=0; //ratio of major to minor axis
	double start=0; //start of arc
	double end=0;  // end of arc

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadEllipse() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with Ellipse
			        DerefACI();
				OnReadEllipse(c, m, ratio, start, end);
				return true;
			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 10:
				// centre x
				get_line();
				ss.str(m_str); ss >> c[0]; c[0] = mm(c[0]); if(ss.fail()) return false;
				break;
			case 20:
				// centre y
				get_line();
				ss.str(m_str); ss >> c[1]; c[1] = mm(c[1]); if(ss.fail()) return false;
				break;
			case 30:
				// centre z
				get_line();
				ss.str(m_str); ss >> c[2]; c[2] = mm(c[2]); if(ss.fail()) return false;
				break;
			case 11:
				// major x
				get_line();
				ss.str(m_str); ss >> m[0]; m[0] = mm(m[0]); if(ss.fail()) return false;
				break;
			case 21:
				// major y
				get_line();
				ss.str(m_str); ss >> m[1]; m[1] = mm(m[1]); if(ss.fail()) return false;
				break;
			case 31:
				// major z
				get_line();
				ss.str(m_str); ss >> m[2]; m[2] = mm(m[2]); if(ss.fail()) return false;
				break;
			case 40:
				// ratio
				get_line();
				ss.str(m_str); ss >> ratio; if(ss.fail()) return false;
				break;
			case 41:
				// start
				get_line();
				ss.str(m_str); ss >> start; if(ss.fail()) return false;
				break;
			case 42:
				// end
				get_line();
				ss.str(m_str); ss >> end; if(ss.fail()) return false;
				break;
		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;
			case 100:
			case 210:
			case 220:
			case 230:
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	DerefACI();
	OnReadEllipse(c, m, ratio, start, end);
	return false;
}


static bool poly_prev_found = false;
static double poly_prev_x;
static double poly_prev_y;
static double poly_prev_z;
static double poly_prev_bulge_found;
static double poly_prev_bulge;
static bool poly_first_found = false;
static double poly_first_x;
static double poly_first_y;
static double poly_first_z;
static std::list<CPolyLinePoint> poly_line_points;
static bool poly_mirrored = false;

static void AddPolyLinePoint(CDxfRead* dxf_read, CPolyLinePoint& p)
{
	try {
		if(poly_prev_found)
		{
			bool arc_done = false;
			if(poly_prev_bulge_found)
			{
				double cot = 0.5 * ((1.0 / poly_prev_bulge) - poly_prev_bulge);
				double cx = ((poly_prev_x + p.x) - ((p.y - poly_prev_y) * cot)) / 2.0;
				double cy = ((poly_prev_y + p.y) + ((p.x - poly_prev_x) * cot)) / 2.0;
				double ps[3] = {poly_prev_x, poly_prev_y, poly_prev_z};
				double pe[3] = {p.x, p.y, p.z};
				double pc[3] = {cx, cy, (poly_prev_z + p.z)/2.0};
				if(poly_mirrored)
				{
					ps[0] = -ps[0];
					pe[0] = -pe[0];
					pc[0] = -pc[0];
				}
				bool dir = (poly_prev_bulge >= 0);
				if(poly_mirrored)dir = !dir;
				dxf_read->OnReadArc(ps, pe, pc, dir, false);
				arc_done = true;
			}

			if(!arc_done)
			{
				double s[3] = {poly_prev_x, poly_prev_y, poly_prev_z};
				double e[3] = {p.x, p.y, p.z};
				if(poly_mirrored)
				{
					s[0] = -s[0];
					e[0] = -e[0];
				}
				dxf_read->OnReadLine(s, e, false);
			}
		}

		poly_prev_found = true;
		poly_prev_x = p.x;
		poly_prev_y = p.y;
		poly_prev_z = p.z;
		if(!poly_first_found)
		{
			poly_first_x = p.x;
			poly_first_y = p.y;
			poly_first_z = p.z;
			poly_first_found = true;
		}
		poly_prev_bulge_found = p.bulge_found;
		poly_prev_bulge = p.bulge;
	}
	catch(...)
	{
		if (! dxf_read->IgnoreErrors())	throw;	// Re-throw it.
	}
}

void CDxfRead::AddPolyLinePoints(bool mirrored, bool closed)
{
	poly_mirrored = mirrored;
	for(std::list<CPolyLinePoint>::iterator It = poly_line_points.begin(); It != poly_line_points.end(); It++)
	{
		CPolyLinePoint &p = *It;
		AddPolyLinePoint(this, p);
	}

	if (closed && (poly_line_points.size() > 0))
	{
		// repeat the first point
		AddPolyLinePoint(this, poly_line_points.front());
	}

	poly_line_points.clear();
}

void CDxfRead::ResetExtrusionAndThickness()
{
	m_thickness = 0.0;
	m_extrusion_vector[0] = 0.0;
	m_extrusion_vector[1] = 0.0;
	m_extrusion_vector[2] = 1.0;
}

bool CDxfRead::ReadExtrusionOrThickness(int n)
{
	std::istringstream ss;
	ss.imbue(std::locale("C"));

	switch (n)
	{
	case 39:
		// thickness
		get_line();
		ss.str(m_str); ss >> m_thickness; m_thickness = mm(m_thickness); if (ss.fail()) return false;
		break;

	case 210:
		// extrusion_vector
		get_line();
		ss.str(m_str); ss >> m_extrusion_vector[0]; if (ss.fail()) return false;
		break;

	case 220:
		// extrusion_vector
		get_line();
		ss.str(m_str); ss >> m_extrusion_vector[1]; if (ss.fail()) return false;
		break;

	case 230:
		// extrusion_vector
		get_line();
		ss.str(m_str); ss >> m_extrusion_vector[2]; if (ss.fail()) return false;
		break;
	}

	return true;
}

void CDxfRead::StorePolyLinePoint(double x, double y, double z, bool bulge_found, double bulge)
{
	poly_line_points.push_back(CPolyLinePoint(x, y, z, bulge_found, bulge));
}

static void PolyLineStart()
{
	poly_prev_found = false;
	poly_first_found = false;
}

bool CDxfRead::ReadLwPolyLine()
{
	PolyLineStart();

	bool x_found = false;
	bool y_found = false;
	double x = 0.0;
	double y = 0.0;
	double z = 0.0;
	bool bulge_found = false;
	double bulge = 0.0;
	bool closed = false;
	int flags;
	bool next_item_found = false;
	bool mirrored = false;

	while(!((*m_ifs).eof()) && !next_item_found)
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
			wprintf(wxT("CDxfRead::ReadLwPolyLine() Failed to read integer from '%s'\n"), m_str);
			return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found

			        DerefACI();
			        if(x_found && y_found){
					// add point
					StorePolyLinePoint(x, y, z, bulge_found, bulge);
					bulge_found = false;
					x_found = false;
					y_found = false;
				}
				next_item_found = true;
				break;
			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;

			case 10:
				// x
				get_line();
				if(x_found && y_found){
					// add point
					StorePolyLinePoint(x, y, z, bulge_found, bulge);
					bulge_found = false;
					x_found = false;
					y_found = false;
				}
				ss.str(m_str); ss >> x; x = mm(x); if(ss.fail()) return false;
				x_found = true;
				break;
			case 20:
				// y
				get_line();
				ss.str(m_str); ss >> y; y = mm(y); if(ss.fail()) return false;
				y_found = true;
				break;
			case 230:
				// z extrusion direction
				get_line();
				ss.str(m_str); ss >> z; if(ss.fail()) return false;
				mirrored = (z < 0);
				break;
			case 42:
				// bulge
				get_line();
				ss.str(m_str); ss >> bulge; if(ss.fail()) return false;
				bulge_found = true;
				break;
			case 70:
				// flags
				get_line();
				if(sscanf(m_str, "%d", &flags) != 1)return false;
				closed = ((flags & 1) != 0);
				break;
		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	if(next_item_found)
	{
		AddPolyLinePoints(mirrored, closed);
		return true;
	}

	return false;
}


bool CDxfRead::ReadVertex(double *pVertex, bool *bulge_found, double *bulge)
{
    bool x_found = false;
    bool y_found = false;

    double x = 0.0;
    double y = 0.0;
    double z = 0.0;
    *bulge = 0.0;
    *bulge_found = false;

    pVertex[0] = 0.0;
    pVertex[1] = 0.0;
    pVertex[2] = 0.0;

    while(!(*m_ifs).eof()) {
        get_line();
        int n;
        if(sscanf(m_str, "%d", &n) != 1) {
            wprintf(wxT("CDxfRead::ReadVertex() Failed to read integer from '%s'\n"), m_str);
            return false;
        }
        std::istringstream ss;
        ss.imbue(std::locale("C"));
        switch(n){
        case 0:
	    DerefACI();
            put_line(m_str);    // read one line too many.  put it back.
            return(x_found && y_found);
            break;

        case 8: // Layer name follows
            get_line();
            strcpy(m_layer_name, m_str);
            break;

        case 10:
            // x
            get_line();
            ss.str(m_str); ss >> x; pVertex[0] = mm(x); if(ss.fail()) return false;
            x_found = true;
            break;
        case 20:
            // y
            get_line();
            ss.str(m_str); ss >> y; pVertex[1] = mm(y); if(ss.fail()) return false;
            y_found = true;
            break;
        case 30:
            // z
            get_line();
            ss.str(m_str); ss >> z; pVertex[2] = mm(z); if(ss.fail()) return false;
            break;

        case 42:
            get_line();
            *bulge_found = true;
            ss.str(m_str); ss >> *bulge; if(ss.fail()) return false;
            break;
	case 62:
	    // color index
	    get_line();
	    ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
	    break;

        default:
            // skip the next line
            get_line();
            break;
        }
    }

    return false;
}



bool CDxfRead::ReadPolyLine()
{
	PolyLineStart();

	ResetExtrusionAndThickness();

	bool closed = false;
	int flags;
	bool first_vertex_section_found = false;
	double first_vertex[3];
	bool bulge_found;
	double bulge;

	while(!(*m_ifs).eof())
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadPolyLine() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found
			        DerefACI();
				get_line();
				if (! strcmp(m_str,"VERTEX"))
				{
				    double vertex[3];
					if (CDxfRead::ReadVertex(vertex, &bulge_found, &bulge))
					{
						if(!first_vertex_section_found) {
							first_vertex_section_found = true;
							memcpy(first_vertex, vertex, 3*sizeof(double));
						}
						StorePolyLinePoint(vertex[0], vertex[1], vertex[2], bulge_found, bulge);
						break;
					}
				}
				if (! strcmp(m_str,"SEQEND"))
				{
					AddPolyLinePoints(false, closed);
					return true;
				}
				break;
			case 70:
				// flags
				get_line();
				if(sscanf(m_str, "%d", &flags) != 1)return false;
				closed = ((flags & 1) != 0);
				break;
		        case 62:
				// color index
				get_line();
				ss.str(m_str); ss >> m_aci; if(ss.fail()) return false;
				break;
			case 39:
			case 210:
			case 220:
			case 230:
				if (!ReadExtrusionOrThickness(n))
					return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	return false;
}

struct three_doubles
{
	double x[3];
};

bool CDxfRead::ReadLeader()
{
	double vertex_coordinates[3] = {0, 0, 0};
	double horizontal_direction[3] = {1, 0, 0};
	double insertion_offset[3] = { 0, 0, 0 };
	double placement_offset[3] = { 0, 0, 0 };
	double normal_vector[3] = { 0, 0, 1 };
	int leader_creation_flag = 3;
	int arrowhead_flag = 1;
	int leader_path_type = 0;
	int hookline_direction_flag = 1;
	int hookline_flag = 0;
	double text_annotation_height = 0.3;
	double text_annotation_width = 0.3;
	bool next_item_found = false;
	std::list<three_doubles> vertices;

	while(!((*m_ifs).eof()) && !next_item_found)
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadLeader() Failed to read integer from '%s'\n"), m_str);
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish with Leader
			    DerefACI();
				next_item_found = true;
				break;
			case 8: // Layer name follows
				get_line();
				strcpy(m_layer_name, m_str);
				break;
			case 10:
				// x
				get_line();
				ss.str(m_str); ss >> vertex_coordinates[0]; vertex_coordinates[0] = mm(vertex_coordinates[0]); if(ss.fail()) return false;
				break;
			case 20:
				// y
				get_line();
				ss.str(m_str); ss >> vertex_coordinates[1]; vertex_coordinates[1] = mm(vertex_coordinates[1]); if(ss.fail()) return false;
				break;
			case 30:
				// z
				get_line();
				ss.str(m_str); ss >> vertex_coordinates[2]; vertex_coordinates[2] = mm(vertex_coordinates[2]); if(ss.fail()) return false;
				three_doubles td;
				for(int i = 0; i<3; i++)td.x[i] = vertex_coordinates[i];
				vertices.push_back(td);
				break;
			case 71:
				get_line();
				ss.str(m_str); ss >> arrowhead_flag; if (ss.fail()) return false;
				break; 
			case 72:
				get_line();
				ss.str(m_str); ss >> leader_path_type; if (ss.fail()) return false;
				break;
			case 73:
				get_line();
				ss.str(m_str); ss >> leader_creation_flag; if (ss.fail()) return false;
				break;
			case 74:
				get_line();
				ss.str(m_str); ss >> hookline_direction_flag; if (ss.fail()) return false;
				break;
			case 75:
				get_line();
				ss.str(m_str); ss >> hookline_flag; if (ss.fail()) return false;
				break;
			case 40:
				get_line();
				ss.str(m_str); ss >> text_annotation_height; if (ss.fail()) return false;
				break;
			case 41:
				get_line();
				ss.str(m_str); ss >> text_annotation_width; if (ss.fail()) return false;
				break;
			case 211:
				// x
				get_line();
				ss.str(m_str); ss >> horizontal_direction[0]; if (ss.fail()) return false;
				break;
			case 221:
				// y
				get_line();
				ss.str(m_str); ss >> horizontal_direction[1]; if (ss.fail()) return false;
				break;
			case 231:
				// z
				get_line();
				ss.str(m_str); ss >> horizontal_direction[2]; if (ss.fail()) return false;
				break;
			case 212:
				// x
				get_line();
				ss.str(m_str); ss >> insertion_offset[0]; if (ss.fail()) return false;
				break;
			case 222:
				// y
				get_line();
				ss.str(m_str); ss >> insertion_offset[1]; if (ss.fail()) return false;
				break;
			case 232:
				// z
				get_line();
				ss.str(m_str); ss >> insertion_offset[2]; if (ss.fail()) return false;
				break;
			case 213:
				// x
				get_line();
				ss.str(m_str); ss >> placement_offset[0]; if (ss.fail()) return false;
				break;
			case 223:
				// y
				get_line();
				ss.str(m_str); ss >> placement_offset[1]; if (ss.fail()) return false;
				break;
			case 233:
				// z
				get_line();
				ss.str(m_str); ss >> placement_offset[2]; if (ss.fail()) return false;
				break;
			case 210:
				// x
				get_line();
				ss.str(m_str); ss >> normal_vector[0]; if (ss.fail()) return false;
				break;
			case 220:
				// y
				get_line();
				ss.str(m_str); ss >> normal_vector[1]; if (ss.fail()) return false;
				break;
			case 230:
				// z
				get_line();
				ss.str(m_str); ss >> normal_vector[2]; if (ss.fail()) return false;
				break;
			case 100:
				// skip the next line
				get_line();
				break;
			case 340:
				// Hard reference to associated annotation (mtext, tolerance, or insert entity)
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	double leftward_direction[3] = {-horizontal_direction[1] * 0.25, horizontal_direction[0] * 0.25, 0};
	for(std::list<three_doubles>::iterator It = vertices.begin(); It != vertices.end(); It++)
	{
		three_doubles &td = *It;
		{
			// just draw a triangle with 3 lines; HeeksCAD doesn't really support leaders
			double v1[3] = {td.x[0], td.x[1], td.x[2]};
			double v2[3], v3[3];

			for(int i = 0; i<3; i++)
			{
				v2[i] = v1[i] + horizontal_direction[i] + leftward_direction[i];
				v3[i] = v1[i] + horizontal_direction[i] - leftward_direction[i];
			}

			OnReadLine(v1, v2, false);
			OnReadLine(v2, v3, false);
			OnReadLine(v3, v1, false);
		}
	}

	return next_item_found;
}

bool CDxfRead::ReadMLine()
{
	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadMLine() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}
		switch(n){
        case 0:
		    DerefACI();
            return true;
		default:
			get_line();
			break;
		}
	}

	return false;
}

bool CDxfRead::ReadXLine()
{
	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadXLine() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}
		switch(n){
        case 0:
		    DerefACI();
            return true;
		default:
			get_line();
			break;
		}
	}

	return false;
}

bool CDxfRead::ReadDimension()
{
	double def_point[3] = {0, 0, 0};
	double mid[3] = {0, 0, 0};
	double p1[3] = {0, 0, 0};
	double p2[3] = {0, 0, 0};
	double p3[3] = {0, 0, 0};
	double p4[3] = {0, 0, 0};
	double p5[3] = {0, 0, 0};
	int dimension_type = 0;
	double angle = 0;
	double angle2 = 0;
	double angle3 = 0;
	double radius_leader_length = 0;
	std::string str;

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;
		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadDimension() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}
		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:
				// next item found, so finish
				DerefACI();
				OnReadDimension(dimension_type, angle, angle2, angle3, radius_leader_length, def_point, mid, p1, p2, p3, p4, p5);
				return true;
			case 3:
				// style name
				get_line();
				//ss.str(m_str); ss >> str; if(ss.fail()) return false;
				break;
			case 70:
				// dimension type
				get_line();
				ss.str(m_str); ss >> dimension_type; if(ss.fail()) return false;
				break;
			case 50:
				// angle
				get_line();
				ss.str(m_str); ss >> angle; if(ss.fail()) return false;
				break;
			case 51:
				// angle2
				get_line();
				ss.str(m_str); ss >> angle2; if(ss.fail()) return false;
				break;
			case 52:
				// angle3
				get_line();
				ss.str(m_str); ss >> angle3; if(ss.fail()) return false;
				break;
			case 40:
				// radius leader length
				get_line();
				ss.str(m_str); ss >> radius_leader_length; if(ss.fail()) return false;
				break;
			case 10:
				// x
				get_line();
				ss.str(m_str); ss >> def_point[0]; def_point[0] = mm(def_point[0]); if(ss.fail()) return false;
				break;
			case 20:
				// y
				get_line();
				ss.str(m_str); ss >> def_point[1]; def_point[1] = mm(def_point[1]); if(ss.fail()) return false;
				break;
			case 30:
				// z
				get_line();
				ss.str(m_str); ss >> def_point[2]; def_point[2] = mm(def_point[2]); if(ss.fail()) return false;
				break;
			case 11:
				// x
				get_line();
				ss.str(m_str); ss >> mid[0]; mid[0] = mm(mid[0]); if(ss.fail()) return false;
				break;
			case 21:
				// y
				get_line();
				ss.str(m_str); ss >> mid[1]; mid[1] = mm(mid[1]); if(ss.fail()) return false;
				break;
			case 31:
				// z
				get_line();
				ss.str(m_str); ss >> mid[2]; mid[2] = mm(mid[2]); if(ss.fail()) return false;
				break;
			case 12:
				// x
				get_line();
				ss.str(m_str); ss >> p1[0]; p1[0] = mm(p1[0]); if(ss.fail()) return false;
				break;
			case 22:
				// y
				get_line();
				ss.str(m_str); ss >> p1[1]; p1[1] = mm(p1[1]); if(ss.fail()) return false;
				break;
			case 32:
				// z
				get_line();
				ss.str(m_str); ss >> p1[2]; p1[2] = mm(p1[2]); if(ss.fail()) return false;
				break;
			case 13:
				// x
				get_line();
				ss.str(m_str); ss >> p2[0]; p2[0] = mm(p2[0]); if(ss.fail()) return false;
				break;
			case 23:
				// y
				get_line();
				ss.str(m_str); ss >> p2[1]; p2[1] = mm(p2[1]); if(ss.fail()) return false;
				break;
			case 33:
				// z
				get_line();
				ss.str(m_str); ss >> p2[2]; p2[2] = mm(p2[2]); if(ss.fail()) return false;
				break;
			case 14:
				// x
				get_line();
				ss.str(m_str); ss >> p3[0]; p3[0] = mm(p3[0]); if(ss.fail()) return false;
				break;
			case 24:
				// y
				get_line();
				ss.str(m_str); ss >> p3[1]; p3[1] = mm(p3[1]); if(ss.fail()) return false;
				break;
			case 34:
				// z
				get_line();
				ss.str(m_str); ss >> p3[2]; p3[2] = mm(p3[2]); if(ss.fail()) return false;
				break;
			case 15:
				// x
				get_line();
				ss.str(m_str); ss >> p4[0]; p4[0] = mm(p4[0]); if(ss.fail()) return false;
				break;
			case 25:
				// y
				get_line();
				ss.str(m_str); ss >> p4[1]; p4[1] = mm(p4[1]); if(ss.fail()) return false;
				break;
			case 35:
				// z
				get_line();
				ss.str(m_str); ss >> p4[2]; p4[2] = mm(p4[2]); if(ss.fail()) return false;
				break;
			case 16:
				// x
				get_line();
				ss.str(m_str); ss >> p5[0]; p5[0] = mm(p5[0]); if(ss.fail()) return false;
				break;
			case 26:
				// y
				get_line();
				ss.str(m_str); ss >> p5[1]; p5[1] = mm(p5[1]); if(ss.fail()) return false;
				break;
			case 36:
				// z
				get_line();
				ss.str(m_str); ss >> p5[2]; p5[2] = mm(p5[2]); if(ss.fail()) return false;
				break;

			case 53:
			case 100:
			case 210:
			case 220:
			case 230:
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	return false;
}

void CDxfRead::OnReadArc(double start_angle, double end_angle, double radius, const double* c, bool hidden){
	double s[3], e[3], temp[3] ;
    if (m_extrusion_vector[2]>0.0)
  {
    temp[0] =c[0];
    temp[1] =c[1];
    temp[2] =c[2];
	s[0] = c[0] + radius * cos(start_angle * Pi/180);
	s[1] = c[1] + radius * sin(start_angle * Pi/180);
	s[2] = c[2];
	e[0] = c[0] + radius * cos(end_angle * Pi/180);
	e[1] = c[1] + radius * sin(end_angle * Pi/180);
	e[2] = c[2];
   }
    else
    {
    temp[0] =-c[0];
    temp[1] =c[1];
    temp[2] =c[2];
    
    e[0] = -(c[0] + radius * cos(start_angle * Pi/180));
	e[1] = (c[1] + radius * sin(start_angle * Pi/180));
	e[2] = c[2];
	s[0] = -(c[0] + radius * cos(end_angle * Pi/180));
	s[1] = (c[1] + radius * sin(end_angle * Pi/180));
	s[2] = c[2];

    }
	OnReadArc(s, e, temp, true, hidden);
}

void CDxfRead::OnReadCircle(const double* c, double radius, bool hidden){
	double s[3], c2[3];
    double start_angle = 0;
	s[0] = c[0] + radius * cos(start_angle * Pi/180);
	s[1] = c[1] + radius * sin(start_angle * Pi/180);
	s[2] = c[2];

	for (int i = 0; i < 3; i++)c2[i] = c[i];
	if (m_extrusion_vector[2] < 0)
	{
		c2[0] = -c2[0];
		s[0] = -s[0];
	}

	OnReadCircle(s, c2, false, hidden); //false to change direction because otherwise the arc length is zero
}

void CDxfRead::OnReadEllipse(const double* c, const double* m, double ratio, double start_angle, double end_angle){
	double major_radius = sqrt(m[0]*m[0] + m[1]*m[1] + m[2]*m[2]);
	double minor_radius = major_radius * ratio;

	//Since we only support 2d stuff, we can calculate the rotation from the major axis x and y value only,
	//since z is zero, major_radius is the vector length

	double rotation = atan2(m[1]/major_radius,m[0]/major_radius);


	OnReadEllipse(c, major_radius, minor_radius, rotation, start_angle, end_angle, true);
}

void CDxfRead::get_line()
{
    if (m_unused_line[0] != '\0')
    {
        strcpy(m_str, m_unused_line);
        memset( m_unused_line, '\0', sizeof(m_unused_line));
        return;
    }

	m_ifs->getline(m_str, 1024);

	char str[1024];
	int len = strlen(m_str);
	int j = 0;
	bool non_white_found = false;
	for(int i = 0; i<len; i++){
		if(non_white_found || (m_str[i] != ' ' && m_str[i] != '\t')){
#if wxUSE_UNICODE
			if(m_str[i] != '\r')
#endif
			{
				str[j] = m_str[i]; j++;
			}
			non_white_found = true;
		}
	}
	str[j] = 0;
	strcpy(m_str, str);

#ifdef STORE_LINE_NUMBERS
	m_line_number++;
#endif
}

void CDxfRead::put_line(const char *value)
{
	strcpy( m_unused_line, value );
}

bool CDxfRead::ReadUCS()
{
	double e[3] = {0, 0, 0};

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadUCS() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 9:	// next item found, so finish
				OnReadUCS(e);
				return true;

			case 10:
				// x
				get_line();
				ss.str(m_str); ss >> e[0]; e[0] = mm(e[0]); if(ss.fail()) return false;
				break;
			case 20:
				// y
				get_line();
				ss.str(m_str); ss >> e[1]; e[1] = mm(e[1]); if(ss.fail()) return false;
				break;
			case 30:
				// z
				get_line();
				ss.str(m_str); ss >> e[2]; e[2] = mm(e[2]); if(ss.fail()) return false;
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}

	return false;
}

bool CDxfRead::ReadUnits()
{
	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadUnits() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 9:	// next item found, so finish
				return true;

			case 70:
				// x
				get_line();
				if(sscanf(m_str, "%d", &n) == 1)
				{
					m_eUnits = eDxfUnits_t( n );
				}
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	return false;
}


bool CDxfRead::ReadLayer()
{
        std::string layername;
	int aci = -1;

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadLayer() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:	// next item found, so finish with line
			        if (layername.empty())
				{
				    wprintf(wxT("CDxfRead::ReadLayer() - no layer name\n"));
				    return false;
				}
			        m_layer_aci[layername] = aci;
				return true;

			case 2: // Layer name follows
				get_line();
				layername = m_str;
				break;

			case 62:
				// layer color ; if negative, layer is off
				get_line();
				if(sscanf(m_str, "%d", &aci) != 1)return false;
				break;

			case 6:	// linetype name
			case 70: // layer flags
			case 100:
			case 290:
			case 370:
			case 390:
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	return false;
}

bool CDxfRead::ReadSection()
{
	get_line();
	get_line();
	strcpy(m_section_name, m_str);
	get_line();

	while(!((*m_ifs).eof()))
	{
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadSection() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		switch(n){
			case 0:	// next item found, so finish with section
				return true;

			case 9:	// header variable
				get_line();
				if (!strcmp( m_str, "$INSUNITS" )){
					if (!ReadUnits())	
					{
						wprintf(wxT("CDxfRead::DoRead() Failed to read block\n"));
						return false;
					}
					continue;
				} // End if - then
				if (!strcmp( m_str, "$MEASUREMENT" )){
					get_line();
					get_line();
					int n = 1;
					if(sscanf(m_str, "%d", &n) == 1)
					{
						if(n == 0)m_measurement_inch = true;
					}
					break;
				} // End if - then

				if (!strcmp( m_str, "$UCSORG" )){
					if(!ReadUCS())return false;
					continue;
				} // End if - then
				break;

			default:
				// skip the next line
				get_line();
				break;
		}

		get_line();
	}

	return false;
}

bool CDxfRead::ReadBlock()
{
        wxString block_name;
	double e[3] = {0, 0, 0};

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadBlock() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:	// next item found, so finish with line
			        if (block_name.empty())
				{
				    wprintf(wxT("CDxfRead::ReadBlock() - no block name\n"));
				    return false;
				}
				OnReadBlock(block_name, e);
				return true;

			case 2: // Block name follows
			case 3: // Block name follows
				get_line();
				block_name = ParseUnicode(wxString::FromAscii(m_str));
				break;

			case 10:
				// base point x
				get_line();
				ss.str(m_str); ss >> e[0]; e[0] = mm(e[0]); if(ss.fail()) return false;
				break;
			case 20:
				// base point y
				get_line();
				ss.str(m_str); ss >> e[1]; e[1] = mm(e[1]); if(ss.fail()) return false;
				break;
			case 30:
				// base point z
				get_line();
				ss.str(m_str); ss >> e[2]; e[2] = mm(e[2]); if(ss.fail()) return false;
				break;

			case 5:	// handle
			case 8:	// layer name
			case 70: // layer flags
			case 100: // subclass marker
			case 102: // start of app defined group, or end of app defined group
			case 1:	// xref path name
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	return false;
}


bool CDxfRead::ReadInsert()
{
    wxString block_name;
	double e[3] = {0, 0, 0};
	double rotation_angle = 0.0;

	// to do, scale, rotation etc.

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadInsert() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		std::istringstream ss;
		ss.imbue(std::locale("C"));
		switch(n){
			case 0:	// next item found, so finish with line
			        if (block_name.empty())
				{
				    wprintf(wxT("CDxfRead::ReadInsert() - no block name\n"));
				    return false;
				}
				OnReadInsert(block_name, e, rotation_angle);
				return true;

			case 2: // Block name follows
				get_line();
				block_name = ParseUnicode(wxString::FromAscii(m_str));
				break;

			case 10:
				// insert point x
				get_line();
				ss.str(m_str); ss >> e[0]; e[0] = mm(e[0]); if(ss.fail()) return false;
				break;
			case 20:
				// insert point y
				get_line();
				ss.str(m_str); ss >> e[1]; e[1] = mm(e[1]); if(ss.fail()) return false;
				break;
			case 30:
				// insert point z
				get_line();
				ss.str(m_str); ss >> e[2]; e[2] = mm(e[2]); if(ss.fail()) return false;
				break;

			case 50:
				// rotation angle
				get_line();
				ss.str(m_str); ss >> rotation_angle; if(ss.fail()) return false;
				break;

			case 100: // subclass marker
			case 70: // layer flags
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	return false;
}

bool CDxfRead::ReadEndBlock()
{
    wxString block_name;

	while(!((*m_ifs).eof()))
	{
		get_line();
		int n;

		if(sscanf(m_str, "%d", &n) != 1)
		{
		    wprintf(wxT("CDxfRead::ReadEndBlock() Failed to read integer from '%s'\n"), m_str );
		    return false;
		}

		switch(n){
			case 0:	// next item found, so finish with line
				OnReadEndBlock();
				return true;

			case 2: // Block name follows
			case 3: // Block name follows
				get_line();
				block_name = ParseUnicode(wxString::FromAscii(m_str));
				break;

			case 5:	// handle
			case 100: // subclass marker
			case 102: // start of app defined group, or end of app defined group
				// skip the next line
				get_line();
				break;
			default:
				// skip the next line
				get_line();
				break;
		}
	}
	return false;
}

enum DxfVariable
{
	DxfVariableOther,
	DxfVariableUCSORG,
};

void CDxfRead::DoRead(const bool ignore_errors /* = false */ )
{
	m_ignore_errors = ignore_errors;
	if(m_fail)return;

	get_line();

	while(!((*m_ifs).eof()))
	{
		if(!strcmp(m_str, "0"))
		{
			m_thickness = 0.0;
			get_line();
			if (!strcmp( m_str, "SECTION" )){
				if(!ReadSection())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read block\n"));
					return;
				}
				continue;
			} // End if - then
			if (!strcmp( m_str, "BLOCK" )){
				if(!ReadBlock())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read block\n"));
					return;
				}
				continue;

			} // End if - then
			if (!strcmp( m_str, "ENDBLK" )){
				if(!ReadEndBlock())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read end block\n"));
					return;
				}
				continue;

			} // End if - then
			if (!strcmp( m_str, "INSERT" )){
				if(!ReadInsert())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read insert\n"));
					return;
				}
				continue;

			} // End if - then
			else if (!strcmp( m_str, "TABLE" )){
				get_line();
				get_line();
			}

			else if (!strcmp( m_str, "LAYER" )){
				if(!ReadLayer())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read layer\n"));
					return;
				}
				continue;		}

			else if (!strcmp( m_str, "ENDSEC" )){
				strcpy(m_section_name, "");
			} // End if - then
			else if(!strcmp(m_str, "LINE")){
				if(!ReadLine())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read line\n"));
					return;
				}
				continue;
			}
			else if(!strcmp(m_str, "ARC")){
				if(!ReadArc())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read arc\n"));
					return;
				}
				continue;
			}
			else if(!strcmp(m_str, "CIRCLE")){
				if(!ReadCircle())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read circle\n"));
					return;
				}
				continue;
			}
			else if(!strcmp(m_str, "TEXT")){
				if(!ReadText())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read text\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "MTEXT")){
				if (!ReadMText())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read mtext\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "RTEXT")){
				if (!ReadRText())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read rtext\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "ELLIPSE")){
				if(!ReadEllipse())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read ellipse\n"));
					return;
				}
				continue;
			}
			else if(!strcmp(m_str, "SPLINE")){
				if(!ReadSpline())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read spline\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "LWPOLYLINE")) {
				if(!ReadLwPolyLine())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read LW Polyline\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "POLYLINE")) {
				if(!ReadPolyLine())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read Polyline\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "POINT")) {
				if(!ReadPoint())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read Point\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "LEADER")) {
				if(!ReadLeader())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read Leader\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "MLINE")) {
				if(!ReadMLine())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read MLine\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "XLINE")) {
				if(!ReadXLine())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read XLine\n"));
					return;
				}
				continue;
			}
			else if (!strcmp(m_str, "DIMENSION")) {
				if(!ReadDimension())
				{
					wprintf(wxT("CDxfRead::DoRead() Failed to read Dimension\n"));
					return;
				}
				continue;
			}
		}

		get_line();
	}

	AddGraphics();
}

void  CDxfRead::DerefACI()
{

    if (m_aci == 256) // if color = layer color, replace by color from layer
    {
         m_aci = m_layer_aci[std::string(m_layer_name)];
    }
}

wxString CDxfRead::ParseUnicode(const wxString& str) const
{
	wxString ret = str;
	wxRegEx reg;

	if (reg.Compile(wxT("\\\\[Uu]\\+([0-9a-fA-F]{4})"))) {
		while (reg.Matches(ret)) {
			wxString unicode_as_hex = reg.GetMatch(ret, 1);
			unsigned long val;
			unicode_as_hex.ToULong(&val, 16);
			wchar_t unicode = val;
			reg.ReplaceFirst(&ret, wxString(unicode));
		}
	}
	return ret;
}

wxString CDxfRead::LayerName() const
{
	wxString result;

	if (strlen(m_section_name) > 0)
	{
		result.append(wxString::FromAscii(m_section_name));
	}

	if (strlen(m_layer_name) > 0)
	{
		result.append(wxT(" "));
		result.append(ParseUnicode(wxString::FromAscii(m_layer_name)));
	}

	return(result);
}