<commit_before>// Fixture.cpp
/*
 * Copyright (c) 2009, <NAME>, <NAME>
 * This program is released under the BSD license. See the file COPYING for
 * details.
 */

#include "stdafx.h"
#include <math.h>
#include "Fixture.h"
#include "CNCConfig.h"
#include "ProgramCanvas.h"
#include "interface/HeeksObj.h"
#include "interface/PropertyInt.h"
#include "interface/PropertyDouble.h"
#include "interface/PropertyLength.h"
#include "interface/PropertyChoice.h"
#include "interface/PropertyString.h"
#include "interface/PropertyVertex.h"
#include "tinyxml/tinyxml.h"
#include "Op.h"

#include <gp_Pnt.hxx>
#include <gp_Ax1.hxx>
#include <gp_Trsf.hxx>

#include <sstream>
#include <string>
#include <algorithm>

extern CHeeksCADInterface* heeksCAD;

void CFixtureParams::set_initial_values()
{
	CNCConfig config;

	config.Read(_T("m_a_axis"), &m_a_axis, 0.0);
	config.Read(_T("m_b_axis"), &m_a_axis, 0.0);
	config.Read(_T("m_c_axis"), &m_a_axis, 0.0);

	double pivot_point_x, pivot_point_y, pivot_point_z;
	config.Read(_T("pivot_point_x"), &pivot_point_x, 0.0);
	config.Read(_T("pivot_point_y"), &pivot_point_y, 0.0);
	config.Read(_T("pivot_point_z"), &pivot_point_z, 0.0);

	m_pivot_point = gp_Pnt( pivot_point_x, pivot_point_y, pivot_point_z );
}

void CFixtureParams::write_values_to_config()
{
	CNCConfig config;

	// We ALWAYS write the parameters into the configuration file in mm (for consistency).
	// If we're now in inches then convert the values.
	// We're in mm already.
	config.Write(_T("m_a_axis"), m_a_axis);
	config.Write(_T("m_b_axis"), m_b_axis);
	config.Write(_T("m_c_axis"), m_c_axis);

	config.Write(_T("pivot_point_x"), m_pivot_point.X());
	config.Write(_T("pivot_point_y"), m_pivot_point.Y());
	config.Write(_T("pivot_point_z"), m_pivot_point.Z());
}

static void on_set_a_axis(double value, HeeksObj* object){((CFixture*)object)->m_params.m_a_axis = value; ((CFixture*)object)->ResetTitle(); }
static void on_set_b_axis(double value, HeeksObj* object){((CFixture*)object)->m_params.m_b_axis = value; ((CFixture*)object)->ResetTitle(); }
static void on_set_c_axis(double value, HeeksObj* object){((CFixture*)object)->m_params.m_c_axis = value; ((CFixture*)object)->ResetTitle(); }

static void on_set_pivot_point(const double *vt, HeeksObj* object){
	((CFixtureParams *)object)->m_pivot_point.SetX( vt[0] );
	((CFixtureParams *)object)->m_pivot_point.SetY( vt[1] );
	((CFixtureParams *)object)->m_pivot_point.SetZ( vt[2] );
}

void CFixtureParams::GetProperties(CFixture* parent, std::list<Property *> *list)
{
	list->push_back(new PropertyDouble(_("WARNING: This function is not yet complete"), m_a_axis, parent, on_set_a_axis));

	list->push_back(new PropertyDouble(_("A axis (around X) rotation"), m_a_axis, parent, on_set_a_axis));
	list->push_back(new PropertyDouble(_("B axis (around Y) rotation"), m_b_axis, parent, on_set_b_axis));
	list->push_back(new PropertyDouble(_("C axis (around Z) rotation"), m_c_axis, parent, on_set_c_axis));

	double pivot_point[3];
	pivot_point[0] = m_pivot_point.X();
	pivot_point[1] = m_pivot_point.Y();
	pivot_point[2] = m_pivot_point.Z();

	list->push_back(new PropertyVertex(_("Origin"), pivot_point, parent, on_set_pivot_point));
}

