#include "stdafx.h"
#include "math.h"
#include "geom.h"
#include "bemstream.h"

#include "bemstreamDoc.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////
// Class of nodes

IMPLEMENT_SERIAL (CNode,CObject,1);

CNode::CNode (float x,float y)
{
	xb=x;yb=y;ok=0;
}	                              

CNode::CNode() {ok=1;};

CNode::CNode (CPoint p,float *gc)
{
	xi=p.x;yi=p.y;ok=0;
	RevTran (gc);
}

void CNode::Bound (int i)
{
	ok=i;
}
		
void CNode::TranCoord (float *gcb)
{
// transformation from world coordinates to the logical coordinates
 	xi=gcb[0]+gcb[1]*(xb-gcb[2])+0.5;
 	yi=gcb[3]+gcb[4]*(yb-gcb[5])+0.5;
}

void CNode::RevTran (float *gcb)
{
 	xb=((float)xi-gcb[0])/gcb[1]+gcb[2];
 	yb=((float)yi-gcb[3])/gcb[4]+gcb[5];
}

void CNode::Serialize(CArchive& ar)
{               
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{           
		ar << xb << yb;
	}
	else
	{                                        
		ar >> xb >> yb;
	}
}

BOOL CNode::operator ==(const CNode& other) const
{
 return (fabs(other.xb-xb)<1e-6)&&(fabs(other.yb-yb)<1e-6);
}

int CNode::IsEqu (CPoint p,float *gc)
{                                  
	TranCoord (gc);
 	return (abs(xi-p.x)<3) && (abs(yi-p.y)<3);
}

void CNode::PlotNode (CDC *DC,int ib,int vel,float *gc)
{
  char msg[10];
  TranCoord(gc);                                
  switch (ok)
  {
  	case 1:DC->Rectangle (xi-vel,yi-vel,xi+vel,yi+vel);break;
  	case 0:
 	 	DC->MoveTo(xi,yi);DC->LineTo(xi+vel,yi);
  		DC->MoveTo(xi,yi);DC->LineTo(xi-vel,yi);
  		DC->MoveTo(xi,yi);DC->LineTo(xi,yi-vel);
  		DC->MoveTo(xi,yi);DC->LineTo(xi,yi+vel);
  		break;
  	case 2:
  		DC->Ellipse (xi-vel,yi-vel,xi+vel,yi+vel);break;	
  }	
  if (ib>0)
  {
	DC->SetTextAlign (TA_LEFT | TA_BOTTOM);
	sprintf (msg,"N%d",ib);
	DC->TextOut (xi+vel*1.5,yi-0.8*vel,msg,strlen(msg));
  }
}

void CNode::Coord (float& x,float &y)
{
	x=xb;y=yb;
}

void CNode::Mult (float nas)
{
	xb*=nas;yb*=nas;
}

CPoint CNode::Coord (void)
{
	CPoint p;
	p.x=xi;p.y=yi;
	return p;
}

//////////////////////////////////////////////////////////////////////////
//  Class of elements

IMPLEMENT_SERIAL (CElement,CObject,1);

CElement::CElement() 
{
	pot=der=dist=kf0=level=0.0f;
}

CElement::CElement (int u1,int u2)
{
	nod1=u1;nod2=u2;type=0;
	pot=der=dist=kf0=level=0.0f;
}	

void CElement::Serialize(CArchive& ar)
{                                               
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{                                                                        
		ar << nod1 << nod2 << type;
		ar << pot << der << level << kf0 << dist;
	}
	else
	{                                                            
		ar >> nod1 >> nod2 >> type;
		ar >> pot >> der >> level >> kf0 >> dist;
	}
}

/////////////////////////////////////////////////////////////////////////
// class of wells

IMPLEMENT_SERIAL (CWell,CObject,1);

CWell::CWell() {};

CWell::CWell (CString s,float x,float y,float *gc,float dis,float d)
{
	name=s;
	xz=x;yz=y;yield=dis;diam=d;
	TranCoord (gc);
}

CWell::CWell (CString s,CPoint p,float *gc,float dis,float d)
{
	name=s;
	xi=p.x;yi=p.y;yield=dis;diam=d;
	RevTran (gc);
}

