		/****************************************************/
		/* Gestion des composants specifiques aux microndes */
		/****************************************************/

		/* Fichier MUONDE.CPP */

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"
#include "trigo.h"
#include "pcbnew.h"
#include "autorout.h"

#include "drag.h"

#include <string.h>
#include "protos.h"

/* fonctions importees */

/* Fonctions locales */
static void Exit_Muonde(WinEDA_DrawFrame * frame, wxDC *DC);

/* Variables locales : */
#define COEFF_COUNT 6
double * PolyEdges;
int PolyEdgesCount;
double ShapeScaleX, ShapeScaleY;
wxSize ShapeSize;
int PolyShapeType;

#include "gen_self.h"

/***************************************************************************/
MODULE * WinEDA_PcbFrame::Create_MuWaveBasicShape(wxDC * DC,
			const wxString & name, int pad_count)
/***************************************************************************/
/* Create a footprint with pad_count pads for micro wave applications
This footprint has pad_count pads:
 SMD, rectangular, H size = V size = current track width.
*/
{
MODULE * Module;
int pad_num = 1;
wxString Line;	

	Module = Create_1_Module(DC, name);
	if ( Module == NULL ) return NULL;
	
	Module->m_TimeStamp = GetTimeStamp();
	Module->m_Value->m_Size = wxSize(30,30);
	Module->m_Value->m_Pos0.y = -30;
	Module->m_Value->m_Pos.y += Module->m_Value->m_Pos0.y;
	Module->m_Reference->m_Size = wxSize(30,30);
	Module->m_Reference->m_Pos0.y = 30;
	Module->m_Reference->m_Pos.y += Module->m_Reference->m_Pos0.y;

	/* Creation des pastilles formant le gap */
	while ( pad_count -- )
	{
	D_PAD* pad;
		pad = new D_PAD(Module);
		pad->Pback = Module;
		if ( Module->m_Pads == NULL )
		{
			Module->m_Pads = pad;
		}
		else
		{
			Module->m_Pads->Pback = pad;
			pad->Pnext = Module->m_Pads;
			Module->m_Pads = pad;
		}
		pad->m_Size.x = pad->m_Size.y = g_DesignSettings.m_CurrentTrackWidth;
		pad->m_Pos = Module->m_Pos;
		pad->m_PadShape = RECT;
		pad->m_Attribut = SMD;
		pad->m_Masque_Layer = CMP_LAYER;
		Line.Printf( wxT("%d"), pad_num);
		pad->SetPadName(Line);
		pad_num++;
	}

	if (DC) Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_OR) ;
	return Module;
}



/**********************************************************/
static void Exit_Muonde(WinEDA_DrawFrame * frame, wxDC *DC )
/**********************************************************/
{
MODULE * Module = (MODULE*) frame->m_CurrentScreen->m_CurrentItem;

	if( Module )
		{
		if ( Module->m_Flags & IS_NEW)
			{
			Module->Draw(frame->DrawPanel, DC, wxPoint(0,0), GR_XOR) ;
			DeleteStructure( Module);
			}
		else
			{
			Module->Draw(frame->DrawPanel, DC, wxPoint(0,0), GR_XOR) ;
			}
		}

	frame->DrawPanel->ManageCurseur = NULL;
	frame->DrawPanel->ForceCloseManageCurseur = NULL;
	frame->m_CurrentScreen->m_CurrentItem = NULL;
}