void CFixtureParams::WriteXMLAttributes(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "params" );
	root->LinkEndChild( element );  

	element->SetDoubleAttribute("a_axis", m_a_axis);
	element->SetDoubleAttribute("b_axis", m_b_axis);
	element->SetDoubleAttribute("c_axis", m_c_axis);

	element->SetDoubleAttribute("pivot_point_x", m_pivot_point.X());
	element->SetDoubleAttribute("pivot_point_y", m_pivot_point.Y());
	element->SetDoubleAttribute("pivot_point_z", m_pivot_point.Z());
}

void CFixtureParams::ReadParametersFromXMLElement(TiXmlElement* pElem)
{
	set_initial_values();

	if (pElem->Attribute("a_axis")) m_a_axis = atof(pElem->Attribute("a_axis"));
	if (pElem->Attribute("b_axis")) m_b_axis = atof(pElem->Attribute("b_axis"));
	if (pElem->Attribute("c_axis")) m_c_axis = atof(pElem->Attribute("c_axis"));

	if (pElem->Attribute("pivot_point_x")) m_pivot_point.SetX( atof(pElem->Attribute("pivot_point_x")) );
	if (pElem->Attribute("pivot_point_y")) m_pivot_point.SetY( atof(pElem->Attribute("pivot_point_y")) );
	if (pElem->Attribute("pivot_point_z")) m_pivot_point.SetZ( atof(pElem->Attribute("pivot_point_z")) );

}

/**
	This method is called when the CAD operator presses the Python button.  This method generates
	Python source code whose job will be to generate RS-274 GCode.  It's done in two steps so that
	the Python code can be configured to generate GCode suitable for various CNC interpreters.

	This class should just select the appropriate coordinate system.
 */
void CFixture::AppendTextToProgram() const
{

#ifdef UNICODE
	std::wostringstream ss;
#else
    std::ostringstream ss;
#endif
    ss.imbue(std::locale("C"));

	if (m_title.size() > 0)
	{
		ss << "comment('" << m_title.c_str() << "')\n";
	} // End if - then

	ss << "workplane(" << m_coordinate_system_number << ")\n";

	theApp.m_program_canvas->m_textCtrl->AppendText(ss.str().c_str());
}


// 1 = G54, 2 = G55 etc.
static void on_set_coordinate_system_number(const int value, HeeksObj* object)
{
	((CFixture*)object)->m_coordinate_system_number = CFixture::eCoordinateSystemNumber_t(value + 1);	// Change from zero-based to one-based offset
	((CFixture*)object)->ResetTitle();
} // End on_set_coordinate_system_number

/**
	NOTE: The m_title member is a special case.  The HeeksObj code looks for a 'GetShortString()' method.  If found, it
	adds a Property called 'Object Title'.  If the value is changed, it tries to call the 'OnEditString()' method.
	That's why the m_title value is not defined here
 */
void CFixture::GetProperties(std::list<Property *> *list)
{
	std::list< wxString > choices;

	{
		choices.push_back(_("G54"));
		choices.push_back(_("G55"));
		choices.push_back(_("G56"));
		choices.push_back(_("G57"));
		choices.push_back(_("G58"));
		choices.push_back(_("G59"));
		choices.push_back(_("G59.1"));
		choices.push_back(_("G59.2"));
		choices.push_back(_("G59.3"));
	} // End for
	list->push_back(new PropertyChoice(_("Coordinate System"), choices, int(m_coordinate_system_number) - 1, this, on_set_coordinate_system_number));

	m_params.GetProperties(this, list);
	HeeksObj::GetProperties(list);
}


HeeksObj *CFixture::MakeACopy(void)const
{
	return new CFixture(*this);
}

void CFixture::CopyFrom(const HeeksObj* object)
{
	operator=(*((CFixture*)object));
}

bool CFixture::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == ToolsType;
}

void CFixture::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element = new TiXmlElement( "Fixture" );
	root->LinkEndChild( element );  
	element->SetAttribute("title", Ttc(m_title.c_str()));

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_coordinate_system_number;
	element->SetAttribute("coordinate_system_number", l_ossValue.str().c_str() );

	m_params.WriteXMLAttributes(element);
	WriteBaseXML(element);
}

