
//	Title:		Block.cpp
//	Purpose:	Contains all Block related code.
//	Authors:	IntEng gp.
//	Source:		C++ texts & IntEng gp.
//	Date:		28-8-2008 (start), 1-12-08 (updated)

#include "stdafx.h"					// rqd. for precompiled header info.
#include <fstream>					// rqd. for file i/o in WriteBlockDataToFile()
#include <iostream>
#include <string.h>
#include <math.h>
#include <vector>
#include <list>
using namespace std;
#include "Block.h" 
#include "SystemModel.h"			// rqd. since Block() destr potentially deletes a ptr-to-CSystemModel (m_pSubSystemModel)
#include "DiagramEngDoc.h"			// rqd. since GetDocumentGlobalFn() called within SetBlockPosition()
#include "ConstantBlockDialog.h"	// rqd. since CConstantBlock::BlockDlgWndParameterInput() creates a CConstantBlockDialog obj.
#include "DerivativeBlockDialog.h"	// rqd. since CDerivativeBlock::BlockDlgWndParameterInput() creates a CDerivativeBlockDialog obj.
#include "DivideBlockDialog.h"		// rqd. since CDivideBlock::BlockDlgWndParameterInput() creates a CDivideBlockDialog obj.
#include "GainBlockDialog.h"		// rqd. since CGainBlock::BlockDlgWndParameterInput() creates a CGainBlockDialog obj.
#include "IntegratorBlockDialog.h"	// rqd. since CIntegratorBlock::BlockDlgWndParameterInput() creates a CIntegratorBlockDialog obj.
#include "LinearFnBlockDialog.h"	// rqd. since CLinearFnBlock::BlockDlgWndParameterInput() creates a CLinearFnBlockDialog obj.
#include "OutputBlockDialog.h"		// rqd. since COutputBlock::BlockDlgWndParameterInput() creates a COutputBlockDialog obj.
#include "PortPropertiesDialog.h"	// rqd. since CBlock::SetPortProperties() creates a CPortPropertiesDialog obj.
#include "SignalGeneratorBlockDialog.h"	// rqd. since CSignalGeneratorBlock::BlockDlgWndParameterInput() creates a CSignalGeneratorBlockDialog obj.
#include "SubsystemBlockDialog.h"	// rqd. since CSubsystemBlock::BlockDlgWndParameterInput() creates a CSubsystemBlockDialog obj.
#include "SubsystemInBlockDialog.h"	// rqd. since CSubsystemInBlock::BlockDlgWndParameterInput() creates a CSubsystemInBlockDialog obj.
#include "SubsystemOutBlockDialog.h"// rqd. since CSubsystemOutBlock::BlockDlgWndParameterInput() creates a CSubsystemOutBlockDialog obj.
#include "SumBlockDialog.h"			// rqd. since CSumBlock::BlockDlgWndParameterInput() creates a CSumBlockDialog obj.
#include "TransferFnBlockDialog.h"	// rqd. since CTransferFnBlock::BlockDlgWndParameterInput() creates a CTransferFnBlockDialog obj.
#include "OutputSignalDialog.h"		// rqd. since CBlock::AssignBlockOutputSignal() creates a COutputSignalDialog obj.


CBlockShape::CBlockShape(void)
{
	m_eBlockDirection = e_right;		// default direc is to the right.
	m_dBlockWidth = (GetDocumentGlobalFn()->GetDeltaLength())*2.0;
	m_dBlockHeight = m_dBlockWidth;
}

CBlockShape::~CBlockShape(void)
{
	//AfxMessageBox("\n CBlockShape::~CBlockShape()\n", MB_OK, 0);
}

CPort::CPort(CBlock &block_ref):
m_rRefToBlock(block_ref)					// must init the m_rRefToBlock rather than assign on CPort obj. creation
{
	// Init
	m_strPortName = "actual_port_name";
	m_ptPortPosition.x = 0.0;				// generalized coords not rel. coords.
	m_ptPortPosition.y = 0.0;				// generalized coords not rel. coords.
	m_ePortArrowDirec = e_right_arrow;		// in general port arrows point to the right.
}

CPort::~CPort(void)
{
	//AfxMessageBox("\n CPort::~CPort()\n", MB_OK, 0);
}

CBlock::CBlock(void)
{
	// Init
	m_strBlockName  = "actual_block_name";

	// -- Vector of input ptrs-to-CPort
	/*CString sMsg;									// msg string
	CString sMsgTemp;								// temp msg string
	UINT nType = MB_OK;								// style of msg. box
	UINT nIDhelp = 0;								// help context ID for the msg
	CPort *p_port_in = new CPort(*this);
	vector<CPort*>::iterator it_in;					// generate an iterator for vec-of-ptrs-to-CPort

	it_in = m_vecInputPorts.begin();				// start of the vec
	m_vecInputPorts.insert(it_in, p_port_in);		// insert a new ptr-to-CPort in the vector
	*/
	/*for(it_in = m_vecInputPorts.begin(); it_in < m_vecInputPorts.end(); it_in++)
	{	
		sMsgTemp.Format(" CBlock::CBlock(), m_vecInputPorts item name = %s\n",(*it_in)->GetName());
		sMsg += sMsgTemp;
	}
	*/

	// -- Vector of output ptrs-to-CPort
	/*CPort *p_port_out = new CPort(*this);
	vector<CPort*>::iterator it_out;				// generate an iterator for vec-of-ptrs-to-CPort

	it_out = m_vecOutputPorts.begin();				// start of the vec
	m_vecOutputPorts.insert(it_out, p_port_out);	// insert a new ptr-to-CPort in the vector
	*/
	/*for(it_out = m_vecOutputPorts.begin(); it_out < m_vecOutputPorts.end(); it_out++)
	{
		sMsgTemp.Format(" CBlock::CBlock(), m_vecOutputPorts item name = %s\n",(*it_out)->GetName());
		sMsg += sMsgTemp;
	}
	AfxMessageBox(sMsg, nType, nIDhelp);
	*/

	m_pSubSystemModel = NULL;			// ptr to a possibly CONTAINED SUB MODEL: ptr = NULL => no contained system model, ptr = !NULL => system model		
}

CBlock::~CBlock(void)
{
	// MEMORY DELETE

	vector<CPort*>::iterator it_in;		// generate an iterator for vec-of-ptrs-to-CPort
	vector<CPort*>::iterator it_out;	// generate an iterator for vec-of-ptrs-to-CPort
	
	for(it_in = m_vecInputPorts.begin(); it_in < m_vecInputPorts.end(); it_in++)
	{
		delete (*it_in);	// delete what it_in is pointing to: i.e. deref the it_in ptr and delete the ptr-to-CPort.
	}
	// vector is then destroyed automatically by vector destructor

	for(it_out = m_vecOutputPorts.begin(); it_out < m_vecOutputPorts.end(); it_out++)
	{
		delete (*it_out);	// delete what it_out is pointing to: i.e. deref the it_out ptr and delete the ptr-to-CPort.
	}
	// vector is then destroyed automatically by vector destructor

	if(m_pSubSystemModel != NULL)
	{
		delete m_pSubSystemModel;
		m_pSubSystemModel = NULL;
	}
}

CString CBlock::GetBlockName(void) const
{
	return m_strBlockName;
}

CChirpSignalBlock::CChirpSignalBlock(void)
{
	//AfxMessageBox("\n CChirpSignalBlock::CChirpSignalBlock()\n", MB_OK, 0);
}

CChirpSignalBlock::~CChirpSignalBlock(void)
{
	//AfxMessageBox("\n CChirpSignalBlock::~CChirpSignalBlock()\n", MB_OK, 0);
}

CConstantBlock::CConstantBlock(void)
{
	//AfxMessageBox("\n CConstantBlock::CConstantBlock()\n", MB_OK, 0);
}

CConstantBlock::~CConstantBlock(void)
{
	int i;

	// MEMORY DEALLOCATION

	// Delete the input data matrix whose memory was allocated in ConvertStringMatrixToDoubleMatrix()
	if(m_dConstMatrix != NULL)
	{
		for(i=0; i<m_iNrows; i++)
		{
			delete [] m_dConstMatrix[i];
		}
		delete [] m_dConstMatrix;
		m_dConstMatrix = NULL;
	}
	
	// Reset member vars.
	m_iNrows = 0;
	m_iNcols = 0;
}

CDerivativeBlock::CDerivativeBlock(void)
{
	//AfxMessageBox("\n CDerivativeBlock::CDerivativeBlock()\n", MB_OK, 0);
}

CDerivativeBlock::~CDerivativeBlock(void)
{
	// Reset block data
	ResetBlockData();	// reset: m_f_at_t_minus_h, m_f_at_t_minus_2h, m_dMatrixOut
}

CDivideBlock::CDivideBlock(void)
{
	//AfxMessageBox("\n CDivideBlock::CDivideBlock()\n", MB_OK, 0);
}

CDivideBlock::~CDivideBlock(void)
{
	int i;

	// MEMORY DELETE
	// Delete the initial signal matrix whose memory was allocated in AssignBlockOutputSignal()
	if(m_dInitSignal != NULL)
	{
		for(i=0; i<m_iNrowsInitSignal; i++)
		{
			delete [] m_dInitSignal[i];
		}
		delete [] m_dInitSignal;
		m_dInitSignal = NULL;
	}
}

CGainBlock::CGainBlock(void)
{
	//AfxMessageBox("\n CGainBlock::CGainBlock()\n", MB_OK, 0);
}

CGainBlock::~CGainBlock(void)
{
	int i;

	// MEMORY DEALLOCATION

	// Delete the input data matrix whose memory was allocated in ConvertStringMatrixToDoubleMatrix()
	if(m_dGainMatrix != NULL)
	{
		for(i=0; i<m_iNrows; i++)
		{
			delete [] m_dGainMatrix[i];
		}
		delete [] m_dGainMatrix;
		m_dGainMatrix = NULL;
	}
	
	// Reset member vars.
	m_iNrows = 0;
	m_iNcols = 0;
}

CIntegratorBlock::CIntegratorBlock(void)
{
	//AfxMessageBox("\n CIntegratorBlock::CIntegratorBlock()\n", MB_OK, 0);
}

CIntegratorBlock::~CIntegratorBlock(void)
{
	// Delete the initial condition vector whose memory was allocated in ConvertStringToDoubleVector()
	if(m_dICVector != NULL)
	{
		delete [] m_dICVector;
		m_dICVector = NULL;
	}

	// Reset block data
	ResetBlockData();	// reset: m_y_at_t_minus_h, m_y_dot_at_t_minus_h, m_dMatrixOut
}

CLinearFnBlock::CLinearFnBlock(void)
{
	//AfxMessageBox("\n CLinearFnBlock::CLinearFnBlock()\n", MB_OK, 0);
}

CLinearFnBlock::~CLinearFnBlock(void)
{
	//AfxMessageBox("\n CLinearFnBlock::~CLinearFnBlock()\n", MB_OK, 0);
}

COutputBlock::COutputBlock(void)
{
	//AfxMessageBox("\n COutputBlock::COutputBlock()\n", MB_OK, 0);
}

COutputBlock::~COutputBlock(void)
{
	int i;

	// MEMORY DEALLOCATION
	// Delete the data matrix whose memory was allocated in COutputBlock::OperateOnData()
	if(m_dOutputMatrix != NULL)
	{
		for(i=0; i<m_iNrows; i++)
		{
			delete [] m_dOutputMatrix[i];
		}
		delete [] m_dOutputMatrix;
		m_dOutputMatrix = NULL;
	}
	
	// Reset member vars.
	m_iNrows = 0;
	m_iNcols = 0;
}

CSignalGeneratorBlock::CSignalGeneratorBlock(void)
{
	//AfxMessageBox("\n CSignalGeneratorBlock::CSignalGeneratorBlock()\n", MB_OK, 0);
}

CSignalGeneratorBlock::~CSignalGeneratorBlock(void)
{
	//AfxMessageBox("\n CSignalGeneratorBlock::~CSignalGeneratorBlock()\n", MB_OK, 0);
}

CSubsystemBlock::CSubsystemBlock(void)
{
	//AfxMessageBox("\n CSubsystemBlock::CSubsystemBlock()\n", MB_OK, 0);
}

CSubsystemBlock::~CSubsystemBlock(void)
{
	//AfxMessageBox("\n CSubsystemBlock::~CSubsystemBlock()\n", MB_OK, 0);
}

CSubsystemInBlock::CSubsystemInBlock(void)
{
	//AfxMessageBox("\n CSubsystemInBlock::CSubsystemInBlock()\n", MB_OK, 0);
}

CSubsystemInBlock::~CSubsystemInBlock(void)
{
	//AfxMessageBox("\n CSubsystemInBlock::~CSubsystemInBlock()\n", MB_OK, 0);
}

CSubsystemOutBlock::CSubsystemOutBlock(void)
{
	//AfxMessageBox("\n CSubsystemOutBlock::CSubsystemOutBlock()\n", MB_OK, 0);
}

CSubsystemOutBlock::~CSubsystemOutBlock(void)
{
	//AfxMessageBox("\n CSubsystemOutBlock::~CSubsystemOutBlock()\n", MB_OK, 0);
}

CSumBlock::CSumBlock(void)
{
	//AfxMessageBox("\n CSumBlock::CSumBlock()\n", MB_OK, 0);
}

CSumBlock::~CSumBlock(void)
{
	//AfxMessageBox("\n CSumBlock::~CSumBlock()\n", MB_OK, 0);
}

CTransferFnBlock::CTransferFnBlock(void)
{
	//AfxMessageBox("\n CTransferFnBlock::CTransferFnBlock()\n", MB_OK, 0);
}

CTransferFnBlock::~CTransferFnBlock(void)
{
	// Delete the coefficient vector whose memory was allocated in ConvertStringToDoubleVector()
	if(m_dNumerVector != NULL)
	{
		delete [] m_dNumerVector;
		m_dNumerVector = NULL;
	}

	if(m_dDenomVector != NULL)
	{
		delete [] m_dDenomVector;
		m_dDenomVector = NULL;
	}
}

CConstantBlock::CConstantBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape) 
{
	SetBlockName("constant_block");

	// Set the constant scalar/vector/matrix CString value.
	m_strConstValue = "1";

	// Create an output port
	CPort *p_output_port = new CPort(*this);

	// Set port properties
	p_output_port->SetPortName("_");					// "_" no sign associated with output argument.
	p_output_port->SetPortPositionAngle(0.0);			// port posn angle 0 degrees, i.e. right side.
	p_output_port->CalculatePortPosition();
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Initialize m_dConstMatrix to have the default numerical value of the CString arg. (a non-NULL value).
	// If a Constant block were to be deleted, then memory would be deleted correctly.
	m_dConstMatrix = ConvertStringToDouble(m_strConstValue, m_iNrows, m_iNcols);
}

CBlock::CBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
m_ptBlockPosition(blk_posn)
{
	// Init
	m_BlockShape.SetBlockShapeType(e_blk_shape);	// block shape: ellipse, rectangle, triangle
	m_iPenColor = RGB(0,0,255);						// red = RGB(255,0,0), green = RGB(0,255,0), blue = RGB(0,0,255), Black = RGB(0,0,0), White = (255,255,255)
	m_iPenWidth = 1;								// 1 = v. thin, 8 = thin, 16 = medium, 24 = thick, 32 = v. thick. (mults. of 8)
	m_pParentSystemModel = pParentSystemModel;		// ptr to parent system model.
	m_pSubSystemModel = NULL;						// ptr to a possibly CONTAINED SUB MODEL: ptr = NULL => no contained system model, ptr = !NULL => system model
	m_strBlockName = "actual_block_name";			// block name id
}

void CBlockShape::SetBlockShapeType(EBlockShape e_blk_shape)
{
	m_eBlockShape = e_blk_shape;
}

void CBlock::SetBlockName(CString blk_name)
{
	m_strBlockName = blk_name;
}

void CBlock::DrawBlock(CDC *pDC)
{
	// WARNING! THIS FN HAS BEEN MADE VIRTUAL AND IS TO BE OVERRIDDEN BY ALL DERIVED CLASSES THAT DRAW OBJS.
	/*
	EBlockShape e_blk_shape;	// enum block shape: ellipse, rectangle, triangle.

	//AfxMessageBox("\n CBlock::DrawBlock()\n", MB_OK, 0);

	// Get the EBlockShape of the current block via the member obj. CBlockShape m_BlockShape;
	e_blk_shape = m_BlockShape.GetBlockShapeType();

	switch(e_blk_shape)
	{
	case e_ellipse:
		DrawEllipseBlock(pDC);
		break;

	case e_rectangle:
		DrawRectangleBlock(pDC);
		break;

	case e_triangle:
		DrawTriangleBlock(pDC);
		break;

	default:
		// Inform user of switch default
		DrawRectangleBlock(pDC);
		//AfxMessageBox("\n CBlock::DrawBlock(), switch(e_blk_shape) default case\n", MB_OK, 0);
		break;
	}// end switch
	*/
}

EBlockShape CBlockShape::GetBlockShapeType() const
{
	return m_eBlockShape;
}

void CBlock::DrawEllipseBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	double l_width = m_BlockShape.GetBlockWidth();
	CPoint bottom_right;
	CPoint top_left;

	// Create a pen
	CPen lpen(PS_SOLID, m_iPenWidth, m_iPenColor);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the ellipse
	top_left.x = (int)(m_ptBlockPosition.x - l_width*0.5);
	top_left.y = (int)(m_ptBlockPosition.y - l_width*0.5);
	bottom_right.x = (int)(m_ptBlockPosition.x + l_width*0.5);
	bottom_right.y = (int)(m_ptBlockPosition.y + l_width*0.5);
	pDC->Ellipse(top_left.x, top_left.y, bottom_right.x, bottom_right.y);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);
}

double CBlockShape::GetBlockWidth() const
{
	return m_dBlockWidth;
}

int CBlock::GetPenWidth() const
{
	return m_iPenWidth;
}

int CBlock::GetPenColor() const
{
	return m_iPenColor;
}

void CBlock::DrawRectangleBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	CPoint top_left;		// top left cnr. of rectangle
	CPoint top_right;		// top right cnr. of rectangle
	CPoint bottom_right;	// bottom right cnr. of rectangle
	CPoint bottom_left;		// bottom left cnr. of rectangle
	double l_width = m_BlockShape.GetBlockWidth();

	// Assign vals to the cnr. pts.
	top_left.x = m_ptBlockPosition.x - l_width*0.5;
	top_left.y = m_ptBlockPosition.y - l_width*0.5;
	top_right.x = m_ptBlockPosition.x + l_width*0.5;
	top_right.y = m_ptBlockPosition.y - l_width*0.5;
	bottom_right.x = m_ptBlockPosition.x + l_width*0.5;
	bottom_right.y = m_ptBlockPosition.y + l_width*0.5;
	bottom_left.x = m_ptBlockPosition.x - l_width*0.5;
	bottom_left.y = m_ptBlockPosition.y + l_width*0.5;

	// Create a pen
	CPen lpen(PS_SOLID, m_iPenWidth, m_iPenColor);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the rectangle (clockwise)
	pDC->MoveTo(top_left);
	pDC->LineTo(top_right);
	pDC->LineTo(bottom_right);
	pDC->LineTo(bottom_left);
	pDC->LineTo(top_left);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);
}

void CBlock::DrawTriangleBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	CPoint A;		// vertex A of the equilateral triangle.
	CPoint B;		// vertex B of the equilateral triangle that points in the direc of m_eBlockDirection.
	CPoint C;		// vertex C of the equilateral triangle.
	double d;		// opp side length of a subtriangle with hypotenuse h, and base length l_width*0.5.
	double h;		// hypotenuse of a subtriangle with opp. side length d, and base length l_width*0.5.
	double length;	// length of side of triangle
	double width = m_BlockShape.GetBlockWidth();						// equilateral triangle side length
	EBlockDirection e_triangle_direc = m_BlockShape.GetBlockDirection();// direction of vertex B


	// Assign vals to subtriangle paras d and h.
	length = 1.0*width;		// length of side of triangle
	d = length*0.2887;		// d = (length*0.5)*tan(30)
	h = length*0.5773;		// h = (length*0.5)*(1/cos(30))

	// Get A, B, and C vertices given triangle block direc.
	switch(e_triangle_direc)
	{
	case e_left:	// vertex B pts. to the left
		A.x = m_ptBlockPosition.x + d;
		A.y = m_ptBlockPosition.y + length*0.5;
		B.x = m_ptBlockPosition.x - h;
		B.y = m_ptBlockPosition.y;
		C.x = m_ptBlockPosition.x + d;
		C.y = m_ptBlockPosition.y - length*0.5;
		break;
	case e_up:		// vertex B pts. up
		A.x = m_ptBlockPosition.x - length*0.5;
		A.y = m_ptBlockPosition.y + d;
		B.x = m_ptBlockPosition.x;
		B.y = m_ptBlockPosition.y - h;
		C.x = m_ptBlockPosition.x + length*0.5;
		C.y = m_ptBlockPosition.y + d;
		break;
	case e_right:	// vertex B pts. to the right
		A.x = m_ptBlockPosition.x - d;
		A.y = m_ptBlockPosition.y - length*0.5;
		B.x = m_ptBlockPosition.x + h;
		B.y = m_ptBlockPosition.y;
		C.x = m_ptBlockPosition.x - d;
		C.y = m_ptBlockPosition.y + length*0.5;
		break;
	case e_down:	// vertex B pts. down
		A.x = m_ptBlockPosition.x + length*0.5;
		A.y = m_ptBlockPosition.y - d;
		B.x = m_ptBlockPosition.x;
		B.y = m_ptBlockPosition.y + h;
		C.x = m_ptBlockPosition.x - length*0.5;
		C.y = m_ptBlockPosition.y - d;
		break;
	default:		// assign same values as for e_right assuming default direc. vertex B pointing to the right.
		A.x = m_ptBlockPosition.x - d;
		A.y = m_ptBlockPosition.y - length*0.5;
		B.x = m_ptBlockPosition.x + h;
		B.y = m_ptBlockPosition.y;
		C.x = m_ptBlockPosition.x - d;
		C.y = m_ptBlockPosition.y + length*0.5;
		break;
	}// end switch

	// Create a pen
	CPen lpen(PS_SOLID, m_iPenWidth, m_iPenColor);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the triangle (A to B to C)
	pDC->MoveTo(A);
	pDC->LineTo(B);
	pDC->LineTo(C);
	pDC->LineTo(A);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);
}


EBlockDirection CBlockShape::GetBlockDirection() const
{
	return m_eBlockDirection;
}

CGainBlock::CGainBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("gain_block");

	// Set the Gain block member vars.
	m_iGainType = 1;
	m_strGainValue = "1";

	// Create input and output ports
	CPort *p_input_port = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port->SetPortName("_");			// no sign assoc. with input port
	p_output_port->SetPortName("_");		// no sign assoc. with output port

	// Set port positions
	p_input_port->SetPortPositionAngle(180);		
	p_input_port->CalculatePortPosition();
	p_output_port->SetPortPositionAngle(0);	
	p_output_port->CalculatePortPosition();

	// Set the port IDs
	p_input_port->SetPortArrowDirection(e_right_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Initialize m_dGainMatrix to have the default numerical value of the CString arg. (a non-NULL value).
	// If a Gain block were to be deleted, then memory would be deleted correctly.
	m_dGainMatrix = ConvertStringToDouble(m_strGainValue, m_iNrows, m_iNcols);
}

CSumBlock::CSumBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("sum_block");

	// Create input and output ports
	CPort *p_input_port1 = new CPort(*this);
	CPort *p_input_port2 = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port1->SetPortName("+");				// "+" sign assoc. with input port			
	p_input_port2->SetPortName("+");				// "+" sign assoc. with input port			
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the port posns.
	p_input_port1->SetPortPositionAngle(180.0);		// port on left side at 180.0
	p_input_port1->CalculatePortPosition();	
	p_input_port2->SetPortPositionAngle(270.0);		// port below at 270.0
	p_input_port2->CalculatePortPosition();	
	p_output_port->SetPortPositionAngle(0.0);		// port on right side at 0.0
	p_output_port->CalculatePortPosition();		

	// Set the port IDs
	p_input_port1->SetPortArrowDirection(e_right_arrow);
	p_input_port2->SetPortArrowDirection(e_up_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port1);
	GetVectorOfInputPorts().push_back(p_input_port2);
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Init. the integer vars.
	m_iNAddInputs = 2;
	m_iNSubtractInputs = 0;
}

CChirpSignalBlock::CChirpSignalBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{	
	SetBlockName("chirp_signal_block");

	// Create an output port
	CPort *p_output_port = new CPort(*this);

	// Set the port name
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port ID
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfOutputPorts().push_back(p_output_port);
}

CDerivativeBlock::CDerivativeBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("derivative_block");

	// Set the derivative method 
	m_iDerivativeMethod = 1;

	// Create input and output ports
	CPort *p_input_port = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port->SetPortName("_");					// no sign assoc. with input port			
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the input port posn.
	p_input_port->SetPortPositionAngle(180.0);
	p_input_port->CalculatePortPosition();

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port IDs
	p_input_port->SetPortArrowDirection(e_right_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Set memory based vars.
	m_iNcallsPerTimeCnt = 0;	// no. of times the fn is called per t_cnt (time point)
	m_iNrows = 0;				// no. of rows of output matrix signal		
	m_i_t_cnt_ref = 0;			// ref time cnt 
	m_f_at_t_minus_h = NULL;	// f(t-h)
	m_f_at_t_minus_2h = NULL;	// f(t-2h)
	m_dMatrixOut = NULL;		// matrix output signal
}

CIntegratorBlock::CIntegratorBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("integrator_block");

	// Set the Integrator block member var.
	m_strICVector = "[0]";

	// Create input and output ports
	CPort *p_input_port = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port->SetPortName("_");					// no sign assoc. with input port			
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the input port posn.
	p_input_port->SetPortPositionAngle(180.0);
	p_input_port->CalculatePortPosition();

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port IDs
	p_input_port->SetPortArrowDirection(e_right_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Initialize m_dICVector to have the default numerical value of the CString arg. (a non-NULL value).
	// If an Integrator block were to be deleted, then memory would be deleted correctly.
	m_dICVector = ConvertStringToDoubleVector(m_strICVector, m_iNrows, m_iNcols);

	// Set memory based vars.
	m_iNcallsPerTimeCnt = 0;		// no. of times the fn is called per t_cnt (time point)
	m_iNrowsOut = 0;				// no. of rows of output matrix signal
	m_i_t_cnt_ref = 0;				// ref time cnt 
	m_dMatrixOut = NULL;			// output matrix signal
	m_y_at_t_minus_h = NULL;		// y(t-h)
	m_y_dot_at_t_minus_h = NULL;	// y_dot(t-h)
}

CDivideBlock::CDivideBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("divide_block");

	// Set the Divide block member vars
	m_iNMultiplyInputs = 1;
	m_iNDivideInputs = 1;
	m_iMultType = 1;

	// Set the initial signal member vars for a Divide block forming a loop-repeated node.
	m_iNrowsInitSignal = 0;
	m_iNcolsInitSignal = 0;
	m_dInitSignal = NULL;
	m_strInitSignal = "";

	// Create input and output ports
	CPort *p_input_port1 = new CPort(*this);
	CPort *p_input_port2 = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port1->SetPortName("*");				// "*" sign assoc. with input port			
	p_input_port2->SetPortName("/");				// "/" sign assoc. with input port			
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the input port posn.
	p_input_port1->SetPortPositionAngle(150.0);
	p_input_port1->CalculatePortPosition();

	p_input_port2->SetPortPositionAngle(210.0);
	p_input_port2->CalculatePortPosition();

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port IDs
	p_input_port1->SetPortArrowDirection(e_right_arrow);
	p_input_port2->SetPortArrowDirection(e_right_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port1);
	GetVectorOfInputPorts().push_back(p_input_port2);
	GetVectorOfOutputPorts().push_back(p_output_port);
}

CLinearFnBlock::CLinearFnBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("linear_fn_block");

	// Set the LinearFnBlock member vars.
	m_dTimeInit = 0.0;
	m_dTimeFinal = 10.0;
	m_dValueInit = 0.0;
	m_dDerivative = 1.0;

	// Create output port
	CPort *p_output_port = new CPort(*this);

	// Set the port name
	p_output_port->SetPortName("_");						// no sign assoc. with output port			

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port ID
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfOutputPorts().push_back(p_output_port);
}

COutputBlock::COutputBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("output_block");

	// Set COutputBlock member var.
	m_iNrows = 0;
	m_iNcols = 0;
	m_iNotation = 0;
	m_iTimePtDisplay = 0;
	m_dOutputMatrix = NULL;

	// Create input port
	CPort *p_input_port = new CPort(*this);

	// Set the port name
	p_input_port->SetPortName("_");				// no sign assoc. with input port			

	// Set the input port posn.
	p_input_port->SetPortPositionAngle(180.0);
	p_input_port->CalculatePortPosition();

	// Set the port ID
	p_input_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);
}

CSignalGeneratorBlock::CSignalGeneratorBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("signal_generator_block");

	// Init. member vars.
	m_strFnType = "Sine";
	m_dAmplitude = 1.0;
	m_dFrequency = 1.0;
	m_dPhase = 0.0;
	m_strUnits = "rad/s";

	// Create output port
	CPort *p_output_port = new CPort(*this);

	// Set the port name
	p_output_port->SetPortName("_");			// no sign assoc. with output port			

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port ID
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfOutputPorts().push_back(p_output_port);
}

CSubsystemBlock::CSubsystemBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("subsystem_block");

	// Create input and output ports
	CPort *p_input_port = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port->SetPortName("_");					// no sign assoc. with input port			
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the input port posn.
	p_input_port->SetPortPositionAngle(180.0);
	p_input_port->CalculatePortPosition();

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port IDs
	p_input_port->SetPortArrowDirection(e_right_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Assign init values to the CString vars.
	m_strInputPortName = "input port name";
	m_strOutputPortName = "output port name";
}

CSubsystemInBlock::CSubsystemInBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("subsystem_in_block");

	// Create output port
	CPort *p_output_port = new CPort(*this);

	// Set the port name
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port ID
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Init. the member CString var.
	m_strInputPortName = "input port name";
}

CSubsystemOutBlock::CSubsystemOutBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("subsystem_out_block");

	// Create input port
	CPort *p_input_port = new CPort(*this);

	// Set the port name
	p_input_port->SetPortName("_");					// no sign assoc. with input port			

	// Set the input port posn.
	p_input_port->SetPortPositionAngle(180.0);
	p_input_port->CalculatePortPosition();

	// Set the port ID
	p_input_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);

	// Init. the member CString var.
	m_strOutputPortName = "output port name";
}

CTransferFnBlock::CTransferFnBlock(CSystemModel *pParentSystemModel, CPoint blk_posn, EBlockShape e_blk_shape):
CBlock(pParentSystemModel, blk_posn, e_blk_shape)
{
	SetBlockName("transfer_fn_block");

	// Create input and output ports
	CPort *p_input_port = new CPort(*this);
	CPort *p_output_port = new CPort(*this);

	// Set the port names
	p_input_port->SetPortName("_");					// no sign assoc. with input port			
	p_output_port->SetPortName("_");				// no sign assoc. with output port			

	// Set the input port posn.
	p_input_port->SetPortPositionAngle(180.0);
	p_input_port->CalculatePortPosition();

	// Set the output port posn.
	p_output_port->SetPortPositionAngle(0.0);
	p_output_port->CalculatePortPosition();

	// Set the port IDs
	p_input_port->SetPortArrowDirection(e_right_arrow);
	p_output_port->SetPortArrowDirection(e_right_arrow);

	// Add the port to the vector of ports
	GetVectorOfInputPorts().push_back(p_input_port);
	GetVectorOfOutputPorts().push_back(p_output_port);

	// Init. the CString member vars.
	m_strNumerCoeffs = "0 2 1";
	m_strDenomCoeffs = "0 3 2 1";

	// Initialize m_dNumerVector and m_dDenomVector to have the default numerical values of the CString args. (non-NULL values).
	// If a TransferFn block were to be deleted, then memory would be deleted correctly.
	m_dNumerVector = ConvertStringToDoubleVector(m_strNumerCoeffs, m_iLengthNumer);
	m_dDenomVector = ConvertStringToDoubleVector(m_strDenomCoeffs, m_iLengthDenom);
}

void CConstantBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int n_pts = 55;			// no. of pts in pt array
	int pen_color;			// color of pen
	int pen_width;			// width of pen
	double degree;			// angle in degrees
	double pi = PI;			// pi rounded
	double radian;			// andgle in radians
	double radius;			// radius in.t.o. width
	double width;			// width of block
	CPoint pt_array[55];	// array of pts
	CPoint blk_posn;		// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	
	//AfxMessageBox("\n CConstantBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to pt_array
	radius = 0.20*width;

	for(i=0;i<n_pts;i++)	
	{
		degree = i*5 + 45;					// arc steps of 5 degrees
		radian = (pi/180)*degree;
		pt_array[i].x = radius*cos(radian);
		pt_array[i].y = radius*sin(radian);
	}

	// Add blk posn to pts.
	for(i=0;i<n_pts;i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the letter "C" 
	pDC->MoveTo(pt_array[0]);
	for(i=1; i<n_pts; i++)
	{
		pDC->LineTo(pt_array[i]);
	}

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

CPoint CBlock::GetBlockPosition() const
{
	return m_ptBlockPosition;
}

CBlockShape& CBlock::GetBlockShape()
{
	return m_BlockShape;	// return a ref-to-a-CBlockShape obj. m_BlockShape (contained obj. of CBlock)
}

void CGainBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int pen_color;		// color of pen
	int pen_width;		// width of pen
	CPoint A;			// top pt. of letter "k"
	CPoint B;			// middle pt. of letter "k"
	CPoint C;			// lower pt. of letter "k"
	CPoint D;			// upper right pt. of letter "k"
	CPoint E;			// central pt. of letter "k"
	CPoint F;			// lower right pt of letter "k"
	CPoint blk_posn;	// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	double width;		// width of block
		
	//AfxMessageBox("\n CGainBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to pts relative to central pt. E of the letter "k"
	E.x = blk_posn.x - 0.02*width;	// was at blk_posn.x - 0.035
	E.y = blk_posn.y + 0.02*width;	// was at blk_posn.y + 0.035
	A.x = E.x - 0.055*width;
	A.y = E.y - 0.23*width;
	B.x = A.x;
	B.y = E.y + 0.035*width;
	C.x = A.x;
	C.y = E.y + 0.145*width;
	D.x = E.x + 0.1*width;
	D.y = E.y - 0.090*width;
	F.x = E.x + 0.135*width;
	F.y = C.y;

	// Chain up to CBlock for primitive drawing
	CBlock::DrawTriangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the letter "C" from lower 4 o'clock posn to upper 2 o'clock posn (clockwise)
	pDC->MoveTo(A);
	pDC->LineTo(C);
	pDC->MoveTo(D);
	pDC->LineTo(B);
	pDC->MoveTo(E);
	pDC->LineTo(F);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);	

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CSumBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int pen_color;		// color of pen
	int pen_width;		// width of pen
	CPoint left;		// left pt. of char "+"
	CPoint right;		// right pt. of char "+"
	CPoint up;			// upper pt. of char "+"
	CPoint down;		// lower pt. of char "+"
	CPoint blk_posn;	// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	double plus_size;	// size of plus sign strokes
	double width;		// width of block
		
	//AfxMessageBox("\n CSumBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to the cnr. pts.
	plus_size = 0.2;
	left.x = blk_posn.x - plus_size*width;
	left.y = blk_posn.y;
	right.x = blk_posn.x + plus_size*width;
	right.y = blk_posn.y;
	up.x = blk_posn.x;
	up.y = blk_posn.y - plus_size*width;
	down.x = blk_posn.x;
	down.y = blk_posn.y + plus_size*width;

	// Chain up to CBlock for primitive drawing
	CBlock::DrawEllipseBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the letter "C" from lower 4 o'clock posn to upper 2 o'clock posn (clockwise)
	pDC->MoveTo(left);
	pDC->LineTo(right);
	pDC->MoveTo(up);
	pDC->LineTo(down);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);	

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CChirpSignalBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int pen_color;		// color of pen
	int pen_width;		// width of pen
	CPoint A;			// pt. on curve graphic.
	CPoint B;
	CPoint C;
	CPoint D;
	CPoint E;
	CPoint F;
	CPoint G;
	CPoint blk_posn;	// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	double width;		// width of block
		
	//AfxMessageBox("\n CChirpSignalBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to graphics pts.
	A.x = blk_posn.x - 0.4*width;
	A.y = blk_posn.y;
	B.x = blk_posn.x - 0.2*width;
	B.y = blk_posn.y - 0.4*width;
	C.x = blk_posn.x;
	C.y = blk_posn.y + 0.4*width;
	D.x = blk_posn.x + 0.1*width;
	D.y = B.y;
	E.x = blk_posn.x + 0.2*width;
	E.y = C.y;
	F.x = blk_posn.x + 0.25*width;
	F.y = B.y;
	G.x = blk_posn.x + 0.3*width;
	G.y = C.y;

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the chirp signal graphic curve
	pDC->MoveTo(A);
	pDC->LineTo(B);
	pDC->LineTo(C);
	pDC->LineTo(D);
	pDC->LineTo(E);
	pDC->LineTo(F);
	pDC->LineTo(G);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);	
}

void CDerivativeBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int pen_color;				// color of pen
	int pen_width;				// width of pen
	double width;				// width of block
	CPoint blk_posn;			// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	CPoint bottom_left;			// derivative box
	CPoint bottom_right;
	CPoint dot_top_left;		// derivative dot	
	CPoint dot_bottom_right;
	CPoint top_left;			// derivative box
	CPoint top_right;
	
	//AfxMessageBox("\n CDerivativeBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to graphics pts.
	top_left.x = blk_posn.x - 0.2*width;
	top_left.y = blk_posn.y - 0.25*width;
	top_right.x = blk_posn.x + 0.2*width;
	top_right.y = top_left.y;
	bottom_right.x = top_right.x;
	bottom_right.y = blk_posn.y + 0.35*width;
	bottom_left.x = top_left.x;
	bottom_left.y = bottom_right.y;
	
	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the derivative box
	pDC->MoveTo(top_left);
	pDC->LineTo(top_right);
	pDC->LineTo(bottom_right);
	pDC->LineTo(bottom_left);
	pDC->LineTo(top_left);

	// Draw the dot (above the derivative box)
	dot_top_left.x = (int)(blk_posn.x - 0.05*width);
	dot_top_left.y = (int)(blk_posn.y - 0.40*width);
	dot_bottom_right.x = (int)(blk_posn.x + 0.05*width);
	dot_bottom_right.y = (int)(blk_posn.y - 0.30*width);
	pDC->Ellipse(dot_top_left.x, dot_top_left.y, dot_bottom_right.x, dot_bottom_right.y);

	// Declare and create the brush, and fill in the ellipse
	CBrush lSolidBrush(pen_color);
	CBrush *pOldBrush = pDC->SelectObject(&lSolidBrush);
	pDC->Ellipse(dot_top_left.x, dot_top_left.y, dot_bottom_right.x, dot_bottom_right.y);

	// Reset the prev. pen and brush
	pDC->SelectObject(pOldPen);	
	pDC->SelectObject(pOldBrush);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CDivideBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int pen_color;					// color of pen
	int pen_width;					// width of pen
	double width;					// width of block
	CPoint pt[8];					// pts of line segments used to draw "divide", "multiply", and "line-separator" symbols.
	CPoint blk_posn;				// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	CPoint lower_dot_top_left;		// lower dot used in divide sign
	CPoint lower_dot_bottom_right;
	CPoint upper_dot_top_left;		// upper dot used in divide sign
	CPoint upper_dot_bottom_right;
		
	//AfxMessageBox("\n CDivideBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to "divide" sign vinculum end pts.
	pt[0].x = blk_posn.x - 0.35*width;
	pt[0].y = blk_posn.y - 0.25*width;
	pt[1].x = blk_posn.x - 0.05*width;
	pt[1].y = pt[0].y;
	
	// Assign vals to "multiply (X)" sign line segment end pts.
	pt[2].x = blk_posn.x + 0.05*width;
	pt[2].y = blk_posn.y + 0.05*width;
	pt[3].x = blk_posn.x + 0.35*width;
	pt[3].y = blk_posn.y + 0.35*width;

	pt[4].x = pt[3].x;
	pt[4].y = pt[2].y;
	pt[5].x = pt[2].x;
	pt[5].y = pt[3].y;

	// Assign vals to the "line separator" symbol bw the "divide" and "multiply" signs
	pt[6].x = blk_posn.x - 0.25*width;
	pt[6].y = blk_posn.y + 0.20*width;
	pt[7].x = blk_posn.x + 0.20*width;
	pt[7].y = blk_posn.y - 0.25*width;

	// Assign vals to ellipse-bounding rectangles for upper and lower dots
	upper_dot_top_left.x = (int)(blk_posn.x - 0.24*width);		
	upper_dot_top_left.y = (int)(blk_posn.y - 0.40*width);		
	upper_dot_bottom_right.x = (int)(blk_posn.x - 0.16*width);	
	upper_dot_bottom_right.y = (int)(blk_posn.y - 0.32*width);	

	lower_dot_top_left.x = (int)(upper_dot_top_left.x);
	lower_dot_top_left.y = (int)(blk_posn.y - 0.18*width);		
	lower_dot_bottom_right.x = (int)(upper_dot_bottom_right.x);
	lower_dot_bottom_right.y = (int)(blk_posn.y - 0.10*width);	

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the vinculum of the "divide" sign.
	pDC->MoveTo(pt[0]);
	pDC->LineTo(pt[1]);

	// Draw the line segments of the "multiply (X)" sign.
	pDC->MoveTo(pt[2]);
	pDC->LineTo(pt[3]);
	pDC->MoveTo(pt[4]);
	pDC->LineTo(pt[5]);

	// Draw the line segment separating the "divide" and "multiply" signs.
	pen_color = RGB(120,120,120);					// set the color to grey
	CPen lnew_pen(PS_SOLID, pen_width, pen_color);	// create a new pen with the new color
	pDC->SelectObject(&lnew_pen);					// select the new pen
	pDC->MoveTo(pt[6]);
	pDC->LineTo(pt[7]);
	
	// Draw the upper and lower dots
	pDC->SelectObject(&lpen);						// select the old pen using "&lpen".
	pDC->Ellipse(upper_dot_top_left.x, upper_dot_top_left.y, upper_dot_bottom_right.x, upper_dot_bottom_right.y);
	pDC->Ellipse(lower_dot_top_left.x, lower_dot_top_left.y, lower_dot_bottom_right.x, lower_dot_bottom_right.y);

	// Declare and create the brush, and fill in the ellipses (dots)
	pen_color = GetPenColor();						// get the blue color again
	CBrush lSolidBrush(pen_color);					// create a brush with the pen color
	CBrush *pOldBrush = pDC->SelectObject(&lSolidBrush);
	pDC->Ellipse(upper_dot_top_left.x, upper_dot_top_left.y, upper_dot_bottom_right.x, upper_dot_bottom_right.y);
	pDC->Ellipse(lower_dot_top_left.x, lower_dot_top_left.y, lower_dot_bottom_right.x, lower_dot_bottom_right.y);

	// Reset the prev. pen and brush
	pDC->SelectObject(pOldPen);	
	pDC->SelectObject(pOldBrush);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CIntegratorBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int k;
	int pen_color;					// color of pen
	int pen_width;					// width of pen
	double width;					// width of block
	CPoint pt_array[25];			// array of CPoint
	CPoint blk_posn;				// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	CPoint upper_dot_top_left;		// upper dot used for integrator sign
	CPoint upper_dot_bottom_right;
	CPoint lower_dot_top_left;		// lower dot used for integrator sign
	CPoint lower_dot_bottom_right;
	
	//AfxMessageBox("\n CIntegratorBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to integral sign pts. (upper right portion of integral sign)
	pt_array[0].x = 0.10*width;
	pt_array[0].y = -0.37*width;
	pt_array[1].x = 0.08*width;
	pt_array[1].y = -0.37*width;
	pt_array[2].x = 0.06*width;
	pt_array[2].y = -0.365*width;
	pt_array[3].x = 0.045*width;
	pt_array[3].y = -0.355*width;
	pt_array[4].x = 0.035*width;
	pt_array[4].y = -0.34*width;
	pt_array[5].x = 0.02*width;
	pt_array[5].y = -0.325*width;
	pt_array[6].x = 0.015*width;
	pt_array[6].y = -0.305*width;
	pt_array[7].x = 0.005*width;
	pt_array[7].y = -0.29*width;
	pt_array[8].x = 0.0025*width;
	pt_array[8].y = -0.27*width;
	pt_array[9].x = 0.00125*width;
	pt_array[9].y = -0.25*width;
	pt_array[10].x = 0.001*width;
	pt_array[10].y = -0.225*width;
	pt_array[11].x = 0.00*width;
	pt_array[11].y = -0.2*width;
	pt_array[12].x = 0.00*width;
	pt_array[12].y = 0.00*width;

	// Assign vals to the lower left portion of integral sign (symmetry) 
	k = 11;
	for(i=0; i<12; i++)
	{
		pt_array[i+13].x = -pt_array[k].x;
		pt_array[i+13].y = -pt_array[k].y;
		k--;
	}

	// Add the blk_posn to the pts.
	for(i=0; i<25; i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Assign vals to ellipse-bounding rectangles for upper and lower dot-end-pts of integral sign
	upper_dot_top_left.x = (int)(blk_posn.x + 0.08*width);
	upper_dot_top_left.y = (int)(blk_posn.y - 0.40*width);
	upper_dot_bottom_right.x = (int)(blk_posn.x + 0.18*width);
	upper_dot_bottom_right.y = (int)(blk_posn.y - 0.30*width);

	lower_dot_top_left.x = (int)(blk_posn.x - 0.18*width);
	lower_dot_top_left.y = (int)(blk_posn.y + 0.30*width);
	lower_dot_bottom_right.x = (int)(blk_posn.x -0.08*width);
	lower_dot_bottom_right.y = (int)(blk_posn.y + 0.40*width);

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw all pts of integral sign.
	pDC->MoveTo(pt_array[0]);
	for(i=0; i<25; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	
	// Draw the upper and lower dots
	pDC->Ellipse(upper_dot_top_left.x, upper_dot_top_left.y, upper_dot_bottom_right.x, upper_dot_bottom_right.y);
	pDC->Ellipse(lower_dot_top_left.x, lower_dot_top_left.y, lower_dot_bottom_right.x, lower_dot_bottom_right.y);

	// Declare and create the brush, and fill in the ellipses (dots)
	CBrush lSolidBrush(pen_color);
	CBrush *pOldBrush = pDC->SelectObject(&lSolidBrush);
	pDC->Ellipse(upper_dot_top_left.x, upper_dot_top_left.y, upper_dot_bottom_right.x, upper_dot_bottom_right.y);
	pDC->Ellipse(lower_dot_top_left.x, lower_dot_top_left.y, lower_dot_bottom_right.x, lower_dot_bottom_right.y);

	// Reset the prev. pen and brush
	pDC->SelectObject(pOldPen);	
	pDC->SelectObject(pOldBrush);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CLinearFnBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int pen_color;		// color of pen
	int pen_width;		// width of pen
	CPoint A;			// pt. on curve graphic.
	CPoint B;
	CPoint C;
	CPoint blk_posn;	// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	double width;		// width of block
		
	//AfxMessageBox("\n CLinearFnBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to graphics pts.
	A.x = blk_posn.x - 0.47*width;
	A.y = blk_posn.y + 0.25*width;
	B.x = blk_posn.x - 0.1*width;
	B.y = A.y;
	C.x = blk_posn.x + 0.5*width;
	C.y = blk_posn.y - 0.4*width;

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	//pen_color = GetPenColor();
	pen_color = RGB(0,255,0);
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the linear fn. graphic curve
	pDC->MoveTo(A);
	pDC->LineTo(B);
	pDC->LineTo(C);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void COutputBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int pen_color;				// color of pen
	int pen_width;				// width of pen
	double width;				// width of block
	CPoint blk_posn;			// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	CPoint dot_top_left;		// green dot top left
	CPoint dot_bottom_right;	// green dot bottom right
	CPoint pt_array[20];		// array of CPoint
	
	//AfxMessageBox("\n COutputBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to graphic pts.

	// Outer box pts
	pt_array[0].x = -0.4*width;
	pt_array[0].y = -0.4*width;
	pt_array[1].x = 0.4*width;
	pt_array[1].y = pt_array[0].y;
	pt_array[2].x = pt_array[1].x;
	pt_array[2].y = 0.3*width;
	pt_array[3].x = pt_array[0].x;
	pt_array[3].y = pt_array[2].y;

	// Inner box pts
	pt_array[4].x = -0.35*width;
	pt_array[4].y = -0.35*width;
	pt_array[5].x = 0.35*width;
	pt_array[5].y = pt_array[4].y;
	pt_array[6].x = pt_array[5].x;
	pt_array[6].y = 0.25*width;
	pt_array[7].x = pt_array[4].x;
	pt_array[7].y = pt_array[6].y;

	// Stand pts
	pt_array[8].x = -0.1*width;
	pt_array[8].y = 0.3*width;
	pt_array[9].x = 0.1*width;
	pt_array[9].y = pt_array[8].y;
	pt_array[10].x = pt_array[9].x;
	pt_array[10].y = 0.37*width;
	pt_array[11].x = pt_array[8].x;
	pt_array[11].y = pt_array[10].y;
	pt_array[12].x = -0.2*width;
	pt_array[12].y = pt_array[11].y;
	pt_array[13].x = 0.2*width;
	pt_array[13].y = pt_array[12].y;
	pt_array[14].x = pt_array[13].x;
	pt_array[14].y = 0.45*width;
	pt_array[15].x = pt_array[12].x;
	pt_array[15].y = pt_array[14].y;

	// Pseudo text pts.
	// Line 1
	pt_array[16].x = -0.3*width;
	pt_array[16].y = -0.25*width;
	pt_array[17].x = -0.15*width;
	pt_array[17].y = pt_array[16].y;

	// Line 2
	pt_array[18].x = -0.3*width;
	pt_array[18].y = -0.175*width;
	pt_array[19].x = -0.05*width;
	pt_array[19].y = pt_array[18].y;

	// Add the blk_posn to the pts.
	for(i=0; i<20; i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Assign vals to ellipse-bounding rectangles for green dot
	dot_top_left.x = (int)(blk_posn.x + 0.25*width);
	dot_top_left.y = (int)(blk_posn.y + 0.25*width);
	dot_bottom_right.x = (int)(blk_posn.x + 0.35*width);
	dot_bottom_right.y = (int)(blk_posn.y + 0.35*width);

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw all pts of the monitor graphic.
	// Outer bounding box
	pDC->MoveTo(pt_array[0]);
	for(i=1; i<4; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[0]);

	// Inner bounding box
	/*pDC->MoveTo(pt_array[4]);
	for(i=4; i<8; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[4]);
	*/
	
	// Stand box
	pDC->MoveTo(pt_array[8]);
	for(i=9; i<11; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[13]);
	
	for(i=14; i<16; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[12]);
	pDC->LineTo(pt_array[11]);
	pDC->LineTo(pt_array[8]);

	// Pseudo text pts
	pen_color = RGB(120,120,120);	
	CPen lnew_pen(PS_SOLID, pen_width, pen_color);
	pDC->SelectObject(&lnew_pen);

	pDC->MoveTo(pt_array[16]);
	pDC->LineTo(pt_array[17]);
	pDC->MoveTo(pt_array[18]);
	pDC->LineTo(pt_array[19]);

	// Declare and create the brush, and fill in the ellipse: green dot
	pDC->SelectObject(&lpen);
	pen_color = RGB(0, 255,0);
	CBrush lSolidBrush(pen_color);
	CBrush *pOldBrush = pDC->SelectObject(&lSolidBrush);
	pDC->Ellipse(dot_top_left.x, dot_top_left.y, dot_bottom_right.x, dot_bottom_right.y);

	// Reset the prev. pen and brush
	pDC->SelectObject(pOldPen);	
	pDC->SelectObject(pOldBrush);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CSignalGeneratorBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int pen_color;		// color of pen
	int pen_width;		// width of pen
	double pi = PI;		// pi rounded
	double width;		// width of block
	double degree;		// angle theta in degrees
	double radian;		// angle theta in radians
	CPoint fn1[361];	// function 1 of theta (sin)
	CPoint fn2[361];	// function 2 of theta (cos)
	CPoint blk_posn;	// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	
	//AfxMessageBox("\n CSignalGeneratorBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Generate functional eval of pts for sine and cosine curves
	for(i=0; i<361; i++)
	{
		degree = i;
		radian = (pi/180)*degree;

		fn1[i].x = ((degree - 180)/360)*width;		// ((degree - 180)/360) scales the angle val bw. [-0.5,0.5]
		fn1[i].y = sin(radian)*(-0.4)*width;		// (-0.4)*width scales the curve the right way around
		fn2[i].x = ((degree - 180)/360)*width;		// ((degree - 180)/360) scales the angle val bw. [-0.5,0.5]
		fn2[i].y = cos(radian)*(-0.4)*width;		// (-0.4)*width scales the curve the right way around
	}

	// Add the blk_posn to the pts.
	for(i=0; i<361; i++)
	{
		fn1[i].x = blk_posn.x + fn1[i].x;
		fn1[i].y = blk_posn.y + fn1[i].y;
		fn2[i].x = blk_posn.x + fn2[i].x;
		fn2[i].y = blk_posn.y + fn2[i].y;
	}

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	//pen_color = GetPenColor();
	pen_color = RGB(0,255,0);		// green
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Create a new pen
	pen_color = RGB(255,0,0);		// red
	CPen lnew_pen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the sine curve
	pDC->MoveTo(fn1[0]);
	for(i=1; i<361; i++)
	{
		pDC->LineTo(fn1[i]);
	}

	// Draw the cosine curve
	pDC->SelectObject(&lnew_pen);	// select the pen that's red.
	pDC->MoveTo(fn2[0]);
	for(i=1; i<361; i++)
	{
		pDC->LineTo(fn2[i]);
	}

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CSubsystemBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int pen_color;			// color of pen
	int pen_width;			// width of pen
	double width;			// width of block
	CPoint pt_array[18];	// array of CPoints to draw the block graphics
	CPoint blk_posn;		// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	
	//AfxMessageBox("\n CSubsystemBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Pt arrays coords.
	pt_array[0].x = -0.4*width;
	pt_array[0].y = -0.4*width;
	pt_array[1].x = -0.1*width;
	pt_array[1].y = pt_array[0].y;
	pt_array[2].x = pt_array[1].x;
	pt_array[2].y = -0.1*width;
	pt_array[3].x = pt_array[0].x;
	pt_array[3].y = pt_array[2].y;
	pt_array[4].x = 0.1*width;
	pt_array[4].y = 0.1*width;
	pt_array[5].x = 0.4*width;
	pt_array[5].y = pt_array[4].y;
	pt_array[6].x = pt_array[5].x;
	pt_array[6].y = 0.4*width;
	pt_array[7].x = pt_array[4].x;
	pt_array[7].y = pt_array[6].y;
	pt_array[8].x = -0.1*width;
	pt_array[8].y = -0.25*width;
	pt_array[9].x = 0.25*width;
	pt_array[9].y = pt_array[8].y;
	pt_array[10].x = pt_array[9].x;
	pt_array[10].y = 0.1*width;
	pt_array[11].x = 0.1*width;
	pt_array[11].y = 0.25*width;
	pt_array[12].x = -0.25*width;
	pt_array[12].y = pt_array[11].y;
	pt_array[13].x = pt_array[12].x;
	pt_array[13].y = -0.1*width;
	pt_array[14].x = pt_array[0].x;
	pt_array[14].y = -0.25*width;
	pt_array[15].x = -0.5*width;
	pt_array[15].y = pt_array[14].y;
	pt_array[16].x = pt_array[5].x;
	pt_array[16].y = 0.25*width;
	pt_array[17].x = 0.5*width;
	pt_array[17].y = pt_array[16].y;

	// Add the blk_posn to the pts*width.
	for(i=0; i<18; i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Create a new pen
	pen_color = RGB(0,255,0);		// green
	CPen lnew_pen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the i/o blocks
	pDC->MoveTo(pt_array[0]);
	for(i=1; i<4; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[0]);

	pDC->MoveTo(pt_array[4]);
	for(i=4; i<8; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[4]);

	// Draw the connecting wires
	pDC->SelectObject(&lnew_pen);	// select the pen that's green.
	pDC->MoveTo(pt_array[8]);
	pDC->LineTo(pt_array[9]);
	pDC->LineTo(pt_array[10]);

	pDC->MoveTo(pt_array[11]);
	pDC->LineTo(pt_array[12]);
	pDC->LineTo(pt_array[13]);

	pDC->MoveTo(pt_array[14]);
	pDC->LineTo(pt_array[15]);

	pDC->MoveTo(pt_array[16]);
	pDC->LineTo(pt_array[17]);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CSubsystemInBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int pen_color;			// color of pen
	int pen_width;			// width of pen
	double width;			// width of block
	CPoint pt_array[18];	// array of CPoints to draw the block graphics
	CPoint blk_posn;		// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
		
	//AfxMessageBox("\n CSubsystemInBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Pt arrays coords.
	pt_array[0].x = -0.4*width;
	pt_array[0].y = -0.4*width;
	pt_array[1].x = -0.1*width;
	pt_array[1].y = pt_array[0].y;
	pt_array[2].x = pt_array[1].x;
	pt_array[2].y = -0.1*width;
	pt_array[3].x = pt_array[0].x;
	pt_array[3].y = pt_array[2].y;
	pt_array[4].x = 0.1*width;
	pt_array[4].y = 0.1*width;
	pt_array[5].x = 0.4*width;
	pt_array[5].y = pt_array[4].y;
	pt_array[6].x = pt_array[5].x;
	pt_array[6].y = 0.4*width;
	pt_array[7].x = pt_array[4].x;
	pt_array[7].y = pt_array[6].y;
	pt_array[8].x = -0.1*width;
	pt_array[8].y = -0.25*width;
	pt_array[9].x = 0.25*width;
	pt_array[9].y = pt_array[8].y;
	pt_array[10].x = pt_array[9].x;
	pt_array[10].y = 0.1*width;
	pt_array[11].x = 0.1*width;
	pt_array[11].y = 0.25*width;
	pt_array[12].x = -0.25*width;
	pt_array[12].y = pt_array[11].y;

	// modified from CSubsystemBlock::DrawBlock() to be on side of "input" triangle
	pt_array[13].x = pt_array[12].x;
	pt_array[13].y = -(0.1+0.075)*width;
	// end modification

	pt_array[14].x = pt_array[0].x;
	pt_array[14].y = -0.25*width;
	pt_array[15].x = -0.5*width;
	pt_array[15].y = pt_array[14].y;
	pt_array[16].x = pt_array[5].x;
	pt_array[16].y = 0.25*width;
	pt_array[17].x = 0.5*width;
	pt_array[17].y = pt_array[16].y;

	// Add the blk_posn to the pts*width.
	for(i=0; i<18; i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	//pen_color = GetPenColor();
	pen_color = RGB(180,180,180);
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Create a new pen
	pen_color = RGB(0,255,0);	
	CPen lnew_pen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the i/o blocks
	pDC->MoveTo(pt_array[0]);
	/*for(i=1; i<4; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[0]);
	*/

	pDC->MoveTo(pt_array[4]);
	for(i=4; i<8; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[4]);

	// Draw the connecting wires
	pDC->MoveTo(pt_array[8]);
	pDC->LineTo(pt_array[9]);
	pDC->LineTo(pt_array[10]);

	pDC->MoveTo(pt_array[11]);
	pDC->LineTo(pt_array[12]);
	pDC->LineTo(pt_array[13]);

	pDC->MoveTo(pt_array[16]);
	pDC->LineTo(pt_array[17]);

	// Draw the input graphics denoted by green
	pDC->SelectObject(&lnew_pen);	
	pDC->MoveTo(pt_array[0]);
	pDC->LineTo(pt_array[8]);
	pDC->LineTo(pt_array[3]);
	pDC->LineTo(pt_array[0]);
	pDC->MoveTo(pt_array[14]);
	pDC->LineTo(pt_array[15]);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CSubsystemOutBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int pen_color;			// color of pen
	int pen_width;			// width of pen
	double width;			// width of block
	CPoint pt_array[18];	// array of CPoints to draw the block graphics
	CPoint blk_posn;		// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
		
	//AfxMessageBox("\n CSubsystemOutBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Pt arrays coords.
	pt_array[0].x = -0.4*width;
	pt_array[0].y = -0.4*width;
	pt_array[1].x = -0.1*width;
	pt_array[1].y = pt_array[0].y;
	pt_array[2].x = pt_array[1].x;
	pt_array[2].y = -0.1*width;
	pt_array[3].x = pt_array[0].x;
	pt_array[3].y = pt_array[2].y;
	pt_array[4].x = 0.1*width;
	pt_array[4].y = 0.1*width;
	pt_array[5].x = 0.4*width;
	pt_array[5].y = pt_array[4].y;
	pt_array[6].x = pt_array[5].x;
	pt_array[6].y = 0.4*width;
	pt_array[7].x = pt_array[4].x;
	pt_array[7].y = pt_array[6].y;
	pt_array[8].x = -0.1*width;
	pt_array[8].y = -0.25*width;
	pt_array[9].x = 0.25*width;
	pt_array[9].y = pt_array[8].y;

	// modified from CSubsystemBlock::DrawBlock() to be on side of "output" triangle
	pt_array[10].x = pt_array[9].x;
	pt_array[10].y = (0.1+0.075)*width;
	// end modification

	pt_array[11].x = 0.1*width;
	pt_array[11].y = 0.25*width;
	pt_array[12].x = -0.25*width;
	pt_array[12].y = pt_array[11].y;
	pt_array[13].x = pt_array[12].x;
	pt_array[13].y = -0.1*width;
	pt_array[14].x = pt_array[0].x;
	pt_array[14].y = -0.25*width;
	pt_array[15].x = -0.5*width;
	pt_array[15].y = pt_array[14].y;
	pt_array[16].x = pt_array[5].x;
	pt_array[16].y = 0.25*width;
	pt_array[17].x = 0.5*width;
	pt_array[17].y = pt_array[16].y;

	// Add the blk_posn to the pts*width.
	for(i=0; i<18; i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	//pen_color = GetPenColor();
	pen_color = RGB(180,180,180);
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Create a new pen
	pen_color = RGB(0,255,0);	
	CPen lnew_pen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the i/o blocks
	pDC->MoveTo(pt_array[0]);
	for(i=1; i<4; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[0]);

	/*pDC->MoveTo(pt_array[4]);
	for(i=4; i<8; i++)
	{
		pDC->LineTo(pt_array[i]);
	}
	pDC->LineTo(pt_array[4]);
	*/

	// Draw the connecting wires
	pDC->MoveTo(pt_array[8]);
	pDC->LineTo(pt_array[9]);
	pDC->LineTo(pt_array[10]);

	pDC->MoveTo(pt_array[11]);
	pDC->LineTo(pt_array[12]);
	pDC->LineTo(pt_array[13]);

	pDC->MoveTo(pt_array[14]);
	pDC->LineTo(pt_array[15]);

	pDC->MoveTo(pt_array[16]);
	pDC->LineTo(pt_array[17]);

	// Draw the output graphics denoted by green
	pDC->SelectObject(&lnew_pen);	
	pDC->MoveTo(pt_array[4]);
	pDC->LineTo(pt_array[16]);
	pDC->LineTo(pt_array[7]);
	pDC->LineTo(pt_array[4]);
	pDC->MoveTo(pt_array[16]);
	pDC->LineTo(pt_array[17]);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

void CTransferFnBlock::DrawBlock(CDC *pDC)
{
	// Note: pDC is a ptr to the device context of "Class Device Context" (CDC)
	int i;
	int pen_color;			// color of pen
	int pen_width;			// width of pen
	CPoint pt_array[10];	// pt. on curve graphic.
	CPoint blk_posn;		// local blk_posn var. that is assigned m_ptBlockPosition of CBlock
	double width;			// width of block
		
	//AfxMessageBox("\n CTransferFnBlock::DrawBlock()\n", MB_OK, 0);

	// Get CBlock and CBlockShape vars.
	blk_posn = GetBlockPosition();
	width = GetBlockShape().GetBlockWidth();
	
	// Assign vals to graphics pts.
	// Letter Y
	pt_array[0].x = -0.15*width;
	pt_array[0].y = -0.4*width;
	pt_array[1].x = 0.15*width;
	pt_array[1].y = pt_array[0].y;
	pt_array[2].x = 0.0;
	pt_array[2].y = -0.2*width;
	pt_array[3].x = 0.0;
	pt_array[3].y = -0.05*width;

	// Letter X
	pt_array[4].x = -0.15*width;
	pt_array[4].y = 0.05*width;
	pt_array[5].x = 0.15*width;
	pt_array[5].y = 0.4*width;
	pt_array[6].x = pt_array[5].x;
	pt_array[6].y = pt_array[4].y;
	pt_array[7].x = pt_array[4].x;
	pt_array[7].y = pt_array[5].y;

	// Vinculum
	pt_array[8].x = -0.2*width;
	pt_array[8].y = 0.0;
	pt_array[9].x = 0.2*width;
	pt_array[9].y = 0.0;

	// Add the blk_posn to the pts*width.
	for(i=0; i<10; i++)
	{
		pt_array[i].x = blk_posn.x + pt_array[i].x;
		pt_array[i].y = blk_posn.y + pt_array[i].y;
	}

	// Chain up to CBlock for primitive drawing
	CBlock::DrawRectangleBlock(pDC);

	// Create a pen
	pen_width = GetPenWidth();
	pen_color = GetPenColor();
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Set the new pen as the drawing obj.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	// Draw the transfer fn. graphic curve
	pDC->MoveTo(pt_array[0]);
	pDC->LineTo(pt_array[2]);
	pDC->MoveTo(pt_array[1]);
	pDC->LineTo(pt_array[2]);
	pDC->MoveTo(pt_array[2]);
	pDC->LineTo(pt_array[3]);
	
	pDC->MoveTo(pt_array[4]);
	pDC->LineTo(pt_array[5]);
	pDC->MoveTo(pt_array[6]);
	pDC->LineTo(pt_array[7]);

	pDC->MoveTo(pt_array[8]);
	pDC->LineTo(pt_array[9]);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);

	// Draw block ports
	DrawBlockPorts(pDC);
}

CString CPort::GetPortName() const
{
	return m_strPortName;
}

void CPort::SetPortName(CString name)
{
	m_strPortName = name;
}

CPoint CPort::GetPortPosition() const
{
	return m_ptPortPosition;
}

void CPort::SetPortPosition(CPoint port_posn)
{
	m_ptPortPosition = port_posn;
}

vector<CPort*> &CBlock::GetVectorOfInputPorts()
{
	return m_vecInputPorts;
}

vector<CPort*> &CBlock::GetVectorOfOutputPorts()
{
	return m_vecOutputPorts;
}

void CBlock::CheckBlockPorts()
{
	// Message box vars.
	CString sMsg;		// main msg string
	CString sMsgTemp;	// temp msg string
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	sMsgTemp.Format("\n CBlock::CheckBlockPorts()\n");
	sMsg += sMsgTemp;
	
	// Block vec vars.
	vector<CPort*> vec_input_ports;
	vector<CPort*> vec_output_ports;
	vector<CPort*>::iterator it_port;			// iterator for vector of CPort ptrs.

	// Get vec of input and output ports
	vec_input_ports = GetVectorOfInputPorts();
	vec_output_ports = GetVectorOfOutputPorts();

	// Check vec of input ports
	for(it_port = vec_input_ports.begin(); it_port != vec_input_ports.end(); it_port++)
	{
		sMsgTemp.Format(" input port name = %s\n",(*it_port)->GetPortName());
		sMsg += sMsgTemp;
	}

	for(it_port = vec_output_ports.begin(); it_port != vec_output_ports.end(); it_port++)
	{
		sMsgTemp.Format(" output port name = %s\n",(*it_port)->GetPortName());
		sMsg += sMsgTemp;
	}

	AfxMessageBox(sMsg, nType, nIDhelp);
}

void CBlock::DrawBlockPorts(CDC *pDC)
{
	vector<CPort*>::iterator it_port; // vector iterator.
	
	//AfxMessageBox("\n CBlock::DrawBlockPorts()\n", MB_OK, 0);

	// Iterate through vec of input ports
	for(it_port = m_vecInputPorts.begin(); it_port != m_vecInputPorts.end(); it_port++)
	{
		// Draw port if not connected to a connection object
		if(CheckPortConnection(*it_port) == 0)
		{
			(*it_port)->DrawPort(pDC);		// call CPort::DrawPort()
		}

		// Draw port signs
		(*it_port)->DrawPortSign(pDC);
	}

	// Iterate through vec of output ports
	for(it_port = m_vecOutputPorts.begin(); it_port != m_vecOutputPorts.end(); it_port++)
	{
		// Draw port if not connected to a connection object
		if(CheckPortConnection(*it_port) == 0)
		{
			(*it_port)->DrawPort(pDC);		// call CPort::DrawPort()
		}

		// Draw port signs
		(*it_port)->DrawPortSign(pDC);
	}
}

void CPort::DrawPort(CDC *pDC)
{
	int i;
	int	brush_color;		// local brush color
	int model_status = 0;	// model status flag
	int pen_color;			// local pen color
	int pen_width;			// local pen width
	int shift_left = 0;		// shift left arrow port graphic
	int shift_up = 0;		// shift up arrow port graphic
	int shift_right = 0;	// shift right arrow port graphic
	int shift_down = 0;		// shift down arrow port graphic
	double d;				// half the length of the longest port triangle side
	double width;			// block width
	CPoint pt_array[3];		// array of pts to draw the port graphic
	CString sMsg;			// main msg string
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
	
	// Msg. box
	sMsg.Format("\n CPort::DrawPort(), m_ePortArrowDirec = %d\n", m_ePortArrowDirec);
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Get block width using the m_rRefToBlock
	width = m_rRefToBlock.GetBlockShape().GetBlockWidth();
	d = 0.05*width;			// d as a percentage of block width

	// Switch on EPortArrowDirection m_ePortArrowDirec
	switch(m_ePortArrowDirec)
	{
	case e_left_arrow:
		pt_array[0].x = m_ptPortPosition.x + 0.5*d;
		pt_array[0].y = m_ptPortPosition.y + d;
		pt_array[1].x = m_ptPortPosition.x - 0.5*d;
		pt_array[1].y = m_ptPortPosition.y;
		pt_array[2].x = pt_array[0].x;
		pt_array[2].y = m_ptPortPosition.y - d;

		// Shift pts as desired
		if(shift_left)
		{
			for(i=0;i<3;i++)
			{
				pt_array[i].x = pt_array[i].x - 0.5*d;
			}
		}
		break;

	case e_up_arrow:
		pt_array[0].x = m_ptPortPosition.x - d;
		pt_array[0].y = m_ptPortPosition.y + 0.5*d;
		pt_array[1].x = m_ptPortPosition.x;
		pt_array[1].y = m_ptPortPosition.y - 0.5*d;
		pt_array[2].x = m_ptPortPosition.x + d;
		pt_array[2].y = pt_array[0].y;

		// Shift pts as desired
		if(shift_up)
		{
			for(i=0;i<3;i++)
			{
				pt_array[i].y = pt_array[i].y + 0.5*d;
			}
		}
		break;

	case e_right_arrow:
		pt_array[0].x = m_ptPortPosition.x - 0.5*d;
		pt_array[0].y = m_ptPortPosition.y - d;
		pt_array[1].x = m_ptPortPosition.x + 0.5*d;
		pt_array[1].y = m_ptPortPosition.y;
		pt_array[2].x = pt_array[0].x;
		pt_array[2].y = m_ptPortPosition.y + d;

		// Shift pts as desired
		if(shift_right)
		{
			for(i=0;i<3;i++)
			{
				pt_array[i].x = pt_array[i].x + 0.5*d;
			}
		}
		break;

	case e_down_arrow:
		pt_array[0].x = m_ptPortPosition.x + d;
		pt_array[0].y = m_ptPortPosition.y - 0.5*d;
		pt_array[1].x = m_ptPortPosition.x;
		pt_array[1].y = m_ptPortPosition.y + 0.5*d;
		pt_array[2].x = m_ptPortPosition.x - d;
		pt_array[2].y = pt_array[0].y;

		// Shift pts as desired
		if(shift_down)
		{
			for(i=0;i<3;i++)
			{
				pt_array[i].y = pt_array[i].y - 0.5*d;
			}
		}
		break;

	default:
		// Use e_right_arrow case
		pt_array[0].x = m_ptPortPosition.x - 0.5*d;
		pt_array[0].y = m_ptPortPosition.y - d;
		pt_array[1].x = m_ptPortPosition.x + 0.5*d;
		pt_array[1].y = m_ptPortPosition.y;
		pt_array[2].x = m_ptPortPosition.x - 0.5*d;
		pt_array[2].y = m_ptPortPosition.y + d;

		// Shift pts as desired
		if(shift_right)
		{
			for(i=0;i<3;i++)
			{
				pt_array[i].x = pt_array[i].x + 0.5*d;
			}
		}
		break;
	}// end switch


	// -- FILL THE TRIANGULAR PORT POLYGON
	// Create a brush
	brush_color = RGB(200,200,200);		// White = RGB(255,255,255), Black = RGB(0,0,0)
	CBrush NewBrush(brush_color);		// create a new brush using the brush_color
	CBrush *pBrush;						// declare a ptr-to-CBrush (for resetting below)

	// Select the new brush
	pBrush = pDC->SelectObject(&NewBrush);

	// Fill the polygon
	pDC->Polygon(pt_array, 3);			// 3 vertices of triangle stored in pt_array enclose polygon region

	// Reset the old brush
	pDC->SelectObject(pBrush);


	// -- DRAW THE BORDER OF THE TRIANGULAR PORT POLYGON 
	// Set a new pen color for the border only
	pen_color = RGB(0,0,0);									// White = RGB(255,255,255), Black = RGB(0,0,0)	
	m_rRefToBlock.GetParentSystemModel()->ModelErrorPenColor(&pen_color);	// change the pen color if model is in error
	pen_width = 1;

	// Create the pen
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Select the pen as the drawing obj. 
	// The value returned by SelectObject() is a ptr to the obj. being replaced, i.e. an old-pen-ptr.
	CPen *pOldPen = pDC->SelectObject(&lpen);
	
	// Draw the arrow/triangle (clockwise)
	pDC->MoveTo(pt_array[0]);
	pDC->LineTo(pt_array[1]);
	pDC->LineTo(pt_array[2]);
	pDC->LineTo(pt_array[0]);

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);
}

void CPort::SetPortPositionAngle(double angle)
{
	// Set the angle w.r.t. the horiztonal x-axis that the port should be located at, on the bndy of the block.
	m_dPortPositionAngle = angle;
}

double CPort::GetPortPositionAngle() const
{
	// Port position angle
	return m_dPortPositionAngle;
}

void CPort::SetPortArrowDirection(EPortArrowDirection arrow_direc)
{
	m_ePortArrowDirec = arrow_direc;
}

EPortArrowDirection CPort::GetPortArrowDirection() const
{
	return m_ePortArrowDirec;
}

CPoint CPort::CalculatePortPosition()
{
	int count;			// no. of times 360 divides into m_dPortPositionAngle.
	double c;			// length of ray from triangle CM to port posn on bndy of triangle.
	double d;			// opp. side length of a subtriangle with hypotenuse h, and adjacent side length width/2.
	double eps = 0.0087;// epsilon value (radians) to allow setting of angle at 2*pi; (0.0087 radians = 0.5 degrees)
	double h;			// hypotenuse of a subtriangle with opp. side length d, and adjacent side length width/2.
	double height = m_rRefToBlock.GetBlockShape().GetBlockHeight();
	double pi = PI;
	double r;			// length of port posn vector.
	double theta;		// m_dPortPositionAngle coverted to an angle in radians.
	double theta_crit;	// critical theta value used to determine port_posn.x and port_posn.y
	double width = m_rRefToBlock.GetBlockShape().GetBlockWidth();
	CPoint blk_posn = m_rRefToBlock.GetBlockPosition();
	CPoint port_posn;
	EBlockDirection e_blk_direc = m_rRefToBlock.GetBlockShape().GetBlockDirection();
	EBlockShape e_blk_shape = m_rRefToBlock.GetBlockShape().GetBlockShapeType();
	CString sMsg;		// main msg string
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	
	// Convert port position angle into domain [0,360]
	if(m_dPortPositionAngle > 360.00)
	{
		count = int(m_dPortPositionAngle/360.00);
		m_dPortPositionAngle = m_dPortPositionAngle - count*360.00;
	}
	if(m_dPortPositionAngle < 0.00)
	{
		count = int(fabs(m_dPortPositionAngle/360.00));
		m_dPortPositionAngle = m_dPortPositionAngle + (count + 1)*360.00;
	}

	// Convert port position angle from degrees into radians
	theta = m_dPortPositionAngle*pi/180.00;
	
	//sMsg.Format("\n CPort::CalculatePortPosition(), m_dPortPositionAngle = %lf, theta = %3.15lf, 2*pi+eps = %3.15lf\n", m_dPortPositionAngle, theta, 2*pi+eps);
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Switch upon shape
	switch(e_blk_shape)
	{
	case e_ellipse:	
		
		port_posn.x = blk_posn.x + 0.5*width*cos(theta);
		port_posn.y = blk_posn.y - 0.5*width*sin(theta);
		break;

	case e_rectangle:		// rectangle caters for squares (width = height) and rectangles (width != height)

		theta_crit = atan(height/width);	// atan2(y,x) = arctangent of y/x

		if((theta >= 0) && (theta <= theta_crit))
		{
			r = width/(2*cos(theta));
			port_posn.x = blk_posn.x + width*0.5;
			port_posn.y = blk_posn.y - r*sin(theta);
		}
		if( (theta > theta_crit) && (theta < (pi - theta_crit)) )
		{	
			r = height/(2*sin(theta));
			port_posn.x = blk_posn.x + r*cos(theta);
			port_posn.y = blk_posn.y - height*0.5;
		}
		if((theta >= (pi - theta_crit)) && (theta <= (pi + theta_crit)))
		{
			r = -width/(2*cos(theta));
			port_posn.x = blk_posn.x - width*0.5;
			port_posn.y = blk_posn.y - r*sin(theta);
		}
		if((theta > (pi + theta_crit)) && (theta < (2*pi - theta_crit)))
		{
			r = -height/(2*sin(theta));
			port_posn.x = blk_posn.x + r*cos(theta);
			port_posn.y = blk_posn.y + height*0.5;
		}
		if( (theta >= (2*pi - theta_crit)) && (theta <= (2*pi + eps)) )
		{
			r = width/(2*cos(theta));
			port_posn.x = blk_posn.x + width*0.5;
			port_posn.y = blk_posn.y - r*sin(theta);
		}

		break;

	case e_triangle:

		// Get lengths of subtriangle sides: hypotenuse h, opp. side length d., and base side length width/2.
		d = (width/2)*tan(pi/6);
		h = width/sqrt(3);

		if(e_blk_direc == e_right)		// triangle pointing to the right.
		{
			if((theta >= 0) && (theta < 2*pi/3)) 
			{
				c = h/(2*sin(5*pi/6 - theta));		// length of ray from CM to port posn on bndy of triangle.
				port_posn.x = blk_posn.x + c*cos(theta);
				port_posn.y = blk_posn.y - c*sin(theta);
			}
			if( (theta >= 2*pi/3) && (theta <= 4*pi/3))
			{
				port_posn.x = blk_posn.x - d;
				port_posn.y = blk_posn.y - d*tan(pi - theta);
			}
			if( (theta > 4*pi/3) && (theta <= (2*pi + eps)))
			{
				c = h/(2*sin(theta - 7*pi/6));
				port_posn.x = blk_posn.x + c*cos(theta);
				port_posn.y = blk_posn.y - c*sin(theta);
			}
		}
		else if(e_blk_direc == e_left)	// triangle pointing to the left.
		{
			if((theta >= 0) && (theta <= pi/3)) 
			{
				port_posn.x = blk_posn.x + d;
				port_posn.y = blk_posn.y - d*tan(theta);
			}
			if( (theta > pi/3) && (theta <= pi) )
			{
				c = h/(2*sin(theta - pi/6));			// length of ray from CM to port posn on bndy of triangle.
				port_posn.x = blk_posn.x + c*cos(theta);
				port_posn.y = blk_posn.y - c*sin(theta);
			}
			if((theta > pi) && (theta < 5*pi/3))
			{
				c = h/(2*sin(11*pi/6 - theta));
				port_posn.x = blk_posn.x + c*cos(theta);
				port_posn.y = blk_posn.y - c*sin(theta);
			}
			if((theta >= 5*pi/3) && (theta <= (2*pi + eps)))
			{
				port_posn.x = blk_posn.x + d;
				port_posn.y = blk_posn.y + d*tan(2*pi - theta);
			}
		}
		else
		{
			// Print msg.
			sMsg.Format("\n CPort::CalculatePortPosition()\n e_blk_direc for triangles should be e_left or e_right only!");
			AfxMessageBox(sMsg, nType, nIDhelp);
		}
		break;

	default:
		// no code for now
		break;
	}// end switch

	// Set port position within CalculatePortPosition() to prevent an additional call.
	SetPortPosition(port_posn);

	return port_posn;
}

void CBlockShape::SetBlockHeight(double blk_height)
{
	// Set the member var m_dBlockHeight
	m_dBlockHeight = blk_height;
}

double CBlockShape::GetBlockHeight() const
{
	// Return the member var m_dBlockHeight
	return m_dBlockHeight;
}

void CBlockShape::SetBlockWidth(double blk_width)
{
	// Set the member var m_dBlockWidth
	m_dBlockWidth = blk_width;
}

void CBlock::SetBlockPosition(CPoint blk_posn)
{
	vector<CPort*>::iterator it_port; 	// vector iterator.

	// Set the member var. to the incoming value.
	m_ptBlockPosition = blk_posn;

	// Calculate the position of the ports associated with this block since its position has moved by iterating through the vector of i/o ports.

	// Iterate through vec of input ports
	for(it_port = m_vecInputPorts.begin(); it_port != m_vecInputPorts.end(); it_port++)
	{
		// Calculate the new port position
		(*it_port)->CalculatePortPosition();			// deref the iterator to get the ptr-to-CPort obj.

		// Update any connection head end point associated with the port.
		m_pParentSystemModel->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.	
	}

	// Iterate through vec of output ports
	for(it_port = m_vecOutputPorts.begin(); it_port != m_vecOutputPorts.end(); it_port++)
	{
		// Calculate the new port position
		(*it_port)->CalculatePortPosition();			// deref the iterator to get the ptr-to-CPort obj.

		// Update any connection tail end point associated with the port.
		m_pParentSystemModel->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
	}
}

void CBlock::BlockDlgWndParameterInput()
{
	// VIRTUAL FN to be OVERRIDDEN by each DERIVED Block class.
	// This is done, so the correct BlockDlgWndParameterInput() fn is called,
	// based on the run time type of the ptr-to-CBlock, within the block list.
}

void CConstantBlock::BlockDlgWndParameterInput()
{
	int i;		
	int input = 0;		// input: (0) incomplete, (1) complete
	CString	sMsg;		// string msg. to be displayed
	CString sMsgTemp;	// temp string msg.
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	// Create a dlg obj. of class CConstantBlockDialog : public CDialog
	CConstantBlockDialog oDlg;		

	// Set the dialog class vars using the block class vars
	oDlg.m_strConstValue = m_strConstValue;

	// While input not correct
	while(input == 0)
	{
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK) 
		{	
			// Assign CConstantBlockDialog variable values to CConstantBlock variable values.
			m_strConstValue = oDlg.m_strConstValue;
			// Print msg with variable value.
			//sMsg.Format("\n CConstantBlock::BlockDlgWndParameterInput(), string = %s\n", m_strConstValue);
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}	

		// DELETE POSSIBLY EXISTING MATRIX 
		// Delete the input data matrix whose memory was allocated in ConvertStringMatrixToDoubleMatrix()
		if(m_dConstMatrix != NULL)
		{
			for(i=0; i<m_iNrows; i++)
			{
				delete [] m_dConstMatrix[i];
			}
			delete [] m_dConstMatrix;
		}

		// Convert the input string into a double matrix.
		m_dConstMatrix = ConvertStringToDouble(m_strConstValue, m_iNrows, m_iNcols);
		//PrintMatrix(m_dConstMatrix, m_iNrows, m_iNcols);

		// Check validity of input
		if(m_dConstMatrix == NULL)
		{
			sMsgTemp.Format("\n WARNING!: Incorrect constant scalar/vector/matrix input.  \n");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Please enter consistent numerical data.  \n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
		}
		else
		{
			input = 1;
		}
	}
}

void CDerivativeBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CDerivativeBlockDialog : public CDialog
	CDerivativeBlockDialog oDlg;	

	// Set the dialog class vars using the block class vars
	oDlg.m_iDerivativeMethod = m_iDerivativeMethod;

	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign CDerivativeBlockDialog variable values to CDerivativeBlock variable values.
		m_iDerivativeMethod = oDlg.m_iDerivativeMethod;

		// Print msg with variable value.
		sMsg.Format("\n CDerivativeBlock::BlockDlgWndParameterInput(), m_iDerivativeMethod = %d\n", m_iDerivativeMethod);
		//AfxMessageBox(sMsg, nType, nIDhelp);
	}	
}

void CDivideBlock::BlockDlgWndParameterInput()
{
	int	n_inputs = 0;		// number of input ports
	CString	sMsg;			// string to be displayed
	CString sMsgTemp;		// temp string msg.
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CDivideBlockDialog : public CDialog
	CDivideBlockDialog oDlg;	

	// Update the sign count since a port may have been deleted
	UpdateSignCount();

	// Set the dialog class vars using the block class vars
	oDlg.m_iMultType = m_iMultType;
	oDlg.m_iNDivideInputs = m_iNDivideInputs;
	oDlg.m_iNMultiplyInputs = m_iNMultiplyInputs;

	// While less than two input ports get user input
	while(n_inputs < 2)
	{
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK) 
		{	
			// Assign CDivideBlockDialog variable values to CDivideBlock variable values.
			m_iNDivideInputs = oDlg.m_iNDivideInputs;
			m_iNMultiplyInputs = oDlg.m_iNMultiplyInputs;
			m_iMultType = oDlg.m_iMultType;

			// Print msg with variable value.
			//sMsg.Format("\n CDivideBlock::BlockDlgWndParameterInput(), m_iMultType = %d\n", m_iMultType);
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}

		// Check input for correctness and warn user if approp.
		n_inputs = m_iNDivideInputs + m_iNMultiplyInputs;
		
		if(n_inputs < 2)
		{
			sMsgTemp.Format("\n CDivideBlock::BlockDlgWndParameterInput()\n");
			sMsg += sMsgTemp;
			sMsgTemp.Format(" No. of input ports = %d\n", n_inputs);
			sMsg += sMsgTemp;
			sMsgTemp.Format(" Two or more input ports are required!\n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
		}
	}

	// Reset ports
	ResetInputPorts(m_iNMultiplyInputs, m_iNDivideInputs);
	ResetOutputPorts();
}

void CGainBlock::BlockDlgWndParameterInput()
{
	int i;
	int input = 0;		// input: (0) incomplete, (1) complete
	CString	sMsg;		// string msg. to be displayed
	CString sMsgTemp;	// temp string msg.
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	// Create a dialog object. of class CGainBlockDialog : public CDialog
	CGainBlockDialog oDlg;	

	// Set the dialog class vars using the block class vars
	oDlg.m_iGainType = m_iGainType;
	oDlg.m_strGainValue = m_strGainValue;
	
	// While input not correct
	while(input == 0)
	{
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK) 
		{	
			// Assign CGainBlockDialog variable values to CGainBlock variable values.
			m_strGainValue = oDlg.m_strGainValue;
			m_iGainType = oDlg.m_iGainType;

			// Print msg with variable value.
			//sMsg.Format("\n CGainBlock::BlockDlgWndParameterInput(), m_strGainValue = %s\n", m_strGainValue);
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}
		
		// DELETE POSSIBLY EXISTING MATRIX 
		// Delete the input data matrix whose memory was allocated in ConvertStringMatrixToDoubleMatrix()
		if(m_dGainMatrix != NULL)
		{
			for(i=0; i<m_iNrows; i++)
			{
				delete [] m_dGainMatrix[i];
			}
			delete [] m_dGainMatrix;
		}

		// Convert the input string into a double matrix.
		m_dGainMatrix = ConvertStringToDouble(m_strGainValue, m_iNrows, m_iNcols);
		//PrintMatrix(m_dGainMatrix, m_iNrows, m_iNcols);

		// Check validity of input
		if(m_dGainMatrix == NULL)
		{
			sMsgTemp.Format("\n WARNING!: Incorrect gain scalar/vector/matrix input.  \n");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Please enter consistent numerical data.  \n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
		}
		else
		{
			input = 1;
		}
	}
}