/***************************************************************************/
MODULE * WinEDA_PcbFrame::Create_MuWaveComponent(wxDC * DC, int shape_type)
/***************************************************************************/
/* Create a module "GAP" or "STUB"
This a "gap" or  "stub" used in micro wave designs
This modue has 2 pads:
 SMD, rectangular, H size = V size = current track width.
 the "gap" is isolation created between this 2 pads 
*/
{
int gap_size, oX, ii;
float fcoeff;
D_PAD* pt_pad;
MODULE * Module;
wxString msg, cmp_name;
int pad_count = 2;
int angle = 0;
bool abort;
	
	/* Entree de la longueur desiree du gap*/
	gap_size = g_DesignSettings.m_CurrentTrackWidth;		// Valeur raisonnable

	switch ( shape_type )
	{
		case 0:
			msg = _("Gap");
			cmp_name = wxT("GAP");
			break;

		case 1:
			msg = _("Stub");
			cmp_name = wxT("STUB");
			pad_count = 2;
			break;

		case 2:
			msg = _("Arc Stub");
			cmp_name = wxT("ASTUB");
			pad_count = 1;
			break;

		default:
			msg = wxT("???");
			break;
	}
	
wxString value;	
	if( g_UnitMetric)
	{
		fcoeff = 10000.0/25.4 ;
		value.Printf( wxT("%2.4f"),gap_size / fcoeff);
		msg += _(" (mm):");
		abort = Get_Message(msg,value, this);
	}
	else
	{
		fcoeff = 10000.0 ;
		value.Printf( wxT("%2.3f"),gap_size / fcoeff);
		msg += _(" (inch):");
		abort = Get_Message(msg, value, this);
	}

	double fval;
	if ( ! value.ToDouble(&fval) )
	{
		DisplayError(this, _("Incorrect number, abort"));
		abort = TRUE;
	}
	gap_size = ABS( (int) round( fval * fcoeff ));

	if ( ! abort && (shape_type == 2) )
	{
		fcoeff = 10.0 ;
		value.Printf( wxT("%3.1f"),angle / fcoeff);
		msg = _("Angle (0.1deg):");
		abort = Get_Message(msg, value, this);
		if ( ! value.ToDouble(&fval) )
		{
			DisplayError(this, _("Incorrect number, abort"));
			abort = TRUE;
		}
		angle = ABS( (int) round( fval * fcoeff ));
		if ( angle > 1800 ) angle = 1800;
	}

	if (abort)
	{
		DrawPanel->MouseToCursorSchema();
		return NULL;
	}

	Module = Create_MuWaveBasicShape(NULL, cmp_name, pad_count);	
	pt_pad = Module->m_Pads;

	switch ( shape_type )
	{
		case 0:	//Gap :
			oX = pt_pad->m_Pos0.x = - (gap_size + pt_pad->m_Size.x) / 2;
			pt_pad->m_Pos.x += pt_pad->m_Pos0.x;
		
			pt_pad = (D_PAD *) pt_pad->Pnext;
			pt_pad->m_Pos0.x = oX + gap_size + pt_pad->m_Size.x;
			pt_pad->m_Pos.x += pt_pad->m_Pos0.x;
			break;

		case 1:	//Stub :
			pt_pad->SetPadName( wxT("1"));
			pt_pad = (D_PAD *) pt_pad->Pnext;
			pt_pad->m_Pos0.y = -(gap_size + pt_pad->m_Size.y) /2;
			pt_pad->m_Size.y = gap_size;
			pt_pad->m_Pos.y += pt_pad->m_Pos0.y;
			break;
		
		case 2:	//Arc Stub :
		{
			EDGE_MODULE * edge; int * ptr, theta;
			ii = angle / 50; 
			edge = new EDGE_MODULE(Module);
			Module->m_Drawings = edge;
			edge->Pback = Module;
			edge->m_Shape = S_POLYGON;
			edge->m_Layer = LAYER_CMP_N;
			edge->m_PolyCount = ii + 3;
			edge->m_PolyList = (int*) MyMalloc( edge->m_PolyCount * 2 * sizeof(int) );
			ptr = edge->m_PolyList;
			edge->m_Start0.y = - pt_pad->m_Size.y / 2;
			
			* ptr = 0; ptr++;
			* ptr = 0; ptr++;
			theta = - angle/2;
			for ( ii = 1; ii < edge->m_PolyCount - 1; ii ++)
			{
				int x, y;
				x = 0; y = - gap_size;
				RotatePoint(&x, &y, theta);
				* ptr = x; ptr++; *ptr = y; ptr++;
				theta += 50;
				if ( theta > angle/2) theta = angle/2;
			}
			*ptr = edge->m_PolyList[0]; ptr++;
			*ptr = edge->m_PolyList[1];
			break;
		}
		
		default:
			break;
	}

	Module->Set_Rectangle_Encadrement();
	Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_OR) ;
	DrawPanel->MouseToCursorSchema();
	m_Pcb->m_Status_Pcb = 0 ;
	m_CurrentScreen->SetModify();
	return Module;
}