// static member function
HeeksObj* CFixture::ReadFromXMLElement(TiXmlElement* element)
{
	int coordinate_system_number = 1;
	if (element->Attribute("coordinate_system_number")) coordinate_system_number = atoi(element->Attribute("coordinate_system_number"));

	if (element->Attribute("title"))
	{
		wxString title(Ctt(element->Attribute("title")));
		CFixture* new_object = new CFixture( title.c_str(), CFixture::eCoordinateSystemNumber_t(coordinate_system_number));

		for(TiXmlElement* pElem = TiXmlHandle(element).FirstChildElement().Element(); pElem; pElem = pElem->NextSiblingElement())
		{
			std::string name(pElem->Value());
			if(name == "params"){
				new_object->m_params.ReadParametersFromXMLElement(pElem);
			}
		}

		new_object->ReadBaseXML(element);
		return new_object;
	} // End if - then

	return(NULL);
}


void CFixture::OnEditString(const wxChar* str){
        m_title.assign(str);
	heeksCAD->WasModified(this);
}

CFixture *CFixture::Find( const eCoordinateSystemNumber_t coordinate_system_number )
{
	CHeeksCNCApp::Symbols_t all_symbols = CHeeksCNCApp::GetAllSymbols();
	for (CHeeksCNCApp::Symbols_t::const_iterator l_itSymbol = all_symbols.begin(); l_itSymbol != all_symbols.end(); l_itSymbol++)
	{
                if (l_itSymbol->first != FixtureType) continue;

		HeeksObj *ob = heeksCAD->GetIDObject( l_itSymbol->first, l_itSymbol->second );
                if (ob != NULL)
                {
			if (((CFixture *)ob)->m_coordinate_system_number == coordinate_system_number)
			{
				return( (CFixture *) ob );
			} // End if - then
                } // End if - then
        } // End for

	return(NULL);

} // End Find() method

int CFixture::GetNextFixture()
{
	std::set< int > existing_fixtures;

	CHeeksCNCApp::Symbols_t all_symbols = CHeeksCNCApp::GetAllSymbols();
	for (CHeeksCNCApp::Symbols_t::const_iterator l_itSymbol = all_symbols.begin(); l_itSymbol != all_symbols.end(); l_itSymbol++)
	{
                if (l_itSymbol->first != FixtureType) continue;

		HeeksObj *ob = heeksCAD->GetIDObject( l_itSymbol->first, l_itSymbol->second );
                if (ob != NULL)
                {
			existing_fixtures.insert( int(((CFixture *)ob)->m_coordinate_system_number) );
                } // End if - then
        } // End for

	// Now run through and find one that's not already used.
	for (int fixture = int(CFixture::G54); fixture <= int(CFixture::G59_3); fixture++)
	{
		if (std::find( existing_fixtures.begin(), existing_fixtures.end(), fixture ) == existing_fixtures.end())
		{
			// This one is free.

			return(fixture);
		} // End if - then
	} // End for

	return(-1);	// None available.
} // End GetNextFixture() method



/**
 * This method uses the various attributes of the cutting tool to produce a meaningful name.
 * eg: with diameter = 6, units = 1 (mm) and type = 'drill' the name would be '6mm Drill Bit".  The
 * idea is to produce a m_title value that is representative of the cutting tool.  This will
 * make selection in the program list easier.
 *
 * NOTE: The ResetTitle() method looks at the m_title value for strings that are likely to
 * have come from this method.  If this method changes, the ResetTitle() method may also
 * need to change.
 */
wxString CFixture::GenerateMeaningfulName() const
{
#ifdef UNICODE
	std::wostringstream l_ossName;
#else
    std::ostringstream l_ossName;
#endif

	switch (m_coordinate_system_number)
	{
		case CFixture::G54:		l_ossName << "G54";
							break;

		case CFixture::G55:		l_ossName << "G55";
							break;

		case CFixture::G56:		l_ossName << "G56";
							break;

		case CFixture::G57:		l_ossName << "G57";
							break;

		case CFixture::G58:		l_ossName << "G58";
							break;

		case CFixture::G59:		l_ossName << "G59";
							break;

		case CFixture::G59_1:		l_ossName << "G59.1";
							break;

		case CFixture::G59_2:		l_ossName << "G59.2";
							break;

		case CFixture::G59_3:		l_ossName << "G59.3";
							break;

		default:				break;
	} // End switch

	if (abs(m_params.m_a_axis) > 0.0000001)
	{
		l_ossName << " rotated " << m_params.m_a_axis << " degrees in YZ plane";
	} // End if - then

	if (abs(m_params.m_b_axis) > 0.0000001)
	{
		l_ossName << " rotated " << m_params.m_b_axis << " degrees in XZ plane";
	} // End if - then

	if (abs(m_params.m_c_axis) > 0.0000001)
	{
		l_ossName << " rotated " << m_params.m_c_axis << " degrees in XY plane";
	} // End if - then

	return( l_ossName.str().c_str() );
} // End GenerateMeaningfulName() method