void CIntegratorBlock::BlockDlgWndParameterInput()
{
	int input = 0;		// input: (0) incomplete, (1) complete
	CString	sMsg;		// string msg. to be displayed
	CString sMsgTemp;	// temp string msg.
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	// Create a dialog object. of class CIntegratorBlockDialog : public CDialog
	CIntegratorBlockDialog oDlg;	

	// Set the dialog class vars using the block class vars
	oDlg.m_strICVector = m_strICVector;

	// While input not correct
	while(input == 0)
	{
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK) 
		{	
			// Assign CIntegratorBlockDialog variable value to CIntegratorBlock variable value.
			m_strICVector = oDlg.m_strICVector;

			// Print msg with variable value.
			//sMsg.Format("\n CIntegratorBlock::BlockDlgWndParameterInput(), m_strICVector = %s\n", m_strICVector);
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}
		
		// DELETE POSSIBLY EXISTING VECTOR
		// Delete the initial condition vector whose memory was allocated in ConvertStringToDoubleVector()
		if(m_dICVector != NULL)
		{
			delete [] m_dICVector;
		}

		// Convert the input string into a double vector
		m_dICVector = ConvertStringToDoubleVector(m_strICVector, m_iNrows, m_iNcols);
		//PrintVector(m_dICVector, m_iLength);

		// Check validity of input
		if(m_dICVector == NULL)
		{
			sMsgTemp.Format("\n WARNING!: Incorrect initial condition vector input.  \n");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Please enter numerical vector data.  \n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
		}
		else
		{
			input = 1;
		}
	}
}

void CLinearFnBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CLinearFnBlockDialog : public CDialog
	CLinearFnBlockDialog oDlg;	

	// Set the dialog class vars using the block class vars
	oDlg.m_dDerivative = m_dDerivative;
	oDlg.m_dTimeFinal = m_dTimeFinal;
	oDlg.m_dTimeInit = m_dTimeInit;
	oDlg.m_dValueInit = m_dValueInit;
	
	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign CLinearFnBlockDialog variable values to CLinearFnBlock variable values.
		m_dDerivative = oDlg.m_dDerivative;
		m_dTimeInit = oDlg.m_dTimeInit;
		m_dTimeFinal = oDlg.m_dTimeFinal;
		m_dValueInit = oDlg.m_dValueInit;

		// Print msg with variable value.
		sMsg.Format("\n CLinearFnBlock::BlockDlgWndParameterInput(), m_dDerivative = %lf\n", m_dDerivative);
		//AfxMessageBox(sMsg, nType, nIDhelp);
	}	
}

void COutputBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class COutputBlockDialog : public CDialog
//	COutputBlockDialog oDlg;	
	COutputBlockDialog oDlg(this);	

	// Set the dialog class vars using the block class vars
	oDlg.m_iNotation = m_iNotation;
	oDlg.m_iTimePtDisplay = m_iTimePtDisplay;

	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign COutputBlockDialog variable values to COutputBlock variable values.
		m_iNotation = oDlg.m_iNotation;
		m_iTimePtDisplay = oDlg.m_iTimePtDisplay;

		// Print msg with variable value.
		sMsg.Format("\n COutputBlock::BlockDlgWndParameterInput(), m_iNotation = %d\n", m_iNotation);
		//AfxMessageBox(sMsg, nType, nIDhelp);

		// Update the view, since changing the notation type changes the numbers on the graph.
		CDiagramEngDoc *pDoc = GetDocumentGlobalFn();
		pDoc->SetModifiedFlag(TRUE); 	// set the doc. as having been modified to prompt user to save
		pDoc->UpdateAllViews(NULL); 	// indicate that sys. should redraw.
	}	
}

void CSignalGeneratorBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CSignalGeneratorBlockDialog : public CDialog
	CSignalGeneratorBlockDialog oDlg;	

	// Set the dialog class vars using the block class vars
	oDlg.m_strFnType = m_strFnType;
	oDlg.m_dAmplitude = m_dAmplitude;
	oDlg.m_dFrequency = m_dFrequency;
	oDlg.m_dPhase = m_dPhase;
	oDlg.m_strUnits = m_strUnits;

	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign CSignalGeneratorBlockDialog variable values to CSignalGeneratorBlock variable values.
		m_strFnType = oDlg.m_strFnType;
		m_dAmplitude = oDlg.m_dAmplitude;
		m_dFrequency = oDlg.m_dFrequency;
		m_dPhase = oDlg.m_dPhase;
		m_strUnits = oDlg.m_strUnits;

		// Print msg with variable value.
		sMsg.Format("\n CSignalGeneratorBlock::BlockDlgWndParameterInput(), m_strFnType = %s\n", m_strFnType);
		//AfxMessageBox(sMsg, nType, nIDhelp);
	}	
}

void CSubsystemBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CSubsystemBlockDialog : public CDialog
	CSubsystemBlockDialog oDlg;	
	
	// Set the dialog class vars using the block class vars
	oDlg.m_strInputPortName = m_strInputPortName;
	oDlg.m_strOutputPortName = m_strOutputPortName;

	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign CSubsystemBlockDialog variable values to CSubsystemBlock variable values.
		m_strInputPortName = oDlg.m_strInputPortName;
		m_strOutputPortName = oDlg.m_strOutputPortName;

		// Print msg with variable value.
		sMsg.Format("\n CSubsystemBlock::BlockDlgWndParameterInput(), ports: %s, %s\n", m_strInputPortName, m_strOutputPortName);
		//AfxMessageBox(sMsg, nType, nIDhelp);
	}	
}

void CSubsystemInBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CSubsystemInBlockDialog : public CDialog
	CSubsystemInBlockDialog oDlg;	

	// Set the dialog class var using the block class var
	oDlg.m_strInputPortName = m_strInputPortName;

	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign CSubsystemInBlockDialog variable values to CSubsystemInBlock variable values.
		m_strInputPortName = oDlg.m_strInputPortName;

		// Print msg with variable value.
		sMsg.Format("\n CSubsystemInBlock::BlockDlgWndParameterInput(), port: %s\n", m_strInputPortName);
		//AfxMessageBox(sMsg, nType, nIDhelp);
	}	
}

void CSubsystemOutBlock::BlockDlgWndParameterInput()
{
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CSubsystemOutBlockDialog : public CDialog
	CSubsystemOutBlockDialog oDlg;	

	// Set the dialog class var using the block class var
	oDlg.m_strOutputPortName = m_strOutputPortName;

	// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
	if(oDlg.DoModal() == IDOK) 
	{	
		// Assign CSubsystemOutBlockDialog variable values to CSubsystemOutBlock variable values.
		m_strOutputPortName = oDlg.m_strOutputPortName;

		// Print msg with variable value.
		sMsg.Format("\n CSubsystemOutBlock::BlockDlgWndParameterInput(), port: %s\n", m_strOutputPortName);
		//AfxMessageBox(sMsg, nType, nIDhelp);
	}	
}

void CSumBlock::BlockDlgWndParameterInput()
{
	int n_inputs = 0;		// number of input ports	
	CString	sMsg;			// string to be displayed
	CString sMsgTemp;		// temp string msg.
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	// Create a dialog object. of class CSumBlockDialog : public CDialog
	CSumBlockDialog oDlg;	

	// Update the sign count since a port may have been deleted
	UpdateSignCount();

	// Set the dialog class var using the block class var
	oDlg.m_iNAddInputs = m_iNAddInputs;
	oDlg.m_iNSubtractInputs = m_iNSubtractInputs;

	// While less than two input ports get user input
	while(n_inputs < 2)
	{
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK) 
		{	
			// Assign CSumBlockDialog variable values to CSumBlock variable values.
			m_iNAddInputs = oDlg.m_iNAddInputs;
			m_iNSubtractInputs = oDlg.m_iNSubtractInputs;

			// Print msg with variable value.
			//sMsg.Format("\n CSumBlock::BlockDlgWndParameterInput(), m_iNAddInputs = %d, m_iNSubractInputs = %d\n", m_iNAddInputs, m_iNSubtractInputs);
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}
		
		// Check input for correctness and warn user if approp.
		n_inputs = m_iNAddInputs + m_iNSubtractInputs;
		
		if(n_inputs < 2)
		{
			sMsgTemp.Format("\n CSumBlock::BlockDlgWndParameterInput()\n");
			sMsg += sMsgTemp;
			sMsgTemp.Format(" No. of input ports = %d\n", n_inputs);
			sMsg += sMsgTemp;
			sMsgTemp.Format(" Two or more input ports are required!\n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
		}
	}

	// Reset ports
	ResetInputPorts(m_iNAddInputs, m_iNSubtractInputs);
	ResetOutputPorts();
}

void CTransferFnBlock::BlockDlgWndParameterInput()
{
	int input = 0;		// input: (0) incomplete, (1) complete
	CString	sMsg;		// string msg. to be displayed
	CString sMsgTemp;	// temp string msg.
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	// Create a dialog object. of class CTransferFnBlockDialog : public CDialog
	CTransferFnBlockDialog oDlg;	

	// Set the dialog class vars using the block class vars
	oDlg.m_strNumerCoeffs = m_strNumerCoeffs;
	oDlg.m_strDenomCoeffs = m_strDenomCoeffs;

	// While input not correct
	while(input == 0)
	{
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK) 
		{	
			// Assign CTransferFnBlockDialog variable values to CTransferFnBlock variable values.
			m_strNumerCoeffs = oDlg.m_strNumerCoeffs;
			m_strDenomCoeffs = oDlg.m_strDenomCoeffs;

			// Print msg with variable value.
			//sMsg.Format("\n CTransferFnBlock::BlockDlgWndParameterInput(), m_strNumerCoeffs = %s, m_strDenomCoeffs = %s\n", m_strNumerCoeffs, m_strDenomCoeffs);
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}

		// DELETE POSSIBLY EXISTING VECTORS
		// Delete the coeff vectors whose memory was allocated in ConvertStringToDoubleVector()
		if(m_dNumerVector != NULL)
		{
			delete [] m_dNumerVector;
		}

		if(m_dDenomVector != NULL)
		{
			delete [] m_dDenomVector;
		}

		// Convert the input strings into double vectors
		m_dNumerVector = ConvertStringToDoubleVector(m_strNumerCoeffs, m_iLengthNumer);
		//PrintVector(m_dNumerVector, m_iLengthNumer);

		m_dDenomVector = ConvertStringToDoubleVector(m_strDenomCoeffs, m_iLengthDenom);
		//PrintVector(m_dDenomVector, m_iLengthDenom);

		// Check validity of input
		if(m_dNumerVector == NULL || m_dDenomVector == NULL)
		{
			sMsgTemp.Format("\n WARNING!: Incorrect coefficient vector input.  \n");
			sMsg += sMsgTemp;

			if(m_dNumerVector == NULL)
			{
				sMsgTemp.Format("\n Please enter correct numerator coefficient vector data.  \n");
				sMsg += sMsgTemp;
			}
			if(m_dDenomVector == NULL)
			{
				sMsgTemp.Format("\n Please enter correct denominator coefficient vector data.  \n");
				sMsg += sMsgTemp;
			}

			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
		}
		else
		{
			input = 1;
		}
	}
}

void CDivideBlock::ResetInputPorts(int n_mult_ports, int n_divide_ports)
{
	int i = 0;
	int cnt_mults = 0;						// no. of mult ports present in the vector
	int cnt_divides = 0;					// no. of divide ports present in the vector
	int	connected = 0;						// flag indicating a connection "connected" to a port
	int delete_ports = 1;					// flag to control port deletion
	int n_inputs;							// total number of input ports for the Divide block.
	CString	sMsg;							// string to be displayed
	UINT nType = MB_OK;						// style of msg. box
	UINT nIDhelp = 0;						// help context ID for the msg.
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;		// iterator for vector of CPort ptrs.

	// Get connection list
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();
	list<CConnection*> &con_list = GetParentSystemModel()->GetConnectionList();

	// Get vec of input ports
	vector<CPort*> &vec_input_ports = GetVectorOfInputPorts();	// vector of input ports

	// -- ERASE INPUT PORTS FROM VEC THAT DO NOT HAVE CONNECTIONS ATTACHED
	it_port = vec_input_ports.begin();
	while(it_port != vec_input_ports.end())
	{
		// Reset connectivity flag to "not connected"
		connected = 0;

		// Iterate through connection list
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
		{
			// If a connection is attached to this port
			if((*it_con)->GetRefToPort() == *it_port)
			{
				(*it_port)->SetPortArrowDirection(e_right_arrow);
				connected = 1;
			} 
		}

		// If there are no connections to this port
		if(connected == 0)
		{
			// Delete the port
			delete *it_port;							// delete port pointed to by it_port
			it_port = vec_input_ports.erase(it_port);	// delete element at offset it_port and return the loc of the next item
		}
		else
		{
			it_port++;
		}
		
	}// end while it_port


	// -- GET THE NO. OF MULT AND DIVIDE PORTS (with connections attached) REMAINING IN THE DEPLETED LIST
	for(it_port = vec_input_ports.begin(); it_port != vec_input_ports.end(); it_port++)
	{
		if((*it_port)->GetPortName() == "*")
		{
			cnt_mults++;
		}
		if((*it_port)->GetPortName() == "/")
		{
			cnt_divides++;
		}
	}

	// Simple msg.
	sMsg.Format("\n CDivideBlock::ResetInputPorts(), n_mult_ports = %d, cnt_mults = %d, n_divide_ports = %d, cnt_divides = %d\n", n_mult_ports, cnt_mults, n_divide_ports, cnt_divides);
	//AfxMessageBox(sMsg, nType, nIDhelp);


	// -- ADD OR DELETE THE DIFFERENCE IN THE NO. OF MULT PORTS
	if(n_mult_ports > cnt_mults)
	{
		for(i=0; i<(n_mult_ports - cnt_mults); i++)
		{
			CPort *p_input_port = new CPort(*this);
			p_input_port->SetPortName("*");						// "*" sign assoc. with mult input port		
			p_input_port->SetPortArrowDirection(e_right_arrow);	// input ports point to the right
			vec_input_ports.push_back(p_input_port);			// add port to the end of the vector		
		}
	}
	else if(n_mult_ports < cnt_mults)
	{
		// -- DISCONNECT CONNECTIONS AND DELETE MULT PORTS
		it_port = vec_input_ports.begin();
		while((delete_ports == 1) && (it_port != vec_input_ports.end()))
		{
			if((*it_port)->GetPortName() == "*")
			{			
				// Disconnect the connection object from the port
				pDoc->DisconnectEndPointFromPort(*it_port);
			
				// Delete port
				delete *it_port;								// delete actual port pointed to by it_port
				it_port = vec_input_ports.erase(it_port); 		// delete element at offset it_port in vec (that held the port)

				cnt_mults--;
			}
			else
			{
				it_port++;
			}

			if(n_mult_ports == cnt_mults)
			{
				delete_ports = 0;
			}	
		}// end while
	}


	// -- ADD OR DELETE THE DIFFERENCE IN THE NO. OF DIVIDE PORTS
	if(n_divide_ports > cnt_divides)
	{
		for(i=0; i<(n_divide_ports - cnt_divides); i++)
		{
			CPort *p_input_port = new CPort(*this);
			p_input_port->SetPortName("/");						// "/" sign assoc. with divide input port		
			p_input_port->SetPortArrowDirection(e_right_arrow);	// input ports point to the right
			vec_input_ports.push_back(p_input_port);			// add port to the end of the vector		
		}
	}
	else if(n_divide_ports < cnt_divides)
	{
		// -- DISCONNECT CONNECTIONS AND DELETE DIVIDE PORTS
		delete_ports = 1;
		it_port = vec_input_ports.begin();
		while((delete_ports == 1) && (it_port != vec_input_ports.end()))
		{
			if((*it_port)->GetPortName() == "/")
			{			
				// Disconnect the connection object from the port
				pDoc->DisconnectEndPointFromPort(*it_port);
			
				// Delete port
				delete *it_port;							// delete actual port pointed to by it_port
				it_port = vec_input_ports.erase(it_port); 	// delete element at offset it_port in vec (that held the port)

				cnt_divides--;
			}
			else	// only increment the iterator if there were no deletion
			{
				it_port++;
			}

			if(n_divide_ports == cnt_divides)
			{
				delete_ports = 0;
			}	
		}// end while
	}	

	// Simple msg.
	sMsg.Format("\n CDivideBlock::ResetInputPorts(), vec_input_ports.size() = %d\n", vec_input_ports.size());
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Calculate the port position angles to locate the ports on the left side of the Divide block.
	n_inputs =  n_mult_ports + n_divide_ports;
	CalculatePortPositionAngles(n_inputs);

	// Set flags and redraw the doc
	pDoc->SetModifiedFlag(TRUE); 		// set the doc. as having been modified to prompt user to save
	pDoc->UpdateAllViews(NULL); 		// indicate that sys. should redraw.
}