/**************** Polygon Shapes ***********************/

enum id_mw_cmd
{
	ID_ACCEPT_OPT = 1000,
	ID_CANCEL_OPT,
	ID_READ_SHAPE_FILE
};

/*************************************************/
class WinEDA_SetParamShapeFrame: public wxDialog
/*************************************************/
/* Reglages des parametres des forme polynomiales
*/
{
private:
	WinEDA_PcbFrame * m_Parent;
	wxRadioBox * m_ShapeOptionCtrl;
	WinEDA_SizeCtrl * m_SizeCtrl;

public:
	// Constructor and destructor
	WinEDA_SetParamShapeFrame(WinEDA_PcbFrame *parent,const wxPoint& pos);
	~WinEDA_SetParamShapeFrame(void) {};

private:
	void OnCloseWindow(wxCloseEvent & event);
	void OnCancel(wxCommandEvent& event);
	void ReadDataShapeDescr(wxCommandEvent& event);
	void AcceptOptions(wxCommandEvent& event);

	DECLARE_EVENT_TABLE()

};
/* Construction de la table des evenements pour WinEDA_SetParamShapeFrame */
BEGIN_EVENT_TABLE(WinEDA_SetParamShapeFrame, wxDialog)
	EVT_BUTTON(ID_ACCEPT_OPT, WinEDA_SetParamShapeFrame::AcceptOptions)
	EVT_BUTTON(ID_CANCEL_OPT, WinEDA_SetParamShapeFrame::OnCancel)
	EVT_BUTTON(ID_READ_SHAPE_FILE, WinEDA_SetParamShapeFrame::ReadDataShapeDescr)
END_EVENT_TABLE()



	/*************************************************/
	/* Constructeur de WinEDA_SetParamShapeFrame */
	/************************************************/

WinEDA_SetParamShapeFrame::WinEDA_SetParamShapeFrame(WinEDA_PcbFrame *parent,
		const wxPoint& framepos):
		wxDialog(parent, -1, _("Complex shape"), framepos, wxSize(350, 280),
		DIALOG_STYLE )
{
	m_Parent = parent;
	SetFont(*g_DialogFont);
	
	if ( PolyEdges ) free(PolyEdges);
	PolyEdges = NULL;
	PolyEdgesCount = 0;

	wxBoxSizer * MainBoxSizer = new wxBoxSizer(wxHORIZONTAL);
	SetSizer(MainBoxSizer);
	wxBoxSizer * LeftBoxSizer = new wxBoxSizer(wxVERTICAL);
	wxBoxSizer * RightBoxSizer = new wxBoxSizer(wxVERTICAL);
	MainBoxSizer->Add(LeftBoxSizer, 0, wxGROW|wxALL, 5);
	MainBoxSizer->Add(RightBoxSizer, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);

	wxButton * Button = new wxButton(this, ID_ACCEPT_OPT, _("Ok"));
	Button->SetForegroundColour(*wxRED);
	RightBoxSizer->Add(Button, 0, wxGROW|wxALL, 5);

	Button = new wxButton(this, ID_CANCEL_OPT, _("Cancel"));
	Button->SetForegroundColour(*wxBLUE);
	RightBoxSizer->Add(Button, 0, wxGROW|wxALL, 5);

	Button = new wxButton(this, ID_READ_SHAPE_FILE, _("Read Shape Descr File"));
	Button->SetForegroundColour(wxColor(0,100,0) );
	RightBoxSizer->Add(Button, 0, wxGROW|wxALL, 5);

wxString shapelist[3] = { _("Normal"), _("Symmetrical"), _("mirrored") };
	m_ShapeOptionCtrl = new wxRadioBox(this, -1, _("ShapeOption"),
			wxDefaultPosition, wxDefaultSize, 3, shapelist, 1, wxRA_SPECIFY_COLS);
	LeftBoxSizer->Add(m_ShapeOptionCtrl, 0, wxGROW|wxALL, 5);

	m_SizeCtrl = new WinEDA_SizeCtrl(this, _("Size"),
						ShapeSize,
						g_UnitMetric, LeftBoxSizer, PCB_INTERNAL_UNIT) ;
	

	GetSizer()->Fit(this);
    GetSizer()->SetSizeHints(this);
}