/**
	Reset the m_title value with a meaningful name ONLY if it does not look like it was
	automatically generated in the first place.  If someone has reset it manually then leave it alone.

	Return a verbose description of what we've done (if anything) so that we can pop up a
	warning message to the operator letting them know.
 */
wxString CFixture::ResetTitle()
{
#ifdef UNICODE
	std::wostringstream l_ossUnits;
#else
    std::ostringstream l_ossUnits;
#endif

	if ( (m_title == GetTypeString()) ||
	     ((m_title.Find( _T("G5") ) != -1)))
	{
		// It has the default title.  Give it a name that makes sense.
		m_title = GenerateMeaningfulName();
		heeksCAD->WasModified(this);

#ifdef UNICODE
		std::wostringstream l_ossChange;
#else
		std::ostringstream l_ossChange;
#endif
		l_ossChange << "Changing name to " << m_title.c_str() << "\n";
		return( l_ossChange.str().c_str() );
	} // End if - then

	// Nothing changed, nothing to report
	return(_T(""));
} // End ResetTitle() method



/**
        This is the Graphics Library Commands (from the OpenGL set).  This method calls the OpenGL
        routines to paint the cutting tool in the graphics window.  The graphics is transient.
 */
void CFixture::glCommands(bool select, bool marked, bool no_color)
{

} // End glCommands() method


/**
	The Adjustment() method is the workhorse of this class.  This is where the coordinate
	data that's used to generate GCode is rotated to its new position based on the
	fixture's settings.  All the NC Operations classes should use this method to rotate
	their values immediately prior to generating GCode.
 */

gp_Pnt CFixture::Adjustment( const gp_Pnt & point ) const
{
	gp_Pnt transformed_point(point);

	gp_Dir x_direction( 1, 0, 0 );
	gp_Dir y_direction( 0, 1, 0 );
	gp_Dir z_direction( 0, 0, 1 );

	double a_axis_angle_in_radians = (m_params.m_a_axis / 360) * (2 * 3.1415926);	// degrees expressed in radians
	double b_axis_angle_in_radians = (m_params.m_b_axis / 360) * (2 * 3.1415926);	// degrees expressed in radians
	double c_axis_angle_in_radians = (m_params.m_c_axis / 360) * (2 * 3.1415926);	// degrees expressed in radians

	gp_Trsf a_axis_rotation_matrix;
	a_axis_rotation_matrix.SetRotation( gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), x_direction), a_axis_angle_in_radians );

	gp_Trsf b_axis_rotation_matrix;
	b_axis_rotation_matrix.SetRotation( gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), y_direction), b_axis_angle_in_radians );

	gp_Trsf c_axis_rotation_matrix;
	c_axis_rotation_matrix.SetRotation( gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), z_direction), c_axis_angle_in_radians );

	transformed_point.Transform( a_axis_rotation_matrix );
	transformed_point.Transform( b_axis_rotation_matrix );
	transformed_point.Transform( c_axis_rotation_matrix );

	return(transformed_point);
} // End Adjustment() method

void CFixture::Adjustment( double *point ) const
{
	gp_Pnt ref( point[0], point[1], point[2] );
	ref = Adjustment( ref );
	point[0] = ref.X();
	point[1] = ref.Y();
	point[2] = ref.Z();

} // End Adjustment() method




<commit_msg>Renamed 'origin' to 'pivot point' so as to avoid confusion.<commit_after>// Fixture.cpp
/*
 * Copyright (c) 2009, <NAME>, <NAME>
 * This program is released under the BSD license. See the file COPYING for
 * details.
 */