BOOL CWell::operator ==(const CWell& other) const { return &other == this; }

void CWell::TranCoord (float *gcb)
{
 	xi=gcb[0]+gcb[1]*(xz-gcb[2])+0.5;
 	yi=gcb[3]+gcb[4]*(yz-gcb[5])+0.5;
}

void CWell::RevTran (float *gcb)
{
 	xz=((float)xi-gcb[0])/gcb[1]+gcb[2];
 	yz=((float)yi-gcb[3])/gcb[4]+gcb[5];
}

int CWell::IsEqu (CPoint p,float *gc)
{                                  
	TranCoord (gc);
 	return (abs(xi-p.x)<5) && (abs(yi-p.y)<5);
}

CPoint CWell::GetCoord (void)
{
	CPoint p;
	p.x=xi;p.y=yi;
	return p;
}

void CWell::Serialize(CArchive& ar)
{                                       
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{            
		ar << name << xz << yz << yield << diam << drwdown;  
 	}
	else
	{   
		ar >> name >> xz >> yz >> yield >> diam >> drwdown;  
	}
}

void CWell::Plot(CDC *pDC, float *gc,int sz)
{
	CBrush bred(RGB(255,0,0)),*bpr;
	int sz1=MulDiv(sz,5,3);
	TranCoord(gc);
	pDC->Ellipse(xi-sz1,yi-sz1,xi+sz1,yi+sz1);
	bpr=pDC->SelectObject(&bred);
	pDC->Ellipse(xi-sz,yi-sz,xi+sz,yi+sz);
	pDC->SelectObject(bpr);
	pDC->TextOut(xi+sz1,yi,name);
}

/////////////////////////////////////////////////////////////////////////
// class of internal points

IMPLEMENT_SERIAL (CIntPoint,CObject,1);

CIntPoint::CIntPoint() {};

CIntPoint::CIntPoint (float x,float y,float *gc)
{
	xz=x;yz=y;
	TranCoord (gc);
}

CIntPoint::CIntPoint (CPoint p,float *gc)
{
	xi=p.x;yi=p.y;
	RevTran (gc);
}

BOOL CIntPoint::operator ==(const CIntPoint& other) const { return &other == this; }

void CIntPoint::TranCoord (float *gcb)
{
 	xi=gcb[0]+gcb[1]*(xz-gcb[2])+0.5;
 	yi=gcb[3]+gcb[4]*(yz-gcb[5])+0.5;
}

void CIntPoint::RevTran (float *gcb)
{
 	xz=((float)xi-gcb[0])/gcb[1]+gcb[2];
 	yz=((float)yi-gcb[3])/gcb[4]+gcb[5];
}

int CIntPoint::IsEqu (CPoint p,float *gc)
{                                  
	TranCoord (gc);
 	return (abs(xi-p.x)<5) && (abs(yi-p.y)<5);
}

CPoint CIntPoint::GetCoord (void)
{
	CPoint p;
	p.x=xi;p.y=yi;
	return p;
}

void CIntPoint::PlotPt (CDC *DC,int ib,int vel,float *gc)
{
	char msg[10];
	TranCoord(gc);                                
 	DC->MoveTo(xi-vel,yi-vel);DC->LineTo(xi+vel,yi+vel);
 	DC->MoveTo(xi+vel,yi-vel);DC->LineTo(xi-vel,yi+vel);
	if (ib>0)
	{
		DC->SetTextAlign (TA_LEFT | TA_BOTTOM);
		sprintf (msg,"P%d",ib);
		DC->TextOut (xi+vel*1.5,yi-0.8*vel,msg,strlen(msg));
	}
}

void CIntPoint::Serialize(CArchive& ar)
{                                       
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{            
		ar << xz << yz << drwdown << vx << vy;
 	}
	else
	{   
		ar >> xz >> yz >> drwdown >> vx >> vy;
	}
}

/////////////////////////////////////////////////////////////////////////
// class of internal elements

IMPLEMENT_SERIAL (CIntElem,CObject,1);

CIntElem::CIntElem() {};

CIntElem::CIntElem (float *x,float *y,float pr)
{
	for (int i=0;i<3;i++) {xp[i]=x[i];yp[i]=y[i];}
	precip=pr;
}