void CDivideBlock::CalculatePortPositionAngles(int n_inputs)
{
	int i = 0;				// used to set the no. of distance increments (dist) from top of block
	double dist;			// dist from the top of the block
	double b;				// dist from middle of block (local y=0) to port (up is > 0, down is < 0 )
	double height;			// height of block
	double pi = PI;			// pi rounded.
	double alpha;			// angle in radians
	double theta;			// angle in radians
	double width;			// width of block
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
	vector<CPort*>::iterator it_port;		// iterator for vector of CPort ptrs.
	
	// Init paras
	height = GetBlockShape().GetBlockHeight();
	width = GetBlockShape().GetBlockWidth();
	dist = height/(n_inputs + 1);

	// Simple msg.
	//sMsg.Format("\n CDivideBlock::CalculatePortPositionAngles(), height = %lf, width = %lf, dist = %lf\n", height, width, dist);
	//AfxMessageBox(sMsg, nType, nIDhelp);
	
	// Get vec of input ports
	vector<CPort*> &vec_input_ports = GetVectorOfInputPorts();	// vector of input ports

	// Loop through the vector and set the port position angle
	for(it_port = vec_input_ports.begin(); it_port != vec_input_ports.end(); it_port++)
	{
		b = height/2 - (i+1)*dist;									// b = top of block - a multiple of dist
		alpha = atan(2.0*b/width);									// tan(theta) = b/(w/2) = opp./adj.
		theta = pi - alpha;											// theta w.r.t. block coord. sys.
		theta = theta*180.0/pi;										// convert from radians into degrees
		(*it_port)->SetPortPositionAngle(theta);					// set the port position angle
		(*it_port)->CalculatePortPosition();						// calculate port posn based on prev. angle.
		GetParentSystemModel()->UpdateConnectionPointHead(*it_port);// deref the iterator to get the ptr-to-CPort obj.
		i++;														// incr the multiplier of the no. of dists
	}
}

void CSumBlock::ResetInputPorts(int n_add_ports, int n_subtract_ports)
{
	int i = 0;
	int cnt_adds = 0;		// no. of add ports present in the vector
	int cnt_subtracts = 0;	// no. of subtract ports present in the vector
	int	connected = 0;		// flag indicating a connection "connected" to a port
	int delete_ports = 1;	// flag to control port deletion
	int n_inputs;			// total number of input ports for the Sum block.
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;		// iterator for vector of CPort ptrs.

	// Get connection list
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();
	list<CConnection*> &con_list = GetParentSystemModel()->GetConnectionList();

	// Get vec of input ports
	vector<CPort*> &vec_input_ports = GetVectorOfInputPorts();	// vector of input ports

	// -- ERASE INPUT PORTS FROM VEC THAT DO NOT HAVE CONNECTIONS ATTACHED
	it_port = vec_input_ports.begin();
	while(it_port != vec_input_ports.end())
	{
		// Reset connectivity flag to "not connected"
		connected = 0;

		// Iterate through connection list
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
		{
			// If a connection is attached to this port
			if((*it_con)->GetRefToPort() == *it_port)
			{
				(*it_port)->SetPortArrowDirection(e_right_arrow);
				connected = 1;
			} 
		}

		// If there are no connections to this port
		if(connected == 0)
		{
			// Delete the port
			delete *it_port;							// delete port pointed to by it_port
			it_port = vec_input_ports.erase(it_port);	// delete element at offset it_port and return the loc of the next item
		}
		else
		{
			it_port++;
		}
		
	}// end while it_port


	// -- GET THE NO. OF ADD AND SUBTRACT PORTS (with connections attached) REMAINING IN THE DEPLETED LIST
	for(it_port = vec_input_ports.begin(); it_port != vec_input_ports.end(); it_port++)
	{
		if((*it_port)->GetPortName() == "+")
		{
			cnt_adds++;
		}
		if((*it_port)->GetPortName() == "-")
		{
			cnt_subtracts++;
		}
	}

	// Simple msg.
	sMsg.Format("\n CSumBlock::ResetInputPorts(), n_add_ports = %d, cnt_adds = %d, n_subtract_ports = %d, cnt_subtracts = %d\n", n_add_ports, cnt_adds, n_subtract_ports, cnt_subtracts);
	//AfxMessageBox(sMsg, nType, nIDhelp);


	// -- ADD OR DELETE THE DIFFERENCE IN THE NO. OF ADD PORTS
	if(n_add_ports > cnt_adds)
	{
		for(i=0; i<(n_add_ports - cnt_adds); i++)
		{
			CPort *p_input_port = new CPort(*this);
			p_input_port->SetPortName("+");						// "*" sign assoc. with add input port		
			vec_input_ports.push_back(p_input_port);			// add port to the end of the vector		
		}
	}
	else if(n_add_ports < cnt_adds)
	{
		// -- DISCONNECT CONNECTIONS AND DELETE ADD PORTS
		it_port = vec_input_ports.begin();
		while((delete_ports == 1) && (it_port != vec_input_ports.end()))
		{
			if((*it_port)->GetPortName() == "+")
			{			
				// Disconnect the connection object from the port
				pDoc->DisconnectEndPointFromPort(*it_port);
			
				// Delete port
				delete *it_port;								// delete actual port pointed to by it_port
				it_port = vec_input_ports.erase(it_port); 		// delete element at offset it_port in vec (that held the port)

				cnt_adds--;
			}
			else
			{
				it_port++;
			}

			if(n_add_ports == cnt_adds)
			{
				delete_ports = 0;
			}	
		}// end while
	}


	// -- ADD OR DELETE THE DIFFERENCE IN THE NO. OF SUBTRACT PORTS
	if(n_subtract_ports > cnt_subtracts)
	{
		for(i=0; i<(n_subtract_ports - cnt_subtracts); i++)
		{
			CPort *p_input_port = new CPort(*this);
			p_input_port->SetPortName("-");						// "-" sign assoc. with subtract input port		
			vec_input_ports.push_back(p_input_port);			// add port to the end of the vector		
		}
	}
	else if(n_subtract_ports < cnt_subtracts)
	{
		// -- DISCONNECT CONNECTIONS AND DELETE SUBTRACT PORTS
		delete_ports = 1;
		it_port = vec_input_ports.begin();
		while((delete_ports == 1) && (it_port != vec_input_ports.end()))
		{
			if((*it_port)->GetPortName() == "-")
			{			
				// Disconnect the connection object from the port
				pDoc->DisconnectEndPointFromPort(*it_port);
			
				// Delete port
				delete *it_port;							// delete actual port pointed to by it_port
				it_port = vec_input_ports.erase(it_port); 	// delete element at offset it_port in vec (that held the port)

				cnt_subtracts--;
			}
			else	// only increment the iterator if there were no deletion
			{
				it_port++;
			}

			if(n_subtract_ports == cnt_subtracts)
			{
				delete_ports = 0;
			}	
		}// end while
	}	

	// Simple msg.
	sMsg.Format("\n CSumBlock::ResetInputPorts(), vec_input_ports.size() = %d\n", vec_input_ports.size());
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Calculate the port position angles to locate the ports on the left hemicircle of the Sum block.
	n_inputs =  n_add_ports + n_subtract_ports;
	CalculatePortPositionAngles(n_inputs);

	// Set flags and redraw the doc
	pDoc->SetModifiedFlag(TRUE); 		// set the doc. as having been modified to prompt user to save
	pDoc->UpdateAllViews (NULL); 		// indicate that sys. should redraw.
}

void CSumBlock::CalculatePortPositionAngles(int n_inputs)
{
	int i = 0;				// used to set the no. of arc spacing increments
	double arc_spacing;		// angular spacing bw. ports
	double eps = 10.0;		// angular epsilon
	double pi = PI;			// pi rounded.
	double theta;			// angle in radians
	CString	sMsg;			// string to be displayed
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.

	// Get vec of input ports
	vector<CPort*> &vec_input_ports = GetVectorOfInputPorts();	// vector of input ports


	// -- CHECK THE NUMBER OF INPUT PORTS AND EITHER POSITION EXPLICITLY OR AUTOMATICALLY.

	// If no. of input ports <= 3, then place ports manually.
	if(n_inputs <= 3)
	{
		i = 1;
		for(it_port = vec_input_ports.begin(); it_port != vec_input_ports.end(); it_port++)
		{
			if(i == 1)
			{
				(*it_port)->SetPortArrowDirection(e_right_arrow);	// input ports point to the right
				(*it_port)->SetPortPositionAngle((i+1)*90);
			}
			else if(i == 2)
			{
				(*it_port)->SetPortArrowDirection(e_up_arrow);		// input ports point to the right
				(*it_port)->SetPortPositionAngle((i+1)*90);
			}			
			else if(i == 3)
			{
				(*it_port)->SetPortArrowDirection(e_down_arrow);	// input ports point to the right
				(*it_port)->SetPortPositionAngle(90);
			}
			(*it_port)->CalculatePortPosition();
			GetParentSystemModel()->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.

			i++;
		}// end for
	}// end if

	// If no. of input ports > 3, then place ports automatically.
	if(n_inputs > 3)
	{
		i = 0;
		arc_spacing = 180.0/(n_inputs - 1);	// angular arc spacing bw ports within 180 semicircle.

		// Simple msg.
		sMsg.Format("\n CSumBlock::CalculatePortPositionAngles(), arc_spacing = %lf\n", arc_spacing);
		//AfxMessageBox(sMsg, nType, nIDhelp);

		for(it_port = vec_input_ports.begin(); it_port != vec_input_ports.end(); it_port++)
		{
			// Get port position angle
			theta = 90.0 + i*arc_spacing;
			(*it_port)->SetPortPositionAngle(theta);
			(*it_port)->SetPortArrowDirection(e_right_arrow);

			// Manually set the arrow direction if close to the vertical
			if(fabs(theta - 90.0) < eps)
			{
				(*it_port)->SetPortArrowDirection(e_down_arrow);
			}
			if(fabs(theta - 270.0) < eps)
			{
				(*it_port)->SetPortArrowDirection(e_up_arrow);
			}
			
			// Calculate the new port position and snap any connections to port
			(*it_port)->CalculatePortPosition();
			GetParentSystemModel()->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.

			// Increment mult. of arc_spacing.
			i++;
		}// end for
	}// end if
}

int CBlock::CheckPortConnection(CPort *port)
{
	// Input: ptr-to-CPort, i.e. the address of the port.
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.

	// Get the connection list
	list<CConnection*> &con_list = GetParentSystemModel()->GetConnectionList();

	// Iterate through the list of connections and check connectivity.
	for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
	{
		// Check whether a connection object is attached to the input port.
		if((*it_con)->GetRefToPort() == port)
		{
			return 1;
		} 

		// Check whether a connection object is attached to the output port.
		if((*it_con)->GetRefFromPort() == port)
		{
			return 1;
		}
	}

	return 0;
}

void CPort::DrawPortSign(CDC *pDC)
{
	int	bounding_rect = 0;		// bounding rectangle around the port sign
	int pen_color;				// local pen color
	int pen_width;				// local pen width
	double blk_width;			// block width
	double sign_width;			// sign squre ('block') width
	double scale = 0.85;		// scaling constant
	CPoint blk_posn;			// position of the block upon which the port and port sign reside
	CPoint pt[4];				// pt array holding pts to draw sign graphic
	CPoint sign_posn;			// position of the center of the box within which the sign is placed
	CString port_name;			// name of port, i.e. the sign to be placed next to the port
	
	// Get block and sign properties
	blk_width = m_rRefToBlock.GetBlockShape().GetBlockWidth();
	sign_width = 0.1*blk_width; 
	

	// -- GET SIGN POSITION, i.e. center of square that holds the sign icon
	sign_posn = CalculatePortSignPosition(scale);


	// -- PREPARE PEN FOR DRAWING THE SIGN GRPHIC 
	pen_color = RGB(0,0,0);				// White = RGB(255,255,255), Black = RGB(0,0,0)
	pen_width = 1;

	// Create the pen
	CPen lpen(PS_SOLID, pen_width, pen_color);

	// Select the pen as the drawing obj. 
	// The value returned by SelectObject() is a ptr to the obj. being replaced, i.e. an old-pen-ptr.
	CPen *pOldPen = pDC->SelectObject(&lpen);

	
	// -- SET SIGN COORDS BASED UPON PORT NAME, I.E. PORT SIGN: '*', '/', '+', '-', or '_'
	port_name = GetPortName();

	if(port_name == "_")	// underscore not minus
	{
		// No sign to be drawn
		bounding_rect = 0;
	}
	else if(port_name == "*")
	{
		// Set coords of multiplication sign 'x'
		pt[0].x = sign_posn.x - 0.3*sign_width;
		pt[0].y = sign_posn.y - 0.3*sign_width;
		pt[1].x = sign_posn.x + 0.3*sign_width;
		pt[1].y = sign_posn.y + 0.3*sign_width;

		pt[2].x = pt[0].x;
		pt[2].y = pt[1].y;
		pt[3].x = pt[1].x;
		pt[3].y = pt[0].y;

		// Draw the sign
		pDC->MoveTo(pt[0]);
		pDC->LineTo(pt[1]);
		pDC->MoveTo(pt[2]);
		pDC->LineTo(pt[3]);

		// Redraw in reverse direction to make sign perfect.
		pDC->MoveTo(pt[1]);
		pDC->LineTo(pt[0]);
		pDC->MoveTo(pt[3]);
		pDC->LineTo(pt[2]);

		bounding_rect = 0;
	}
	else if(port_name == "/")
	{
		// Set coords of divide sign '/'
		pt[0].x = sign_posn.x - 0.3*sign_width;
		pt[0].y = sign_posn.y + 0.3*sign_width;
		pt[1].x = sign_posn.x + 0.3*sign_width;
		pt[1].y = sign_posn.y - 0.3*sign_width;

		// Draw the sign
		pDC->MoveTo(pt[0]);
		pDC->LineTo(pt[1]);

		// Redraw in reverse direction.
		pDC->MoveTo(pt[1]);
		pDC->LineTo(pt[0]);

		bounding_rect = 0;
	}
	else if(port_name == "+")
	{
		// Set coords of plus sign '+'
		pt[0].x = sign_posn.x;
		pt[0].y = sign_posn.y - 0.3*sign_width;
		pt[1].x = sign_posn.x;
		pt[1].y = sign_posn.y + 0.3*sign_width;

		pt[2].x = sign_posn.x - 0.3*sign_width;
		pt[2].y = sign_posn.y;
		pt[3].x = sign_posn.x + 0.3*sign_width;
		pt[3].y = sign_posn.y;

		// Draw the sign
		pDC->MoveTo(pt[0]);
		pDC->LineTo(pt[1]);
		pDC->MoveTo(pt[2]);
		pDC->LineTo(pt[3]);

		// Redraw in reverse direction
		pDC->MoveTo(pt[1]);
		pDC->LineTo(pt[0]);
		pDC->MoveTo(pt[3]);
		pDC->LineTo(pt[2]);

		bounding_rect = 0;
	}
	else if(port_name == "-")
	{
		// Set coords of minus sign '-'
		pt[0].x = sign_posn.x - 0.3*sign_width;
		pt[0].y = sign_posn.y;
		pt[1].x = sign_posn.x + 0.3*sign_width;
		pt[1].y = sign_posn.y;

		// Draw the sign
		pDC->MoveTo(pt[0]);
		pDC->LineTo(pt[1]);

		// Redraw in reverse direction
		pDC->MoveTo(pt[1]);
		pDC->LineTo(pt[0]);

		bounding_rect = 0;
	}
	
	// Draw a bounding rectangle
	if(bounding_rect)
	{
		// Set rectangle points
		pt[0].x = sign_posn.x - 0.3*sign_width;
		pt[0].y = sign_posn.y - 0.3*sign_width;
		pt[1].x = sign_posn.x + 0.3*sign_width;
		pt[1].y = sign_posn.y + 0.3*sign_width;

		pt[2].x = pt[0].x;
		pt[2].y = pt[1].y;
		pt[3].x = pt[1].x;
		pt[3].y = pt[0].y;

		// Draw bounding rectangle
		pDC->MoveTo(pt[0]);
		pDC->LineTo(pt[2]);
		pDC->LineTo(pt[1]);
		pDC->LineTo(pt[3]);
		pDC->LineTo(pt[0]);
	}

	// Reset the prev. pen
	pDC->SelectObject(pOldPen);
}

CPoint CPort::CalculatePortSignPosition(double scale)
{
	int count;			// no. of times 360 divides into m_dPortPositionAngle.
	double c;			// length of ray from triangle CM to port posn on bndy of triangle.
	double d;			// opp. side length of a subtriangle with hypotenuse h, and adjacent side length width/2.
	double eps = 0.0087;// epsilon value (radians) to allow setting of angle at 2*pi; (0.0087 radians = 0.5 degrees)
	double h;			// hypotenuse of a subtriangle with opp. side length d, and adjacent side length width/2.
	double height = m_rRefToBlock.GetBlockShape().GetBlockHeight();
	double pi = PI;
	double r;			// length of port sign posn vector.
	double theta;		// m_dPortPositionAngle coverted to an angle in radians.
	double theta_crit;	// critical theta value used to determine sign_posn.x and sign_posn.y
	double width = m_rRefToBlock.GetBlockShape().GetBlockWidth();
	CPoint blk_posn = m_rRefToBlock.GetBlockPosition();
	CPoint sign_posn;
	EBlockDirection e_blk_direc = m_rRefToBlock.GetBlockShape().GetBlockDirection();
	EBlockShape e_blk_shape = m_rRefToBlock.GetBlockShape().GetBlockShapeType();

	CString sMsg;		// main msg string
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	// Scale the width and height
	height = scale*height;
	width = scale*width;

	// Convert port position angle into domain [0,360]
	if(m_dPortPositionAngle > 360.00)
	{
		count = int(m_dPortPositionAngle/360.00);
		m_dPortPositionAngle = m_dPortPositionAngle - count*360.00;
	}
	if(m_dPortPositionAngle < 0.00)
	{
		count = int(fabs(m_dPortPositionAngle/360.00));
		m_dPortPositionAngle = m_dPortPositionAngle + (count + 1)*360.00;
	}

	// Convert port position angle from degrees into radians
	theta = m_dPortPositionAngle*pi/180.00;
	
	//sMsg.Format("\n CPort::CalculatePortSignPosition(), m_dPortPositionAngle = %lf, theta = %3.15lf, 2*pi+eps = %3.15lf\n", m_dPortPositionAngle, theta, 2*pi+eps);
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Switch upon shape
	switch(e_blk_shape)
	{
	case e_ellipse:	
		
		sign_posn.x = blk_posn.x + 0.5*width*cos(theta);
		sign_posn.y = blk_posn.y - 0.5*width*sin(theta);
		break;

	case e_rectangle:		// rectangle caters for squares (width = height) and rectangles (width != height)

		theta_crit = atan(height/width);	// atan2(y,x) = arctangent of y/x

		if((theta >= 0) && (theta <= theta_crit))
		{
			r = width/(2*cos(theta));
			sign_posn.x = blk_posn.x + width*0.5;
			//sign_posn.y = blk_posn.y - r*sin(theta);
			sign_posn.y = m_ptPortPosition.y;				
		}
		if( (theta > theta_crit) && (theta < (pi - theta_crit)) )
		{	
			r = height/(2*sin(theta));
			//sign_posn.x = blk_posn.x + r*cos(theta);
			sign_posn.x = m_ptPortPosition.x;
			sign_posn.y = blk_posn.y - height*0.5;
		}
		if((theta >= (pi - theta_crit)) && (theta <= (pi + theta_crit)))
		{
			r = -width/(2*cos(theta));
			sign_posn.x = blk_posn.x - width*0.5;
			//sign_posn.y = blk_posn.y - r*sin(theta);
			sign_posn.y = m_ptPortPosition.y;
		}
		if((theta > (pi + theta_crit)) && (theta < (2*pi - theta_crit)))
		{
			r = -height/(2*sin(theta));
			//sign_posn.x = blk_posn.x + r*cos(theta);
			sign_posn.x = m_ptPortPosition.x;
			sign_posn.y = blk_posn.y + height*0.5;
		}
		if( (theta >= (2*pi - theta_crit)) && (theta <= (2*pi + eps)) )
		{
			r = width/(2*cos(theta));
			sign_posn.x = blk_posn.x + width*0.5;
			//sign_posn.y = blk_posn.y - r*sin(theta);
			sign_posn.y = m_ptPortPosition.y;
		}

		break;

	case e_triangle:

		// Get lengths of subtriangle sides: hypotenuse h, opp. side length d., and base side length width/2.
		d = (width/2)*tan(pi/6);
		h = width/sqrt(3);

		if(e_blk_direc == e_right)		// triangle pointing to the right.
		{
			if((theta >= 0) && (theta < 2*pi/3)) 
			{
				c = h/(2*sin(5*pi/6 - theta));		// length of ray from CM to port sign posn near bndy of triangle.
				sign_posn.x = blk_posn.x + c*cos(theta);
				sign_posn.y = blk_posn.y - c*sin(theta);
			}
			if( (theta >= 2*pi/3) && (theta <= 4*pi/3))
			{
				sign_posn.x = blk_posn.x - d;
				//sign_posn.y = blk_posn.y - d*tan(pi - theta);
				sign_posn.y = m_ptPortPosition.y;
			}
			if( (theta > 4*pi/3) && (theta <= (2*pi + eps)))
			{
				c = h/(2*sin(theta - 7*pi/6));
				sign_posn.x = blk_posn.x + c*cos(theta);
				sign_posn.y = blk_posn.y - c*sin(theta);
			}
		}
		else if(e_blk_direc == e_left)	// triangle pointing to the left.
		{
			if((theta >= 0) && (theta <= pi/3)) 
			{
				sign_posn.x = blk_posn.x + d;
				//sign_posn.y = blk_posn.y - d*tan(theta);
				sign_posn.y = m_ptPortPosition.y;
			}
			if( (theta > pi/3) && (theta <= pi) )
			{
				c = h/(2*sin(theta - pi/6));			// length of ray from CM to port sign posn near bndy of triangle.
				sign_posn.x = blk_posn.x + c*cos(theta);
				sign_posn.y = blk_posn.y - c*sin(theta);
			}
			if((theta > pi) && (theta < 5*pi/3))
			{
				c = h/(2*sin(11*pi/6 - theta));
				sign_posn.x = blk_posn.x + c*cos(theta);
				sign_posn.y = blk_posn.y - c*sin(theta);
			}
			if((theta >= 5*pi/3) && (theta <= (2*pi + eps)))
			{
				sign_posn.x = blk_posn.x + d;
				//sign_posn.y = blk_posn.y + d*tan(2*pi - theta);
				sign_posn.y = m_ptPortPosition.y;
			}
		}
		else
		{
			// Print msg.
			//sMsg.Format("\n CPort::CalculatePortSignPosition()\n e_blk_direc for triangles should be e_left or e_right only!");
			//AfxMessageBox(sMsg, nType, nIDhelp);
		}
		break;

	default:
		// no code for now
		break;
	}// end switch

	// Set port sign position within CalculatePortSignPosition() to prevent an additional call.
	SetPortSignPosition(sign_posn);

	return sign_posn;
}

void CPort::SetPortSignPosition(CPoint sign_posn)
{
	m_ptPortSignPosition = sign_posn;
}

int CBlock::SetPortProperties(CPoint point)
{
	int port_flag = 0;		// flag indicating whether port properties were changed
	int	sign_flag = 0;		// flag to toggle the approp. sign-based dlg wnd controls
	double blk_width;		// block width
	double sign_width;		// port sign width
	CPoint sign_posn;		// port sign posn
	vector<CPort*>::iterator it_port; // vector iterator.
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();
	
	//AfxMessageBox("\n CBlock::SetPortProperties()\n", MB_OK, 0);

	// Port sign properties
	blk_width = GetBlockShape().GetBlockWidth();
	sign_width = 0.1*blk_width; 

	// -- ITERATE THROUGH VEC OF INPUT PORTS 
	for(it_port = m_vecInputPorts.begin(); it_port != m_vecInputPorts.end(); it_port++)
	{
		sign_posn = (*it_port)->GetPortSignPosition();
		
		// If the point is upon the current port sign
		if((abs(point.x - sign_posn.x) <= sign_width*0.5) && (abs(point.y - sign_posn.y) <= sign_width*0.5))
		{
			// Create the port properties dialog and populate the fields
			//CPortPropertiesDialog oDlg;	
			CPortPropertiesDialog oDlg(sign_flag);	
			oDlg.m_dPortPositionAngle = (*it_port)->GetPortPositionAngle();
			oDlg.m_iPortArrowDirection = (*it_port)->GetPortArrowDirection();

			// Set the port properties using dlg input.
			if(oDlg.DoModal() == IDOK)
			{
				(*it_port)->SetPortPositionAngle(oDlg.m_dPortPositionAngle);
				(*it_port)->CalculatePortPosition();
				(*it_port)->SetPortArrowDirection(EPortArrowDirection(oDlg.m_iPortArrowDirection));

				// Update any connection head end point associated with the port.
				m_pParentSystemModel->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
			}

			port_flag = 1;
			break;
		}
	}

	// -- ITERATE THROUGH VEC OF OUTPUT PORTS
	for(it_port = m_vecOutputPorts.begin(); it_port != m_vecOutputPorts.end(); it_port++)
	{
		sign_posn = (*it_port)->GetPortSignPosition();
		
		// If the point is upon the current port sign
		if((abs(point.x - sign_posn.x) <= sign_width*0.5) && (abs(point.y - sign_posn.y) <= sign_width*0.5))
		{
			// Create the port properties dialog and populate the fields
			//CPortPropertiesDialog oDlg;	
			CPortPropertiesDialog oDlg(sign_flag);	
			oDlg.m_dPortPositionAngle = (*it_port)->GetPortPositionAngle();
			oDlg.m_iPortArrowDirection = (*it_port)->GetPortArrowDirection();

			// Set the port properties using dlg input.
			if(oDlg.DoModal() == IDOK)
			{
				(*it_port)->SetPortPositionAngle(oDlg.m_dPortPositionAngle);
				(*it_port)->CalculatePortPosition();
				(*it_port)->SetPortArrowDirection(EPortArrowDirection(oDlg.m_iPortArrowDirection));

				// Update any connection tail end point associated with the port.
				m_pParentSystemModel->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
			}

			port_flag = 1;
			break;
		}
	}

	// Mark the document as changed
	pDoc->SetModifiedFlag(TRUE);	// prompt the user to save 
	pDoc->UpdateAllViews(NULL);		// this fn calls OnDraw to redraw the system model.

	return port_flag;
}

CPoint CPort::GetPortSignPosition() const
{
	return m_ptPortSignPosition;
}

int CDivideBlock::SetPortProperties(CPoint point)
{
	int port_flag = 0;		// flag indicating whether port properties were changed
	int	sign_flag = 1;		// flag to toggle the approp. sign-based dlg wnd controls
	double blk_width;		// block width
	double sign_width;		// port sign width
	CPoint sign_posn;		// port sign posn
	CString port_name;		// port name reflecting the sign type
	vector<CPort*>::iterator it_port; // vector iterator.
	vector<CPort*> &vec_of_input_ports = GetVectorOfInputPorts();	
	vector<CPort*> &vec_of_output_ports = GetVectorOfOutputPorts();
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();	

	//AfxMessageBox("\n CDivideBlock::SetPortProperties()\n", MB_OK, 0);

	// Port sign properties
	blk_width = GetBlockShape().GetBlockWidth();
	sign_width = 0.1*blk_width; 

	// -- ITERATE THROUGH VEC OF INPUT PORTS 
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		sign_posn = (*it_port)->GetPortSignPosition();
		
		// If the point is upon the current port sign
		if((abs(point.x - sign_posn.x) <= sign_width*0.5) && (abs(point.y - sign_posn.y) <= sign_width*0.5))
		{
			// Create the port properties dialog and populate the fields
			//CPortPropertiesDialog oDlg;	
			CPortPropertiesDialog oDlg(sign_flag);	
			oDlg.m_dPortPositionAngle = (*it_port)->GetPortPositionAngle();
			oDlg.m_iPortArrowDirection = (*it_port)->GetPortArrowDirection();
			port_name = (*it_port)->GetPortName();

			if(port_name == "*")
			{
				oDlg.m_iPortSignMultiplication = 0;
			}
			else
			{
				oDlg.m_iPortSignMultiplication = 1;
			}

			// Set the port properties using dlg input.
			if(oDlg.DoModal() == IDOK)
			{
				(*it_port)->SetPortPositionAngle(oDlg.m_dPortPositionAngle);
				(*it_port)->CalculatePortPosition();
				(*it_port)->SetPortArrowDirection(EPortArrowDirection(oDlg.m_iPortArrowDirection));

				if(oDlg.m_iPortSignMultiplication == 0)
				{
					(*it_port)->SetPortName("*");
				}
				else
				{
					(*it_port)->SetPortName("/");
				}
				UpdateSignCount();

				// Update any connection head end point associated with the port.
				GetParentSystemModel()->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
			}

			port_flag = 1;
			break;
		}
	}

	// -- ITERATE THROUGH VEC OF OUTPUT PORTS
	for(it_port = vec_of_output_ports.begin(); it_port != vec_of_output_ports.end(); it_port++)
	{
		sign_posn = (*it_port)->GetPortSignPosition();
		
		// If the point is upon the current port sign
		if((abs(point.x - sign_posn.x) <= sign_width*0.5) && (abs(point.y - sign_posn.y) <= sign_width*0.5))
		{
			// Create the port properties dialog and populate the fields
			//CPortPropertiesDialog oDlg;	
			CPortPropertiesDialog oDlg(sign_flag);	
			oDlg.m_dPortPositionAngle = (*it_port)->GetPortPositionAngle();
			oDlg.m_iPortArrowDirection = (*it_port)->GetPortArrowDirection();

			// DO NOT UPDATE PORT SIGN FOR OUTPUT PORT

			// Set the port properties using dlg input.
			if(oDlg.DoModal() == IDOK)
			{
				(*it_port)->SetPortPositionAngle(oDlg.m_dPortPositionAngle);
				(*it_port)->CalculatePortPosition();
				(*it_port)->SetPortArrowDirection(EPortArrowDirection(oDlg.m_iPortArrowDirection));

				// DO NOT SET PORT SIGN FOR OUTPUT PORT SINCE THEY HAVE NO SIGN ASSOCIATION

				// Update any connection tail end point associated with the port.
				GetParentSystemModel()->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
			}

			port_flag = 1;
			break;
		}
	}

	// Mark the document as changed
	pDoc->SetModifiedFlag(TRUE);	// prompt the user to save 
	pDoc->UpdateAllViews(NULL);		// this fn calls OnDraw to redraw the system model.

	return port_flag;
}