#include "stdafx.h"
#include <math.h>
#include "Fixture.h"
#include "CNCConfig.h"
#include "ProgramCanvas.h"
#include "interface/HeeksObj.h"
#include "interface/PropertyInt.h"
#include "interface/PropertyDouble.h"
#include "interface/PropertyLength.h"
#include "interface/PropertyChoice.h"
#include "interface/PropertyString.h"
#include "interface/PropertyVertex.h"
#include "tinyxml/tinyxml.h"
#include "Op.h"

#include <gp_Pnt.hxx>
#include <gp_Ax1.hxx>
#include <gp_Trsf.hxx>

#include <sstream>
#include <string>
#include <algorithm>

extern CHeeksCADInterface* heeksCAD;

void CFixtureParams::set_initial_values()
{
	CNCConfig config;

	config.Read(_T("m_a_axis"), &m_a_axis, 0.0);
	config.Read(_T("m_b_axis"), &m_a_axis, 0.0);
	config.Read(_T("m_c_axis"), &m_a_axis, 0.0);

	double pivot_point_x, pivot_point_y, pivot_point_z;
	config.Read(_T("pivot_point_x"), &pivot_point_x, 0.0);
	config.Read(_T("pivot_point_y"), &pivot_point_y, 0.0);
	config.Read(_T("pivot_point_z"), &pivot_point_z, 0.0);

	m_pivot_point = gp_Pnt( pivot_point_x, pivot_point_y, pivot_point_z );
}

void CFixtureParams::write_values_to_config()
{
	CNCConfig config;

	// We ALWAYS write the parameters into the configuration file in mm (for consistency).
	// If we're now in inches then convert the values.
	// We're in mm already.
	config.Write(_T("m_a_axis"), m_a_axis);
	config.Write(_T("m_b_axis"), m_b_axis);
	config.Write(_T("m_c_axis"), m_c_axis);

	config.Write(_T("pivot_point_x"), m_pivot_point.X());
	config.Write(_T("pivot_point_y"), m_pivot_point.Y());
	config.Write(_T("pivot_point_z"), m_pivot_point.Z());
}

static void on_set_a_axis(double value, HeeksObj* object){((CFixture*)object)->m_params.m_a_axis = value; ((CFixture*)object)->ResetTitle(); }
static void on_set_b_axis(double value, HeeksObj* object){((CFixture*)object)->m_params.m_b_axis = value; ((CFixture*)object)->ResetTitle(); }
static void on_set_c_axis(double value, HeeksObj* object){((CFixture*)object)->m_params.m_c_axis = value; ((CFixture*)object)->ResetTitle(); }

static void on_set_pivot_point(const double *vt, HeeksObj* object){
	((CFixtureParams *)object)->m_pivot_point.SetX( vt[0] );
	((CFixtureParams *)object)->m_pivot_point.SetY( vt[1] );
	((CFixtureParams *)object)->m_pivot_point.SetZ( vt[2] );
}

void CFixtureParams::GetProperties(CFixture* parent, std::list<Property *> *list)
{
	list->push_back(new PropertyDouble(_("WARNING: This function is not yet complete"), m_a_axis, parent, on_set_a_axis));

	list->push_back(new PropertyDouble(_("A axis (around X) rotation"), m_a_axis, parent, on_set_a_axis));
	list->push_back(new PropertyDouble(_("B axis (around Y) rotation"), m_b_axis, parent, on_set_b_axis));
	list->push_back(new PropertyDouble(_("C axis (around Z) rotation"), m_c_axis, parent, on_set_c_axis));

	double pivot_point[3];
	pivot_point[0] = m_pivot_point.X();
	pivot_point[1] = m_pivot_point.Y();
	pivot_point[2] = m_pivot_point.Z();

	list->push_back(new PropertyVertex(_("Pivot Point"), pivot_point, parent, on_set_pivot_point));
}

void CFixtureParams::WriteXMLAttributes(TiXmlNode *root)
{
	TiXmlElement * element;
	element = new TiXmlElement( "params" );
	root->LinkEndChild( element );  

	element->SetDoubleAttribute("a_axis", m_a_axis);
	element->SetDoubleAttribute("b_axis", m_b_axis);
	element->SetDoubleAttribute("c_axis", m_c_axis);

	element->SetDoubleAttribute("pivot_point_x", m_pivot_point.X());
	element->SetDoubleAttribute("pivot_point_y", m_pivot_point.Y());
	element->SetDoubleAttribute("pivot_point_z", m_pivot_point.Z());
}