void CIntElem::Serialize(CArchive& ar)
{                                       
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{            
		ar.Write (xp,sizeof(xp));
		ar.Write (yp,sizeof(yp));
		ar << precip;
 	}
	else
	{   
		ar.Read (xp,sizeof(xp));
		ar.Read (yp,sizeof(yp));
		ar >> precip;
	}
}

/////////////////////////////////////////////////////////////////////////
IMPLEMENT_SERIAL (CStrPoint,CObject,1);

CStrPoint::CStrPoint (float x,float y,float tim)
{
	xb=x;yb=y;time=tim;
}	                              

CStrPoint::CStrPoint() {};

CStrPoint::CStrPoint (CPoint p,float *gc,float tim)
{
	xi=p.x;yi=p.y;
	RevTran (gc);time=tim;
}
		
void CStrPoint::TranCoord (float *gcb)
{
// transformation from world coordinates to the logical coordinates
	float dx,dy;
	dx=gcb[1]*(xb-gcb[2]);dy=gcb[4]*(yb-gcb[5]);
	if (dx>0.0f) dx+=0.5f;
	else dx-=0.5f;
	if (dy>0.0f) dy+=0.5f;
	else dy-=0.5f;
 	xi=gcb[0]+dx;
 	yi=gcb[3]+dy;
}

void CStrPoint::RevTran (float *gcb)
{
 	xb=((float)xi-gcb[0])/gcb[1]+gcb[2];
 	yb=((float)yi-gcb[3])/gcb[4]+gcb[5];
}

void CStrPoint::Serialize(CArchive& ar)
{               
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{           
		ar << xb << yb << time;
	}
	else
	{                                        
		ar >> xb >> yb >> time;
	}
}

BOOL CStrPoint::operator ==(const CStrPoint& other) const
{
 return (fabs(other.xb-xb)<1e-6)&&(fabs(other.yb-yb)<1e-6);
}

void CStrPoint::Coord (float& x,float &y)
{
	x=xb;y=yb;
}

CPoint CStrPoint::Coord (void)
{
	CPoint p;
	p.x=xi;p.y=yi;
	return p;
}

////////////////////////////////////////
IMPLEMENT_SERIAL (CStamp,CObject,1);

CStamp::CStamp (float x,float y,float c)
{
	xb=x;yb=y;time=c;
	clr=RGB(0,0,0);
}	                              

CStamp::CStamp() {};

CStamp::CStamp(CStamp *st)
{
	xb=st->xb;yb=st->yb;clr=st->clr;
	time=st->time;
}

void CStamp::Transf (float *gcb)
{
 	xi=gcb[0]+gcb[1]*(xb-gcb[2])+0.5;
 	yi=gcb[3]+gcb[4]*(yb-gcb[5])+0.5;
}

void CStamp::Serialize(CArchive& ar)
{               
	CObject::Serialize(ar);
	if (ar.IsStoring())
	{           
		ar << xb << yb << time << clr;
	}
	else
	{                                        
		ar >> xb >> yb >> time >> clr;
	}
}

void CStamp::Plot (CDC& td,float *gc,int sz)
{
	Transf(gc);
	CBrush brf(clr),*brp;
	brp=td.SelectObject(&brf);
	td.Rectangle (xi-sz,yi-sz,xi+sz,yi+sz);
	td.SelectObject(brp);
	brf.DeleteObject();
}

/////////////////////////////////////////////////////////////////////////
IMPLEMENT_SERIAL (CStream,CObject,1);

CStream::CStream (float x,float y,int iz)
{
	AddPoint (x,y,0.0F);
	iwl=iz;
}	                              

CStream::CStream (CPoint p,float *gc,int iz)
{
	AddPoint (p,gc,0.0F);
	iwl=iz;
}	                              

CStream::CStream() {};

CStream::~CStream() 
{
	int i=0;
	while (i<Points.GetSize())
	{
		delete Points.GetAt(i++);
	}	                     
	Points.RemoveAll();
}