int CSumBlock::SetPortProperties(CPoint point)
{
	int port_flag = 0;		// flag indicating whether port properties were changed
	int	sign_flag = 2;		// flag to toggle the approp. sign-based dlg wnd controls
	double blk_width;		// block width
	double sign_width;		// port sign width
	CPoint sign_posn;		// port sign posn
	CString port_name;		// port name reflecting the sign type
	vector<CPort*>::iterator it_port; // vector iterator.
	vector<CPort*> &vec_of_input_ports = GetVectorOfInputPorts();	
	vector<CPort*> &vec_of_output_ports = GetVectorOfOutputPorts();
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();	
	
	//AfxMessageBox("\n CSumBlock::SetPortProperties()\n", MB_OK, 0);

	// Port sign properties
	blk_width = GetBlockShape().GetBlockWidth();
	sign_width = 0.1*blk_width; 

	// -- ITERATE THROUGH VEC OF INPUT PORTS 
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		sign_posn = (*it_port)->GetPortSignPosition();
		
		// If the point is upon the current port sign
		if((abs(point.x - sign_posn.x) <= sign_width*0.5) && (abs(point.y - sign_posn.y) <= sign_width*0.5))
		{
			// Create the port properties dialog and populate the fields
			//CPortPropertiesDialog oDlg;	
			CPortPropertiesDialog oDlg(sign_flag);	
			oDlg.m_dPortPositionAngle = (*it_port)->GetPortPositionAngle();
			oDlg.m_iPortArrowDirection = (*it_port)->GetPortArrowDirection();
			port_name = (*it_port)->GetPortName();

			if(port_name == "+")
			{
				oDlg.m_iPortSignAddition = 0;
			}
			else
			{
				oDlg.m_iPortSignAddition = 1;
			}

			// Set the port properties using dlg input.
			if(oDlg.DoModal() == IDOK)
			{
				(*it_port)->SetPortPositionAngle(oDlg.m_dPortPositionAngle);
				(*it_port)->CalculatePortPosition();
				(*it_port)->SetPortArrowDirection(EPortArrowDirection(oDlg.m_iPortArrowDirection));

				if(oDlg.m_iPortSignAddition == 0)
				{
					(*it_port)->SetPortName("+");
				}
				else
				{
					(*it_port)->SetPortName("-");
				}
				UpdateSignCount();

				// Update any connection head end point associated with the port.
				GetParentSystemModel()->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
			}

			port_flag = 1;
			break;
		}
	}

	// -- ITERATE THROUGH VEC OF OUTPUT PORTS
	for(it_port = vec_of_output_ports.begin(); it_port != vec_of_output_ports.end(); it_port++)
	{
		sign_posn = (*it_port)->GetPortSignPosition();
		
		// If the point is upon the current port sign
		if((abs(point.x - sign_posn.x) <= sign_width*0.5) && (abs(point.y - sign_posn.y) <= sign_width*0.5))
		{
			// Create the port properties dialog and populate the fields
			//CPortPropertiesDialog oDlg;	
			CPortPropertiesDialog oDlg(sign_flag);	
			oDlg.m_dPortPositionAngle = (*it_port)->GetPortPositionAngle();
			oDlg.m_iPortArrowDirection = (*it_port)->GetPortArrowDirection();

			// DO NOT UPDATE PORT SIGN FOR OUTPUT PORT

			// Set the port properties using dlg input.
			if(oDlg.DoModal() == IDOK)
			{
				(*it_port)->SetPortPositionAngle(oDlg.m_dPortPositionAngle);
				(*it_port)->CalculatePortPosition();
				(*it_port)->SetPortArrowDirection(EPortArrowDirection(oDlg.m_iPortArrowDirection));
			}

			// DO NOT SET PORT SIGN FOR OUTPUT PORT SINCE THEY HAVE NO SIGN ASSOCIATION

			// Update any connection tail end point associated with the port.
			GetParentSystemModel()->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.

			port_flag = 1;
			break;
		}
	}

	// Mark the document as changed
	pDoc->SetModifiedFlag(TRUE);	// prompt the user to save 
	pDoc->UpdateAllViews(NULL);		// this fn calls OnDraw to redraw the system model.

	return port_flag;
}

void CDivideBlock::UpdateSignCount()
{
	CString port_name;					// port name, i.e. port sign
	vector<CPort*>::iterator it_port;	// vector iterator.

	// Get vector of input and output ports
	vector<CPort*> &vec_of_input_ports = GetVectorOfInputPorts();	
	vector<CPort*> &vec_of_output_ports = GetVectorOfOutputPorts();

	// Reset member variables
	m_iNMultiplyInputs = 0;
	m_iNDivideInputs = 0;

	// -- ITERATE THROUGH INPUT PORTS
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		// Get port name, i.e. the port sign.
		port_name = (*it_port)->GetPortName();

		// Addjust the sign count
		if(port_name == "*")
		{
			m_iNMultiplyInputs++;
		}
		else if(port_name == "/")
		{
			m_iNDivideInputs++;
		}
	}

	// Do not iterate through output ports since they have no sign association!
}

void CSumBlock::UpdateSignCount()
{
	CString port_name;					// port name, i.e. port sign
	vector<CPort*>::iterator it_port;	// vector iterator.

	// Get vector of input and output ports
	vector<CPort*> &vec_of_input_ports = GetVectorOfInputPorts();	
	vector<CPort*> &vec_of_output_ports = GetVectorOfOutputPorts();

	// Reset member variables
	m_iNAddInputs = 0;
	m_iNSubtractInputs = 0;

	// -- ITERATE THROUGH INPUT PORTS
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		// Get port name, i.e. the port sign.
		port_name = (*it_port)->GetPortName();

		// Addjust the sign count
		if(port_name == "+")
		{
			m_iNAddInputs++;
		}
		else if(port_name == "-")
		{
			m_iNSubtractInputs++;
		}
	}

	// Do not iterate through output ports since they have no sign association!
}

void CBlock::ReverseBlockDirection()
{
	double theta;						// port position angle in degrees (not radians)
	vector<CPort*>::iterator it_port;	// iterator for ptr-to-CPort
	EBlockDirection e_blk_direc;		// block direc. (of local coord sys x-axis)
	EPortArrowDirection e_port_direc;	// port direc, i.e. direc in which arrow points.

	// -- CHANGE THE BLOCK'S DIRECTION
	e_blk_direc = GetBlockShape().GetBlockDirection();

	if(e_blk_direc == e_left)
	{
		GetBlockShape().SetBlockDirection(e_right);
	}
	else if(e_blk_direc == e_right)
	{
		GetBlockShape().SetBlockDirection(e_left);
	}

	// -- CHANGE BLOCK PORT DIRECTIONS AND POSITIONS
	// Input ports
	for(it_port = m_vecInputPorts.begin(); it_port != m_vecInputPorts.end(); it_port++)
	{
		// Change port arrow direction
		e_port_direc = (*it_port)->GetPortArrowDirection();
		if(e_port_direc == e_left_arrow)
		{
			(*it_port)->SetPortArrowDirection(e_right_arrow);	
		}
		else if(e_port_direc == e_right_arrow)
		{
			(*it_port)->SetPortArrowDirection(e_left_arrow);	
		}		

		// Change port position angle and recalculate position
		theta = (*it_port)->GetPortPositionAngle();
		theta = 180.0 - theta;
		(*it_port)->SetPortPositionAngle(theta);
		(*it_port)->CalculatePortPosition();

		// Update any connection head end point associated with the port.
		m_pParentSystemModel->UpdateConnectionPointHead(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
	}

	// Output ports
	for(it_port = m_vecOutputPorts.begin(); it_port != m_vecOutputPorts.end(); it_port++)
	{
		// Change port arrow direction
		e_port_direc = (*it_port)->GetPortArrowDirection();
		if(e_port_direc == e_left_arrow)
		{
			(*it_port)->SetPortArrowDirection(e_right_arrow);	
		}
		else if(e_port_direc == e_right_arrow)
		{
			(*it_port)->SetPortArrowDirection(e_left_arrow);	
		}	
		
		// Change port position angle and recalculate position
		theta = (*it_port)->GetPortPositionAngle();
		theta = 180.0 - theta;
		(*it_port)->SetPortPositionAngle(theta);
		(*it_port)->CalculatePortPosition();

		// Update any connection tail end point associated with the port.
		m_pParentSystemModel->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
	}
}

void CBlockShape::SetBlockDirection(EBlockDirection e_blk_direc)
{
	// Assign member variable.
	m_eBlockDirection = e_blk_direc;
}

void CDivideBlock::ResetOutputPorts()
{
	int size;				// size of vec of output ports
	CString sMsg;			// main msg string
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
	vector<CPort*>::iterator it_port; // iterator for vector of CPort ptrs.

	// Get the system model
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();		// get a ptr to the doc.
	
	// Get vec of output ports
	vector<CPort*> &vec_output_ports = GetVectorOfOutputPorts();	// vector of input ports
	size = vec_output_ports.size();

	// Msg. box
	//sMsg.Format("\n CDivideBlock::ResetOutputPorts(): size = %d\n", size);
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Check size not greater than one, since only one output port per block
	if(size > 1)
	{
		sMsg.Format("\n CDivideBlock::ResetOutputPorts(): WARNING! size = %d != 1\n", size);
		AfxMessageBox(sMsg, nType, nIDhelp);
	}

	// Reset angle, posn, and arrow direc of output port(s)
	for(it_port = vec_output_ports.begin(); it_port != vec_output_ports.end(); it_port++)
	{
		(*it_port)->SetPortPositionAngle(0.0);	
		(*it_port)->CalculatePortPosition();
		(*it_port)->SetPortArrowDirection(e_right_arrow);

		// Update any connection tail end point associated with the port.
		GetParentSystemModel()->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
	}

	// Set flags and redraw the doc
	pDoc->SetModifiedFlag(TRUE); 		// set the doc. as having been modified to prompt user to save
	pDoc->UpdateAllViews(NULL); 		// indicate that sys. should redraw.
}

void CSumBlock::ResetOutputPorts()
{
	int size;				// size of vec of output ports
	CString sMsg;			// main msg string
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
	vector<CPort*>::iterator it_port; // iterator for vector of CPort ptrs.

	// Get the system model
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();		// get a ptr to the doc.
	
	// Get vec of output ports
	vector<CPort*> &vec_output_ports = GetVectorOfOutputPorts();	// vector of input ports
	size = vec_output_ports.size();

	// Msg. box
	//sMsg.Format("\n CSumBlock::ResetOutputPorts(): size = %d\n", size);
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Check size not greater than one, since only one output port per block
	if(size > 1)
	{
		sMsg.Format("\n CSumBlock::ResetOutputPorts(): WARNING! size = %d != 1\n", size);
		AfxMessageBox(sMsg, nType, nIDhelp);
	}

	// Reset angle, posn, and arrow direc of output port(s)
	for(it_port = vec_output_ports.begin(); it_port != vec_output_ports.end(); it_port++)
	{
		(*it_port)->SetPortPositionAngle(0.0);	
		(*it_port)->CalculatePortPosition();
		(*it_port)->SetPortArrowDirection(e_right_arrow);

		// Update any connection tail end point associated with the port.
		GetParentSystemModel()->UpdateConnectionPointTail(*it_port);	// deref the iterator to get the ptr-to-CPort obj.
	}

	// Set flags and redraw the doc
	pDoc->SetModifiedFlag(TRUE); 		// set the doc. as having been modified to prompt user to save
	pDoc->UpdateAllViews(NULL); 		// indicate that sys. should redraw.
}

double *CIntegratorBlock::ConvertStringToDoubleVector(CString string, int &nrows, int &ncols)
{
	int i;
	double *ICVector = NULL;	// temporary initial condition vector
	double **matrix = NULL;		// matrix returned by ConvertStringToDouble()
	CString	sMsg;				// string to be displayed
	CString sMsgTemp;			// temp string
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.

	//sMsgTemp.Format("\n ConvertStringToDoubleVector()\n");
	//sMsg += sMsgTemp;
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// Convert the input string into a double matrix
	matrix = ConvertStringToDouble(string, nrows, ncols);

	// Check if matrix is NULL
	if(matrix == NULL)
	{
		return NULL;
	}

	// Assign the dimensions of the vector to the member vars.
	m_iNrows = nrows;
	m_iNcols = ncols;

	if(ncols >= nrows)
	{
		m_iLength = ncols;
	}
	else
	{
		m_iLength = nrows;
	}

	// Check the dimensions of the input matrix
	if(((nrows >= 1) && (ncols == 1)) || ((nrows == 1) && (ncols >= 1)))
	{
		// MEMORY ALLOCATION
		ICVector = new double[m_iLength];

		// Copy the double matrix into the initial condition vector
		if(ncols >= nrows)
		{
			for(i=0; i<ncols; i++)
			{
				ICVector[i] = matrix[0][i];	// zeroth row, m_iNcols
			}
		}
		else if(nrows >= ncols)
		{
			for(i=0; i<m_iNrows; i++)
			{
				ICVector[i] = matrix[i][0];	// m_iNrows, zeroth col.
			}
		}
	}
	else if((nrows == 0) && (ncols == 0))
	{
		sMsgTemp.Format("\n CIntegratorBlock::ConvertStringToDoubleVector()\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Size of initial condition vector is zero!\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Re-enter initial condition vector.\n");
		sMsg += sMsgTemp;
		AfxMessageBox(sMsg, nType, nIDhelp);

		// Assign NULL indicating that something is wrong
		ICVector = NULL;
	}
	else
	{
		sMsgTemp.Format("\n CIntegratorBlock::ConvertStringToDoubleVector()\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Dimensions of initial condition vector are that of a matrix!\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n nrows = %d, ncols = %d\n", nrows, ncols);
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Re-enter initial condition vector.\n");
		sMsg += sMsgTemp;
		AfxMessageBox(sMsg, nType, nIDhelp);

		// Assign NULL indicating that something is wrong
		ICVector = NULL;
	}

	// MEMORY DELETE
	// Delete the input data matrix whose memory was allocated in ConvertStringMatrixToDoubleMatrix()
	// Note: if matrix = NULL, then fn already returns NULL and hence memory not deleted as expected.
	for(i=0; i<m_iNrows; i++)
	{
		delete [] matrix[i];
	}
	delete [] matrix;

	return ICVector;
}

double *CTransferFnBlock::ConvertStringToDoubleVector(CString string, int &length)
{
	int i;
	int nrows = 0;				// no. of rows of data
	int ncols = 0;				// no. of cols of data
	double *coeff_vector = NULL;// temporary coefficient vector
	double **matrix = NULL;		// matrix returned by ConvertStringToDouble()
	CString	sMsg;				// string to be displayed
	CString sMsgTemp;			// temp string
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.

	// Convert the input string into a double matrix
	matrix = ConvertStringToDouble(string, nrows, ncols);

	// Check if matrix is NULL
	if(matrix == NULL)
	{
		return NULL;
	}

	// Assign the length of the vector to the member var.
	if(ncols >= nrows)
	{
		length = ncols;
	}
	else
	{
		length = nrows;
	}

	// Check the dimensions of the input matrix
	if(((nrows >= 1) && (ncols == 1)) || ((nrows == 1) && (ncols >= 1)))
	{
		// MEMORY ALLOCATION
		coeff_vector = new double[length];

		// Copy the double matrix into the vector of coefficients
		if(ncols >= nrows)
		{
			for(i=0; i<ncols; i++)
			{
				coeff_vector[i] = matrix[0][i];	// zeroth row, m_iNcols
			}
		}
		else if(nrows >= ncols)
		{
			for(i=0; i<nrows; i++)
			{
				coeff_vector[i] = matrix[i][0];	// m_iNrows, zeroth col.
			}
		}
	}
	else if((nrows == 0) && (ncols == 0))
	{
		sMsgTemp.Format("\n CTransferFnBlock::ConvertStringToDoubleVector()\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Size of coefficient vector is zero!\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Re-enter coefficient vector.\n");
		sMsg += sMsgTemp;
		AfxMessageBox(sMsg, nType, nIDhelp);

		// Assign NULL indicating that something is wrong
		coeff_vector = NULL;
	}
	else
	{
		sMsgTemp.Format("\n CTransferFnBlock::ConvertStringToDoubleVector()\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Dimensions of coefficient vector are that of a matrix!\n");
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n nrows = %d, ncols = %d\n", nrows, ncols);
		sMsg += sMsgTemp;
		sMsgTemp.Format("\n Re-enter coefficient vector.\n");
		sMsg += sMsgTemp;
		AfxMessageBox(sMsg, nType, nIDhelp);

		// Assign NULL indicating that something is wrong
		coeff_vector = NULL;
	}

	// MEMORY DELETE
	// Delete the input data matrix whose memory was allocated in ConvertStringMatrixToDoubleMatrix()
	// Note: if matrix = NULL, then fn already returns NULL and hence memory not deleted as expected.
	for(i=0; i<nrows; i++)
	{
		delete [] matrix[i];
	}
	delete [] matrix;

	return coeff_vector;
}

CBlock &CPort::GetRefToBlock()
{	
	return m_rRefToBlock;
}

int CBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	// This fn has been made virtual and is to be overridden by all derived CBlock classes.

	int valid = 1;		// (-1) operational error, (0) read/write error, (1) no error
	CString	sMsg;		// string to be displayed
	CString sMsgTemp;	// temp string msg.
	UINT nType = MB_OK;	// style of msg. box
	UINT nIDhelp = 0;	// help context ID for the msg.

	// Print msg.
	sMsgTemp.Format(" CBlock::OperateOnData().    \n\n");
	sMsg+=sMsgTemp;
	sMsgTemp.Format(" t_cnt = %d, t = %lf, delta_t = %lf.    \n", t_cnt, t, delta_t);
	sMsg+=sMsgTemp;
	AfxMessageBox(sMsg, nType, nIDhelp);

	return valid;
}

int CConstantBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int valid = 0;		// (-1) operational error, (0) read/write error, (1) no error

	// WRITE DATA TO OUTPUT SIGNAL
	valid = WriteDataToOutputSignal(m_dConstMatrix, m_iNrows, m_iNcols);
	
	return valid;
}

int COutputBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;	
	int j;	
	int ncols;					// no. of cols of input signal
	int nrows;					// no. of rows of input signal
	int n_TimeSteps;			// total no. of time steps in simulation
	int valid = 0;				// (-1) operational error, (0) read/write error, (1) no error
	double **matrix_in = NULL;	// input signal
	CString	sMsg;				// string to be displayed
	CString sMsgTemp;			// temp msg.
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.

	// Get the no. of time steps
	n_TimeSteps = GetParentSystemModel()->DetermineNTimeSteps();
	
	// -- GET INPUT SIGNAL DATA
	valid = ReadDataFromSingleInputSignal(matrix_in, &nrows, &ncols);
	if(valid == 0)
	{	
		return valid;	// Exit function since input invalid
	}

	// -- MEMORY NEW/DELETE
	if(t_cnt == 0)
	{
		// Delete m_dOutputMatrix if it already exists, i.e. non-NULL
		if(m_dOutputMatrix != NULL)
		{
			for(i=0; i<m_iNrows; i++)
			{
				delete [] m_dOutputMatrix[i];
			}
			delete [] m_dOutputMatrix;
		}
		
		// Allocate memory
		m_iNrows = nrows;
		m_iNcols = (n_TimeSteps + 1)*ncols;			// determine total no. of cols for data_record (t_cnt starts from 0)

		m_dOutputMatrix = new double *[m_iNrows];	// allocate an array of ptrs-to-double
		for(i=0; i<m_iNrows; i++)
		{
			m_dOutputMatrix[i] = new double[m_iNcols];
		}

		// Initialize matrix values to nullity.
		for(i=0; i<m_iNrows; i++)
		{
			for(j=0; j<m_iNcols; j++)
			{
				m_dOutputMatrix[i][j] = 0.0;
			}
		}
	}

	// -- ADD MATRIX INPUT SIGNAL DATA TO DATA RECORD
	for(i=0; i<nrows; i++)
	{
		for(j=0; j<ncols; j++)
		{
			m_dOutputMatrix[i][j + t_cnt*ncols] = matrix_in[i][j];	// offset cols by t_cnt multiples of ncols
		}
	}

	// -- PLOT/PRINT INPUT SIGNAL AS SIMULATION OUTPUT
	//sMsgTemp.Format("\n COutputBlock::OperateOnData()    \n");
	//sMsg+=sMsgTemp;
	//sMsgTemp.Format("\n t_cnt = %d, t = %lf\n", t_cnt, t);
	//sMsgTemp.Format("\n t_cnt = %d, t = %10.5lf\n", t_cnt, t);
	//sMsgTemp.Format("\n n_TimeSteps = %d, m_iNrows = %d\n", n_TimeSteps, m_iNrows);
	//sMsg+=sMsgTemp;	
	//AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box

	//PrintMatrix(matrix_in, nrows, ncols);
	//PrintMatrix(m_dOutputMatrix, m_iNrows, m_iNcols);

	// -- MEMORY DELETE
	// m_dOutputMatrix deleted above on t_cnt = 0, or in ~COutputBlock() destructor.

	return valid;
}

int CBlock::WriteDataToOutputSignal(double **matrix_out, int nrows, int ncols)
{
	int valid = 0;							// (-1) operational error, (0) read/write error, (1) no error
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;		// iterator for vector of CPort ptrs.
	vector<CPort*> vector_of_output_ports = GetVectorOfOutputPorts(); // vector of output ports

	// Get connection list
	list<CConnection*> &con_list = m_pParentSystemModel->GetConnectionList();	

	// -- WRITE OUTPUT DATA TO OUTPUT CONNECTION'S SIGNAL

	// Iterate over output ports
	for(it_port = vector_of_output_ports.begin(); it_port != vector_of_output_ports.end(); it_port++)	
	{
		// Iterate over list of connections
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// If connection attached to output port: either directly or INDIRECTLY through a bend point
			if((*it_con)->GetRefFromPort() == (*it_port))
			{
				// Set signal properties for this connection
				valid = 1;
				(*it_con)->GetSignal()->SetSignalData(matrix_out, nrows, ncols);
				(*it_con)->GetSignal()->SetSignalValidity(valid);

				// NOTE: "break" is not used here, after calling SetSignalData(), since more than one Connection object
				// may share the same ref-from-port. For example, a secondary connection emanating from a primary
				// connection's bend point, will share the same ref-from-port as the primary connection, and hence
				// it too should have the same signal data matrix: i.e. both connections share the same signal data.
			}
		}// end it_con

		if(valid)
		{
			break; // exit for it_port
		}
	}// end it_port
	
	return valid;
}

int CBlock::ReadDataFromSingleInputSignal(double **&matrix_in, int *nrows_in, int *ncols_in)
{
	// NOTE: The base address of the 2-dim array m_dSignalMatrix, obtained from GetSignalData() below,
	// is assigned to the var matrix_in (of the same double** type). But for the variable "matrix_in" in the calling
	// environment, i.e. the environment from which the current fn was called, to be assigned this address, it must be
	// passed by reference, resulting in the "matrix_in" variable in the current fn header, to be an alias (&) for the 
	// var in the calling environment. 
	//
	// Alternatively, using the call ReadDataFromSingleInputSignal(&matrix_in, &nrows, &ncols) from the calling environ,
	// would result in the prototype: ReadDataFromSingleInputSignal(double ***matrix_in, int *nrows_in, int *ncols_in). 
	// That is, a triple-ptr-to-double would be required, in the same way a single ptr is used for nrows_in and ncols_in, 
	// since the address of the 2-D array is being passed.

	int valid = 0;							// (-1) operational error, (0) read/write error, (1) no error
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;		// iterator for vector of CPort ptrs.
	vector<CPort*> vector_of_input_ports = GetVectorOfInputPorts();	// vector of input ports

	// Get connection list
	list<CConnection*> &con_list = m_pParentSystemModel->GetConnectionList();	

	// Iterate over ports
	for(it_port = vector_of_input_ports.begin(); it_port != vector_of_input_ports.end(); it_port++)	
	{
		// Iterate over connections
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// Find connection attached to input port
			if((*it_con)->GetRefToPort() == (*it_port))
			{
				valid = (*it_con)->GetSignal()->GetSignalValidity();
				
				if(valid == 0)
				{
					return valid;
				}
				else
				{
					matrix_in = (*it_con)->GetSignal()->GetSignalData(nrows_in, ncols_in);	// nrows_in, ncols_in are of type int*.
					break;	// only one input signal so exit "for it_con"
				}
			}
		}// end it_con

		if(valid)
		{
			break; // only one input port so exit "for it_port"
		}
	}// end it_port	

	return valid;
}

int CLinearFnBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;	
	int nrows = 1;					// nrows of matrix Y
	int ncols = 1;					// ncols of matrix Y
	int valid = 0;					// (-1) operational error, (0) read/write error, (1) no error
	double c;						// y intercept
	double m = m_dDerivative;		// gradient
	double t_init = m_dTimeInit;	// t_init
	double t_final = m_dTimeFinal; 	// t_final
	double y;						// y(t) = linear fn. val at time t.
	double y_init = m_dValueInit;	// y(t_init)
	double **Y_matrix = NULL;		// Y matrix to hold y(t) output value


	// -- MEMORY NEW
	Y_matrix = new double *[nrows];			// allocate an array of ptrs-to-double
	for(i=0; i<nrows; i++)
	{
		Y_matrix[i] = new double[ncols];	// allocate an array of doubles
	}
	
	// -- EVALUATE LINEAR FN SIGNAL
	c = y_init - m*t_init; 				// y intercept "c" for the equ. of a line, y = mt + c

	if(t < m_dTimeInit)					// before linear fn starts
	{
		y = y_init;
	}
	else if((t >= m_dTimeInit) && (t <= m_dTimeFinal))	// during linear fn
	{
		y = m*t + c;
	}
	else if(t > m_dTimeFinal)			// after linear fn ends
	{
		y = m*t_final + c;
	}

	Y_matrix[0][0] = y;					// assign linear fn signal to matrix


	// WRITE DATA TO OUTPUT SIGNAL
	valid = WriteDataToOutputSignal(Y_matrix, nrows, ncols);

	// -- MEMORY DELETE
	for(i=0; i<nrows; i++)
	{
		delete [] Y_matrix[i];	// delete the row arrays
	}
	delete [] Y_matrix;			// delete the array (column vector) holding the row arrays

	// Return connection signal status
	return valid;	
}

int CGainBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;
	int j;
	int nrows_del = 0;			// no. of rows to delete of matrix_out
	int nrows_in = 0;			// nrows of input signal
	int ncols_in = 0;			// ncols of input signal
	int valid = 0;				// (-1) operational error, (0) read/write error, (1) no error
	double c;					// input c as a scalar
	double k;					// Gain k as a scalar
	double **matrix_in = NULL;	// matrix data of input signal
	double **matrix_out = NULL;	// matrix data of output signal
	CString	sMsg;				// string to be displayed
	CString sMsgTemp;			// temp msg.
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.


	// -- GET INPUT SIGNAL DATA
	valid = ReadDataFromSingleInputSignal(matrix_in, &nrows_in, &ncols_in);
	if(valid == 0)
	{	
		return valid;	// Exit function since input invalid
	}
	else if(valid == 1)
	{
		valid = 0;	// Reset signal validity for output signal
	}	

	// -- PERFORM GAIN OPERATION: GAIN = SCALAR
	if((m_iNrows == 1) && (m_iNcols == 1))
	{
		k = m_dGainMatrix[0][0];					// gain constant as a scalar

		// -- MEMORY NEW
		matrix_out = new double *[nrows_in];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_in; i++)
		{
			matrix_out[i] = new double[ncols_in];	// allocate an array of doubles
		}	
		nrows_del = nrows_in;

		// OPERATE ON DATA
		for(i=0; i<nrows_in; i++)
		{
			for(j=0; j<ncols_in; j++)
			{
				matrix_out[i][j] = k*matrix_in[i][j];	
			}	
		}

		// WRITE DATA TO OUTPUT SIGNAL
		valid = WriteDataToOutputSignal(matrix_out, nrows_in, ncols_in);
	}
	// -- PERFORM GAIN OPERATION: INPUT = SCALAR
	else if((nrows_in == 1) && (ncols_in == 1))
	{
		c = matrix_in[0][0];						// input as a scalar

		// -- MEMORY NEW
		matrix_out = new double *[m_iNrows];		// allocate an array of ptrs-to-double
		for(i=0; i<m_iNrows; i++)
		{
			matrix_out[i] = new double[m_iNcols];	// allocate an array of doubles
		}	
		nrows_del = m_iNrows;

		// OPERATE ON DATA
		for(i=0; i<m_iNrows; i++)
		{
			for(j=0; j<m_iNcols; j++)
			{
				matrix_out[i][j] = c*m_dGainMatrix[i][j];	
			}	
		}

		// WRITE DATA TO OUTPUT SIGNAL
		valid = WriteDataToOutputSignal(matrix_out, m_iNrows, m_iNcols);
	}
	// -- PERFORM GAIN OPERATION: GAIN = NON-SCALAR
	else if((m_iNrows > 1) || (m_iNcols > 1))		
	{
		if(m_iGainType == 0)		// ELEMENTAL OPERATION
		{
			if((m_iNrows == nrows_in) && (m_iNcols == ncols_in))
			{
				// -- MEMORY NEW
				matrix_out = new double *[m_iNrows];		// allocate an array of ptrs-to-double	
				for(i=0;i<m_iNrows;i++)
				{
					matrix_out[i] = new double[m_iNcols];	// allocate an array of doubles
				}
				nrows_del = m_iNrows;
				
				// ELEMENTAL OPERATION
				for(i=0; i<m_iNrows; i++)
				{
					for(j=0; j<m_iNcols; j++)
					{
						matrix_out[i][j] = m_dGainMatrix[i][j]*matrix_in[i][j];		
					}
				}

				// WRITE DATA TO OUTPUT SIGNAL
				valid = WriteDataToOutputSignal(matrix_out, m_iNrows, m_iNcols);
			}
			else if(((m_iNrows == 1) || (m_iNcols == 1)) && (m_iNrows == ncols_in) && (m_iNcols == nrows_in))
			{
				// -- MEMORY NEW
				matrix_out = new double *[m_iNrows];		// allocate an array of ptrs-to-double	
				for(i=0;i<m_iNrows;i++)
				{
					matrix_out[i] = new double[m_iNcols];	// allocate an array of doubles
				}
				nrows_del = m_iNrows;

				// ELEMENTAL MULT	
				for(i=0; i<m_iNrows; i++)
				{
					for(j=0; j<m_iNcols; j++)
					{
						matrix_out[i][j] = m_dGainMatrix[i][j]*matrix_in[j][i];
					}
				}
				
				// WRITE DATA TO OUTPUT SIGNAL
				valid = WriteDataToOutputSignal(matrix_out, m_iNrows, m_iNcols);
			}
			else
			{
				valid = -1;	// operational error
			}		
		}
		else if(m_iGainType == 1)	// Gain*Input OPERATION
		{
			// Check dimensions
			if(m_iNcols == nrows_in)
			{
				// -- MEMORY NEW
				matrix_out = new double *[m_iNrows];		// allocate an array of ptrs-to-double	
				for(i=0;i<m_iNrows;i++)
				{
					matrix_out[i] = new double[ncols_in];	// allocate an array of doubles
				}
				nrows_del = m_iNrows;

				// Matrix mult: Gain*Input = Output
				MatrixMultiply(m_iNrows, m_iNcols, ncols_in, m_dGainMatrix, matrix_in, matrix_out);

				// WRITE DATA TO OUTPUT SIGNAL
				valid = WriteDataToOutputSignal(matrix_out, m_iNrows, ncols_in);
			}
			else
			{
				valid = -1;	// operational eror
			}
		}
		else if(m_iGainType == 2)	// Input*Gain OPERATION
		{
			// Check dimensions
			if(ncols_in == m_iNrows)
			{		
				// -- MEMORY NEW
				matrix_out = new double *[nrows_in];		// allocate an array of ptrs-to-double	
				for(i=0;i<nrows_in;i++)
				{
					matrix_out[i] = new double[m_iNcols];	// allocate an array of doubles
				}
				nrows_del = nrows_in;

				// Matrix mult: Input*Gain = Output
				MatrixMultiply(nrows_in, ncols_in, m_iNcols, matrix_in, m_dGainMatrix, matrix_out);

				// WRITE DATA TO OUTPUT SIGNAL
				valid = WriteDataToOutputSignal(matrix_out, nrows_in, m_iNcols);
			}
			else
			{
				valid = -1;	// operational error
			}
		}
	}

	// -- Error msg concerning invalid signal or inconsistent data dimensions
	if(valid == 0)
	{
		sMsgTemp.Format("\n CGainBlock::OperateOnData()\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format("\n Error in writing data to output signal.   \n");
		sMsg+=sMsgTemp;	
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
	}
	else if(valid == -1)
	{
		sMsgTemp.Format("\n CGainBlock::OperateOnData()\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format("\n Error: inconsistent data dimensions, aborting operation.   \n");
		sMsg+=sMsgTemp;	
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
	}
	
	// -- MEMORY DELETE
	if(matrix_out != NULL)				// only delete memory if it was in fact allocated
	{
		for(i=0; i<nrows_del; i++)
		{
			delete [] matrix_out[i];	// delete the row arrays
		}
		delete [] matrix_out;			// delete the array (column vector) holding the row arrays	
	}

	return valid;
}

int CSignalGeneratorBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;
	int nrows = 1;				// nrows of matrix Y
	int ncols = 1;				// ncols of matrix Y
	int valid = 0;				// (-1) operational error, (0) read/write error, (1) no error
	int random_no;				// integer random number generated
	static int rand_flag = 0;	// random no. generator seed flag 
	double uniformly_rand;		// random number converted to the unit interval
	double A = m_dAmplitude;	// amplitude
	double phase = m_dPhase;	// phase angle (rad)
	double omega = m_dFrequency;// angular frequency (rad/s)
	double y;					// y(t)
	double **Y_matrix = NULL;	// Y matrix to hold y(t) output value
	

	// -- MEMORY NEW
	Y_matrix = new double *[nrows];				// allocate an array of ptrs-to-double
	for(i=0; i<nrows; i++)
	{
		Y_matrix[i] = new double[ncols];		// allocate an array of doubles
	}
	
	// -- GENERATE SIGNAL
	if(m_strFnType == "Random")			// uniformly random number [0,1]					
	{
		if(rand_flag == 0)
		{
			srand((unsigned)time(NULL));// seed the random number generator with time value to get truly random numbers
			rand_flag++;				// seed once per simulation 	
		}
		random_no = rand();
		uniformly_rand = double(random_no)/double(RAND_MAX);
		y = uniformly_rand;
	}
	else if(m_strFnType == "Sine")		// sine wave
	{
		y = A*sin(omega*t + phase);
	}
	else if(m_strFnType == "Square")	// square wave based on sine wave 
	{
		y = A*sin(omega*t + phase);		// use the sin wave to generate the square wave

		if(y > 0)
		{
			y = 1;
		}
		else if(y == 0)
		{
			y = 0;
		}
		else if(y < 0)
		{
			y = -1;
		}
	}

	Y_matrix[0][0] = y;					// assign linear fn signal to matrix

	// WRITE DATA TO OUTPUT SIGNAL
	valid = WriteDataToOutputSignal(Y_matrix, nrows, ncols);

	// -- MEMORY DELETE
	for(i=0; i<nrows; i++)
	{
		delete [] Y_matrix[i];	// delete the row arrays
	}
	delete [] Y_matrix;		// delete the array (column vector) holding the row arrays

	// Return connection signal status
	return valid;	
}

int CSumBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;
	int j;
	int first_in = 1;			// first input data flag
	int nrows = 0;				// no. of rows of data		
	int nrows_del;				// no. of rows to delete of matrix_out
	int ncols = 0;				// no. of cols of data
	int nrows_ref = 0;			// ref. no. of rows of data
	int ncols_ref = 0;			// ref. no. of cols of data
	int valid = 0;				// (-1) operational error, (0) reade/write error, (1) no error
	double **matrix_in = NULL;	// input signal
	double **matrix_out = NULL;	// output signal
	CString port_name;			// port name for sum block: "+" or "-"
	CString	sMsg;				// string to be displayed
	CString sMsgTemp;			// temp msg.
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;		// iterator for vector of CPort ptrs.
	vector<CPort*> &vec_of_input_ports = GetVectorOfInputPorts();

	// Get connection list
	list<CConnection*> &con_list = GetParentSystemModel()->GetConnectionList();
	
	// -- ITERATE OVER ALL PORTS AND CHECK INPUT SIGNAL DATA DIMENSIONALITY
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
		{
			if((*it_con)->GetRefToPort() == *it_port)	// if the input port of this connection is the current port
			{
				valid = (*it_con)->GetSignal()->GetSignalValidity();
				if(valid == 0)
				{
					return valid;			// invalid signal hence return
				}
				else if(valid == 1)
				{
					(*it_con)->GetSignal()->GetSignalDataDimensions(&nrows, &ncols);
					if(first_in)
					{
						nrows_ref = nrows;
						ncols_ref = ncols;
						first_in = 0;
					}
					else
					{
						if((nrows != nrows_ref) || (ncols != ncols_ref))
						{
							valid = -1;		// data dimensional inconsistency

							// Error msg concerning invalid signal or inconsistent data dimensions
							sMsgTemp.Format("\n CSumBlock::OperateOnData()\n");
							sMsg+=sMsgTemp;	
							sMsgTemp.Format("\n Error! Inconsistent data dimensions: aborting operation.   \n");
							sMsg+=sMsgTemp;	
							AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box

							return valid;
						}
					}
				}
			}		
		}// end it_con
	}// end it_port

	// -- MEMORY NEW
	matrix_out = new double *[nrows];		// allocate an array of ptrs-to-double
	for(i=0; i<nrows; i++)
	{
		matrix_out[i] = new double[ncols];	// allocate an array of doubles
	}
	nrows_del = nrows;	

	// -- NULLIFY OUTPUT MATRIX
	for(i=0; i<nrows; i++)
	{
		for(j=0; j<ncols; j++)
		{
			matrix_out[i][j] = 0.0;
		}
	}

	// -- ITERATE OVER ALL PORTS AND PERFORM SUM OPERATION ON SIGNAL DATA
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
		{
			if((*it_con)->GetRefToPort() == *it_port)	// if the input port of this connection is the current port
			{
				matrix_in = (*it_con)->GetSignal()->GetSignalData(&nrows, &ncols);
				port_name = (*it_port)->GetPortName();
				
				// MATRIX OPERATION
				if(port_name == "+")		
				{
					for(i=0; i<nrows; i++)
					{
						for(j=0; j<ncols; j++)
						{
							matrix_out[i][j] = matrix_out[i][j] + matrix_in[i][j];
						}
					}
				}
				else if(port_name == "-")
				{
					for(i=0; i<nrows; i++)
					{
						for(j=0; j<ncols; j++)
						{
							matrix_out[i][j] = matrix_out[i][j] - matrix_in[i][j];
						}
					}
				}
			}		
		}// end it_con
	}// end it_port

	// WRITE DATA TO OUTPUT SIGNAL
	valid = WriteDataToOutputSignal(matrix_out, nrows, ncols);

	// Error msg.
	if(valid == -1)
	{
		sMsgTemp.Format("\n CSumBlock::OperateOnData()\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format("\n Error in data dimensionality.   \n");
		sMsg+=sMsgTemp;	
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
	}

	// -- MEMORY DELETE
	for(i=0; i<nrows_del; i++)
	{
		delete [] matrix_out[i];	// delete the row arrays
	}
	delete [] matrix_out;			// delete the array (column vector) holding the row arrays	

	return valid;
}

int CDerivativeBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;			
	int j;
	int ncols_in = 0;			// ncols of input signal matrix
	int nrows_in = 0;			// nrows of input signal matrix
	int nsignals = 0;			// number of incoming signals
	int valid = 0;				// (-1) operational error, (0) read/write error, (1) no error
	double f_dot = 0;			// f'(t), the derivative of f() at current time t
	double *f_at_t = NULL;		// f(t), the input signal vector to the block	
	double **matrix_in = NULL;	// matrix data of input signals
	CString	sMsg;				// string to be displayed
	CString sMsgTemp;			// temp msg.
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.


	// GET INPUT SIGNAL DATA
	valid = ReadDataFromSingleInputSignal(matrix_in, &nrows_in, &ncols_in);
	
	if(valid == 0)
	{	
		return valid;			// exit function since input invalid
	}
	else if(valid == 1)
	{
		valid = 0;				// reset signal validity for output signal test
	}	

	// CHECK IF INPUT SIGNAL IS NOT A SCALAR, ROW OR COLUMN VECTOR
	if((nrows_in > 1) && (ncols_in > 1))
	{
		sMsgTemp.Format("\n CDerivativeBlock::OperateOnData()\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format("\n WARNING: error in computing the numerical derivative!\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format(" Invalid input signal!\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format(" Input signal should be a scalar function, or a vector of scalar functions.\n");
		sMsg+=sMsgTemp;
		sMsgTemp.Format(" That is: signal = f(t), or signal = [f1(t), f2(t), ... , fm(t)].\n");
		sMsg+=sMsgTemp;		
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
		valid = -1;		// valid = -1 implies dimensionality error
		return valid;	// Exit function since input not a scalar fn of a scalar var, or a vector of scalar fns of scalar vars.	
	}
	else
	{
		m_iNrows = nrows_in;	// record the no. of rows for memory deletion
	}

	// SET TIME COUNT REF AND NO. OF TIMES THE FN IS CALLED AT THIS TIME POINT
	if(m_i_t_cnt_ref == t_cnt)
	{
		m_iNcallsPerTimeCnt++;	// no. of calls per time-based iteration (t_cnt)
	}
	else
	{
		m_i_t_cnt_ref = t_cnt;
		m_iNcallsPerTimeCnt = 1;
	}
		
	// WRITE DATA TO OUTPUT SIGNAL IF ALREADY DETERMINED ON A PREVIOUS CALL
	if(m_iNcallsPerTimeCnt > 1)
	{
		valid = WriteDataToOutputSignal(m_dMatrixOut, nrows_in, ncols_in);
		return valid;	
	}

	// GET THE NUMBER OF INCOMING SIGNALS
	if((nrows_in >= 1) && (ncols_in == 1))
	{
		nsignals = nrows_in;
	}
	else if((nrows_in == 1) && (ncols_in >= 1))
	{
		nsignals = ncols_in;
	}

	// MEMORY ALLOC UPON EACH CALL TO THE FN
	f_at_t = new double[nsignals];				// memory alloc for double *f_at_t, i.e., f(t).

	// MEMORY ALLOC OF VARS ONLY WHEN t = 0 
	if(t_cnt == 0)
	{
		m_f_at_t_minus_h = new double[nsignals];	// memory alloc for double *m_f_at_t_minus_h member var (array): f(t-h).
		m_f_at_t_minus_2h = new double[nsignals];	// memory alloc for double *m_f_at_t_minus_2h member var (array): f(t-2h).

		m_dMatrixOut = new double *[nrows_in];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_in; i++)
		{
			m_dMatrixOut[i] = new double[ncols_in];	// allocate an array of doubles
		}
	}
	
	// ASSIGN INPUT SIGNAL MATRIX DATA TO f(t) VECTOR
	if(nrows_in >= ncols_in)
	{
		for(i=0; i<nsignals; i++)
		{
			f_at_t[i] = matrix_in[i][0];		// f(t) is current incoming signal at time t
		}
	}
	else if(ncols_in >= nrows_in)
	{
		for(i=0; i<nsignals; i++)
		{
			f_at_t[i] = matrix_in[0][i];		// f(t) is current incoming signal at time t
		}
	}

	// -- THREE(3)-POINT DERIVATIVE
	if((m_iDerivativeMethod == 0) && (t_cnt == 0))		// At time t_cnt = 0
	{
		// No derivative can be determined
		for(i=0; i<nrows_in; i++)
		{
			for(j=0; j<ncols_in; j++)
			{
				m_dMatrixOut[i][j] = 0.0;
			}
		}

		// FOR EACH INCOMING SIGNAL STORED IN EACH ROW OF signal_vec
		for(i=0; i<nsignals; i++)
		{
			m_f_at_t_minus_h[i] = f_at_t[i]; 		// Set f(t-h) FOR THE NEXT ITERATION to be f(t) OF THE CURRENT ITERATION
		}
	}
	else if((m_iDerivativeMethod == 0) && (t_cnt >= 1))	// At time t_cnt >= 1
	{	
		// FOR EACH INCOMING SIGNAL STORED IN EACH ROW OF signal_vec
		for(i=0; i<nsignals; i++)
		{			
			// Calculate 3-pt derivative using f(t), f(t-h) and delta_t
			f_dot = CalculateThreePointDerivative(m_f_at_t_minus_h[i], f_at_t[i], delta_t);
			
			// Assign f_dot = f'(t) to the output signal
			if(nrows_in >= ncols_in)
			{
				m_dMatrixOut[i][0] = f_dot;
			}
			else if(ncols_in >= nrows_in)
			{
				m_dMatrixOut[0][i] = f_dot;	
			}
				
			// Set f(t-h) FOR THE NEXT ITERATION to be f(t) OF THE CURRENT ITERATION
			m_f_at_t_minus_h[i] = f_at_t[i];
		}
	}
	
	// -- FIVE(5)-POINT DERIVATIVE	
	if((m_iDerivativeMethod == 1) && (t_cnt < 2))		// At less than 2 calls to the fn
	{
		// No derivative can be determined
		for(i=0; i<nrows_in; i++)
		{
			for(j=0; j<ncols_in; j++)
			{
				m_dMatrixOut[i][j] = 0.0;		
			}
		}
	
		// SET UP PREVIOUS VALUES f(t-2h) for t_cnt = 0, and f(t-h) for t_cnt = 1
		if(t_cnt == 0)
		{
			for(i=0; i<nsignals; i++)		// For each incoming signal stored in each row of signal_vec
			{	
				m_f_at_t_minus_2h[i] = f_at_t[i]; // Set f(t-2h) FOR THE NEXT ITERATION to be f(t) OF THE CURRENT ITERATION 
			}
		}
		else if(t_cnt == 1)
		{
			for(i=0; i<nsignals; i++)		// For each incoming signal stored in each row of signal_vec
			{
				m_f_at_t_minus_h[i] = f_at_t[i];	// Set f(t-h) FOR THE NEXT ITERATION to be f(t) OF THE CURRENT ITERATION
			}
		}
	}
	else if((m_iDerivativeMethod == 1) && (t_cnt >= 2))	// At time t_cnt >= 2
	{
		// FOR EACH INCOMING SIGNAL STORED IN EACH ROW OF signal_vec
		for(i=0; i<nsignals; i++)
		{			
			// Calculate 5-pt derivative using f(t), f(t-h), f(t-2h) and delta_t
			f_dot = CalculateFivePointDerivative(m_f_at_t_minus_2h[i], m_f_at_t_minus_h[i], f_at_t[i], delta_t);
			
			// Assign f_dot = f'(t) to the output signal
			if(nrows_in >= ncols_in)
			{
				m_dMatrixOut[i][0] = f_dot;
			}
			else if(ncols_in >= nrows_in)
			{
				m_dMatrixOut[0][i] = f_dot;	
			}
				
			// Set f(t-2h) and f(t-h) FOR THE NEXT ITERATION, to be f(t-h) and f(t) OF THE CURRENT ITERATION, respectively.
			m_f_at_t_minus_2h[i] = m_f_at_t_minus_h[i];
			m_f_at_t_minus_h[i] = f_at_t[i];
		}		
	}

	// WRITE DATA TO OUTPUT SIGNAL
	valid = WriteDataToOutputSignal(m_dMatrixOut, nrows_in, ncols_in);

	// MEMORY DELETE
	delete [] f_at_t;		// delete the incoming signal vector f(t)	
	
	return valid;
}

double CDerivativeBlock::CalculateThreePointDerivative(double m_f_at_t_minus_h, double f_at_t, double delta_t)
{
	// -- NUMERICAL 3-POINT DERIVATIVE
	// The 3-pt derivative of a fn f(t) is
	//			 f'(t) = (f(t+h) - f(t-h))/2h
	//
	// However, f(t+h) = f(t + delta_t) is not available at time t, but may be obtained by linear extrapolation.
	//
	// Linear extrapolation: f(tk) = f0 + ((f1 - f0)/(t1 - t0))*(tk - t0)
	//
	// So, letting tk = t + h, f0 = f(t-h) and f1 = f(t), the extrapolated value f(tk) is 
	//			f(t+h) = f(t-h) + (f(t) - f(t-h))/(t - (t-h))*(t+h -(t-h))
	//			       = f(t-h) + 2(f(t) - f(t-h))
	//			       = 2f(t) - f(t-h)
	//
	// Now upon substituting the expression for f(t+h) into the defintion of the derivative, one finds
	//			f'(t) = (f(t+h) - f(t-h))/2h
	//			      = (2f(t) - f(t-h) - f(t-h))/2h
	//			      = (f(t) - f(t-h))/h
	//
	// Hence, if linear extrapolation is used to determine f(t+h) in order to determine f'(t), then the formula
	// for f'(t) reduces to a fn involving known values, f(t) and f(t-h), at the current time point t.
	
	double f_dot_at_t;		// derivative f'(t) at time t.

	// 3-POINT DERIVATIVE
	f_dot_at_t = (f_at_t - m_f_at_t_minus_h)/delta_t;

	return f_dot_at_t;
}

double CDerivativeBlock::CalculateFivePointDerivative(double m_f_at_t_minus_2h, double m_f_at_t_minus_h, double f_at_t, double delta_t)
{
	// -- NUMERICAL 5-POINT DERIVATIVE
	// The 5-pt derivative of a fn f(t) is
	//			 f'(t) = (-f(t+2h) + 8f(t+h) - 8f(t-h) + f(t-2h))/12h
	//
	// However, f(t+h) and f(t+2h) are not available at time t, but may be obtained by linear extrapolation.
	//
	// Linear extrapolation: f(tk) = f0 + ((f1 - f0)/(t1 - t0))*(tk - t0)
	//
	// Let f(t-2h) = f0, f(t-h) = f1, f(t) = f2, f(t+h) = f3, and f(t+2h) = f4.
	// Then, RTF f(t+h) = f3 and f(t+2h) = f4, in order to use the expression for f'(t).
	//
	//			f3 = f1 + ((f2 - f1)/(t2 - t1))*(t3 - t1)
	//			   = 2f2 - f1
	// and
	//			f4 = f2 + ((f3 - f2)/(t3 - t2))*(t4 - t2)
	//			   = 2f3 - f2
	//
	// Now upon substituting the expressions for f(t+h) = f3 and f(t+2h) = f4 into the defintion of the derivative f'(t), 
	// one finds
	//			f'(t) = (-f(t+2h) + 8f(t+h) - 8f(t-h) + f(t-2h))/12h
	//			      = (-f4 + 8f3 - 8f1 + f0)/12h
	//			      = (-(2f3 - f2) + 8(2f2 - f1) - 8f1 + f0)/12h
	//			      = (13f2 - 14f1 + f0)/12h
	//			      = (13f(t) - 14f(t-h) + f(t-2h))/12h
	//
	// Hence, if linear extrapolation is used to determine f(t+h) and f(t+2h) in order to determine f'(t), then the formula
	// for f'(t) reduces to a fn involving known values, f(t), f(t-h) and f(t-2h), at the current time point t.
	
	double f_dot_at_t;		// derivative f'(t) at time t.

	// 5-POINT DERIVATIVE
	f_dot_at_t = (13*f_at_t - 14*m_f_at_t_minus_h + m_f_at_t_minus_2h)/(12*delta_t);

	return f_dot_at_t;
}

int CIntegratorBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;
	int length_y;				// length of y vector
	int ncols;					// no. of cols of matrix_in
	int nrows;					// no. of rows of matrix_in
	int valid = 0;				// (-1) operational error, (0) read/write error, (1) no error
	double *y_at_t = NULL;		// y_i = y_i-1 + h*f(t_i-1, y_i-1)
	double **matrix_in = NULL;	// input signal
	CString sIntegrationMethod;	// integration method
	CString sMsg;				// string to be displayed
	CString sMsgTemp;			// temp msg.
	UINT nType = MB_OK;			// style of msg. box
	UINT nIDhelp = 0;			// help context ID for the msg.

	// -- GET SYS MODEL VAR
	sIntegrationMethod = GetParentSystemModel()->GetIntegrationMethod();	// get integration method from CSystemModel

	// Inform user of default integration method
	if(t_cnt == 0)
	{
		if(sIntegrationMethod == "Runge-Kutta (4th Order)")
		{
			sMsgTemp.Format("\n CIntegratorBlock::OperateOnData()    \n");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n No Runge-Kutta method specified as yet: defaulting to Euler method.    \n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
		}
	}

	// -- GET INPUT SIGNAL DATA
	valid = ReadDataFromSingleInputSignal(matrix_in, &nrows, &ncols);
	if(valid == 0)
	{	
		return valid;	// Exit function since input invalid
	}
	else if(valid == 1)
	{
		valid = 0;
	}

	// -- CHECK SIZE OF MATRIX_IN
	if((nrows > 1) && (ncols > 1))
	{
		sMsgTemp.Format("\n CIntegratorBlock::OperateOnData()\n");
		sMsg+=sMsgTemp;
		sMsgTemp.Format(" Input signal is not a row or column vector, but a matrix.");
		sMsg+=sMsgTemp;
		sMsgTemp.Format(" Aborting integration operation.");
		sMsg+=sMsgTemp;
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box

		valid = -1;		// dimensionality error
		return valid;
	}

	// -- DETERMINE CONSISTENCY OF LENGTHS OF Y AND Y_INIT_COND
	if(nrows >= ncols)
	{	
		length_y = nrows;
	}
	else
	{
		length_y = ncols;
	}

	// If incoming signal length not equal to length of init. cond. member variable vec, m_dICVector
	if(length_y != m_iLength)
	{
		sMsgTemp.Format("\n CIntegratorBlock::OperateOnData()\n");
		sMsg+=sMsgTemp;
		sMsgTemp.Format(" Input signal is not of same dimension as initial condition vector.");
		sMsg+=sMsgTemp;
		sMsgTemp.Format(" Aborting integration operation.");
		sMsg+=sMsgTemp;
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box

		valid = -1;	// dimensionality error
		return valid;
	}	
	else
	{
		m_iNrowsOut = nrows;	// assign the no. of rows of the output matrix signal for memory deletion purposes
	}

	// SET TIME COUNT REF AND NO. OF TIMES THE FN IS CALLED AT THIS TIME POINT
	if(m_i_t_cnt_ref == t_cnt)
	{
		m_iNcallsPerTimeCnt++;
	}
	else
	{
		m_i_t_cnt_ref = t_cnt;
		m_iNcallsPerTimeCnt = 1;
	}
		
	// WRITE DATA TO OUTPUT SIGNAL IF ALREADY DETERMINED ON A PREVIOUS CALL
	if(m_iNcallsPerTimeCnt > 1)
	{
		valid = WriteDataToOutputSignal(m_dMatrixOut, nrows, ncols);
		return valid;	
	}	

	// -- MEMORY NEW
	y_at_t = new double[length_y];

	if(t_cnt == 0)						// allocate memory for y_vec only a t_0
	{
		m_y_at_t_minus_h = new double[length_y];		
		m_y_dot_at_t_minus_h = new double[length_y];	// allocate an array of doubles
	
		m_dMatrixOut = new double *[nrows];		// allocate an array of ptrs-to-double to be same size as matrix_in
		for(i=0; i<nrows; i++)
		{
			m_dMatrixOut[i] = new double[ncols];	// allocate an array of doubles
		}
	}

	// -- ASSIGN IC VECTOR TO Y VECTOR INITIALLY (at t = 0)
	if(t_cnt == 0)
	{	
		for(i=0; i<length_y; i++)
		{
			y_at_t[i] = m_dICVector[i];		// y_0 = y_init_cond = m_dICVector
		}			
	}

	// -- PERFORM EULER INTEGRATION
	// y_i+1 = y_i + delta_t*y_dot(t_i, y_i), and hence y must be static since it holds y_at_t_i and is updated to y_at_t_i+1, which
	// then becomes y_at_t_i upon the next entry into the OperateOnData() fn, i.e. it must be "remembered" or remain
	// persistent/static for the next iteration's evaluation. The vector y_dot is the incoming signal.

	if(t_cnt > 0)
	{
		// -- PERFORM CHOSEN NUMERICAL INTEGRATION
		if(sIntegrationMethod == "Euler (1st Order)")
		{
			EulerMethod(y_at_t, m_y_at_t_minus_h, m_y_dot_at_t_minus_h, delta_t, length_y);
		}
		else if(sIntegrationMethod == "Runge-Kutta (4th Order)")
		{
			// Default Euler method used in absence of Runge-Kutta method.
			EulerMethod(y_at_t, m_y_at_t_minus_h, m_y_dot_at_t_minus_h, delta_t, length_y);
		}
	}

	//sMsgTemp.Format("\n CIntegratorBlock::OperateOnData()\n");
	//sMsg+=sMsgTemp;
	//sMsgTemp.Format(" length_y = %d, y_at_t[0] = %lf, m_y_at_t_minus_h[0] = %lf, m_y_dot_at_t_minus_h[0] = %lf\n", length_y, y_at_t[0], m_y_at_t_minus_h[0], m_y_dot_at_t_minus_h[0]);
	//sMsg+=sMsgTemp;
	//AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box

	// -- ASSIGN MATRIX_IN TO Y_DOT: the incoming signal is y_dot = f(t,y).
	if(nrows >= ncols)
	{
		for(i=0; i<length_y; i++)
		{
			m_y_dot_at_t_minus_h[i] = matrix_in[i][0];
		}
	}
	else
	{
		for(i=0; i<length_y; i++)
		{
			m_y_dot_at_t_minus_h[i] = matrix_in[0][i];
		}
	}

	// -- UPDATE m_y_at_t_minus_h FOR NEXT ITERATION WITH y_at_t OF CURRENT ITERATION.
	for(i=0; i<length_y; i++)
	{
		m_y_at_t_minus_h[i] = y_at_t[i];
	}

	// -- WRITE DATA TO OUTPUT SIGNAL TO HAVE SAME DIMS AS INPUT SIGNAL
	if(nrows >= ncols)
	{
		for(i=0; i<length_y; i++)
		{
			m_dMatrixOut[i][0] = y_at_t[i];
		}
	}
	else
	{
		for(i=0; i<length_y; i++)
		{
			m_dMatrixOut[0][i] = y_at_t[i];
		}
	}
	valid = WriteDataToOutputSignal(m_dMatrixOut, nrows, ncols);	// m_dMatrixOut is of same dim as matrix_in

	// -- MEMORY DELETE
	delete [] y_at_t;			// delete the y_dot array
	
	return valid;
}

int CIntegratorBlock::EulerMethod(double *y_at_t, double *m_y_at_t_minus_h, double *m_y_dot_at_t_minus_h, double delta_t, int length_y)
{
	int i;

	// Euler's Method: y_i = y_i-1 + h*y_dot_i-1
	for(i=0; i<length_y; i++)
	{
		y_at_t[i] = m_y_at_t_minus_h[i] + delta_t*m_y_dot_at_t_minus_h[i];
	}	

	return 0;
}

int CDivideBlock::OperateOnData(int t_cnt, double t, double delta_t)
{
	int i;
	int ncols;							// no. of cols of temp matrix
	int nrows;							// no. of rows of temp matrix
	int ncols_R;						// no. of rows of Result				
	int nrows_R;						// no. of cols of Result
	int port_cnt = 1;					// port counter
	int valid = 0;						// (-1) operational error, (0) read/write error, (1) no error
	double **matrix_in = NULL;			// input signal data
	double **Result = NULL;				// result of operation
	double **temp_matrix = NULL;		// temp matrix which is written to output signal
	CString port_name;					// port name for divide block: "*" or "/"
	list<CConnection*>::iterator it_con;// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.
	vector<CPort*> &vec_of_input_ports = GetVectorOfInputPorts();

	// Get connection list
	list<CConnection*> &con_list = GetParentSystemModel()->GetConnectionList();

	// -- ITERATE OVER ALL PORTS AND CHECK INPUT SIGNAL DATA VALIDITY 	
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
		{
			if((*it_con)->GetRefToPort() == *it_port)	// if the input port of this connection is the current port
			{
				valid = (*it_con)->GetSignal()->GetSignalValidity();
				if(valid == 0)
				{
					return valid;
				}
			}		
		}// end it_con
	}// end it_port

	// -- INITIALIZE THE ORIGINAL TEMP MATRIX
	nrows = 1;					// nrows of temp_matrix
	ncols = 1;					// ncols of temp_matrix
					
	// MEMORY NEW
	temp_matrix = new double *[nrows];		// allocate an array of ptrs-to-double
	for(i=0; i<nrows; i++)
	{
		temp_matrix[i] = new double[ncols];	// allocate an array of doubles
	}

	temp_matrix[0][0] = 1.0;			// init 1x1 matrix to unity.

	// -- ITERATE OVER ALL PORTS AND PERFORM PAIRWISE OPERATIONS ON SIGNAL DATA
	for(it_port = vec_of_input_ports.begin(); it_port != vec_of_input_ports.end(); it_port++)
	{
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
		{
			if((*it_con)->GetRefToPort() == *it_port)	// if the input port of this connection is the current port
			{
				// NOTE: *it_con IS PASSED INTO DivideMultiplyOperation() AND IS USED TO OBTAIN matrix_in, I.E.,
				// matrix_in = (*it_con)->GetSignalData(&nrows, &ncols);

				// Get the port name, i.e. the sign of the port operation: "*" or "/".
				port_name = (*it_port)->GetPortName();	

				Result = DivideMultiplyOperation(temp_matrix, nrows, ncols, *it_con, port_name, nrows_R, ncols_R, valid);

				// MEMORY DELETE
				if(temp_matrix != NULL)
				{
					for(i=0; i<nrows; i++)
					{
						delete [] temp_matrix[i];   	// delete the row arrays
					}
					delete [] temp_matrix;			// delete the array (column vector) holding the row arrays
				}
					
				// ASSIGN RESULT TO TEMP_MATRIX (ASSIGNMENT OF A POINTER)
				temp_matrix = Result;

				// UPDATE nrows AND ncols USED IN DELETE OF temp_matrix WHICH IS ASSIGNED Result
				nrows = nrows_R;
				ncols = ncols_R;
			}// end if it_con	
		}// end it_con

		if(valid != 1)
		{
			break;	// Exit for it_port since DivideMultiplyOperation() is in error.
		}	
		port_cnt++;
	}// end it_port

	// WRITE DATA TO OUTPUT SIGNAL (only if DivideMultiplyOperation() produces a valid result)
	if(valid == 1)
	{
		valid = WriteDataToOutputSignal(temp_matrix, nrows, ncols);
	}

	// -- MEMORY DELETE
	// DELETE temp_matrix, EQUIVALENTLY Result, SINCE temp_matrix WAS ASSIGNED Result AT THE LAST STEP (nrows = nrows_R),
	// AND Result's MEMORY WAS ALLOCATED WITHIN DivideMultiplyOperation().

	if(temp_matrix != NULL)
	{		
		// MEMORY DELETE
		for(i=0; i<nrows; i++)
		{
			delete [] temp_matrix[i];	// delete the row arrays
		}
		delete [] temp_matrix;			// delete the array (column vector) holding the row array
	}

	return valid;
}