void CFixtureParams::ReadParametersFromXMLElement(TiXmlElement* pElem)
{
	set_initial_values();

	if (pElem->Attribute("a_axis")) m_a_axis = atof(pElem->Attribute("a_axis"));
	if (pElem->Attribute("b_axis")) m_b_axis = atof(pElem->Attribute("b_axis"));
	if (pElem->Attribute("c_axis")) m_c_axis = atof(pElem->Attribute("c_axis"));

	if (pElem->Attribute("pivot_point_x")) m_pivot_point.SetX( atof(pElem->Attribute("pivot_point_x")) );
	if (pElem->Attribute("pivot_point_y")) m_pivot_point.SetY( atof(pElem->Attribute("pivot_point_y")) );
	if (pElem->Attribute("pivot_point_z")) m_pivot_point.SetZ( atof(pElem->Attribute("pivot_point_z")) );

}

/**
	This method is called when the CAD operator presses the Python button.  This method generates
	Python source code whose job will be to generate RS-274 GCode.  It's done in two steps so that
	the Python code can be configured to generate GCode suitable for various CNC interpreters.

	This class should just select the appropriate coordinate system.
 */
void CFixture::AppendTextToProgram() const
{

#ifdef UNICODE
	std::wostringstream ss;
#else
    std::ostringstream ss;
#endif
    ss.imbue(std::locale("C"));

	if (m_title.size() > 0)
	{
		ss << "comment('" << m_title.c_str() << "')\n";
	} // End if - then

	ss << "workplane(" << m_coordinate_system_number << ")\n";

	theApp.m_program_canvas->m_textCtrl->AppendText(ss.str().c_str());
}


// 1 = G54, 2 = G55 etc.
static void on_set_coordinate_system_number(const int value, HeeksObj* object)
{
	((CFixture*)object)->m_coordinate_system_number = CFixture::eCoordinateSystemNumber_t(value + 1);	// Change from zero-based to one-based offset
	((CFixture*)object)->ResetTitle();
} // End on_set_coordinate_system_number

/**
	NOTE: The m_title member is a special case.  The HeeksObj code looks for a 'GetShortString()' method.  If found, it
	adds a Property called 'Object Title'.  If the value is changed, it tries to call the 'OnEditString()' method.
	That's why the m_title value is not defined here
 */
void CFixture::GetProperties(std::list<Property *> *list)
{
	std::list< wxString > choices;

	{
		choices.push_back(_("G54"));
		choices.push_back(_("G55"));
		choices.push_back(_("G56"));
		choices.push_back(_("G57"));
		choices.push_back(_("G58"));
		choices.push_back(_("G59"));
		choices.push_back(_("G59.1"));
		choices.push_back(_("G59.2"));
		choices.push_back(_("G59.3"));
	} // End for
	list->push_back(new PropertyChoice(_("Coordinate System"), choices, int(m_coordinate_system_number) - 1, this, on_set_coordinate_system_number));

	m_params.GetProperties(this, list);
	HeeksObj::GetProperties(list);
}


HeeksObj *CFixture::MakeACopy(void)const
{
	return new CFixture(*this);
}

void CFixture::CopyFrom(const HeeksObj* object)
{
	operator=(*((CFixture*)object));
}

bool CFixture::CanAddTo(HeeksObj* owner)
{
	return owner->GetType() == ToolsType;
}

void CFixture::WriteXML(TiXmlNode *root)
{
	TiXmlElement * element = new TiXmlElement( "Fixture" );
	root->LinkEndChild( element );  
	element->SetAttribute("title", Ttc(m_title.c_str()));

	std::ostringstream l_ossValue;
	l_ossValue.str(""); l_ossValue << m_coordinate_system_number;
	element->SetAttribute("coordinate_system_number", l_ossValue.str().c_str() );

	m_params.WriteXMLAttributes(element);
	WriteBaseXML(element);
}