/**********************************************************************/
void  WinEDA_SetParamShapeFrame::OnCancel(wxCommandEvent& WXUNUSED(event))
/**********************************************************************/
{
 	if ( PolyEdges )  free(PolyEdges);
	PolyEdges = NULL;
	PolyEdgesCount = 0;
	EndModal(0);
}


/*******************************************************************/
void WinEDA_SetParamShapeFrame::AcceptOptions(wxCommandEvent& event)
/*******************************************************************/
{
	ShapeSize = m_SizeCtrl->GetValue();
	PolyShapeType = m_ShapeOptionCtrl->GetSelection();
	EndModal(1);
}

/************************************************************************/
void WinEDA_SetParamShapeFrame::ReadDataShapeDescr(wxCommandEvent& event)
/************************************************************************/
/* Read a description shape file
File format is
Unit=MM
XScale=271.501
YScale=1.00133

$COORD
0                      0.6112600148417837
0.001851851851851852   0.6104800531118608
....
$ENDCOORD

Each line is the X Y coord (normalised units from 0 to 1)
*/
{
wxString FullFileName;
wxString ext, mask;
FILE * File;
char Line[1024];
double unitconv = 10000;
char * param1, *param2;
int bufsize;
double * ptbuf;
	
	ext = wxT(".txt");
	mask = wxT("*") + ext;
	FullFileName = EDA_FileSelector(_("Read descr shape file"),
					wxEmptyString,			/* Chemin par defaut */
					FullFileName,		/* nom fichier par defaut */
					ext,				/* extension par defaut */
					mask,				/* Masque d'affichage */
					this,
					wxFD_OPEN,
					TRUE				/* ne change pas de repertoire courant */
					);
	if ( FullFileName.IsEmpty()) return;

	File = wxFopen(FullFileName, wxT("rt"));
	
	if ( File == NULL )
	{
		DisplayError(this, _("File not found") );
		return;
	}
	
	
	bufsize = 100;
	ptbuf = PolyEdges = (double*) MyZMalloc( bufsize * 2 * sizeof(double));
	
	int LineNum = 0;
	while( GetLine(File, Line, &LineNum , sizeof(Line) -1) != NULL )
	{
		from_point(Line);
		
		param1 = strtok(Line," =\n\r");
		param2 = strtok(NULL," \t\n\r");
		
		if ( strnicmp(param1, "Unit", 4) == 0)
		{
			if ( strnicmp(param2, "inch", 4) == 0) unitconv = 10000;
			if ( strnicmp(param2, "mm", 2) == 0) unitconv = 10000/25.4;
		}
		if ( strnicmp(param1, "$ENDCOORD", 8) == 0) break;
		if ( strnicmp(param1, "$COORD", 6) == 0)
		{
			while( GetLine(File, Line, &LineNum , sizeof(Line) -1) != NULL )
			{
				from_point(Line);
				param1 = strtok(Line," \t\n\r");
				param2 = strtok(NULL," \t\n\r");
				if ( strnicmp(param1, "$ENDCOORD", 8) == 0) break;
				if ( bufsize <= PolyEdgesCount )
				{
					int index = ptbuf - PolyEdges;
					bufsize *= 2;
					ptbuf = PolyEdges = (double*) realloc( PolyEdges, bufsize * 2 * sizeof(double));
					ptbuf += index;
				}
				* ptbuf = atof(param1);
				ptbuf++;
				* ptbuf = atof(param2);
				ptbuf++;
				PolyEdgesCount++;
			}
		}
		if ( strnicmp(Line, "XScale", 6) == 0)
		{
			ShapeScaleX = atof(param2);
		}
		if ( strnicmp(Line, "YScale", 6) == 0)
		{
			ShapeScaleY = atof(param2);
		}
	}
	
	if ( PolyEdgesCount == 0 )
	{
		free(PolyEdges);
		PolyEdges = NULL;
	}
	fclose( File);
	
	ShapeScaleX *= unitconv;
	ShapeScaleY *= unitconv;
	
	m_SizeCtrl->SetValue( (int) ShapeScaleX, (int) ShapeScaleY);
}