void CStream::Serialize(CArchive& ar)
{               
	if (ar.IsStoring())
	{           
		ar << iwl;
	}
	else
	{                                        
		ar >> iwl;
	}
	Points.Serialize(ar);
//	Stamps.Serialize(ar);
}

CStrPoint* CStream::GetPoint(int pos)
{
	return (CStrPoint*)Points.GetAt(pos);
}

CStamp* CStream::GetStamp(int pos)
{
	return (CStamp*)Stamps.GetAt(pos);
}

CStrPoint* CStream::AddPoint (float x,float y,float iz)
{                       
	CStrPoint* pt=new CStrPoint(x,y,iz);
	Points.Add (pt);
	return pt;
}

CStamp* CStream::AddStamp (float x,float y,float c)
{                                    
	CStamp* stp=new CStamp(x,y,c);
	Stamps.Add (stp);
	return stp;
}

CStamp* CStream::AddStamp(CStamp *st)
{
	CStamp* stp=new CStamp(st);
	Stamps.Add (stp);
	return stp;
}

CStrPoint* CStream::AddPoint (CPoint p,float *gc,float iz)
{                
	CStrPoint* pt=new CStrPoint(p,gc,iz);
	Points.Add (pt);
	return pt;
}

void CStream::Plot (CDC& td,float *gc,int iscz,int iscc,int vel,float efpo)
{
	int i,nbp;
	CPoint *pt;
	nbp=Points.GetSize();
	pt=new CPoint[nbp];
	for (i=0;i<Points.GetSize();i++)
	{
		CStrPoint* bd=GetPoint(i);
		bd->TranCoord(gc);
		pt[i]=bd->Coord();
	}
	CPen pem(PS_SOLID,1,RGB(0,0,255)),*pep;
	pep=td.SelectObject(&pem);
	td.Polyline (pt,nbp);
	delete pt;
	if (iscz)
	{
		for (i=0;i<Stamps.GetSize();i++)
		{
			CStamp* zn=GetStamp(i);
			zn->Plot (td,gc,vel);
		}
	}
	if (iscc)
	{
		CString msg;
		msg.Format ("%.1f",time*efpo);
		CStrPoint* bd=GetPoint(Points.GetSize()-1);
//		CStrPoint* bd=GetPoint(0);
		bd->TranCoord(gc);
		CPoint p=bd->Coord();
		td.TextOut (p.x,p.y,msg);
	}
	td.SelectObject(pep);
	pem.DeleteObject();
}

void CStream::CreateStamp (float tim,COLORREF clr)
{
	int i;
	float dx,dy,dc,xc,yc,dt;
	for (i=0;i<Points.GetSize()-1;i++)
	{
		CStrPoint* bp1=GetPoint(i);
		CStrPoint* bp2=GetPoint(i+1);
		if (bp2->time>tim&&bp1->time<tim)
		{
			dc=tim-bp1->time;dt=bp2->time-bp1->time;
			dx=bp2->xb-bp1->xb;dy=bp2->yb-bp1->yb;
			xc=dx*dc/dt+bp1->xb;yc=dy*dc/dt+bp1->yb;
			xc=bp1->xb;yc=bp1->yb;
			CStamp* zn=AddStamp(xc,yc,tim);
			zn->clr=clr;
		}
	}
}

void CStream::PoStamps(float efpo)
{
	int i,is;
	float dx,dy,dc,xc,yc,dt,tim,tim1,tim2;
	for (is=0;is<Stamps.GetSize();is++)
	{
		CStamp* stp=GetStamp(is);
		tim=stp->time;
		for (i=0;i<Points.GetSize()-1;i++)
		{
			CStrPoint* bp1=GetPoint(i);
			CStrPoint* bp2=GetPoint(i+1);
			tim1=bp1->time*efpo;tim2=bp2->time*efpo;
			if (tim2>tim&&tim1<tim)
			{
				dc=tim-tim1;dt=tim2-tim1;
				dx=bp2->xb-bp1->xb;dy=bp2->yb-bp1->yb;
				xc=dx*dc/dt+bp1->xb;yc=dy*dc/dt+bp1->yb;
				xc=bp1->xb;yc=bp1->yb;
				stp->xb=xc;stp->yb=yc;
				break;
			}
		}
	}
}