// static member function
HeeksObj* CFixture::ReadFromXMLElement(TiXmlElement* element)
{
	int coordinate_system_number = 1;
	if (element->Attribute("coordinate_system_number")) coordinate_system_number = atoi(element->Attribute("coordinate_system_number"));

	if (element->Attribute("title"))
	{
		wxString title(Ctt(element->Attribute("title")));
		CFixture* new_object = new CFixture( title.c_str(), CFixture::eCoordinateSystemNumber_t(coordinate_system_number));

		for(TiXmlElement* pElem = TiXmlHandle(element).FirstChildElement().Element(); pElem; pElem = pElem->NextSiblingElement())
		{
			std::string name(pElem->Value());
			if(name == "params"){
				new_object->m_params.ReadParametersFromXMLElement(pElem);
			}
		}

		new_object->ReadBaseXML(element);
		return new_object;
	} // End if - then

	return(NULL);
}


void CFixture::OnEditString(const wxChar* str){
        m_title.assign(str);
	heeksCAD->WasModified(this);
}

CFixture *CFixture::Find( const eCoordinateSystemNumber_t coordinate_system_number )
{
	CHeeksCNCApp::Symbols_t all_symbols = CHeeksCNCApp::GetAllSymbols();
	for (CHeeksCNCApp::Symbols_t::const_iterator l_itSymbol = all_symbols.begin(); l_itSymbol != all_symbols.end(); l_itSymbol++)
	{
                if (l_itSymbol->first != FixtureType) continue;

		HeeksObj *ob = heeksCAD->GetIDObject( l_itSymbol->first, l_itSymbol->second );
                if (ob != NULL)
                {
			if (((CFixture *)ob)->m_coordinate_system_number == coordinate_system_number)
			{
				return( (CFixture *) ob );
			} // End if - then
                } // End if - then
        } // End for

	return(NULL);

} // End Find() method

int CFixture::GetNextFixture()
{
	std::set< int > existing_fixtures;

	CHeeksCNCApp::Symbols_t all_symbols = CHeeksCNCApp::GetAllSymbols();
	for (CHeeksCNCApp::Symbols_t::const_iterator l_itSymbol = all_symbols.begin(); l_itSymbol != all_symbols.end(); l_itSymbol++)
	{
                if (l_itSymbol->first != FixtureType) continue;

		HeeksObj *ob = heeksCAD->GetIDObject( l_itSymbol->first, l_itSymbol->second );
                if (ob != NULL)
                {
			existing_fixtures.insert( int(((CFixture *)ob)->m_coordinate_system_number) );
                } // End if - then
        } // End for

	// Now run through and find one that's not already used.
	for (int fixture = int(CFixture::G54); fixture <= int(CFixture::G59_3); fixture++)
	{
		if (std::find( existing_fixtures.begin(), existing_fixtures.end(), fixture ) == existing_fixtures.end())
		{
			// This one is free.

			return(fixture);
		} // End if - then
	} // End for

	return(-1);	// None available.
} // End GetNextFixture() method



/**
 * This method uses the various attributes of the cutting tool to produce a meaningful name.
 * eg: with diameter = 6, units = 1 (mm) and type = 'drill' the name would be '6mm Drill Bit".  The
 * idea is to produce a m_title value that is representative of the cutting tool.  This will
 * make selection in the program list easier.
 *
 * NOTE: The ResetTitle() method looks at the m_title value for strings that are likely to
 * have come from this method.  If this method changes, the ResetTitle() method may also
 * need to change.
 */
wxString CFixture::GenerateMeaningfulName() const
{
#ifdef UNICODE
	std::wostringstream l_ossName;
#else
    std::ostringstream l_ossName;
#endif

	switch (m_coordinate_system_number)
	{
		case CFixture::G54:		l_ossName << "G54";
							break;

		case CFixture::G55:		l_ossName << "G55";
							break;

		case CFixture::G56:		l_ossName << "G56";
							break;

		case CFixture::G57:		l_ossName << "G57";
							break;

		case CFixture::G58:		l_ossName << "G58";
							break;

		case CFixture::G59:		l_ossName << "G59";
							break;

		case CFixture::G59_1:		l_ossName << "G59.1";
							break;

		case CFixture::G59_2:		l_ossName << "G59.2";
							break;

		case CFixture::G59_3:		l_ossName << "G59.3";
							break;

		default:				break;
	} // End switch

	if (abs(m_params.m_a_axis) > 0.0000001)
	{
		l_ossName << " rotated " << m_params.m_a_axis << " degrees in YZ plane";
	} // End if - then

	if (abs(m_params.m_b_axis) > 0.0000001)
	{
		l_ossName << " rotated " << m_params.m_b_axis << " degrees in XZ plane";
	} // End if - then

	if (abs(m_params.m_c_axis) > 0.0000001)
	{
		l_ossName << " rotated " << m_params.m_c_axis << " degrees in XY plane";
	} // End if - then

	return( l_ossName.str().c_str() );
} // End GenerateMeaningfulName() method