/*************************************************************/
MODULE * WinEDA_PcbFrame::Create_MuWavePolygonShape(wxDC * DC)
/*************************************************************/
{
D_PAD * pad1, *pad2;
MODULE * Module;
wxString cmp_name;
int pad_count = 2;
EDGE_MODULE * edge; int * ptr;
int ii, npoints;
	
WinEDA_SetParamShapeFrame * frame = new WinEDA_SetParamShapeFrame(this, wxPoint(-1,-1));
	int ok = frame->ShowModal(); frame->Destroy();
	
	DrawPanel->MouseToCursorSchema();
	
	if ( ok != 1 )
	{
		if ( PolyEdges ) free(PolyEdges);
		PolyEdges = NULL;
		PolyEdgesCount = 0;
		return NULL;
	}
	
	if ( PolyShapeType == 2 )	// mirrored
		ShapeScaleY = - ShapeScaleY;
	ShapeSize.x = (int) round( ShapeScaleX);
	ShapeSize.y = (int) round( ShapeScaleY);
	
	if ( (ShapeSize.x) == 0 || (ShapeSize.y == 0) )
	{
		DisplayError(this, _("Shape has a null size!") );
		return NULL;
	}
	if (PolyEdgesCount == 0)
	{
		DisplayError(this, _("Shape has no points!") );
		return NULL;
	}
	
	cmp_name = wxT("POLY");

	Module = Create_MuWaveBasicShape(NULL, cmp_name, pad_count);	
	pad1 = Module->m_Pads;

	pad1->m_Pos0.x = - ShapeSize.x / 2;
	pad1->m_Pos.x += pad1->m_Pos0.x;

	pad2 = (D_PAD *) pad1->Pnext;
	pad2->m_Pos0.x = pad1->m_Pos0.x + ShapeSize.x;
	pad2->m_Pos.x += pad2->m_Pos0.x;

	edge = new EDGE_MODULE(Module);
	Module->m_Drawings = edge;
	edge->Pback = Module;
	edge->m_Shape = S_POLYGON;
	edge->m_Layer = LAYER_CMP_N;
	npoints = PolyEdgesCount;
	switch (PolyShapeType)
	{
		case 0: // Single
		case 2: // Single, mirrored
			edge->m_PolyCount = PolyEdgesCount + 2;
			break;
		
		case 1: // Symetric
			edge->m_PolyCount = (2 * PolyEdgesCount) + 2;
			break;
	}

	edge->m_PolyList = (int*) MyMalloc( edge->m_PolyCount * 2 * sizeof(int) );
	
	ptr = edge->m_PolyList;
	// Init start point coord:
	* ptr =  pad1->m_Pos0.x; ptr++;
	* ptr = 0; ptr++;
	
	double * dptr = PolyEdges;
	wxPoint first_cordinate, last_cordinate;
	for ( ii = 0; ii < npoints; ii ++)	// Copy points
	{
		last_cordinate.x = * ptr = (int)round(*dptr * ShapeScaleX) + pad1->m_Pos0.x;
		dptr++; ptr++;
		last_cordinate.y = *ptr = - (int) round( *dptr * ShapeScaleY);
		dptr++; ptr++;
		}
	first_cordinate.y = edge->m_PolyList[3];
	
	switch (PolyShapeType)
	{
		int * ptr1;
		case 0: // Single
		case 2: // Single mirrored
			// Init end point coord:
			* ptr = pad2->m_Pos0.x = last_cordinate.x; ptr++;
			* ptr = 0;
			pad1->m_Size.x = pad1->m_Size.y = ABS(first_cordinate.y);
			pad2->m_Size.x = pad2->m_Size.y = ABS(last_cordinate.y);
			pad1->m_Pos0.y = first_cordinate.y/2;
			pad2->m_Pos0.y = last_cordinate.y/2;
			pad1->m_Pos.y = pad1->m_Pos0.y + Module->m_Pos.y;
			pad2->m_Pos.y = pad2->m_Pos0.y + Module->m_Pos.y;
			break;
		
		case 1: // Symetric
			ptr1 = ptr-2;
			for ( ii = 0; ii <= npoints; ii ++)
			{
				* ptr = * ptr1;	// Copy X coord
				ptr++;
				*ptr = - *(ptr1+1);	// Copy Y coord, mirror X axis
				ptr1 -= 2; ptr++;
			}
			pad1->m_Size.x = pad1->m_Size.y = 2 * ABS(first_cordinate.y);
			pad2->m_Size.x = pad2->m_Size.y = 2 * ABS(last_cordinate.y);
			break;
	}
	
	free(PolyEdges);
	PolyEdgesCount = 0;
	PolyEdges = NULL;
	
	Module->Set_Rectangle_Encadrement();
	Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_OR) ;
	m_Pcb->m_Status_Pcb = 0 ;
	m_CurrentScreen->SetModify();
	return Module;
}