double **CDivideBlock::DivideMultiplyOperation(double **A, int nrows_A, int ncols_A, CConnection *ptr_to_con, CString sign, int &nrows_R, int &ncols_R, int &valid)
{
	// Note: nrows_R, ncols_R and valid, are passed by reference for syntactically clean reasons.
	int i;
	int j;
	int ncols_B;			// no. of columns of matrix B
	int ncols_GJ_RHS = 1;	// no. of RHS vectors of the Gauss-Jordan elimination system.
	int nrows_B;			// no. of rows of matrix B
	double a;				// scalar version of A
	double b;				// scalar version of B
	double **B = NULL;		// matrix to which operator is applied w.r.t. matrix A
	double **B_inv = NULL;	// inverse of B to facilitate division
	double **GJ_RHS = NULL;	// Gauss-Jordan elimination system r.h.s.
	double **R = NULL;		// Result of the operation: A operator B.
	CString	sMsg;			// string to be displayed
	CString sMsgTemp;		// temp msg.
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.
		
	// Get signal data and assign pointer to matrix B, but this is the actual signal data not a copy.
	B = ptr_to_con->GetSignal()->GetSignalData(&nrows_B, &ncols_B);	

	// Assume operation will be valid unless explicitly assigned o/wise implying invalid
	// valid = (-3) dimensionality error, (-2) divide by zero error, (-1) singular matrix 
	// THEN FINALLY: (-1) operational error, (0) read/write error, (1) no error
	valid = 1;


	// -- DIFFERENT CASES FOR VALUES A AND B ------------------------------------------------------	
	//    Note: operations are performed as follows: R = A operator B.
	//
	//	  The order of operations is performed in the order of the ports from top to bottom on the block.
	//    Initially, for the first operation, A = 1 (scalar) and B is the signal on the first connection,
	//    that enters the first port. After A op. B is performed, then the result R will re-enter as the new A,
	//    and the second connection's signal data will be B. Then A. op B is performed again.
	//    HENCE THE DEVELOPER MUST BE CLEAR ABOUT WHAT IN FACT IS THE CURRENT FORM OF A: scalar, vector or matrix!
	//
	//    "A" is the CURRENTLY-EVOLVED-TO DATA over the ports thus far, and STARTS AS UNITY (1) scalar on init. entry.
	//	  "B" is the SIGNAL DATA on the connection of the CURRENT PORT (top down) that forms the A op. B operation.
	//
	//    Example 1. 
	//	  Let values on signals entering ports one and two be, v_1 = 2, and v_2 = [1, 2].
	//    For a multiply operation on both ports, one has,
	//	  Entry 1: A = 1, B = v_1 = 2, R = A*B = 1*2 = 2,					(R is passed into A for the next iteration)
	//    Entry 2: A = 2, B = v_2 = [1, 2], R = A*B = 2*[1, 2] = [2, 4],	(R is then written to the output signal)
	//
	//	  Example 2. 
	//    Let values on signals entering ports one and two be, v_1 = [1, 2], and v_2 = [3, 4]
	//    For an ELEMENTAL divide operation on BOTH ports, one has,
	//	  Entry 1: A = 1, B = v_1 = [1, 2], R = A/B = [1/1, 1/2],			(R is passed into A for the next iteration)
	//    Entry 2: A = [1, 1/2], B = v_2 = [3, 4], R = A/B = [1/3, 1/8],	(R is then written to the output signal)
	// --------------------------------------------------------------------------------------------


	// -- A AND B ARE BOTH SCALARS ----------------------------------------------------------------
	if((nrows_A == 1) && (ncols_A == 1) && (nrows_B == 1) && (ncols_B == 1))
	{
		// MEMORY NEW
		nrows_R = 1;
		ncols_R = 1;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}		

		a = A[0][0];
		b = B[0][0];
		
		if(sign == "*")
		{
			R[0][0] = a*b;
		}
		else if(sign == "/")
		{
			if(b != 0)
			{
				R[0][0] = a/b;
			}
			else
			{
				valid = -2;	// divide by zero error
			}
		}
	}

	// -- A IS A SCALAR AND B IS A VECTOR OR VICE VERSA -------------------------------------------
	else if((nrows_A == 1) && (ncols_A == 1) && (nrows_B == 1) && (ncols_B > 1))		// A = scalar, B = row vec
	{
		// MEMORY NEW
		nrows_R = nrows_B;
		ncols_R = ncols_B;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}	
		
		a = A[0][0];

		if(m_iMultType == 0)			// Elemental op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);	// (1x1)*(1xn) = (1xn), A is a scalar
			}
			else if(sign == "/")
			{
				for(i=0; i<ncols_R; i++)
				{
					if(B[0][i] != 0)
					{
						R[0][i] = a/B[0][i];
					}
					else
					{	
						valid = -2;	// divide by zero error
						break;
					}
				}
			}
		}	
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);	// (1x1)*(1xn) = (1xn)
			}
			else if(sign == "/")
			{
				valid = -3;	// dimensionality error (can't divide by a row vector)
			}	
		}
	}
	else if((nrows_A == 1) && (ncols_A == 1) && (nrows_B > 1) && (ncols_B == 1))	// A = scalar, B = col vec
	{
		// MEMORY NEW
		nrows_R = nrows_B;
		ncols_R = ncols_B;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}		
		
		a = A[0][0];

		if(m_iMultType == 0)			// Elemental op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_B, ncols_B, ncols_A, B, A, R);	// (nx1)*(1x1) = (nx1), A is a scalar
			}
			else if(sign == "/")
			{
				for(i=0; i<nrows_R; i++)
				{
					if(B[i][0] != 0)
					{
						R[i][0] = a/B[i][0];
					}
					else
					{	
						valid = -2;	// divide by zero error
						break;
					}
				}
			}
		}	
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_B, ncols_B, ncols_A, B, A, R);	// (nx1)*(1x1) = (nx1), A is a scalar
			}
			else if(sign == "/")
			{
				valid = -3;	// dimensionality error (can't divide by a col vector)
			}			
		}
	}
	else if((nrows_A == 1) && (ncols_A > 1) && (nrows_B == 1) && (ncols_B == 1))	// A = row vec, B = scalar
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_A;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		b = B[0][0];

		// Elemental and Matrix operations are the same for: vector op. scalar (in that order)
		if(sign == "*")
		{
			MatrixMultiply(nrows_B, ncols_B, ncols_A, B, A, R);	// (1x1)*(1xn) = (1xn), B is a scalar
		}
		else if(sign == "/")
		{
			for(i=0; i<ncols_R; i++)
			{
				if(b != 0)
				{
					R[0][i] = A[0][i]/b;
				}
				else
				{	
					valid = -2;	// divide by zero error
					break;
				}
			}
		}	
	}
	else if((nrows_A > 1) && (ncols_A == 1) && (nrows_B == 1) && (ncols_B == 1))	// A = col vec, B = scalar
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_A;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		b = B[0][0];
		
		// Elemental and Matrix operations are the same for: vector op. scalar (in that order)
		if(sign == "*")
		{
			MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);	// (nx1)*(1x1) = (nx1), B is a scalar
		}
		else if(sign == "/")
		{
			for(i=0; i<nrows_R; i++)
			{
				if(b != 0)
				{
					R[i][0] = A[i][0]/b;
				}
				else
				{	
					valid = -2;	// divide by zero error
					break;
				}
			}
		}
	}

	// -- A IS A SCALAR AND B IS A MATRIX OR VICE VERSA -------------------------------------------
	else if((nrows_A == 1) && (ncols_A == 1) && (nrows_B > 1) && (ncols_B > 1))		// A = scalar, B = matrix
	{
		// MEMORY NEW
		nrows_R = nrows_B;
		ncols_R = ncols_B;
		R = new double *[nrows_R];			// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		a = A[0][0];
	
		if(m_iMultType == 0)			// Elemental op.
		{
			if(sign == "*")
			{
				for(i=0; i<nrows_R; i++)
				{
					for(j=0; j<ncols_R; j++)
					{
						R[i][j] = a*B[i][j];
					}
				}
			}
			else if(sign == "/")
			{
				for(i=0; i<nrows_R; i++)
				{
					for(j=0; j<ncols_R; j++)
					{
						if(B[i][j] != 0)
						{
							R[i][j] = a/B[i][j];
						}
						else
						{
							valid = -2;	// divide by zero error
							break;
						}
					}
					if(valid == -2)
					{
						break;
					}
				}
			}
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				for(i=0; i<nrows_R; i++)
				{
					for(j=0; j<ncols_R; j++)
					{
						R[i][j] = a*B[i][j];
					}
				}
			}
			else if(sign == "/")
			{
				if(nrows_B == ncols_B)	// if B is a square matrix
				{
					// MEMORY NEW
					// Inverse matrix B_inv = B^-1
					B_inv = new double *[nrows_B];			// allocate an array of ptrs-to-double
					for(i=0; i<nrows_B; i++)
					{
						B_inv[i] = new double[ncols_B];		// allocate an array of doubles
					}
					
					// GAUSS-JORDAN ELIMINATION R.H.S. MATRIX (dummy vector here since there is no equation soln rqd.)
					GJ_RHS = new double *[nrows_B];			// allocate an array of ptrs-to-double
					for(i=0; i<nrows_B; i++)
					{
						GJ_RHS[i] = new double[ncols_GJ_RHS];	// allocate an array of doubles
					}
					
					// Copy B into B_inv
					for(i=0; i<nrows_B; i++)
					{
						for(j=0; j<ncols_B; j++)
						{
							B_inv[i][j] = B[i][j];
						}
					}

					// -- GAUSS-JORDAN ELIMINATION WITH FULL PIVOTING
					// B_inv starts off as B (see above assig.), then is overwritten with the inverse B^-1.
					// The r.h.s. matrix GJ_RHS is simply a dummy vector that is not used.
					valid = GaussJordanEliminationFullPivoting(B_inv, nrows_B, GJ_RHS, ncols_GJ_RHS);
				
					for(i=0; i<nrows_R; i++)
					{
						for(j=0; j<ncols_R; j++)
						{
							R[i][j] = a*B_inv[i][j];	// a/B = a*B_inv
						}
					}

					// MEMORY DELETE
					for(i=0; i<nrows_B; i++)
					{
						delete [] B_inv[i];	// delete the row arrays
					}
					delete [] B_inv;		// delete the array (column vector) holding the row array
					
					for(i=0; i<nrows_B; i++)
					{
						delete [] GJ_RHS[i];	// delete the row arrays
					}
					delete [] GJ_RHS;		// delete the array (column vector) holding the row array
				}
				else
				{
					valid = -3;	// dimensionality error
				}
			}
		}
	}
	else if((nrows_A > 1) && (ncols_A > 1) && (nrows_B == 1) && (ncols_B == 1))	// A = matrix, B = scalar
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_A;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		b = B[0][0];
	
		// Elemental and matrix operations are the same for the order A op. B, where A is a matrix and B a scalar.
		if(sign == "*")
		{
			for(i=0; i<nrows_R; i++)
			{
				for(j=0; j<ncols_R; j++)
				{
					R[i][j] = b*A[i][j];
				}
			}
		}
		else if(sign == "/")
		{
			if(b != 0)
			{
				for(i=0; i<nrows_R; i++)
				{
					for(j=0; j<ncols_R; j++)
					{
						R[i][j] = A[i][j]/b;	
					}
				}
			}
			else
			{
				valid = -2;	// divide by zero error
			}
		}
	}

	// -- A AND B ARE VECTORS ---------------------------------------------------------------------
	else if((nrows_A == 1) && (ncols_A > 1) && (nrows_B == nrows_A) && (ncols_B == ncols_A))		// A and B are row vecs of the same length
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_A;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		if(m_iMultType == 0)			// Elemental op.
		{
			if(sign == "*")
			{
				for(i=0; i<ncols_R; i++)
				{
					R[0][i] = A[0][i]*B[0][i];
				}
			}
			else if(sign == "/")
			{
				for(i=0; i<ncols_R; i++)
				{
					if(B[0][i] != 0)
					{
						R[0][i] = A[0][i]/B[0][i];
					}
					else
					{	
						valid = -2;	// divide by zero error
						break;
					}
				}
			}
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			valid = -3;	// dimensionality error
		}
	}
	else if((nrows_A > 1) && (ncols_A == 1) && (nrows_B == nrows_A) && (ncols_B == ncols_A))	// A and B are col vecs of the same length
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_A;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		if(m_iMultType == 0)			// Elemental op.
		{
			if(sign == "*")
			{
				for(i=0; i<nrows_R; i++)
				{
					R[i][0] = A[i][0]*B[i][0];
				}
			}
			else if(sign == "/")
			{
				for(i=0; i<nrows_R; i++)
				{
					if(B[i][0] != 0)
					{
						R[i][0] = A[i][0]/B[i][0];
					}
					else
					{
						valid = -2;	// divide by zero error
						break;
					}
				}
			}
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			valid = -3;	// dimensionality error
		}
	}
	else if((nrows_A == 1) && (ncols_A > 1) && (nrows_B == ncols_A) && (ncols_B == nrows_A))	// A = row vec, B = col vec, of same length
	{
		if(m_iMultType == 0)			// Elemental op.
		{
			// MEMORY NEW
			nrows_R = nrows_A;
			ncols_R = ncols_A;
			R = new double *[nrows_R];		// allocate an array of ptrs-to-double
			for(i=0; i<nrows_R; i++)
			{
				R[i] = new double[ncols_R];	// allocate an array of doubles
			}

			if(sign == "*")
			{
				for(i=0; i<ncols_R; i++)
				{
					R[0][i] = A[0][i]*B[i][0];
				}
			}
			else if(sign == "/")
			{
				for(i=0; i<ncols_R; i++)
				{
					if(B[i][0] != 0)
					{
						R[0][i] = A[0][i]/B[i][0];
					}
					else
					{
						valid = -2;	// divide by zero error
						break;
					}
				}
			}	
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				// MEMORY NEW
				nrows_R = nrows_A;
				ncols_R = ncols_B;
				R = new double *[nrows_R];		// allocate an array of ptrs-to-double
				for(i=0; i<nrows_R; i++)
				{
					R[i] = new double[ncols_R];	// allocate an array of doubles
				}
			
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);		// (1xn)*(nx1) = (1x1)
			}
			else if(sign == "/")
			{
				valid = -3;	// dimensionality error, B non-square
			}
		}
	}
	else if((nrows_A > 1) && (ncols_A == 1) && (nrows_B == ncols_A) && (ncols_B == nrows_A))	// A = col vec, B = row vec, of same length
	{
		if(m_iMultType == 0) 				// Elemental op.
		{
			// MEMORY NEW
			nrows_R = nrows_A;
			ncols_R = ncols_A;
			R = new double *[nrows_R];		// allocate an array of ptrs-to-double
			for(i=0; i<nrows_R; i++)
			{
				R[i] = new double[ncols_R];	// allocate an array of doubles
			}

			if(sign == "*")
			{
				for(i=0; i<nrows_R; i++)
				{
					R[i][0] = A[i][0]*B[0][i];
				}
			}
			else if(sign == "/")
			{
				for(i=0; i<nrows_R; i++)
				{
					if(B[0][i] != 0)
					{
						R[i][0] = A[i][0]/B[0][i];
					}
					else
					{
						valid = -2;	// divide by zero error
						break;
					}
				}
			}	
		}
		else if(m_iMultType == 1)			// Matrix op.
		{
			if(sign == "*")
			{
				// MEMORY NEW
				nrows_R = nrows_A;
				ncols_R = ncols_B;
				R = new double *[nrows_R];		// allocate an array of ptrs-to-double
				for(i=0; i<nrows_R; i++)
				{
					R[i] = new double[ncols_R];	// allocate an array of doubles
				}
					
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);		// (nx1)*(1xn) = (nxn)
			}
			else if(sign == "/")
			{
				valid = -3;	// dimensionality error, B non-square
			}
		}
	}
	else if((nrows_A == 1) && (ncols_A > 1) && (nrows_B == 1) && (ncols_B != ncols_A))	// row vecs not of same length
	{
		valid = -3;	// dimensionality error
	}
	else if((nrows_A > 1) && (ncols_A == 1) && (nrows_B != nrows_A) && (ncols_B == 1))	// col vecs not of same length
	{
		valid = -3;	// dimensionality error
	}
	else if((nrows_A == 1) && (ncols_A > 1) && (nrows_B != ncols_A) && (ncols_B == 1))	// length of row vec A and col vec B not equal
	{
		valid = -3;	// dimensionality error
	}
	else if((nrows_A > 1) && (ncols_A == 1) && (nrows_B == 1) && (ncols_B != nrows_A))	// length of col vec A and row vec B not equal
	{
		valid = -3;	// dimensionality error
	}
	
	// -- A AND B ARE MATRICES --------------------------------------------------------------------
	else if((nrows_A == ncols_A) && (nrows_B == ncols_B) && (ncols_A == nrows_B))		// Square matrices of same dimensions
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_B;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		if(m_iMultType == 0)			// Elemental op.
		{
			if(sign == "*")
			{
				for(i=0; i<nrows_R; i++)
				{
					for(j=0; j<ncols_R; j++)
					{
						R[i][j] = A[i][j]*B[i][j];
					}
				}
			}
			else if(sign == "/")
			{
				for(i=0; i<nrows_R; i++)
				{
					for(j=0; j<ncols_R; j++)
					{
						if(B[i][j] != 0)
						{
							R[i][j] = A[i][j]/B[i][j];
						}
						else
						{
							valid = -2; // divide by zero error
							break;
						}
					}
					if(valid == -2)
					{
						break;
					}
				}
			}
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);
			}
			else if(sign == "/")
			{
				// MEMORY NEW
				B_inv = new double *[nrows_B];			// allocate an array of ptrs-to-double
				for(i=0; i<nrows_B; i++)
				{
					B_inv[i] = new double[ncols_B];		// allocate an array of doubles
				}

				// GAUSS-JORDAN ELIMINATION R.H.S. MATRIX (dummy vector here since there is no equation soln rqd.)
				GJ_RHS = new double *[nrows_B];			// allocate an array of ptrs-to-double
				for(i=0; i<nrows_B; i++)
				{
					GJ_RHS[i] = new double[ncols_GJ_RHS];	// allocate an array of doubles
				}

				// Copy B into B_inv
				for(i=0; i<nrows_B; i++)
				{
					for(j=0; j<ncols_B; j++)
					{
						B_inv[i][j] = B[i][j];
					}
				}

				// -- GAUSS-JORDAN ELIMINATION WITH FULL PIVOTING
				// B_inv starts off as B (see above assig.), then is overwritten with the inverse B^-1.
				// The r.h.s. matrix GJ_RHS is simply a dummy vector that is not used.
				valid = GaussJordanEliminationFullPivoting(B_inv, nrows_B, GJ_RHS, ncols_GJ_RHS);	

				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B_inv, R);

				// MEMORY DELETE
				for(i=0; i<nrows_B; i++)
				{
					delete [] B_inv[i];	// delete the row arrays
				}
				delete [] B_inv;		// delete the array (column vector) holding the row array
				
				for(i=0; i<nrows_B; i++)
				{
					delete [] GJ_RHS[i];	// delete the row arrays
				}
				delete [] GJ_RHS;		// delete the array (column vector) holding the row array
			}
		}
	}
	else if((nrows_A != ncols_A) && (ncols_A == nrows_B) && (nrows_B == ncols_B))	// A non-square, B square, inner dims equal, mult, divide, no element op.
	{
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_B;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}	

		if(m_iMultType == 0)			// Elemental op.
		{
			valid = -3;	// dimensionality error
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);
			}
			else if(sign == "/")		// B is square 
			{
				// MEMORY NEW
				B_inv = new double *[nrows_B];			// allocate an array of ptrs-to-double
				for(i=0; i<nrows_B; i++)
				{
					B_inv[i] = new double[ncols_B];		// allocate an array of doubles
				}

				// GAUSS-JORDAN ELIMINATION R.H.S. MATRIX (dummy vector here since there is no equation soln rqd.)
				GJ_RHS = new double *[nrows_B];			// allocate an array of ptrs-to-double
				for(i=0; i<nrows_B; i++)
				{
					GJ_RHS[i] = new double[ncols_GJ_RHS];	// allocate an array of doubles
				}

				// Copy B into B_inv
				for(i=0; i<nrows_B; i++)
				{
					for(j=0; j<ncols_B; j++)
					{
						B_inv[i][j] = B[i][j];
					}
				}

				// -- GAUSS-JORDAN ELIMINATION WITH FULL PIVOTING
				// B_inv starts off as B (see above assig.), then is overwritten with the inverse B^-1.
				// The r.h.s. matrix GJ_RHS is simply a dummy vector that is not used.
				valid = GaussJordanEliminationFullPivoting(B_inv, nrows_B, GJ_RHS, ncols_GJ_RHS);	

				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B_inv, R);

				// MEMORY DELETE
				for(i=0; i<nrows_B; i++)
				{
					delete [] B_inv[i];	// delete the row arrays
				}
				delete [] B_inv;		// delete the array (column vector) holding the row array	

				for(i=0; i<nrows_B; i++)
				{
					delete [] GJ_RHS[i];	// delete the row arrays
				}
				delete [] GJ_RHS;		// delete the array (column vector) holding the row array
			}
		}
	}
	else if((ncols_A == nrows_B) && (nrows_B != ncols_B))	// Inner dims equal, B non-square (mult, no divide, no element op.)
	{	
		// MEMORY NEW
		nrows_R = nrows_A;
		ncols_R = ncols_B;
		R = new double *[nrows_R];		// allocate an array of ptrs-to-double
		for(i=0; i<nrows_R; i++)
		{
			R[i] = new double[ncols_R];	// allocate an array of doubles
		}

		if(m_iMultType == 0)			// Elemental op.
		{
			valid = -3;	// dimensionality error
		}
		else if(m_iMultType == 1)		// Matrix op.
		{
			if(sign == "*")
			{
				MatrixMultiply(nrows_A, ncols_A, ncols_B, A, B, R);
			}
			else if(sign == "/")		
			{
				valid = -3;	// dimensionality error
			}
		}
	}
	else if(ncols_A != nrows_B)	// Matrices can't be multiplied or divided or operated upon
	{
		valid = -3;	// dimensionality error
	}
	
	// -- ERROR MESSAGES
	if(valid == -1)
	{
		sMsgTemp.Format("\n WARNING: error in usage of Divide-Multiply block!\n");
		sMsg+=sMsgTemp;		
		sMsgTemp.Format(" Check that the matrix to be inverted is not singular for division operation.\n");
		sMsg+=sMsgTemp;	
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
	}
	else if(valid == -2)
	{
		sMsgTemp.Format("\n WARNING: error in usage of Divide-Multiply block!\n");
		sMsg+=sMsgTemp;		
		sMsgTemp.Format(" Check that the denominator is not zero for division operation.\n");
		sMsg+=sMsgTemp;	
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
	}
	else if(valid == -3)
	{
		sMsgTemp.Format("\n WARNING: error in usage of Divide-Multiply block!\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format("\n Check data dimensionality of all inputs arguments.\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format(" Check the type of multiplication/division selected: Elemental or Matrix.\n");
		sMsg+=sMsgTemp;	
		sMsgTemp.Format(" Check the order of operations (top-down order of ports).\n");
		sMsg+=sMsgTemp;	
		AfxMessageBox(sMsg, nType, nIDhelp);	// msg. box
	}

	// -- FINALLY SET VALID TO -1 IF VALID < 0
	if(valid < 0)
	{
		valid = -1;	// generalized block operational error
	}

	// -- MEMORY DELETE
	// Note! Memory for R is deleted in the calling environment CDivideBlock::OperateOnData,
	// after re-assignment to "temp_matrix". Hence it should not be deleted here.
	
	// Return result: R = A operator B
	return R;	
}

double **COutputBlock::GetOutputMatrix() const
{
	return m_dOutputMatrix;
}

void COutputBlock::GetDataDimensions(int &nrows, int &ncols) const
{
	// Assign nrows and ncols
	nrows = m_iNrows;
	ncols = m_iNcols;
}

int COutputBlock::GetNotation() const
{
	return m_iNotation;
}

int CBlock::CheckBlockOutputSignalDataValidity()
{
	int valid = 0;				// (0) invalid, (1) valid
	list<CConnection*>::iterator it_con;	// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.
	vector<CPort*> vector_of_output_ports = GetVectorOfOutputPorts(); // vector of output ports

	// Get connection list
	list<CConnection*> &con_list = m_pParentSystemModel->GetConnectionList();	

	// -- CHECK OUTPUT CONNECTION SIGNAL DATA VALIDITY

	// Iterate over output ports
	for(it_port = vector_of_output_ports.begin(); it_port != vector_of_output_ports.end(); it_port++)	
	{
		// Iterate over list of connections
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// If connection attached to output port: either directly or INDIRECTLY through a bend point
			if((*it_con)->GetRefFromPort() == (*it_port))
			{
				// Get signal properties for this connection
				valid = (*it_con)->GetSignal()->GetSignalValidity();
				
				if(valid == 0)
				{
					return valid;
				}
			}
		}// end it_con
	}// end it_port
	
	return valid;	
}

void CBlock::AssignBlockOutputSignal()
{
	int i;
	int attached = 0;					// flag denoting the attachment of an output connection to a block output port
	int input = 0;						// input: (0) incomplete, (1) complete
	int ncols;							// no. of cols of data matrix
	int nrows;							// no. of rows of data matrix
	int valid;							// used to set signal validity
	double **matrix = NULL;				// data matrix
	CSignal *signal = NULL;				// local ptr-to-signal
	CString	sMsg;						// string msg. to be displayed
	CString sMsgTemp;					// temp string msg.
	UINT nType = MB_OK;					// style of msg. box
	UINT nIDhelp = 0;					// help context ID for the msg.
	list<CConnection*>::iterator it_con;// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.
	vector<CPort*> vector_of_output_ports = GetVectorOfOutputPorts(); // vector of output ports

	// Get connection list
	list<CConnection*> &con_list = m_pParentSystemModel->GetConnectionList();	

	// CHECK THAT THERE IS A CONNECTION ATTACHED TO THE OUTPUT PORT
	// Iterate over output ports
	for(it_port = vector_of_output_ports.begin(); it_port != vector_of_output_ports.end(); it_port++)	
	{
		// Iterate over list of connections
		attached = 0;
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// If connection attached to output port: either directly or INDIRECTLY through a bend point
			if((*it_con)->GetRefFromPort() == (*it_port))
			{
				attached = 1;
				break;
			}
		}
		if(!attached)
		{
			sMsgTemp.Format("\n WARNING! Output signal assignment problem.  \n");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Output connection must be connected to block to set output signal.  ");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Aborting output signal assignment.  \n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
			return;
		}
	}

	// SET REF-FROM-PORTS OF CONNECTIONS THAT EMANATE FROM BEND POINTS.
	// These ref-from-ports are then RESET to NULL at the end of the fn (since they don't actually emanate from a PORT).
	m_pParentSystemModel->SetRefFromPortOfConnectionFromBendPoint();

	// Create a dlg obj. of class COutputSignalDialog : public CDialog
	COutputSignalDialog oDlg;

	// GET OUTPUT SIGNAL
	// Iterate over output ports
	for(it_port = vector_of_output_ports.begin(); it_port != vector_of_output_ports.end(); it_port++)	
	{
		// Iterate over list of connections
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// If connection attached to output port: either directly or INDIRECTLY through a bend point
			if((*it_con)->GetRefFromPort() == (*it_port))
			{
				// GET THE ptr-to-CSignal OBJECT OF THE OUTPUT CONNECTION.
				// Note: there could be more than one CConnection object with its CSignal data connected 
				// to the current block's output port. But here the first CSignal object is retrieved,
				// since all CSignal data on CConnection objects associated with the current output port
				// will have identical data. Below, an update of all CConnection objects whose reference-from
				// port is the current output port will have their CSignal data updated individually.
				signal = (*it_con)->GetSignal();								
				break;				
			}
		}
	}

	// Set the COutputSignalDialog var using the CSignal var
	oDlg.m_strOutputSignal = signal->GetOutputSignalString();

	// WHILE NOT CORRECT INPUT
	while(input == 0)
	{
		// DISPLAY DIALOG TO USER USING DoModal() FN
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK)
		{
			// Assign COutputSignalDialog variable values to CSignal variable values.
			signal->SetOutputSignalString(oDlg.m_strOutputSignal);

			// Convert the input string into a double matrix and assign it below.
			matrix = ConvertStringToDouble(oDlg.m_strOutputSignal, nrows, ncols);
			//PrintMatrix(matrix, nrows, ncols);

			if(oDlg.m_strOutputSignal == "")	// Intentional setting of a NULL signal using an empty string
			{
				signal->ResetSignalData();
				input = 1;
			}
			else if(matrix == NULL)				// Unintentional setting of a NULL signal and hence re-enter string
			{
				sMsgTemp.Format("\n WARNING!: Incorrect signal input.  \n");
				sMsg += sMsgTemp;
				sMsgTemp.Format("\n Please enter consistent numerical data.  \n");
				sMsg += sMsgTemp;
				AfxMessageBox(sMsg, nType, nIDhelp);
				sMsg.Format("");	// reset the msg since within a while loop

				input = 0;
			}
			else	// Non-NULL input
			{
				// UPDATE ALL CONNECTION OBJECTS WHOSE REFERENCE-FROM PORT IS THAT OF THE CURRENT BLOCK'S OUTPUT PORT			
				valid = WriteDataToOutputSignal(matrix, nrows, ncols);

				// Matrix is non-NULL implying valid user input.
				input = 1;

			}// end if-else
		}
		else // IDCANCEL is the only other return value from DoModal().
		{
			// Cancel signal data setting operation: no action to be taken (at present).
		}
	}
	
	// -- RESET ALL REF-FROM-PORTS OF CONNECTIONS EMANATING FROM BEND POINTS BACK TO NULL
	// Before AssignBlockOutputSignal() was called the ref-from-ports of connections emanating from bend points
	// were NULL. Now they need to be reset to NULL, to leave the program state as it was previously.
	for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
	{
		if((*it_con)->GetRefFromPoint() != NULL)	// if connection attached to a BEND POINT
		{	
			(*it_con)->SetRefFromPort(NULL);		// set ref-from-port to NULL (since not attached to a block)
		}
	}

	// MEMORY DELETE
	if(matrix != NULL)
	{
		for(i=0; i<nrows; i++)
		{
			delete [] matrix[i];
		}
		delete [] matrix;
		matrix = NULL;
	}
}

void CDerivativeBlock::ResetBlockData()
{
	int i;

	// Reinitialize member vars
	m_iNcallsPerTimeCnt = 0;		// no. of times the fn is called per t_cnt (time point)
	m_i_t_cnt_ref = 0;				// ref time cnt 

	// MEMORY DELETE
	if(m_dMatrixOut != NULL)
	{
		for(i=0; i<m_iNrows; i++)
		{
			delete [] m_dMatrixOut[i];	// delete the row arrays
		}
		delete [] m_dMatrixOut;			// delete the array (column vector) holding the row arrays
		m_dMatrixOut = NULL;
	}

	if(m_f_at_t_minus_h != NULL)
	{
		delete [] m_f_at_t_minus_h;		// delete member var array f(t-h) holding all signal's f(t-h) values		
		m_f_at_t_minus_h = NULL;
	}
	if(m_f_at_t_minus_2h != NULL)
	{
		delete [] m_f_at_t_minus_2h;	// delete member var array f(t-2h) holding all signal's f(t-2h) values		
		m_f_at_t_minus_2h = NULL;
	}
}

void CBlock::ResetBlockData(void)
{
	// This fn has been made virtual and is to be overridden by all derived CBlock classes.

	//AfxMessageBox("\n CBlock::ResetBlockData()    \n", MB_OK, 0);

	return;
}

void CIntegratorBlock::ResetBlockData(void)
{
	int i;

	// Reinitialize member vars
	m_iNcallsPerTimeCnt = 0;		// no. of times the fn is called per t_cnt (time point)
	m_i_t_cnt_ref = 0;				// ref time cnt 

	// MEMORY DELETE
	if(m_dMatrixOut != NULL)
	{
		for(i=0; i<m_iNrowsOut; i++)
		{
			delete [] m_dMatrixOut[i];// delete the row arrays
		}
		delete [] m_dMatrixOut;		// delete the array (column vector) holding the row arrays
		m_dMatrixOut = NULL;
	}

	if(m_y_at_t_minus_h != NULL)
	{
		delete [] m_y_at_t_minus_h;	// delete member var array f(t-h) holding all signal's f(t-h) values		
		m_y_at_t_minus_h = NULL;
	}
	if(m_y_dot_at_t_minus_h != NULL)
	{
		delete [] m_y_dot_at_t_minus_h;	// delete member var array f(t-2h) holding all signal's f(t-2h) values		
		m_y_dot_at_t_minus_h = NULL;
	}
}

int COutputBlock::GetTimePtDisplay() const
{
	return m_iTimePtDisplay;
}

void CBlock::WriteBlockDataToFile(ofstream &fout)
{
	char strBlockName[L_FILE_IO_STR];	// local string reflecting m_strBlockName
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.

	//AfxMessageBox("\n CBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file.
	strcpy(strBlockName, m_strBlockName);
	fout << strBlockName << endl;
	fout << m_ptBlockPosition.x << " " << m_ptBlockPosition.y << endl;
	fout << m_vecInputPorts.size() << " " << m_vecOutputPorts.size() << endl;

	// Write CBlockShape member data to file
	m_BlockShape.WriteBlockShapeDataToFile(fout);

	// Write CPort member data to file
	// Input ports
	for(it_port = m_vecInputPorts.begin(); it_port != m_vecInputPorts.end(); it_port++)
	{
		(*it_port)->WritePortDataToFile(fout);
	}

	// Output ports
	for(it_port = m_vecOutputPorts.begin(); it_port != m_vecOutputPorts.end(); it_port++)
	{
		(*it_port)->WritePortDataToFile(fout);
	}
}

void CBlock::ReadBlockDataFromFile(ifstream &fin)
{
	int i;
	int n_extra_ports;					// no. of extra input ports than the constructed amount
	int n_input_ports;					// no. of input ports
	int n_output_ports;					// no. of output ports
	char strBlockName[L_FILE_IO_STR];	// local string reflecting m_strBlockName
	CPort *p_port = NULL;				// pointer-to-CPort
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.

	//AfxMessageBox("\n CBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// READ CBlock MEMBER DATA FROM FILE
	fin >> strBlockName;
	m_strBlockName = strBlockName;
	fin >> m_ptBlockPosition.x >> m_ptBlockPosition.y;
	fin >> n_input_ports >> n_output_ports;

	// READ CBlockShape MEMBER DATA FROM FILE
	m_BlockShape.ReadBlockShapeDataFromFile(fin);

	// READ CPort MEMBER DATA FROM FILE
	// Add more ports to block if necessary: the CSumBlock and CDivideBlock could have more ports than the constructed amount
	n_extra_ports = n_input_ports - m_vecInputPorts.size();

	if(n_extra_ports > 0)
	{
		for(i=0; i<n_extra_ports; i++)
		{
			p_port = new CPort(*this);
			m_vecInputPorts.push_back(p_port);
		}
	}

	// Input ports
	for(it_port = m_vecInputPorts.begin(); it_port != m_vecInputPorts.end(); it_port++)
	{
		(*it_port)->ReadPortDataFromFile(fin);
	}

	// Output ports
	for(it_port = m_vecOutputPorts.begin(); it_port != m_vecOutputPorts.end(); it_port++)
	{
		(*it_port)->ReadPortDataFromFile(fin);
	}
}

void CBlockShape::WriteBlockShapeDataToFile(ofstream &fout)
{
	//AfxMessageBox("\n CBlockShape::WriteBlockShapeDataToFile()\n", MB_OK, 0);
	
	// Write CBlockShape member data to file.
	fout << m_dBlockWidth << " " << m_dBlockHeight << endl;
	fout << m_eBlockShape << endl;
	fout << m_eBlockDirection << endl;
}

void CBlockShape::ReadBlockShapeDataFromFile(ifstream &fin)
{
	int l_e_block_shape;		// local EBlockShape 
	int l_e_block_direction;	// local EBlockDirectione

	//AfxMessageBox("\n CBlockShape::ReadBlockShapeDataFromFile()\n", MB_OK, 0);

	// Read CBlockShape member data from file
	fin >> m_dBlockWidth >> m_dBlockHeight;

	fin >> l_e_block_shape;
	m_eBlockShape = static_cast<EBlockShape>(l_e_block_shape);

	fin >> l_e_block_direction;
	m_eBlockDirection = static_cast<EBlockDirection>(l_e_block_direction);
}

void CConstantBlock::WriteBlockDataToFile(ofstream &fout)
{
	int i;
	int j;

	//AfxMessageBox("\n CConstantBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CConstantBlock member data to file.
	fout << m_iNrows << endl;
	fout << m_iNcols << endl;
	
	for(i=0; i<m_iNrows; i++)
	{
		for(j=0; j<m_iNcols; j++)
		{
			fout << m_dConstMatrix[i][j] << " ";
		}
		fout << endl;
	}
}

void CConstantBlock::ReadBlockDataFromFile(ifstream &fin)
{
	int i;
	int j;

	//AfxMessageBox("\n CConstantBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// MEMORY DELETE - delete data matrix whose memory was allocated in CConstantBlock::CConstantBlock()
	if(m_dConstMatrix != NULL)
	{
		for(i=0; i<m_iNrows; i++)
		{
			delete [] m_dConstMatrix[i];
		}
		delete [] m_dConstMatrix;
	}
	
	// Reset member vars.
	m_dConstMatrix = NULL;
	m_iNrows = 0;
	m_iNcols = 0;
	
	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CConstantBlock member data from file
	fin >> m_iNrows;
	fin >> m_iNcols;

	// MEMORY NEW - allocate memory to hold data being read in from a file
	m_dConstMatrix = new double *[m_iNrows];
	for(i=0; i<m_iNrows; i++)
	{
		m_dConstMatrix[i] = new double[m_iNcols];			// allocate an array of doubles, return & to matrix[i]	}
	}

	// Read in the constant matrix
	for(i=0; i<m_iNrows; i++)
	{
		for(j=0; j<m_iNcols; j++)
		{
			fin >> m_dConstMatrix[i][j];
		}
	}

	// Assign the member string using the double data
	ConvertDoubleMatrixToString(m_strConstValue, m_dConstMatrix, m_iNrows, m_iNcols);
}
	

void CDerivativeBlock::WriteBlockDataToFile(ofstream &fout)
{
	//AfxMessageBox("\n CDerivativeBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CDerivativeBlock member data to file.
	fout << m_iDerivativeMethod << endl;
}

void CDerivativeBlock::ReadBlockDataFromFile(ifstream &fin)
{
	//AfxMessageBox("\n CDerivativeBlock::ReadBlockDataFromFile()\n", MB_OK, 0);
	
	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CDerivativeBlock member data to file.
	fin >> m_iDerivativeMethod;
}

void CDivideBlock::WriteBlockDataToFile(ofstream &fout)
{
	int i;
	int j;

	//AfxMessageBox("\n CDivideBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CDivideBlock member data to file.
	fout << m_iNDivideInputs << endl;
	fout << m_iNMultiplyInputs << endl;
	fout << m_iMultType << endl;

	// Write CDivideBlock initial signal data to file (only numerical not CString)
	fout << m_iNrowsInitSignal << endl;
	fout << m_iNcolsInitSignal << endl;
	for(i=0; i<m_iNrowsInitSignal; i++)
	{
		for(j=0; j<m_iNcolsInitSignal; j++)
		{
			fout << m_dInitSignal[i][j] << " ";
		}
		fout << endl;
	}
}

void CDivideBlock::ReadBlockDataFromFile(ifstream &fin)
{
	int i;
	int j;

	//AfxMessageBox("\n CDivideBlock::ReadBlockDataFromFile()\n", MB_OK, 0);
	
	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CDivideBlock member data from file.
	fin >> m_iNDivideInputs;
	fin >> m_iNMultiplyInputs;
	fin >> m_iMultType;

	// Read CDivideBlock initial signal data from file (only numerical not CString)
	fin >> m_iNrowsInitSignal;
	fin >> m_iNcolsInitSignal;

	// MEMORY NEW - Allocate memory to hold data being read in from a file
	m_dInitSignal = new double *[m_iNrowsInitSignal];
	for(i=0; i<m_iNrowsInitSignal; i++)
	{
		m_dInitSignal[i] = new double[m_iNcolsInitSignal];	// allocate an array of doubles, return & to matrix[i]	}
	}

	// Read in the signal matrix
	for(i=0; i<m_iNrowsInitSignal; i++)
	{
		for(j=0; j<m_iNcolsInitSignal; j++)
		{
			fin >> m_dInitSignal[i][j];
		}
	}

	// Assign the member string using the double data
	ConvertDoubleMatrixToString(m_strInitSignal, m_dInitSignal, m_iNrowsInitSignal, m_iNcolsInitSignal);
}

void CPort::WritePortDataToFile(ofstream &fout)
{
	char strPortName[L_FILE_IO_STR];	// char array reflecting m_strPortName
	
	//AfxMessageBox("\n CPort::WritePortDataToFile()\n", MB_OK, 0);
	
	// Write CPort member data to file
	strcpy(strPortName, GetPortName());
	fout << GetPortPositionAngle() << " " << strPortName << endl;
	fout << m_ePortArrowDirec << endl;
}

void CPort::ReadPortDataFromFile(ifstream &fin)
{
	int l_e_port_arrow_direc;				// local port arrow direction
	char strPortName[L_FILE_IO_STR];	// char array reflecting m_strPortName

	//AfxMessageBox("\n CPort::ReadPortDataFromFile()\n", MB_OK, 0);

	// Read CPort member data from file
	fin >>  m_dPortPositionAngle >> strPortName;
	m_strPortName = strPortName;

	fin >> l_e_port_arrow_direc;
	m_ePortArrowDirec = static_cast<EPortArrowDirection>(l_e_port_arrow_direc);

	// Calculate the port position based on the m_dPortPositionAngle (already having been set)
	CalculatePortPosition();
}