/**
	Reset the m_title value with a meaningful name ONLY if it does not look like it was
	automatically generated in the first place.  If someone has reset it manually then leave it alone.

	Return a verbose description of what we've done (if anything) so that we can pop up a
	warning message to the operator letting them know.
 */
wxString CFixture::ResetTitle()
{
#ifdef UNICODE
	std::wostringstream l_ossUnits;
#else
    std::ostringstream l_ossUnits;
#endif

	if ( (m_title == GetTypeString()) ||
	     ((m_title.Find( _T("G5") ) != -1)))
	{
		// It has the default title.  Give it a name that makes sense.
		m_title = GenerateMeaningfulName();
		heeksCAD->WasModified(this);

#ifdef UNICODE
		std::wostringstream l_ossChange;
#else
		std::ostringstream l_ossChange;
#endif
		l_ossChange << "Changing name to " << m_title.c_str() << "\n";
		return( l_ossChange.str().c_str() );
	} // End if - then

	// Nothing changed, nothing to report
	return(_T(""));
} // End ResetTitle() method



/**
        This is the Graphics Library Commands (from the OpenGL set).  This method calls the OpenGL
        routines to paint the cutting tool in the graphics window.  The graphics is transient.
 */
void CFixture::glCommands(bool select, bool marked, bool no_color)
{

} // End glCommands() method


/**
	The Adjustment() method is the workhorse of this class.  This is where the coordinate
	data that's used to generate GCode is rotated to its new position based on the
	fixture's settings.  All the NC Operations classes should use this method to rotate
	their values immediately prior to generating GCode.
 */

gp_Pnt CFixture::Adjustment( const gp_Pnt & point ) const
{
	gp_Pnt transformed_point(point);

	gp_Dir x_direction( 1, 0, 0 );
	gp_Dir y_direction( 0, 1, 0 );
	gp_Dir z_direction( 0, 0, 1 );

	double a_axis_angle_in_radians = (m_params.m_a_axis / 360) * (2 * 3.1415926);	// degrees expressed in radians
	double b_axis_angle_in_radians = (m_params.m_b_axis / 360) * (2 * 3.1415926);	// degrees expressed in radians
	double c_axis_angle_in_radians = (m_params.m_c_axis / 360) * (2 * 3.1415926);	// degrees expressed in radians

	gp_Trsf a_axis_rotation_matrix;
	a_axis_rotation_matrix.SetRotation( gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), x_direction), a_axis_angle_in_radians );

	gp_Trsf b_axis_rotation_matrix;
	b_axis_rotation_matrix.SetRotation( gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), y_direction), b_axis_angle_in_radians );

	gp_Trsf c_axis_rotation_matrix;
	c_axis_rotation_matrix.SetRotation( gp_Ax1(gp_Pnt(0.0, 0.0, 0.0), z_direction), c_axis_angle_in_radians );

	transformed_point.Transform( a_axis_rotation_matrix );
	transformed_point.Transform( b_axis_rotation_matrix );
	transformed_point.Transform( c_axis_rotation_matrix );

	return(transformed_point);
} // End Adjustment() method

void CFixture::Adjustment( double *point ) const
{
	gp_Pnt ref( point[0], point[1], point[2] );
	ref = Adjustment( ref );
	point[0] = ref.X();
	point[1] = ref.Y();
	point[2] = ref.Z();

} // End Adjustment() method





{'fraction_non_alphanumeric': 0.14110556225245394, 'fraction_numerical': 0.01425865334940589, 'mean_word_length': 4.804878048780488, 'pattern_counts': {'":': 0, '<': 143, '<?xml version=': 0, '>': 161, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7081297', 'n_tokens_mistral': 11131, 'n_tokens_neox': 10358, 'n_words': 2364}