/***************************************************************/
void WinEDA_PcbFrame::Edit_Gap(wxDC * DC, MODULE * Module)
/***************************************************************/
/*
Edit le module GAP, c'est a dire modifie la position et la taille
des pastilles formant le gap pour obtenir une nouvelle valeur du gap
 */
{
int gap_size, oX;
float fcoeff;
D_PAD* pad, * next_pad;
wxString msg;
	
	if( Module == NULL)  return;	/* Module non trouve */

	/* Test si module = gap ( nom commence par GAP, et 2 pastilles) */
	msg = Module->m_Reference->m_Text.Left(3);
	if( msg != wxT("GAP") ) return;

	pad = Module->m_Pads;
	if(pad == NULL )
	{
		DisplayError(this, _("No pad for this module")); return;
	}
	next_pad = (D_PAD*)pad->Pnext;
	if(next_pad == NULL )
	{
		DisplayError(this, _("Only one pad for this module")); return;
	}

	/* Effacement du module: */
	Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_XOR) ;

	/* Calcul de la dimension actuelle */
	gap_size = next_pad->m_Pos0.x - pad->m_Pos0.x - pad->m_Size.x;

	/* Entree de la longueur desiree du gap*/
	if( g_UnitMetric)
	{
		fcoeff = 10000.0/25.4 ;
		msg.Printf( wxT("%2.3f"),gap_size / fcoeff);
		Get_Message( _("Gap (mm):"),msg, this);
	}
	else
	{
		fcoeff = 10000.0 ;
		msg.Printf( wxT("%2.4f"),gap_size / fcoeff);
		Get_Message( _("Gap (inch):"),msg, this);
	}

	if ( ! msg.IsEmpty() )
	{
		double fval;
		if ( msg.ToDouble(&fval) )
			gap_size = (int)( fval * fcoeff );
	}

	/* Mise a jour des tailles des pastilles formant le gap */
	pad->m_Size.x = pad->m_Size.y = g_DesignSettings.m_CurrentTrackWidth;
	pad->m_Pos0.y = 0;
	oX = pad->m_Pos0.x =- ((gap_size + pad->m_Size.x) /2);
	pad->m_Pos.x = pad->m_Pos0.x + Module->m_Pos.x;
	pad->m_Pos.y = pad->m_Pos0.y + Module->m_Pos.y;
	RotatePoint(&(pad->m_Pos.x),&(pad->m_Pos.y),
					Module->m_Pos.x,Module->m_Pos.y,Module->m_Orient);

	next_pad->m_Size.x = next_pad->m_Size.y = g_DesignSettings.m_CurrentTrackWidth;
	next_pad->m_Pos0.y = 0;
	next_pad->m_Pos0.x = oX + gap_size + next_pad->m_Size.x;
	next_pad->m_Pos.x = next_pad->m_Pos0.x + Module->m_Pos.x;
	next_pad->m_Pos.y = next_pad->m_Pos0.y + Module->m_Pos.y;
	RotatePoint(&(next_pad->m_Pos.x), &(next_pad->m_Pos.y),
					Module->m_Pos.x,Module->m_Pos.y, Module->m_Orient);

	Module->Draw(DrawPanel, DC, wxPoint(0,0), GR_OR) ;
}