void CGainBlock::WriteBlockDataToFile(ofstream &fout)
{
	int i;
	int j;

	//AfxMessageBox("\n CGainBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CGainBlock member data to file.
	fout << m_iGainType << endl;
	fout << m_iNrows << endl;
	fout << m_iNcols << endl;
	
	for(i=0; i<m_iNrows; i++)
	{
		for(j=0; j<m_iNcols; j++)
		{
			fout << m_dGainMatrix[i][j] << " ";
		}
		fout << endl;
	}
}

void CGainBlock::ReadBlockDataFromFile(ifstream &fin)
{
	int i;
	int j;

	//AfxMessageBox("\n CGainBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// MEMORY DELETE - delete data matrix whose memory was allocated in CGainBlock::CGainBlock()
	if(m_dGainMatrix != NULL)
	{
		for(i=0; i<m_iNrows; i++)
		{
			delete [] m_dGainMatrix[i];
		}
		delete [] m_dGainMatrix;
	}
	
	// Reset member vars.
	m_dGainMatrix = NULL;
	m_iNrows = 0;
	m_iNcols = 0;
	
	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CGainBlock member data from file.
	fin >> m_iGainType;
	fin >> m_iNrows;
	fin >> m_iNcols;

	// MEMORY NEW - allocate memory to hold data being read in from a file
	m_dGainMatrix = new double *[m_iNrows];
	for(i=0; i<m_iNrows; i++)
	{
		m_dGainMatrix[i] = new double[m_iNcols];			// allocate an array of doubles, return & to matrix[i]	}
	}

	// Read in the gain matrix
	for(i=0; i<m_iNrows; i++)
	{
		for(j=0; j<m_iNcols; j++)
		{
			fin >> m_dGainMatrix[i][j];
		}
	}

	// Assign the member string using the double data
	ConvertDoubleMatrixToString(m_strGainValue, m_dGainMatrix, m_iNrows, m_iNcols);
}

void CIntegratorBlock::WriteBlockDataToFile(ofstream &fout)
{
	int i;
	
	//AfxMessageBox("\n CIntegratorBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CIntegratorBlock member data to file.
	fout << m_iLength << endl;
	
	for(i=0; i<m_iLength; i++)
	{
		fout << m_dICVector[i] << " ";
	}
	fout << endl;
}

void CIntegratorBlock::ReadBlockDataFromFile(ifstream &fin)
{
	int i;

	//AfxMessageBox("\n CIntegratorBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// MEMORY DELETE
	if(m_dICVector != NULL)
	{
		delete [] m_dICVector;
	}

	// Reset member vars
	m_dICVector = NULL;
	m_iLength = 0;

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CIntegratorBlock member data from file
	fin >> m_iLength;

	// MEMORY NEW
	m_dICVector = new double[m_iLength];

	// Read in the initial condition vector
	for(i=0; i<m_iLength; i++)
	{
		fin >> m_dICVector[i];
	}

	// Assign the member string using the double data
	ConvertDoubleVectorToString(m_strICVector, m_dICVector, m_iLength);
}

void CLinearFnBlock::WriteBlockDataToFile(ofstream &fout)
{
	//AfxMessageBox("\n CLinearFnBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CLinearFnBlock member data to file.
	fout << m_dDerivative << endl;
	fout << m_dTimeInit << endl;
	fout << m_dTimeFinal << endl;
	fout << m_dValueInit << endl;
}

void CLinearFnBlock::ReadBlockDataFromFile(ifstream &fin)
{
	//AfxMessageBox("\n CLinearFnBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CLinearFnBlock member data from file.
	fin >> m_dDerivative;
	fin >> m_dTimeInit;
	fin >> m_dTimeFinal;
	fin >> m_dValueInit;
}

void COutputBlock::WriteBlockDataToFile(ofstream &fout)
{
	//AfxMessageBox("\n COutputBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write COutputBlock member data to file.
	fout << m_iNotation << endl;
	fout << m_iTimePtDisplay << endl;
}

void COutputBlock::ReadBlockDataFromFile(ifstream &fin)
{
	//AfxMessageBox("\n COutputBlock::ReadBlockDataFromFile()\n", MB_OK, 0);
	
	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read COutputBlock member data from file.
	fin >> m_iNotation;
	fin >> m_iTimePtDisplay;
}

void CSignalGeneratorBlock::WriteBlockDataToFile(ofstream &fout)
{
	char strData[L_FILE_IO_STR];	// char array reflecting member CString data

	//AfxMessageBox("\n CSignalGeneratorBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CSignalGeneratorBlock member data to file
	fout << m_dAmplitude << endl;
	fout << m_dFrequency << endl;
	fout << m_dPhase << endl;

	strcpy(strData, m_strFnType);
	fout << strData << endl;

	strcpy(strData, m_strUnits);
	fout << strData << endl;
}

void CSignalGeneratorBlock::ReadBlockDataFromFile(ifstream &fin)
{
	char strVar[L_FILE_IO_STR];		// character array var to work with "fin >>"

	//AfxMessageBox("\n CSignalGeneratorBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CSignalGeneratorBlock member data from file
	fin >> m_dAmplitude;
	fin >> m_dFrequency;
	fin >> m_dPhase;

	// Note: geline() is used here since the string may consist of blank spaces.
	// Fn type
	while(fin.getline(strVar, L_FILE_IO_STR, '\n'))
	{
		// If strVar not an empty string then assume the string is the complete identifier on the line
		if(strcmp(strVar, "") != 0)		
		{
			m_strFnType = strVar;
			break;
		}
	}

	// Units
	while(fin.getline(strVar, L_FILE_IO_STR, '\n'))
	{
		// If strVar not an empty string then assume the string is the complete identifier on the line
		if(strcmp(strVar, "") != 0)		
		{
			m_strUnits = strVar;
			break;
		}
	}
}

void CSubsystemBlock::WriteBlockDataToFile(ofstream &fout)
{
	char strPortName[L_FILE_IO_STR];	// char array reflecting the input and output port names

	//AfxMessageBox("\n CSubsystemBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CSubsystemBlock member data to file
	strcpy(strPortName, m_strInputPortName);
	fout << strPortName << endl;

	strcpy(strPortName, m_strOutputPortName);
	fout << strPortName << endl;
}

void CSubsystemBlock::ReadBlockDataFromFile(ifstream &fin)
{
	char strVar[L_FILE_IO_STR];		// character array var to work with "fin >>"

	//AfxMessageBox("\n CSubsystemBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CSubsystemBlock member data from file
	// Note: geline() is used here since the name the user enters may consist of blank spaces.

	// Input port name
	while(fin.getline(strVar, L_FILE_IO_STR, '\n'))
	{
		// If strVar not an empty string then assume the string is the complete name on the line
		if(strcmp(strVar, "") != 0)		
		{
			m_strInputPortName = strVar;
			break;
		}
	}
	
	// Output port name
	while(fin.getline(strVar, L_FILE_IO_STR, '\n'))
	{	
		// If strVar not an empty string then assume the string is the complete name on the line
		if(strcmp(strVar, "") != 0)		
		{
			m_strOutputPortName = strVar;
			break;
		}
	}
}

void CSubsystemInBlock::WriteBlockDataToFile(ofstream &fout)
{
	char strPortName[L_FILE_IO_STR];	// char array reflecting the input port name

	//AfxMessageBox("\n CSubsystemInBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CSubsystemInBlock member data to file
	strcpy(strPortName, m_strInputPortName);
	fout << strPortName << endl;
}

void CSubsystemInBlock::ReadBlockDataFromFile(ifstream &fin)
{
	char strVar[L_FILE_IO_STR];		// character array var to work with "fin >>"

	//AfxMessageBox("\n CSubsystemInBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Input port name
	while(fin.getline(strVar, L_FILE_IO_STR, '\n'))
	{
		// If strVar not an empty string then assume the string is the complete name on the line
		if(strcmp(strVar, "") != 0)		
		{
			m_strInputPortName = strVar;
			break;
		}
	}
}

void CSubsystemOutBlock::WriteBlockDataToFile(ofstream &fout)
{
	char strPortName[L_FILE_IO_STR];	// char array reflecting the output port name

	//AfxMessageBox("\n CSubsystemOutBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CSubsystemOutBlock member data to file
	strcpy(strPortName, m_strOutputPortName);
	fout << strPortName << endl;
}

void CSubsystemOutBlock::ReadBlockDataFromFile(ifstream &fin)
{
	char strVar[L_FILE_IO_STR];		// character array var to work with "fin >>"

	//AfxMessageBox("\n CSubsystemOutBlock::ReadBlockDataFromFile()\n", MB_OK, 0);

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Input port name
	while(fin.getline(strVar, L_FILE_IO_STR, '\n'))
	{
		// If strVar not an empty string then assume the string is the complete name on the line
		if(strcmp(strVar, "") != 0)		
		{
			m_strOutputPortName = strVar;
			break;
		}
	}
}

void CSumBlock::WriteBlockDataToFile(ofstream &fout)
{
	//AfxMessageBox("\n CSumBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CSumBlock member data to file
	fout << m_iNAddInputs << endl;
	fout << m_iNSubtractInputs << endl;
}

void CSumBlock::ReadBlockDataFromFile(ifstream &fin)
{
	//AfxMessageBox("\n CSumBlock::ReadBlockDataFromFile()\n", MB_OK, 0);
	
	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CSumBlock member data from file
	fin >> m_iNAddInputs;
	fin >> m_iNSubtractInputs;
}

void CTransferFnBlock::WriteBlockDataToFile(ofstream &fout)
{
	int i;
	
	//AfxMessageBox("\n CTransferFnBlock::WriteBlockDataToFile()\n", MB_OK, 0);
	
	// Write CBlock member data to file
	CBlock::WriteBlockDataToFile(fout);

	// Write CTransferFnBlock member data to file
	fout << m_iLengthNumer << endl;
	fout << m_iLengthDenom << endl;

	for(i=0; i<m_iLengthNumer; i++)
	{
		fout << m_dNumerVector[i] << " ";
	}
	fout << endl;

	for(i=0; i<m_iLengthDenom; i++)
	{
		fout << m_dDenomVector[i] << " ";
	}
	fout << endl;
}

void CTransferFnBlock::ReadBlockDataFromFile(ifstream &fin)
{
	int i;

	//AfxMessageBox("\n CTransferFnBlock::ReadBlockDataFromFile()\n", MB_OK, 0);
	
	// MEMORY DELETE
	if(m_dNumerVector != NULL)
	{
		delete [] m_dNumerVector;
	}

	if(m_dDenomVector != NULL)
	{
		delete [] m_dDenomVector;
	}

	// Reset member vars
	m_dNumerVector = NULL;
	m_dDenomVector = NULL;
	m_iLengthNumer = 0;
	m_iLengthDenom = 0;

	// Read CBlock member data from file
	CBlock::ReadBlockDataFromFile(fin);

	// Read CTransferfnBlock member data from file
	fin >> m_iLengthNumer;
	fin >> m_iLengthDenom;

	// MEMORY NEW
	m_dNumerVector = new double[m_iLengthNumer];
	m_dDenomVector = new double[m_iLengthDenom];

	// Read in the coefficient vectors
	for(i=0; i<m_iLengthNumer; i++)
	{
		fin >> m_dNumerVector[i];
	}
	for(i=0; i<m_iLengthDenom; i++)
	{
		fin >> m_dDenomVector[i];
	}

	// Assign the member string using the double data
	ConvertDoubleVectorToString(m_strNumerCoeffs, m_dNumerVector, m_iLengthNumer);
	ConvertDoubleVectorToString(m_strDenomCoeffs, m_dDenomVector, m_iLengthDenom);
}

void COutputBlock::WriteNumericalOutputDataToFile(ofstream &fout)
{
	int j;
	int col;				// column no.
	int n_data_pts;			// no. of data points per signal
	int n_signals_per_row;	// no. of signals per row of m_dOutputMatrix
	int n_TimeSteps;		// no. of simulation time steps
	int sig;				// signal no.
	int t_cnt;				// time-based counter
	double delta_t;			// time step size of simulation
	double t;				// time pt
	double t_final;			// final simulation time
	double t_init;			// initial simulation time
	CString sMsg;			// main msg string
	CString sMsgTemp;		// temp msg string
	UINT nType = MB_OK;		// style of msg. box
	UINT nIDhelp = 0;		// help context ID for the msg.

	//sMsg.Format("\n COutputBlock::WriteNumericalOutputDataToFile()\n");
	//AfxMessageBox(sMsg, nType, nIDhelp);

	// GET TIME DATA
	GetParentSystemModel()->GetTimeParameters(t_init, t_final, delta_t);	// passing time parameters by reference
	n_TimeSteps = GetParentSystemModel()->DetermineNTimeSteps();
	n_data_pts = n_TimeSteps + 1;

	// NUMBER OF INDEP CURVES PER ROW OF DATA
	// e.g. F(t) = [ [f1(t0), f2(t0)], [f1(t1), f2(t1)], ... , [f1(tn), f2(tn)] ], n_signals_per_row = 2: f1(t) and f2(t)
	n_signals_per_row = m_iNcols/n_data_pts;	

	// FOR EACH DATA/TIME POINT OF A SIGNAL
	for(t_cnt=0; t_cnt<n_data_pts; t_cnt++)
	{
		t = t_init + t_cnt*delta_t;		// time value is a multiple of the time step size

		fout << t << "\t";				// first column of output is time

		// FOR EACH ROW OF m_dOutputMatrix EQUIVALENTLY EACH ROW OF THE SUBMATRIX WITHIN m_dOutputMatrix
		for(j=0; j<m_iNrows; j++)	
		{
			// FOR EACH SIGNAL ON A ROW
			for(sig=0; sig<n_signals_per_row; sig++)		// for one or more signals per row
			{
				col = sig + t_cnt*n_signals_per_row;		// colum no. of m_dOutputMatrix extracting correct signal's data
				fout << m_dOutputMatrix[j][col] << "\t";	// all signals printed out on one row for current time point

				//sMsg.Format("\n t_cnt = %d, j = %d, sig = %d, col = %d, f = %lf\n", t_cnt, j, sig, col, m_dOutputMatrix[j][col]);
				//AfxMessageBox(sMsg, nType, nIDhelp);
			}
		}
		fout << endl;	// new line for each time point
	}
}

void CDivideBlock::AssignBlockOutputSignal()
{
	int i;
	int attached = 0;					// flag denoting the attachment of an output connection to a block output port
	int input = 0;						// input: (0) incomplete, (1) complete
	int valid;							// used to set signal validity
	CSignal *signal = NULL;				// local ptr-to-signal
	CString	sMsg;						// string msg. to be displayed
	CString sMsgTemp;					// temp string msg.
	UINT nType = MB_OK;					// style of msg. box
	UINT nIDhelp = 0;					// help context ID for the msg.
	list<CConnection*>::iterator it_con;// iterator for list of CConnection ptrs.
	vector<CPort*>::iterator it_port;	// iterator for vector of CPort ptrs.
	vector<CPort*> vector_of_output_ports = GetVectorOfOutputPorts(); // vector of output ports

	// Get connection list
	CDiagramEngDoc *pDoc = GetDocumentGlobalFn();
	list<CConnection*> &con_list = GetParentSystemModel()->GetConnectionList();	

	// CHECK THAT THERE IS A CONNECTION ATTACHED TO THE OUTPUT PORT
	// Iterate over output ports
	for(it_port = vector_of_output_ports.begin(); it_port != vector_of_output_ports.end(); it_port++)	
	{
		// Iterate over list of connections
		attached = 0;
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// If connection attached to output port: either directly or INDIRECTLY through a bend point
			if((*it_con)->GetRefFromPort() == (*it_port))
			{
				attached = 1;
				break;
			}
		}
		if(!attached)
		{
			sMsgTemp.Format("\n WARNING! Output signal assignment problem.  \n");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Output connection must be connected to block to set output signal.  ");
			sMsg += sMsgTemp;
			sMsgTemp.Format("\n Aborting output signal assignment.  \n");
			sMsg += sMsgTemp;
			AfxMessageBox(sMsg, nType, nIDhelp);
			sMsg.Format("");	// reset the msg since within a while loop
			return;
		}
	}

	// SET REF-FROM-PORTS OF CONNECTIONS THAT EMANATE FROM BEND POINTS.
	// These ref-from-ports are then RESET to NULL at the end of the fn (since they don't actually emanate from a PORT).
	GetParentSystemModel()->SetRefFromPortOfConnectionFromBendPoint();

	// MEMORY DELETE
	if(m_dInitSignal != NULL)
	{
		for(i=0; i<m_iNrowsInitSignal; i++)
		{
			delete [] m_dInitSignal[i];
		}
		delete [] m_dInitSignal;

		m_dInitSignal = NULL;
		m_iNrowsInitSignal = 0;
		m_iNcolsInitSignal = 0;
		// NOTE: m_strInitSignal is not set to empty, since its value is used to setup the new matrix m_dInitSignal
	}
	
	// GET OUTPUT SIGNAL
	// Iterate over output ports
	for(it_port = vector_of_output_ports.begin(); it_port != vector_of_output_ports.end(); it_port++)	
	{
		// Iterate over list of connections
		for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)	
		{
			// If connection attached to output port: either directly or INDIRECTLY through a bend point
			if((*it_con)->GetRefFromPort() == (*it_port))
			{
				// GET THE ptr-to-CSignal OBJECT OF THE OUTPUT CONNECTION.
				// Note: there could be more than one CConnection object with its CSignal data connected 
				// to the current block's output port. But here the first CSignal object is retrieved,
				// since all CSignal data on CConnection objects associated with the current output port
				// will have identical data. Below, an update of all CConnection objects whose reference-from
				// port is the current output port will have their CSignal data updated individually.
				signal = (*it_con)->GetSignal();								
				break;				
			}
		}
	}

	// Create a dlg obj. of class COutputSignalDialog : public CDialog
	COutputSignalDialog oDlg;

	// Set the COutputSignalDialog var using the CDivideBlock var
	oDlg.m_strOutputSignal = m_strInitSignal;

	// WHILE NOT CORRECT INPUT
	while(input == 0)
	{
		// DISPLAY DIALOG TO USER USING DoModal() FN
		// Return val of DoModal() fn of ancestor class CDialog is checked to determine which btn was clicked.
		if(oDlg.DoModal() == IDOK)
		{
			// Assign COutputSignalDialog variable values to CDivideBlock variable values.
			m_strInitSignal = oDlg.m_strOutputSignal;

			// Convert the input string into a double matrix and assign it below.
			m_dInitSignal = ConvertStringToDouble(m_strInitSignal, m_iNrowsInitSignal, m_iNcolsInitSignal);
			//PrintMatrix(matrix, nrows, ncols);

			if(oDlg.m_strOutputSignal == "")	// Intentional setting of a NULL signal using an empty string
			{
				signal->ResetSignalData();
				m_iNrowsInitSignal = 0;
				m_iNcolsInitSignal = 0;
				// m_dInitSignal will already be NULL as returned from ConvertStringToDouble() if string is empty.
				input = 1;
			}
			else if(m_dInitSignal == NULL)		// Unintentional setting of a NULL signal and hence re-enter string
			{
				sMsgTemp.Format("\n WARNING!: Incorrect signal input.  \n");
				sMsg += sMsgTemp;
				sMsgTemp.Format("\n Please enter consistent numerical data.  \n");
				sMsg += sMsgTemp;
				AfxMessageBox(sMsg, nType, nIDhelp);
				sMsg.Format("");	// reset the msg since within a while loop

				input = 0;
			}
			else	// Non-NULL input
			{
				// UPDATE ALL CONNECTION OBJECTS WHOSE REFERENCE-FROM PORT IS THAT OF THE CURRENT BLOCK'S OUTPUT PORT			
				valid = WriteDataToOutputSignal(m_dInitSignal, m_iNrowsInitSignal, m_iNcolsInitSignal);

				// Matrix is non-NULL implying valid user input.
				input = 1;

			}// end if-else

			// Set the doc as having been modified to prompt to save.
			pDoc->SetModifiedFlag(TRUE); 	
		}
		else // IDCANCEL is the only other return value from DoModal().
		{
			// Cancel signal data setting operation: no action to be taken (at present).
			input = 1;
		}
	}

	// -- RESET ALL REF-FROM-PORTS OF CONNECTIONS EMANATING FROM BEND POINTS BACK TO NULL
	// Before AssignBlockOutputSignal() was called the ref-from-ports of connections emanating from bend points
	// were NULL. Now they need to be reset to NULL, to leave the program state as it was previously.
	for(it_con = con_list.begin(); it_con != con_list.end(); it_con++)
	{
		if((*it_con)->GetRefFromPoint() != NULL)	// if connection attached to a BEND POINT
		{	
			(*it_con)->SetRefFromPort(NULL);		// set ref-from-port to NULL (since not attached to a block)
		}
	}

	// MEMORY DELETE
	// m_dInitSignal is deleted upon entry into this fn and then in the CDivideBlock destructor.
}

double** CDivideBlock::GetInitialSignalMatrix(int &nrows, int &ncols)
{
	// Assign the member variables
	nrows = m_iNrowsInitSignal;
	ncols = m_iNcolsInitSignal;

	// Return the signal matrix, regardless of whether it is NULL or not.
	return m_dInitSignal;
}

CSystemModel* CBlock::GetParentSystemModel() const
{
	// Return the parent system model that contains the list of blocks and connections
	return m_pParentSystemModel;
}

CBlock *CBlock::CopyBlockData()
{
	return NULL;	// derived block class will return newly constructed blocks
}

CBlock::CBlock(const CBlock &blk):
m_BlockShape(blk.m_BlockShape)			// call the contained object's copy constructor
{
	m_iPenColor = blk.GetPenColor();		
	m_iPenWidth = blk.GetPenWidth();	
	m_pParentSystemModel = blk.GetParentSystemModel();
	m_pSubSystemModel = blk.GetSubSystemModel();	
	m_ptBlockPosition = blk.GetBlockPosition();		
	m_strBlockName = blk.GetBlockName();	
}

CSystemModel *CBlock::GetSubSystemModel() const
{
	return m_pSubSystemModel;
}

CBlockShape::CBlockShape(const CBlockShape &bs)
{
	m_eBlockDirection = bs.GetBlockDirection();
	m_eBlockShape = bs.GetBlockShapeType();
	m_dBlockWidth = bs.GetBlockWidth();
	m_dBlockHeight = bs.GetBlockHeight();
}

CPort::CPort(const CPort &port, CBlock &blk):
m_rRefToBlock(blk)
{
	m_ePortArrowDirec = port.GetPortArrowDirection();
	m_dPortPositionAngle = port.GetPortPositionAngle();	
	m_ptPortPosition = port.GetPortPosition();	
	m_ptPortSignPosition = port.GetPortSignPosition();
	m_strPortName = port.GetPortName();	
}

CConstantBlock::CConstantBlock(const CConstantBlock &blk):
CBlock(blk)
{
	m_strConstValue = blk.GetStringConstValue();
	m_dConstMatrix = ConvertStringToDouble(m_strConstValue, m_iNrows, m_iNcols);

	// Port Construction
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

CString CConstantBlock::GetStringConstValue() const
{
	return m_strConstValue;
}

const vector<CPort*> *CBlock::GetVectorOfOutputPortsCopy() const
{
	// For the fn to be const, a ptr-to-const type (vector<CPort*>) is returned.
	return &m_vecOutputPorts;
}

const vector<CPort*> *CBlock::GetVectorOfInputPortsCopy() const
{
	// For the fn to be const, a ptr-to-const type (vector<CPort*>) is returned.
	return &m_vecInputPorts;
}

CBlock* CConstantBlock::CopyBlockData()
{
	// Create a new CConstantBlock
	CBlock *pBlock = new CConstantBlock(*this);
	
	return pBlock;
}

CDerivativeBlock::CDerivativeBlock(const CDerivativeBlock &blk):
CBlock(blk)
{
	m_iDerivativeMethod = blk.GetDerivativeMethod(); 	// derivative method
	
	// Dynamical variables reset for each new simualtion
	m_iNcallsPerTimeCnt = 0;				// no. of times the fn is called per t_cnt (time point)
	m_iNrows = 0;						// no. of rows of output matrix signal		
	m_i_t_cnt_ref = 0;					// ref time cnt 
	m_f_at_t_minus_h = NULL;				// f(t-h)
	m_f_at_t_minus_2h = NULL;				// f(t-2h)
	m_dMatrixOut = NULL;					// matrix output signal	

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

int CDerivativeBlock::GetDerivativeMethod() const
{
	return m_iDerivativeMethod;
}

CBlock* CDerivativeBlock::CopyBlockData()
{
	// Create a new CDerivativeBlock
	CBlock *pBlock = new CDerivativeBlock(*this);
	
	return pBlock;
}

CDivideBlock::CDivideBlock(const CDivideBlock &blk):
CBlock(blk)
{
	m_iNMultiplyInputs = blk.GetNMultiplyInputs();
	m_iNDivideInputs = blk.GetNDivideInputs();
	m_iMultType = blk.GetMultType();
	m_strInitSignal = blk.GetStringInitialSignal();
	m_dInitSignal = ConvertStringToDouble(m_strInitSignal, m_iNrowsInitSignal, m_iNcolsInitSignal);

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

int CDivideBlock::GetNMultiplyInputs() const
{
	return m_iNMultiplyInputs;
}

int CDivideBlock::GetNDivideInputs() const
{
	return m_iNDivideInputs;
}

int CDivideBlock::GetMultType() const
{
	return m_iMultType;
}

CString CDivideBlock::GetStringInitialSignal() const
{
	return m_strInitSignal;
}

CBlock* CDivideBlock::CopyBlockData()
{
	// Create a new CDivideBlock
	CBlock *pBlock = new CDivideBlock(*this);
	
	return pBlock;
}

CGainBlock::CGainBlock(const CGainBlock &blk):
CBlock(blk)
{
	m_iGainType = blk.GetGainType();
	m_strGainValue = blk.GetStringGainValue();
	m_dGainMatrix = ConvertStringToDouble(m_strGainValue, m_iNrows, m_iNcols);
	
	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

int CGainBlock::GetGainType() const
{
	return m_iGainType;
}

CString CGainBlock::GetStringGainValue() const
{
	return m_strGainValue;
}

CBlock* CGainBlock::CopyBlockData()
{
	// Create a new CGainBlock
	CBlock *pBlock = new CGainBlock(*this);
	
	return pBlock;
}

CIntegratorBlock::CIntegratorBlock(const CIntegratorBlock &blk):
CBlock(blk)
{
	m_strICVector = blk.GetStringICVector();
	m_dICVector = ConvertStringToDoubleVector(m_strICVector, m_iNrows, m_iNcols);
	m_iLength = blk.GetLengthICVector();
	
	// Dynamical variables reset for each new simualtion
	m_iNcallsPerTimeCnt = 0;		// no. of times the fn is called per t_cnt (time point)
	m_iNrowsOut = 0;				// no. of rows of output matrix signal
	m_i_t_cnt_ref = 0;				// ref time cnt 
	m_dMatrixOut = NULL;			// output matrix signal
	m_y_at_t_minus_h = NULL;		// y(t-h)
	m_y_dot_at_t_minus_h = NULL;	// y_dot(t-h)

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

CString CIntegratorBlock::GetStringICVector() const
{
	return m_strICVector;
}

int CIntegratorBlock::GetLengthICVector() const
{
	return m_iLength;
}

CBlock* CIntegratorBlock::CopyBlockData()
{
	// Create a new CIntegratorBlock
	CBlock *pBlock = new CIntegratorBlock(*this);
	
	return pBlock;
}

CLinearFnBlock::CLinearFnBlock(const CLinearFnBlock &blk):
CBlock(blk)
{
	m_dTimeInit = blk.GetTimeInitial();
	m_dTimeFinal = blk.GetTimeFinal();
	m_dValueInit = blk.GetValueInitial();
	m_dDerivative = blk.GetDerivative();

	// Port Construction
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

double CLinearFnBlock::GetTimeInitial() const
{
	return m_dTimeInit;
}

double CLinearFnBlock::GetTimeFinal() const
{
	return m_dTimeFinal;
}

double CLinearFnBlock::GetValueInitial() const
{
	return m_dValueInit;
}

double CLinearFnBlock::GetDerivative() const
{
	return m_dDerivative;
}

CBlock* CLinearFnBlock::CopyBlockData()
{
	// Create a new CLinearFnBlock
	CBlock *pBlock = new CLinearFnBlock(*this);
	
	return pBlock;
}

COutputBlock::COutputBlock(const COutputBlock &blk):
CBlock(blk)
{
	int i;
	int j;
	double **matrix = NULL;

	m_iNotation = blk.GetNotation();
	m_iTimePtDisplay = blk.GetTimePtDisplay();
	blk.GetDataDimensions(m_iNrows, m_iNcols);
	matrix = blk.GetOutputMatrix();

	// MEMORY NEW
	m_dOutputMatrix = new double *[m_iNrows];
	for(i=0; i<m_iNrows; i++)
	{
		m_dOutputMatrix[i] = new double[m_iNcols];
	}

	// Assign initial signal values
	for(i=0; i<m_iNrows; i++)
	{
		for(j=0; j<m_iNcols; j++)
		{
			m_dOutputMatrix[i][j] = matrix[i][j];
		}
	}

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}
}

CBlock* COutputBlock::CopyBlockData()
{
	// Create a new COutputBlock
	CBlock *pBlock = new COutputBlock(*this);
	
	return pBlock;
}

CSignalGeneratorBlock::CSignalGeneratorBlock(const CSignalGeneratorBlock &blk):
CBlock(blk)
{
	m_dAmplitude = blk.GetAmplitude();
	m_dFrequency = blk.GetFrequency();
	m_dPhase = blk.GetPhase();
	m_strFnType = blk.GetFnType();
	m_strUnits = blk.GetUnits();

	// Port Construction
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

double CSignalGeneratorBlock::GetAmplitude() const
{
	return m_dAmplitude;
}

double CSignalGeneratorBlock::GetFrequency() const
{
	return m_dFrequency;
}

double CSignalGeneratorBlock::GetPhase() const
{
	return m_dPhase;
}

CString CSignalGeneratorBlock::GetFnType() const
{
	return m_strFnType;
}

CString CSignalGeneratorBlock::GetUnits() const
{
	return m_strUnits;
}

CBlock* CSignalGeneratorBlock::CopyBlockData()
{
	// Create a new CSignalGeneratorBlock
	CBlock *pBlock = new CSignalGeneratorBlock(*this);
	
	return pBlock;
}

CSubsystemBlock::CSubsystemBlock(const CSubsystemBlock &blk):
CBlock(blk)
{
	m_strInputPortName = blk.GetInputPortName();
	m_strOutputPortName = blk.GetOutputPortName();

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

CString CSubsystemBlock::GetInputPortName() const
{
	return m_strInputPortName;
}

CString CSubsystemBlock::GetOutputPortName() const
{
	return m_strOutputPortName;
}

CBlock* CSubsystemBlock::CopyBlockData()
{
	// Create a new CSubsystemBlock
	CBlock *pBlock = new CSubsystemBlock(*this);
	
	return pBlock;
}

CSubsystemInBlock::CSubsystemInBlock(const CSubsystemInBlock &blk):
CBlock(blk)
{
	m_strInputPortName = blk.GetInputPortName();
	
	// Port Construction
	
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

CString CSubsystemInBlock::GetInputPortName() const
{
	return m_strInputPortName;
}

CBlock* CSubsystemInBlock::CopyBlockData()
{
	// Create a new CSubsystemInBlock
	CBlock *pBlock = new CSubsystemInBlock(*this);
	
	return pBlock;
}

CSubsystemOutBlock::CSubsystemOutBlock(const CSubsystemOutBlock &blk):
CBlock(blk)
{
	m_strOutputPortName = blk.GetOutputPortName();

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();

	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}
}

CString CSubsystemOutBlock::GetOutputPortName() const
{
	return m_strOutputPortName;
}

CBlock* CSubsystemOutBlock::CopyBlockData()
{
	// Create a new CSubsystemOutBlock
	CBlock *pBlock = new CSubsystemOutBlock(*this);
	
	return pBlock;
}

CSumBlock::CSumBlock(const CSumBlock &blk):
CBlock(blk)
{
	m_iNAddInputs = blk.GetNAddInputs();
	m_iNSubtractInputs = blk.GetNSubtractInputs();

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

int CSumBlock::GetNAddInputs() const
{
	return m_iNAddInputs;
}

int CSumBlock::GetNSubtractInputs() const
{
	return m_iNSubtractInputs;
}

CBlock* CSumBlock::CopyBlockData()
{
	// Create a new CSumBlock
	CBlock *pBlock = new CSumBlock(*this);
	
	return pBlock;
}

CTransferFnBlock::CTransferFnBlock(const CTransferFnBlock &blk):
CBlock(blk)
{
	m_strNumerCoeffs = blk.GetStringNumerCoeffs();
	m_strDenomCoeffs = blk.GetStringDenomCoeffs();
	m_dNumerVector = ConvertStringToDoubleVector(m_strNumerCoeffs, m_iLengthNumer);
	m_dDenomVector = ConvertStringToDoubleVector(m_strDenomCoeffs, m_iLengthDenom);

	// Port Construction
	const vector<CPort*> *p_vec_input_ports = blk.GetVectorOfInputPortsCopy();
	const vector<CPort*> *p_vec_output_ports = blk.GetVectorOfOutputPortsCopy();
	vector<CPort*>::const_iterator it_port;					// const iterator for const vector of CPort ptrs.

	for(it_port = (*p_vec_input_ports).begin(); it_port != (*p_vec_input_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_input_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfInputPorts().push_back(p_input_port);	// add the new port
	}

	for(it_port = (*p_vec_output_ports).begin(); it_port != (*p_vec_output_ports).end(); it_port++)
	{
		// Deref it_port to get ptr-to-CPort and then deref the ptr-to-CPort to get CPort.
		CPort *p_output_port = new CPort(**it_port, *this);	// CPort copy constructor
		GetVectorOfOutputPorts().push_back(p_output_port);	// add the new port
	}
}

CString CTransferFnBlock::GetStringNumerCoeffs() const
{
	return m_strNumerCoeffs;
}

CString CTransferFnBlock::GetStringDenomCoeffs() const
{
	return m_strDenomCoeffs;
}

CBlock* CTransferFnBlock::CopyBlockData()
{
	// Create a new CTransferFnBlock
	CBlock *pBlock = new CTransferFnBlock(*this);
	
	return pBlock;
}