3130 lines
74 KiB
C++
3130 lines
74 KiB
C++
// FemmeDoc.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "femm.h"
|
|
#include "FemmeDoc.h"
|
|
#include "FemmeView.h"
|
|
|
|
#include "probdlg.h"
|
|
#include "PtProp.h"
|
|
#include "OpBlkDlg.h"
|
|
#include "OpNodeDlg.h"
|
|
#include "OpSegDlg.h"
|
|
#include "OpArcSegDlg.h"
|
|
#include "OpGrp.h"
|
|
#include "ArcDlg.h"
|
|
#include "ExteriorProps.h"
|
|
|
|
extern void *pFemmeDoc;
|
|
extern lua_State *lua;
|
|
extern CLuaConsoleDlg *LuaConsole;
|
|
extern BOOL bLinehook;
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmeDoc
|
|
|
|
IMPLEMENT_DYNCREATE(CFemmeDoc, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(CFemmeDoc, CDocument)
|
|
//{{AFX_MSG_MAP(CFemmeDoc)
|
|
ON_COMMAND(ID_DEFINE_PROBLEM, OnDefineProblem)
|
|
ON_COMMAND(ID_EDIT_MATPROPS, OnEditMatprops)
|
|
ON_COMMAND(ID_EDIT_PTPROPS, OnEditPtprops)
|
|
ON_COMMAND(ID_EDIT_SEGPROPS, OnEditSegprops)
|
|
ON_COMMAND(ID_EDIT_CIRCPROPS, OnEditCircprops)
|
|
ON_COMMAND(ID_EDIT_EXTERIOR, OnEditExterior)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
CFemmeDoc::CFemmeDoc()
|
|
{
|
|
// set some default values for starting up rendering
|
|
// things properly
|
|
FirstDraw=FALSE;
|
|
NoDraw=FALSE;
|
|
|
|
// set up some default document behaviors
|
|
d_prec=1.e-08;
|
|
d_minangle=DEFAULT_MINIMUM_ANGLE;
|
|
d_freq=0;
|
|
d_depth=1;
|
|
d_coord=0;
|
|
d_length=0;
|
|
d_type=0;
|
|
d_solver=0;
|
|
|
|
|
|
// Figure out what directory the executables
|
|
// are in, so we can call `triangle' if we need to.
|
|
BinDir=((CFemmApp *)AfxGetApp())->GetExecutablePath();
|
|
|
|
// read document default behaviors from disk
|
|
ScanPreferences();
|
|
|
|
// fire up lua
|
|
initalise_lua();
|
|
|
|
// initialize the data in the document
|
|
OnNewDocument();
|
|
}
|
|
|
|
BOOL CFemmeDoc::OnNewDocument()
|
|
{
|
|
if (!CDocument::OnNewDocument())
|
|
return FALSE;
|
|
|
|
// clear out all current lines, nodes, and block labels
|
|
nodelist.RemoveAll();
|
|
linelist.RemoveAll();
|
|
arclist.RemoveAll();
|
|
blocklist.RemoveAll();
|
|
undonodelist.RemoveAll();
|
|
undolinelist.RemoveAll();
|
|
undoarclist.RemoveAll();
|
|
undoblocklist.RemoveAll();
|
|
nodeproplist.RemoveAll();
|
|
lineproplist.RemoveAll();
|
|
blockproplist.RemoveAll();
|
|
circproplist.RemoveAll();
|
|
meshnode.RemoveAll();
|
|
meshline.RemoveAll();
|
|
greymeshline.RemoveAll();
|
|
|
|
// set problem attributes to generic ones;
|
|
Frequency=d_freq;
|
|
Precision=d_prec;
|
|
MinAngle=d_minangle;
|
|
SmartMesh=theApp.d_SmartMesh;
|
|
Depth=d_depth;
|
|
LengthUnits=d_length;
|
|
ProblemType=d_type;
|
|
ACSolver=d_solver;
|
|
Coords=d_coord;
|
|
ProblemNote="Add comments here.";
|
|
PrevSoln="";
|
|
PrevType = 0;
|
|
extRo=extRi=extZo=0;
|
|
|
|
// reset view to default attributes
|
|
CFemmeView *pView;
|
|
POSITION pos;
|
|
pos=GetFirstViewPosition();
|
|
if (pos!=NULL){
|
|
pView=(CFemmeView *)GetNextView(pos);
|
|
// if (pView!=NULL) pView->OnNewDocument();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
CFemmeDoc::~CFemmeDoc()
|
|
{
|
|
pFemmeDoc=NULL;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmeDoc diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CFemmeDoc::AssertValid() const
|
|
{
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void CFemmeDoc::Dump(CDumpContext& dc) const
|
|
{
|
|
CDocument::Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmeDoc serialization
|
|
|
|
void CFemmeDoc::Serialize(CArchive& ar)
|
|
{
|
|
if (ar.IsStoring())
|
|
{
|
|
// TODO: add storing code here
|
|
}
|
|
else
|
|
{
|
|
// TODO: add loading code here
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFemmeDoc commands
|
|
|
|
void CFemmeDoc::OnDefineProblem()
|
|
{
|
|
probdlg pDlg;
|
|
|
|
// Send present parameter values to the dialog
|
|
// pDlg.m_rji=TheDoc->vi[0];
|
|
pDlg.probtype = ProblemType;
|
|
pDlg.m_problem_note = ProblemNote;
|
|
pDlg.m_frequency = Frequency;
|
|
pDlg.m_precision = Precision;
|
|
pDlg.m_minangle = MinAngle;
|
|
pDlg.bsmart = SmartMesh;
|
|
pDlg.m_depth = Depth;
|
|
pDlg.lengthunits = LengthUnits;
|
|
pDlg.solver = ACSolver;
|
|
pDlg.m_prevsoln = PrevSoln;
|
|
pDlg.prevtype = PrevType;
|
|
|
|
// Display dialog and collect data
|
|
if(pDlg.DoModal()==IDOK)
|
|
{
|
|
Frequency = pDlg.m_frequency;
|
|
Precision = pDlg.m_precision;
|
|
MinAngle = pDlg.m_minangle;
|
|
SmartMesh = pDlg.bsmart;
|
|
ProblemNote = pDlg.m_problem_note;
|
|
ProblemType = pDlg.probtype;
|
|
LengthUnits = pDlg.lengthunits;
|
|
Depth = pDlg.m_depth;
|
|
ACSolver = pDlg.solver;
|
|
PrevSoln = pDlg.m_prevsoln;
|
|
if (PrevSoln.GetLength()==0) PrevType=0;
|
|
else PrevType = pDlg.prevtype;
|
|
}
|
|
|
|
}
|
|
|
|
void CFemmeDoc::UnselectAll()
|
|
{
|
|
int i;
|
|
|
|
for(i=0;i < nodelist.GetSize();i++) nodelist[i].IsSelected=FALSE;
|
|
for(i=0;i < linelist.GetSize();i++) linelist[i].IsSelected=FALSE;
|
|
for(i=0;i < blocklist.GetSize();i++) blocklist[i].IsSelected=FALSE;
|
|
for(i=0;i < arclist.GetSize();i++) arclist[i].IsSelected=FALSE;
|
|
}
|
|
|
|
BOOL CFemmeDoc::AddNode(double x, double y, double d)
|
|
{
|
|
int i,k;
|
|
CNode pt;
|
|
CSegment segm;
|
|
CArcSegment asegm;
|
|
CComplex c,a0,a1,a2;
|
|
double R;
|
|
|
|
// test to see if ``too close'' to existing node...
|
|
for (i=0;i<nodelist.GetSize();i++)
|
|
if(nodelist[i].GetDistance(x,y)<d) return FALSE;
|
|
|
|
// can't put a node on top of a block label; do same sort of test.
|
|
for (i=0;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].GetDistance(x,y)<d) return FALSE;
|
|
|
|
// if all is OK, add point in to the node list...
|
|
pt.x=x; pt.y=y;
|
|
nodelist.Add(pt);
|
|
|
|
// test to see if node is on an existing line; if so,
|
|
// break into two lines;
|
|
k=(int) linelist.GetSize();
|
|
for(i=0;i<k;i++)
|
|
{
|
|
if (fabs(ShortestDistance(x,y,i))<d)
|
|
{
|
|
segm=linelist[i];
|
|
linelist[i].n1=(int) nodelist.GetSize()-1;
|
|
segm.n0=(int) nodelist.GetSize()-1;
|
|
linelist.Add(segm);
|
|
}
|
|
}
|
|
|
|
// test to see if node is on an existing arc; if so,
|
|
// break into two arcs;
|
|
k=(int) arclist.GetSize();
|
|
for(i=0;i<k;i++)
|
|
{
|
|
if (ShortestDistanceFromArc(CComplex(x,y),arclist[i])<d)
|
|
{
|
|
a0.Set(nodelist[arclist[i].n0].x,nodelist[arclist[i].n0].y);
|
|
a1.Set(nodelist[arclist[i].n1].x,nodelist[arclist[i].n1].y);
|
|
a2.Set(x,y);
|
|
GetCircle(arclist[i],c,R);
|
|
asegm=arclist[i];
|
|
arclist[i].n1=(int) nodelist.GetSize()-1;
|
|
arclist[i].ArcLength=arg((a2-c)/(a0-c))*180./PI;
|
|
asegm.n0=(int) nodelist.GetSize()-1;
|
|
asegm.ArcLength=arg((a1-c)/(a2-c))*180./PI;
|
|
arclist.Add(asegm);
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFemmeDoc::AddSegment(int n0, int n1, double tol)
|
|
{
|
|
return AddSegment(n0,n1,NULL,tol);
|
|
}
|
|
|
|
BOOL CFemmeDoc::AddSegment(int n0, int n1, CSegment *parsegm, double tol)
|
|
{
|
|
int i,j,k;
|
|
double xi,yi,t;
|
|
CComplex p[2];
|
|
CSegment segm;
|
|
CArray< CComplex, CComplex&> newnodes;
|
|
|
|
newnodes.RemoveAll();
|
|
|
|
// don't add if line is degenerate
|
|
if (n0==n1) return FALSE;
|
|
|
|
// don't add if the line is already in the list;
|
|
for(i=0;i<linelist.GetSize();i++){
|
|
if ((linelist[i].n0==n0) && (linelist[i].n1==n1)) return FALSE;
|
|
if ((linelist[i].n0==n1) && (linelist[i].n1==n0)) return FALSE;
|
|
}
|
|
|
|
// add proposed line to the linelist
|
|
segm.BoundaryMarker="<None>";
|
|
if (parsegm!=NULL) segm=*parsegm;
|
|
segm.IsSelected=FALSE;
|
|
segm.n0=n0; segm.n1=n1;
|
|
|
|
// check to see if there are intersections with segments
|
|
for(i=0;i<linelist.GetSize();i++)
|
|
if(GetIntersection(n0,n1,i,&xi,&yi)==TRUE) newnodes.Add(CComplex(xi,yi));
|
|
|
|
// check to see if there are intersections with arcs
|
|
for(i=0;i<arclist.GetSize();i++){
|
|
j=GetLineArcIntersection(segm,arclist[i],p);
|
|
if (j>0) for(k=0;k<j;k++) newnodes.Add(p[k]);
|
|
}
|
|
|
|
// add nodes at intersections
|
|
if (tol==0)
|
|
{
|
|
if (nodelist.GetSize()<2) t=1.e-08;
|
|
else{
|
|
CComplex p0,p1;
|
|
p0=nodelist[0].CC();
|
|
p1=p0;
|
|
for(i=1;i<nodelist.GetSize();i++)
|
|
{
|
|
if(nodelist[i].x<p0.re) p0.re=nodelist[i].x;
|
|
if(nodelist[i].x>p1.re) p1.re=nodelist[i].x;
|
|
if(nodelist[i].y<p0.im) p0.im=nodelist[i].y;
|
|
if(nodelist[i].y>p1.im) p1.im=nodelist[i].y;
|
|
}
|
|
t=abs(p1-p0)*CLOSE_ENOUGH;
|
|
}
|
|
}
|
|
else t=tol;
|
|
|
|
for(i=0;i<newnodes.GetSize();i++)
|
|
AddNode(newnodes[i].re,newnodes[i].im,t);
|
|
|
|
// Add proposed line segment
|
|
linelist.Add(segm);
|
|
|
|
// check to see if proposed line passes through other points;
|
|
// if so, delete line and create lines that link intermediate points;
|
|
// does this by recursive use of AddSegment;
|
|
double d,dmin;
|
|
UnselectAll();
|
|
if (tol==0) dmin=abs(nodelist[n1].CC()-nodelist[n0].CC())*1.e-05;
|
|
else dmin=tol;
|
|
|
|
k=(int) linelist.GetSize()-1;
|
|
for(i=0;i<nodelist.GetSize();i++)
|
|
{
|
|
if( (i!=n0) && (i!=n1) )
|
|
{
|
|
d=ShortestDistance(nodelist[i].x,nodelist[i].y,k);
|
|
if (abs(nodelist[i].CC()-nodelist[n0].CC())<dmin) d=2.*dmin;
|
|
if (abs(nodelist[i].CC()-nodelist[n1].CC())<dmin) d=2.*dmin;
|
|
if (d<dmin){
|
|
linelist[k].ToggleSelect();
|
|
DeleteSelectedSegments();
|
|
if(parsegm==NULL)
|
|
{
|
|
AddSegment(n0,i,dmin);
|
|
AddSegment(i,n1,dmin);
|
|
}
|
|
else{
|
|
AddSegment(n0,i,&segm,dmin);
|
|
AddSegment(i,n1,&segm,dmin);
|
|
}
|
|
i=(int) nodelist.GetSize();
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CFemmeDoc::GetCircle(CArcSegment &arc,CComplex &c, double &R)
|
|
{
|
|
CComplex a0,a1,t;
|
|
double d,tta;
|
|
|
|
a0.Set(nodelist[arc.n0].x,nodelist[arc.n0].y);
|
|
a1.Set(nodelist[arc.n1].x,nodelist[arc.n1].y);
|
|
d=abs(a1-a0); // distance between arc endpoints
|
|
|
|
// figure out what the radius of the circle is...
|
|
t=(a1-a0)/d;
|
|
tta=arc.ArcLength*PI/180.;
|
|
R=d/(2.*sin(tta/2.));
|
|
c=a0 + (d/2. + I*sqrt(R*R-d*d/4.))*t; // center of the arc segment's circle...
|
|
}
|
|
|
|
int CFemmeDoc::GetLineArcIntersection(CSegment &seg, CArcSegment &arc, CComplex *p)
|
|
{
|
|
CComplex p0,p1,a0,a1,t,v,c;
|
|
double d,l,R,z,tta;
|
|
int i=0;
|
|
|
|
p0.Set(nodelist[seg.n0].x,nodelist[seg.n0].y);
|
|
p1.Set(nodelist[seg.n1].x,nodelist[seg.n1].y);
|
|
a0.Set(nodelist[arc.n0].x,nodelist[arc.n0].y);
|
|
a1.Set(nodelist[arc.n1].x,nodelist[arc.n1].y);
|
|
d=abs(a1-a0); // distance between arc endpoints
|
|
|
|
// figure out what the radius of the circle is...
|
|
t=(a1-a0)/d;
|
|
tta=arc.ArcLength*PI/180.;
|
|
R=d/(2.*sin(tta/2.));
|
|
c=a0 + (d/2. + I*sqrt(R*R-d*d/4.))*t; // center of the arc segment's circle...
|
|
|
|
// figure out the distance between line and circle's center;
|
|
d=abs(p1-p0);
|
|
t=(p1-p0)/d;
|
|
v=(c-p0)/t;
|
|
if (fabs(Im(v))>R) return 0;
|
|
l=sqrt( R*R - Im(v)*Im(v)); // Im(v) is distance between line and center...
|
|
|
|
if ((l/R) < 1.e-05){ // case where line is very close to a tangent;
|
|
p[i]=p0 + Re(v)*t; // make it be a tangent.
|
|
R=Re((p[i]-p0)/t);
|
|
z=arg((p[i]-c)/(a0-c));
|
|
if ((R>0) && (R<d) && (z>0.) && (z<tta)) i++;
|
|
return i;
|
|
}
|
|
|
|
p[i]=p0 + (Re(v)+l)*t; // first possible intersection;
|
|
R=Re((p[i]-p0)/t);
|
|
z=arg((p[i]-c)/(a0-c));
|
|
if ((R>0) && (R<d) && (z>0.) && (z<tta)) i++;
|
|
|
|
p[i]=p0 + (Re(v)-l)*t; // second possible intersection
|
|
R=Re((p[i]-p0)/t);
|
|
z=arg((p[i]-c)/(a0-c));
|
|
if ((R>0) && (R<d) && (z>0.) && (z<tta)) i++;
|
|
|
|
// returns the number of valid intersections found;
|
|
// intersections are returned in the array p[];
|
|
return i;
|
|
|
|
}
|
|
|
|
int CFemmeDoc::GetArcArcIntersection(CArcSegment &arc0, CArcSegment &arc1, CComplex *p)
|
|
{
|
|
CComplex a0,a1,t,c0,c1;
|
|
double d,l,R0,R1,z0,z1,c,tta0,tta1;
|
|
int i=0;
|
|
|
|
a0.Set(nodelist[arc0.n0].x,nodelist[arc0.n0].y);
|
|
a1.Set(nodelist[arc1.n0].x,nodelist[arc1.n0].y);
|
|
|
|
GetCircle(arc1,c1,R1);
|
|
GetCircle(arc0,c0,R0);
|
|
|
|
d=abs(c1-c0); // distance between centers
|
|
|
|
if ((d>R0+R1) || (d<1.e-08)) return 0;
|
|
// directly eliminate case where there can't
|
|
// be any crossings....
|
|
|
|
l=sqrt((R0+R1-d)*(d+R0-R1)*(d-R0+R1)*(d+R0+R1))/(2.*d);
|
|
c=1.+(R0/d)*(R0/d)-(R1/d)*(R1/d);
|
|
t=(c1-c0)/d;
|
|
tta0=arc0.ArcLength*PI/180;
|
|
tta1=arc1.ArcLength*PI/180;
|
|
|
|
p[i]=c0 + (c*d/2.+ I*l)*t; // first possible intersection;
|
|
z0=arg((p[i]-c0)/(a0-c0));
|
|
z1=arg((p[i]-c1)/(a1-c1));
|
|
if ((z0>0.) && (z0<tta0) && (z1>0.) && (z1<tta1)) i++;
|
|
|
|
if(fabs(d-R0+R1)/(R0+R1)< 1.e-05){
|
|
p[i]=c0+ c*d*t/2.;
|
|
return i;
|
|
}
|
|
|
|
p[i]=c0 + (c*d/2.-I*l)*t; // second possible intersection
|
|
z0=arg((p[i]-c0)/(a0-c0));
|
|
z1=arg((p[i]-c1)/(a1-c1));
|
|
if ((z0>0.) && (z0<tta0) && (z1>0.) && (z1<tta1)) i++;
|
|
|
|
// returns the number of valid intersections found;
|
|
// intersections are returned in the array p[];
|
|
return i;
|
|
}
|
|
|
|
BOOL CFemmeDoc::AddArcSegment(CArcSegment &asegm, double tol)
|
|
{
|
|
int i,j,k;
|
|
CSegment segm;
|
|
CArcSegment newarc;
|
|
CComplex c,p[2];
|
|
CArray< CComplex, CComplex&> newnodes;
|
|
double R,d,dmin,t;
|
|
|
|
newnodes.RemoveAll();
|
|
|
|
// don't add if line is degenerate
|
|
if (asegm.n0==asegm.n1) return FALSE;
|
|
|
|
// don't add if the arc is already in the list;
|
|
for(i=0;i<arclist.GetSize();i++){
|
|
if ((arclist[i].n0==asegm.n0) && (arclist[i].n1==asegm.n1) &&
|
|
(fabs(arclist[i].ArcLength-asegm.ArcLength)<1.e-02)) return FALSE;
|
|
// arcs are ``the same'' if start and end points are the same, and if
|
|
// the arc lengths are relatively close (but a lot farther than
|
|
// machine precision...
|
|
}
|
|
|
|
// add proposed arc to the linelist
|
|
asegm.IsSelected=FALSE;
|
|
|
|
// check to see if there are intersections
|
|
for(i=0;i<linelist.GetSize();i++)
|
|
{
|
|
j=GetLineArcIntersection(linelist[i],asegm,p);
|
|
if(j>0) for(k=0;k<j;k++) newnodes.Add(p[k]);
|
|
}
|
|
for(i=0;i<arclist.GetSize();i++)
|
|
{
|
|
j=GetArcArcIntersection(asegm,arclist[i],p);
|
|
if(j>0) for(k=0;k<j;k++) newnodes.Add(p[k]);
|
|
}
|
|
|
|
// add nodes at intersections
|
|
if(tol==0)
|
|
{
|
|
if (nodelist.GetSize()<2) t=1.e-08;
|
|
else{
|
|
CComplex p0,p1;
|
|
p0=nodelist[0].CC();
|
|
p1=p0;
|
|
for(i=1;i<nodelist.GetSize();i++)
|
|
{
|
|
if(nodelist[i].x<p0.re) p0.re=nodelist[i].x;
|
|
if(nodelist[i].x>p1.re) p1.re=nodelist[i].x;
|
|
if(nodelist[i].y<p0.im) p0.im=nodelist[i].y;
|
|
if(nodelist[i].y>p1.im) p1.im=nodelist[i].y;
|
|
}
|
|
t=abs(p1-p0)*CLOSE_ENOUGH;
|
|
}
|
|
}
|
|
else t=tol;
|
|
|
|
for(i=0;i<newnodes.GetSize();i++)
|
|
AddNode(newnodes[i].re,newnodes[i].im,t);
|
|
|
|
// add proposed arc segment;
|
|
arclist.Add(asegm);
|
|
|
|
// check to see if proposed arc passes through other points;
|
|
// if so, delete arc and create arcs that link intermediate points;
|
|
// does this by recursive use of AddArcSegment;
|
|
|
|
UnselectAll();
|
|
GetCircle(asegm,c,R);
|
|
if (tol==0) dmin=fabs(R*PI*asegm.ArcLength/180.)*1.e-05;
|
|
else dmin=tol;
|
|
k=(int) arclist.GetSize()-1;
|
|
|
|
for(i=0;i<nodelist.GetSize();i++)
|
|
{
|
|
if( (i!=asegm.n0) && (i!=asegm.n1) )
|
|
{
|
|
d=ShortestDistanceFromArc(CComplex(nodelist[i].x,nodelist[i].y),arclist[k]);
|
|
if (d<dmin){
|
|
|
|
CComplex a0,a1,a2;
|
|
a0.Set(nodelist[asegm.n0].x,nodelist[asegm.n0].y);
|
|
a1.Set(nodelist[asegm.n1].x,nodelist[asegm.n1].y);
|
|
a2.Set(nodelist[i].x,nodelist[i].y);
|
|
arclist[k].ToggleSelect();
|
|
DeleteSelectedArcSegments();
|
|
|
|
newarc=asegm;
|
|
newarc.n1=i;
|
|
newarc.ArcLength=arg((a2-c)/(a0-c))*180./PI;
|
|
AddArcSegment(newarc,dmin);
|
|
|
|
newarc=asegm;
|
|
newarc.n0=i;
|
|
newarc.ArcLength=arg((a1-c)/(a2-c))*180./PI;
|
|
AddArcSegment(newarc,dmin);
|
|
|
|
i=(int) nodelist.GetSize();
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CFemmeDoc::AddBlockLabel(double x, double y, double d)
|
|
{
|
|
int i;
|
|
BOOL AddFlag=TRUE;
|
|
|
|
// test to see if ``too close'' to existing node...
|
|
for (i=0;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].GetDistance(x,y)<d) AddFlag=FALSE;
|
|
|
|
// can't put a block label on top of an existing node...
|
|
for (i=0;i<nodelist.GetSize();i++)
|
|
if(nodelist[i].GetDistance(x,y)<d) return FALSE;
|
|
|
|
// can't put a block label on a line, either...
|
|
for (i=0;i<linelist.GetSize();i++)
|
|
if(ShortestDistance(x,y,i)<d) return FALSE ;
|
|
|
|
// if all is OK, add point in to the node list...
|
|
if(AddFlag==TRUE){
|
|
CBlockLabel pt;
|
|
pt.x=x; pt.y=y;
|
|
blocklist.Add(pt);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int CFemmeDoc::ClosestNode(double x, double y)
|
|
{
|
|
int i,j;
|
|
double d0,d1;
|
|
|
|
if(nodelist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=nodelist[0].GetDistance(x,y);
|
|
for(i=0;i<nodelist.GetSize();i++){
|
|
d1=nodelist[i].GetDistance(x,y);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
int CFemmeDoc::ClosestBlockLabel(double x, double y)
|
|
{
|
|
int i,j;
|
|
double d0,d1;
|
|
|
|
if(blocklist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=blocklist[0].GetDistance(x,y);
|
|
for(i=0;i<blocklist.GetSize();i++){
|
|
d1=blocklist[i].GetDistance(x,y);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
double CFemmeDoc::ShortestDistanceFromArc(CComplex p, CArcSegment &arc)
|
|
{
|
|
double R,d,l,z;
|
|
CComplex a0,a1,c,t;
|
|
|
|
a0.Set(nodelist[arc.n0].x,nodelist[arc.n0].y);
|
|
a1.Set(nodelist[arc.n1].x,nodelist[arc.n1].y);
|
|
GetCircle(arc,c,R);
|
|
d=abs(p-c);
|
|
|
|
if(d==0) return R;
|
|
|
|
t=(p-c)/d;
|
|
l=abs(p-c-R*t);
|
|
z=arg(t/(a0-c))*180/PI;
|
|
if ((z>0) && (z<arc.ArcLength)) return l;
|
|
|
|
z=abs(p-a0);
|
|
l=abs(p-a1);
|
|
if(z<l) return z;
|
|
return l;
|
|
}
|
|
|
|
|
|
double CFemmeDoc::ShortestDistance(double p, double q, int segm)
|
|
{
|
|
double t,x[3],y[3];
|
|
|
|
x[0]=nodelist[linelist[segm].n0].x;
|
|
y[0]=nodelist[linelist[segm].n0].y;
|
|
x[1]=nodelist[linelist[segm].n1].x;
|
|
y[1]=nodelist[linelist[segm].n1].y;
|
|
|
|
t=((p-x[0])*(x[1]-x[0]) + (q-y[0])*(y[1]-y[0]))/
|
|
((x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0]));
|
|
|
|
if (t>1.) t=1.;
|
|
if (t<0.) t=0.;
|
|
|
|
x[2]=x[0]+t*(x[1]-x[0]);
|
|
y[2]=y[0]+t*(y[1]-y[0]);
|
|
|
|
return sqrt((p-x[2])*(p-x[2]) + (q-y[2])*(q-y[2]));
|
|
}
|
|
|
|
int CFemmeDoc::ClosestSegment(double x, double y)
|
|
{
|
|
double d0,d1;
|
|
int i,j;
|
|
|
|
if(linelist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=ShortestDistance(x,y,0);
|
|
for(i=0;i<linelist.GetSize();i++){
|
|
d1=ShortestDistance(x,y,i);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
int CFemmeDoc::ClosestArcSegment(double x, double y)
|
|
{
|
|
double d0,d1;
|
|
int i,j;
|
|
|
|
if(arclist.GetSize()==0) return -1;
|
|
|
|
j=0;
|
|
d0=ShortestDistanceFromArc(CComplex(x,y),arclist[0]);
|
|
for(i=0;i<arclist.GetSize();i++){
|
|
d1=ShortestDistanceFromArc(CComplex(x,y),arclist[i]);
|
|
if(d1<d0){
|
|
d0=d1;
|
|
j=i;
|
|
}
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
BOOL CFemmeDoc::GetIntersection(int n0, int n1, int segm, double *xi, double *yi)
|
|
// prospective line specified by n0,n1;
|
|
// segment specified by segm;
|
|
// coordinates of the intersection returned in xi,yi
|
|
{
|
|
CComplex p0,p1,q0,q1;
|
|
double ee,x,z;
|
|
|
|
// Check to see if the two lines have a common endpoint
|
|
// If they do, there can be no other intersection...
|
|
if (n0==linelist[segm].n0) return FALSE;
|
|
if (n0==linelist[segm].n1) return FALSE;
|
|
if (n1==linelist[segm].n0) return FALSE;
|
|
if (n1==linelist[segm].n1) return FALSE;
|
|
|
|
// Get a definition of "real small" based on the lengths
|
|
// of the lines of interest;
|
|
p0=nodelist[linelist[segm].n0].CC();
|
|
p1=nodelist[linelist[segm].n1].CC();
|
|
q0=nodelist[n0].CC();
|
|
q1=nodelist[n1].CC();
|
|
ee=min(abs(p1-p0),abs(q1-q0))*1.0e-8;
|
|
|
|
// Rotate and scale the prospective line
|
|
q0=(q0-p0)/(p1-p0);
|
|
q1=(q1-p0)/(p1-p0);
|
|
|
|
// Check for cases where there is obviously no intersection
|
|
if ((Re(q0)<=0.) && (Re(q1)<=0.)) return FALSE;
|
|
if ((Re(q0)>=1.) && (Re(q1)>=1.)) return FALSE;
|
|
if ((Im(q0)<=0.) && (Im(q1)<=0.)) return FALSE;
|
|
if ((Im(q0)>=0.) && (Im(q1)>=0.)) return FALSE;
|
|
|
|
// compute intersection
|
|
z=Im(q0)/Im(q0-q1);
|
|
|
|
// check to see if the line segments intersect at a point sufficiently
|
|
// far from the segment endpoints....
|
|
x=Re((1.0 - z)*q0 + z*q1);
|
|
if((x < ee) || (x > (1.0 - ee))) return FALSE;
|
|
|
|
// return resulting intersection point
|
|
p0 = (1.0 - z)*nodelist[n0].CC() + z*nodelist[n1].CC();
|
|
*xi=Re(p0);
|
|
*yi=Im(p0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFemmeDoc::DeleteSelectedBlockLabels()
|
|
{
|
|
int i=0;
|
|
BOOL flag=FALSE;
|
|
|
|
if (blocklist.GetSize() > 0) do{
|
|
if(blocklist[i].IsSelected==TRUE){
|
|
blocklist.RemoveAt(i,1);
|
|
flag=TRUE;
|
|
}
|
|
else i++;
|
|
} while (i<blocklist.GetSize());
|
|
|
|
blocklist.FreeExtra();
|
|
return flag;
|
|
}
|
|
|
|
BOOL CFemmeDoc::DeleteSelectedSegments()
|
|
{
|
|
int i=0;
|
|
BOOL flag=FALSE;
|
|
|
|
if (linelist.GetSize() > 0) do{
|
|
if(linelist[i].IsSelected==TRUE){
|
|
linelist.RemoveAt(i,1);
|
|
flag=TRUE;
|
|
}
|
|
else i++;
|
|
} while (i<linelist.GetSize());
|
|
|
|
linelist.FreeExtra();
|
|
|
|
return flag;
|
|
}
|
|
|
|
BOOL CFemmeDoc::DeleteSelectedArcSegments()
|
|
{
|
|
int i=0;
|
|
BOOL flag=FALSE;
|
|
|
|
if (arclist.GetSize() > 0) do{
|
|
if(arclist[i].IsSelected==TRUE){
|
|
arclist.RemoveAt(i,1);
|
|
flag=TRUE;
|
|
}
|
|
else i++;
|
|
} while (i<arclist.GetSize());
|
|
|
|
arclist.FreeExtra();
|
|
|
|
return flag;
|
|
}
|
|
|
|
BOOL CFemmeDoc::DeleteSelectedNodes()
|
|
{
|
|
int i=0;
|
|
int j;
|
|
BOOL flag=FALSE;
|
|
|
|
if (nodelist.GetSize() > 0) do{
|
|
if(nodelist[i].IsSelected==TRUE){
|
|
flag=TRUE;
|
|
// first remove all lines that contain the point;
|
|
for(j=0;j<linelist.GetSize();j++)
|
|
if((linelist[j].n0==i) || (linelist[j].n1==i))
|
|
linelist[j].ToggleSelect();
|
|
DeleteSelectedSegments();
|
|
|
|
// remove all arcs that contain the point;
|
|
for(j=0;j<arclist.GetSize();j++)
|
|
if((arclist[j].n0==i) || (arclist[j].n1==i))
|
|
arclist[j].ToggleSelect();
|
|
DeleteSelectedArcSegments();
|
|
|
|
// remove node from the nodelist...
|
|
nodelist.RemoveAt(i,1);
|
|
|
|
// update lines to point to the new node numbering
|
|
for(j=0;j<linelist.GetSize();j++){
|
|
if (linelist[j].n0>i) linelist[j].n0--;
|
|
if (linelist[j].n1>i) linelist[j].n1--;
|
|
}
|
|
|
|
// update arcs to point to the new node numbering
|
|
for(j=0;j<arclist.GetSize();j++){
|
|
if (arclist[j].n0>i) arclist[j].n0--;
|
|
if (arclist[j].n1>i) arclist[j].n1--;
|
|
}
|
|
}
|
|
else i++;
|
|
} while (i<nodelist.GetSize());
|
|
|
|
nodelist.FreeExtra();
|
|
|
|
return flag;
|
|
}
|
|
|
|
void CFemmeDoc::OnEditMatprops()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
CPtProp pProp;
|
|
|
|
pProp.pblockproplist=&blockproplist;
|
|
pProp.PropType=2;
|
|
pProp.ProblemType=ProblemType;
|
|
|
|
pProp.DoModal();
|
|
}
|
|
|
|
void CFemmeDoc::OnEditPtprops()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
CPtProp pProp;
|
|
|
|
pProp.pnodeproplist=&nodeproplist;
|
|
pProp.PropType=0;
|
|
|
|
pProp.DoModal();
|
|
}
|
|
|
|
void CFemmeDoc::OnEditSegprops()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
CPtProp pProp;
|
|
|
|
pProp.plineproplist=&lineproplist;
|
|
pProp.PropType=1;
|
|
pProp.ProblemType=ProblemType;
|
|
pProp.DoModal();
|
|
}
|
|
|
|
void CFemmeDoc::OnEditCircprops()
|
|
{
|
|
CPtProp pProp;
|
|
|
|
pProp.pcircproplist=&circproplist;
|
|
pProp.ProblemType=ProblemType;
|
|
pProp.PropType=3;
|
|
|
|
pProp.DoModal();
|
|
}
|
|
|
|
BOOL CFemmeDoc::OpBlkDlg()
|
|
{
|
|
int i,j,k,nselected,cselected;
|
|
double a;
|
|
COpBlkDlg zDlg;
|
|
|
|
zDlg.ProblemType=ProblemType;
|
|
|
|
// check to see how many (if any) blocks are selected.
|
|
for(i=0,k=0,nselected=0,cselected=0;i<blocklist.GetSize();i++)
|
|
{
|
|
if (blocklist[i].IsSelected==TRUE){
|
|
if(nselected==0){
|
|
nselected++;
|
|
zDlg.m_ingroup=blocklist[i].InGroup;
|
|
}
|
|
else if(blocklist[i].BlockType!=blocklist[k].BlockType)
|
|
nselected++;
|
|
if(cselected==0) cselected++;
|
|
else if(blocklist[i].InCircuit!=blocklist[k].InCircuit)
|
|
cselected++;
|
|
if(blocklist[i].InGroup!=zDlg.m_ingroup) zDlg.m_ingroup=0;
|
|
k=i;
|
|
if(blocklist[i].IsExternal) zDlg.m_isexternal=TRUE;
|
|
if(blocklist[i].IsDefault) zDlg.m_isdefault=TRUE;
|
|
}
|
|
}
|
|
if (nselected==0) return FALSE;
|
|
if (nselected>1) zDlg.m_isdefault=FALSE;
|
|
|
|
// find average block size;
|
|
for(i=0,j=0,a=0.;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].IsSelected==TRUE)
|
|
if (blocklist[i].MaxArea>a) a=blocklist[i].MaxArea;
|
|
|
|
zDlg.m_sidelength=floor(2.e07*sqrt(a/PI)+0.5)/1.e07;
|
|
|
|
zDlg.pblockproplist=&blockproplist;
|
|
zDlg.pcircproplist=&circproplist;
|
|
|
|
if (nselected==1){
|
|
if(blocklist[k].BlockType=="<No Mesh>") zDlg.cursel=1;
|
|
else for(i=0,zDlg.cursel=0;i<blockproplist.GetSize();i++)
|
|
if (blockproplist[i].BlockName==blocklist[k].BlockType)
|
|
zDlg.cursel=i+2;
|
|
}
|
|
else zDlg.cursel=0;
|
|
|
|
if (cselected==1){
|
|
for(i=0,zDlg.circsel=0;i<circproplist.GetSize();i++)
|
|
if (circproplist[i].CircName==blocklist[k].InCircuit)
|
|
zDlg.circsel=i+1;
|
|
}
|
|
else zDlg.circsel=0;
|
|
|
|
zDlg.m_magdir=blocklist[k].MagDir;
|
|
zDlg.m_magdirfctn=blocklist[k].MagDirFctn;
|
|
zDlg.m_turns=blocklist[k].Turns;
|
|
|
|
if (zDlg.DoModal()==IDOK){
|
|
for(i=0;i<blocklist.GetSize();i++)
|
|
{
|
|
if(blocklist[i].IsSelected==TRUE){
|
|
blocklist[i].MaxArea=PI*zDlg.m_sidelength*zDlg.m_sidelength/4.;
|
|
blocklist[i].MagDir=zDlg.m_magdir;
|
|
blocklist[i].MagDirFctn=zDlg.m_magdirfctn;
|
|
blocklist[i].Turns=zDlg.m_turns;
|
|
if (blocklist[i].Turns==0) blocklist[i].Turns++;
|
|
if (zDlg.cursel==0) blocklist[i].BlockType="<None>";
|
|
else if(zDlg.cursel==1) blocklist[i].BlockType="<No Mesh>";
|
|
else blocklist[i].BlockType=blockproplist[zDlg.cursel-2].BlockName;
|
|
if (zDlg.circsel==0) blocklist[i].InCircuit="<None>";
|
|
else blocklist[i].InCircuit=circproplist[zDlg.circsel-1].CircName;
|
|
blocklist[i].InGroup=zDlg.m_ingroup;
|
|
blocklist[i].IsExternal=zDlg.m_isexternal;
|
|
|
|
// Should be one and only one label specified as the default;
|
|
if (nselected==1){
|
|
if (zDlg.m_isdefault==TRUE)
|
|
{
|
|
blocklist[i].IsDefault=2;
|
|
for(j=0;j<blocklist.GetSize();j++)
|
|
if (j!=i) blocklist[j].IsDefault=FALSE;
|
|
}
|
|
else blocklist[i].IsDefault=FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CFemmeDoc::OpNodeDlg()
|
|
{
|
|
int i,k,nselected;
|
|
COpNodeDlg zDlg;
|
|
|
|
// check to see how many (if any) nodes are selected.
|
|
for(i=0,k=0,nselected=0;i<nodelist.GetSize();i++)
|
|
{
|
|
if (nodelist[i].IsSelected==TRUE){
|
|
if(nselected==0){
|
|
nselected++;
|
|
zDlg.m_ingroup=nodelist[i].InGroup;
|
|
}
|
|
else if(nodelist[i].BoundaryMarker!=nodelist[k].BoundaryMarker)
|
|
nselected++;
|
|
if(nodelist[i].InGroup!=zDlg.m_ingroup) zDlg.m_ingroup=0;
|
|
k=i;
|
|
}
|
|
}
|
|
if (nselected==0) return;
|
|
|
|
zDlg.pnodeproplist=&nodeproplist;
|
|
if (nselected==1){
|
|
for(i=0,zDlg.cursel=0;i<nodeproplist.GetSize();i++)
|
|
if (nodeproplist[i].PointName==nodelist[k].BoundaryMarker)
|
|
zDlg.cursel=i+1;
|
|
}
|
|
else zDlg.cursel=0;
|
|
|
|
if (zDlg.DoModal()==IDOK){
|
|
for(i=0;i<nodelist.GetSize();i++)
|
|
{
|
|
if(nodelist[i].IsSelected==TRUE){
|
|
if (zDlg.cursel==0) nodelist[i].BoundaryMarker="<None>";
|
|
else nodelist[i].BoundaryMarker=nodeproplist[zDlg.cursel-1].PointName;
|
|
nodelist[i].InGroup=zDlg.m_ingroup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFemmeDoc::OpSegDlg()
|
|
{
|
|
int i,j,k,nselected;
|
|
COpSegDlg zDlg;
|
|
|
|
// check to see how many (if any) nodes are selected.
|
|
for(i=0,k=0,nselected=0;i<linelist.GetSize();i++)
|
|
{
|
|
if (linelist[i].IsSelected==TRUE){
|
|
if(nselected==0){
|
|
nselected++;
|
|
zDlg.m_ingroup=linelist[i].InGroup;
|
|
}
|
|
else if(linelist[i].BoundaryMarker!=linelist[k].BoundaryMarker)
|
|
nselected++;
|
|
if(linelist[i].InGroup!=zDlg.m_ingroup) zDlg.m_ingroup=0;
|
|
k=i;
|
|
}
|
|
}
|
|
if (nselected==0) return;
|
|
|
|
// find properties block size;
|
|
double ms=0;
|
|
zDlg.m_hide=FALSE;
|
|
for(i=0,j=0;i<linelist.GetSize();i++)
|
|
if(linelist[i].IsSelected==TRUE){
|
|
if(linelist[i].MaxSideLength<0) ms=-1;
|
|
if (ms>=0) ms+=linelist[k].MaxSideLength;
|
|
j++;
|
|
if (linelist[i].Hidden==TRUE) zDlg.m_hide=TRUE;
|
|
}
|
|
ms/=(double) j;
|
|
|
|
zDlg.plineproplist=&lineproplist;
|
|
if (nselected==1){
|
|
for(i=0,zDlg.cursel=0;i<lineproplist.GetSize();i++)
|
|
if (lineproplist[i].BdryName==linelist[k].BoundaryMarker)
|
|
zDlg.cursel=i+1;
|
|
}
|
|
else zDlg.cursel=0;
|
|
|
|
if (ms<0){
|
|
zDlg.m_automesh=TRUE;
|
|
zDlg.m_linemeshsize=0;
|
|
}
|
|
else{
|
|
zDlg.m_automesh=FALSE;
|
|
zDlg.m_linemeshsize=ms;
|
|
}
|
|
|
|
if (zDlg.DoModal()==IDOK){
|
|
for(i=0;i<linelist.GetSize();i++)
|
|
{
|
|
if(linelist[i].IsSelected==TRUE){
|
|
|
|
if (zDlg.m_automesh==TRUE) linelist[i].MaxSideLength=-1;
|
|
else{
|
|
if (zDlg.m_linemeshsize>0)
|
|
linelist[i].MaxSideLength=zDlg.m_linemeshsize;
|
|
else zDlg.m_linemeshsize=-1;
|
|
}
|
|
if (zDlg.cursel==0) linelist[i].BoundaryMarker="<None>";
|
|
else linelist[i].BoundaryMarker=lineproplist[zDlg.cursel-1].BdryName;
|
|
|
|
linelist[i].Hidden=zDlg.m_hide;
|
|
linelist[i].InGroup=zDlg.m_ingroup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFemmeDoc::OpArcSegDlg()
|
|
{
|
|
int i,j,k,nselected;
|
|
COpArcSegDlg zDlg;
|
|
|
|
// check to see how many (if any) arcs are selected.
|
|
|
|
|
|
for(i=0,k=0,nselected=0;i<arclist.GetSize();i++)
|
|
{
|
|
if (arclist[i].IsSelected==TRUE){
|
|
if(nselected==0){
|
|
nselected++;
|
|
zDlg.m_ingroup=arclist[i].InGroup;
|
|
}
|
|
else if(arclist[i].BoundaryMarker!=arclist[k].BoundaryMarker)
|
|
nselected++;
|
|
if(arclist[i].InGroup!=zDlg.m_ingroup) zDlg.m_ingroup=0;
|
|
k=i;
|
|
}
|
|
}
|
|
if (nselected==0) return;
|
|
|
|
// find properties block size;
|
|
double ms=0;
|
|
zDlg.m_hide=FALSE;
|
|
for(i=0,j=0;i<arclist.GetSize();i++)
|
|
if(arclist[i].IsSelected==TRUE){
|
|
ms+=arclist[k].MaxSideLength;
|
|
j++;
|
|
if(arclist[i].Hidden==TRUE) zDlg.m_hide=TRUE;
|
|
}
|
|
|
|
ms/=(double) j;
|
|
|
|
zDlg.plineproplist=&lineproplist;
|
|
if (nselected==1){
|
|
zDlg.m_MaxSeg=ms;
|
|
for(i=0,zDlg.cursel=0;i<lineproplist.GetSize();i++)
|
|
if (lineproplist[i].BdryName==arclist[k].BoundaryMarker)
|
|
zDlg.cursel=i+1;
|
|
}
|
|
else{
|
|
zDlg.cursel=0;
|
|
zDlg.m_MaxSeg=ms;
|
|
}
|
|
|
|
if (zDlg.DoModal()==IDOK){
|
|
for(i=0;i<arclist.GetSize();i++)
|
|
{
|
|
if(arclist[i].IsSelected==TRUE){
|
|
if (zDlg.cursel==0) arclist[i].BoundaryMarker="<None>";
|
|
else arclist[i].BoundaryMarker=lineproplist[zDlg.cursel-1].BdryName;
|
|
arclist[i].MaxSideLength=zDlg.m_MaxSeg;
|
|
arclist[i].Hidden=zDlg.m_hide;
|
|
arclist[i].InGroup=zDlg.m_ingroup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CFemmeDoc::OpGrpDlg()
|
|
{
|
|
COpGrp dlg;
|
|
BOOL bFlag=FALSE;
|
|
int nsel=0;
|
|
int i;
|
|
|
|
dlg.m_ingroup=0;
|
|
|
|
for(i=0;i<arclist.GetSize();i++)
|
|
if (arclist[i].IsSelected==TRUE){
|
|
nsel++;
|
|
if(dlg.m_ingroup!=arclist[i].InGroup)
|
|
{
|
|
if(bFlag==FALSE){
|
|
dlg.m_ingroup=arclist[i].InGroup;
|
|
bFlag=TRUE;
|
|
}
|
|
else dlg.m_ingroup=0;
|
|
}
|
|
}
|
|
|
|
for(i=0;i<linelist.GetSize();i++)
|
|
if (linelist[i].IsSelected==TRUE)
|
|
{
|
|
nsel++;
|
|
if(dlg.m_ingroup!=linelist[i].InGroup)
|
|
{
|
|
if(bFlag==FALSE){
|
|
dlg.m_ingroup=linelist[i].InGroup;
|
|
bFlag=TRUE;
|
|
}
|
|
else dlg.m_ingroup=0;
|
|
}
|
|
}
|
|
|
|
for(i=0;i<blocklist.GetSize();i++)
|
|
if (blocklist[i].IsSelected==TRUE)
|
|
{
|
|
nsel++;
|
|
if(dlg.m_ingroup!=blocklist[i].InGroup)
|
|
{
|
|
if(bFlag==FALSE){
|
|
dlg.m_ingroup=blocklist[i].InGroup;
|
|
bFlag=TRUE;
|
|
}
|
|
else dlg.m_ingroup=0;
|
|
}
|
|
}
|
|
|
|
for(i=0;i<nodelist.GetSize();i++)
|
|
if (nodelist[i].IsSelected==TRUE)
|
|
{
|
|
nsel++;
|
|
if(dlg.m_ingroup!=nodelist[i].InGroup)
|
|
{
|
|
if(bFlag==FALSE){
|
|
dlg.m_ingroup=nodelist[i].InGroup;
|
|
bFlag=TRUE;
|
|
}
|
|
else dlg.m_ingroup=0;
|
|
}
|
|
}
|
|
if (nsel==0) return;
|
|
|
|
if(dlg.DoModal()==IDOK){
|
|
|
|
for(i=0;i<nodelist.GetSize();i++)
|
|
if(nodelist[i].IsSelected==TRUE)
|
|
nodelist[i].InGroup=dlg.m_ingroup;
|
|
|
|
for(i=0;i<linelist.GetSize();i++)
|
|
if(linelist[i].IsSelected==TRUE)
|
|
linelist[i].InGroup=dlg.m_ingroup;
|
|
|
|
for(i=0;i<arclist.GetSize();i++)
|
|
if(arclist[i].IsSelected==TRUE)
|
|
arclist[i].InGroup=dlg.m_ingroup;
|
|
|
|
for(i=0;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].IsSelected==TRUE)
|
|
blocklist[i].InGroup=dlg.m_ingroup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
BOOL CFemmeDoc::OldOnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
FILE *fp;
|
|
int i,j,k,t,len;
|
|
char s[1024];
|
|
CPointProp PProp;
|
|
CBoundaryProp BProp;
|
|
CMaterialProp MProp;
|
|
CNode node;
|
|
CSegment segm;
|
|
CArcSegment asegm;
|
|
CBlockLabel blk;
|
|
|
|
if ((fp=fopen(lpszPathName,"rt"))==NULL){
|
|
MsgBox("Couldn't read from specified .fem file");
|
|
return FALSE;
|
|
}
|
|
|
|
fscanf(fp,"Frequency = %lf\n",&Frequency);
|
|
fscanf(fp,"LengthUnits = %i\n",&LengthUnits);
|
|
fscanf(fp,"ProblemType = %i\n",&ProblemType);
|
|
fscanf(fp,"Coords = %i\n",&Coords);
|
|
fgets(s,1024,fp);
|
|
len=(int) strlen(s);
|
|
len--;
|
|
s[len]=NULL;
|
|
for(i=0;i<len;i++){
|
|
if(s[i]=='{') s[i]=13;
|
|
if(s[i]=='}') s[i]=10;
|
|
}
|
|
ProblemNote=s;
|
|
|
|
// Read in materials library...
|
|
|
|
fscanf(fp,"%i\n",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
|
|
fgets(s,1024,fp);
|
|
len=(int) strlen(s); for(j=0;j<len;j++) if (s[j]<26) s[j]=NULL;
|
|
PProp.PointName=s;
|
|
fscanf(fp,"%lf %lf %lf %lf\n",&PProp.Jp.re,&PProp.Jp.im,&PProp.Ap.re,&PProp.Ap.im);
|
|
nodeproplist.Add(PProp);
|
|
}
|
|
|
|
fscanf(fp,"%i\n",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
len=(int) strlen(s); for(j=0;j<len;j++) if (s[j]<26) s[j]=NULL;
|
|
BProp.BdryName=s;
|
|
fscanf(fp,"%i %lf %lf %lf %lf %lf %lf %lf %lf\n",&BProp.BdryFormat,
|
|
&BProp.A0,&BProp.A1,&BProp.A2,&BProp.phi,&BProp.Mu,
|
|
&BProp.Sig,&BProp.c0.re,&BProp.c1.re);
|
|
lineproplist.Add(BProp);
|
|
}
|
|
|
|
fscanf(fp,"%i\n",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
len=(int) strlen(s); for(j=0;j<len;j++) if (s[j]<26) s[j]=NULL;
|
|
MProp.BlockName=s;
|
|
fscanf(fp,"%lf %lf %lf %lf %lf %lf %lf %lf %lf %i %lf\n",
|
|
&MProp.mu_x,&MProp.mu_y,&MProp.H_c,
|
|
&MProp.Theta_m,&MProp.Jsrc.re,&MProp.Jsrc.im,&MProp.Cduct,
|
|
&MProp.Lam_d,&MProp.Theta_hn,&MProp.LamType,&MProp.LamFill);
|
|
MProp.Theta_hx=MProp.Theta_hn;
|
|
MProp.Theta_hy=MProp.Theta_hn;
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&MProp.BHpoints);
|
|
if (MProp.BHpoints>0)
|
|
MProp.BHdata=(CComplex *)calloc(MProp.BHpoints,sizeof(CComplex));
|
|
for(j=0;j<MProp.BHpoints;j++){
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%lf %lf",&MProp.BHdata[j].re,&MProp.BHdata[j].im);
|
|
}
|
|
blockproplist.Add(MProp);
|
|
}
|
|
MProp.BHpoints=0;
|
|
|
|
// read in node list
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%lf %lf %i\n",&node.x,&node.y,&t);
|
|
t=t-2;
|
|
if(t<0) node.BoundaryMarker="";
|
|
else node.BoundaryMarker=nodeproplist[t].PointName;
|
|
nodelist.Add(node);
|
|
}
|
|
|
|
// read in segment list
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%i %i %lf %i\n",&segm.n0,&segm.n1,&segm.MaxSideLength,&t);
|
|
t=-(t+2);
|
|
if(t<0) segm.BoundaryMarker="";
|
|
else segm.BoundaryMarker=lineproplist[t].BdryName;
|
|
linelist.Add(segm);
|
|
}
|
|
|
|
// read in arc segment list
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%i %i %lf %lf %i\n",&asegm.n0,&asegm.n1,
|
|
&asegm.ArcLength,&asegm.MaxSideLength,&t);
|
|
t=-(t+2);
|
|
if(t<0) asegm.BoundaryMarker="";
|
|
else asegm.BoundaryMarker=lineproplist[t].BdryName;
|
|
arclist.Add(asegm);
|
|
}
|
|
|
|
// read in list of holes;
|
|
fscanf(fp,"%i\n",&k);
|
|
blk.BlockType="<No Mesh>";
|
|
blk.MaxArea=0;
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%lf %lf\n",&blk.x,&blk.y);
|
|
blocklist.Add(blk);
|
|
}
|
|
|
|
// read in regional attributes
|
|
fscanf(fp,"%i\n",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fscanf(fp,"%lf %lf %i %lf\n",&blk.x,&blk.y,&t,&blk.MaxArea);
|
|
blk.MagDir=0.;
|
|
blk.MagDirFctn.Empty();
|
|
blk.Turns=1;
|
|
if (blk.MaxArea<0) blk.MaxArea=0;
|
|
if (t<0) blk.BlockType="<None>";
|
|
else{
|
|
blk.BlockType=blockproplist[t].BlockName;
|
|
blk.MagDir =blockproplist[t].Theta_m;
|
|
}
|
|
blocklist.Add(blk);
|
|
}
|
|
fclose(fp);
|
|
|
|
FirstDraw=TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
char* StripKey(char *c)
|
|
{
|
|
char *d;
|
|
int i,k;
|
|
|
|
k=(int) strlen(c);
|
|
|
|
for(i=0;i<k;i++){
|
|
if (c[i] == '='){
|
|
d=c+i+1;
|
|
return d;
|
|
}
|
|
}
|
|
|
|
return c+k;
|
|
}
|
|
|
|
char *ParseDbl(char *t, double *f)
|
|
{
|
|
if (t==NULL) return NULL;
|
|
|
|
int i,j,k,u,ws;
|
|
static char w[]="\t, \n";
|
|
char *v;
|
|
|
|
k=(int) strlen(t); if(k==0) return NULL;
|
|
|
|
for(i=0,u=0,v=NULL;i<k;i++){
|
|
for(j=0,ws=0;j<4;j++){
|
|
if (t[i]==w[j]){
|
|
ws=1;
|
|
if (u==1) u=2;
|
|
}
|
|
}
|
|
if ((ws==0) && (u==0)) u=1;
|
|
if ((ws==0) && (u==2)){
|
|
v=t+i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (u==0) return NULL; //nothing left in the string;
|
|
if (v==NULL) v=t+k;
|
|
|
|
sscanf(t,"%lf",f);
|
|
|
|
return v;
|
|
}
|
|
|
|
char *ParseInt(char *t, int *f)
|
|
{
|
|
if (t==NULL) return NULL;
|
|
|
|
int i,j,k,u,ws;
|
|
static char w[]="\t, \n";
|
|
char *v;
|
|
|
|
k=(int) strlen(t); if(k==0) return NULL;
|
|
|
|
for(i=0,u=0,v=NULL;i<k;i++){
|
|
for(j=0,ws=0;j<4;j++){
|
|
if (t[i]==w[j]){
|
|
ws=1;
|
|
if (u==1) u=2;
|
|
}
|
|
}
|
|
if ((ws==0) && (u==0)) u=1;
|
|
if ((ws==0) && (u==2)){
|
|
v=t+i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (u==0) return NULL; //nothing left in the string;
|
|
if (v==NULL) v=t+k;
|
|
|
|
sscanf(t,"%i",f);
|
|
|
|
return v;
|
|
}
|
|
|
|
char *ParseString(char *t, CString *s)
|
|
{
|
|
if (t==NULL) return NULL;
|
|
if (strlen(t)==0) return t;
|
|
|
|
int n1,n2,k;
|
|
|
|
// find first quote in the source string
|
|
for(k=0,n1=-1;k< (int) strlen(t);k++)
|
|
{
|
|
if (t[k]=='\"'){
|
|
n1=k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (n1<0) return t;
|
|
|
|
// find second quote in the source string
|
|
for(k=n1+1,n2=-1;k< (int) strlen(t);k++)
|
|
{
|
|
if (t[k]=='\"'){
|
|
n2=k;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (n2<0) return t;
|
|
|
|
*s=t;
|
|
*s=s->Mid(n1+1,n2-n1-1);
|
|
|
|
return (t+n2+1);
|
|
}
|
|
|
|
BOOL CFemmeDoc::OnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
if (!CDocument::OnOpenDocument(lpszPathName))
|
|
return FALSE;
|
|
|
|
// make sure old document is cleared out...
|
|
OnNewDocument();
|
|
|
|
FILE *fp;
|
|
int i,j,k,t;
|
|
int vers=0;
|
|
char s[1024],q[1024];
|
|
char *v;
|
|
CPointProp PProp;
|
|
CBoundaryProp BProp;
|
|
CMaterialProp MProp;
|
|
CCircuit CProp;
|
|
CNode node;
|
|
CSegment segm;
|
|
CArcSegment asegm;
|
|
CBlockLabel blk;
|
|
|
|
if ((fp=fopen(lpszPathName,"rt"))==NULL){
|
|
MsgBox("Couldn't read from specified .fem file");
|
|
return FALSE;
|
|
}
|
|
|
|
// Check to see if this is an old-version femm datafile
|
|
fgets(s,1024,fp);
|
|
if (strncmp(s,"Frequency",8)==0){
|
|
fclose(fp);
|
|
return OldOnOpenDocument(lpszPathName);
|
|
}
|
|
else rewind(fp); // Go back to beginning of the file;
|
|
|
|
// hook to catch old files where depth wasn't defined:
|
|
Depth=-1;
|
|
|
|
// parse the file
|
|
while (fgets(s,1024,fp)!=NULL)
|
|
{
|
|
if (sscanf(s,"%s",q)==EOF) q[0]=NULL;
|
|
// int _strnicmp( const char *string1, const char *string2, size_t count );
|
|
|
|
// Deal with flag for file format version
|
|
if( _strnicmp(q,"[format]",8)==0 ){
|
|
v=StripKey(s);
|
|
double dblvers;
|
|
sscanf(v,"%lf",&dblvers); vers = (int) (10.*dblvers + 0.5);
|
|
if(vers>40) MsgBox("This file is from a newer version of FEMM\nThis file may contain attributes not\nsupported by this version of FEMM");
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Frequency of the problem
|
|
if( _strnicmp(q,"[frequency]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Frequency);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Depth in the into-the-page direction
|
|
if( _strnicmp(q,"[depth]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Depth);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Required solver precision
|
|
if( _strnicmp(q,"[precision]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&Precision);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Solver to use for AC problems
|
|
if( _strnicmp(q,"[acsolver]",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&ACSolver);
|
|
q[0]=NULL;
|
|
// 0 == successive approx
|
|
// 1 == newton
|
|
}
|
|
|
|
// Minimum Angle Constraint for finite element mesh
|
|
if( _strnicmp(q,"[minangle]",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MinAngle);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Smart Mesh flag
|
|
if( _strnicmp(q,"[dosmartmesh]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&SmartMesh);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Units of length used by the problem
|
|
if( _strnicmp(q,"[lengthunits]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if( _strnicmp(q,"inches",6)==0) LengthUnits=0;
|
|
else if( _strnicmp(q,"millimeters",11)==0) LengthUnits=1;
|
|
else if( _strnicmp(q,"centimeters",1)==0) LengthUnits=2;
|
|
else if( _strnicmp(q,"mils",4)==0) LengthUnits=4;
|
|
else if( _strnicmp(q,"microns",6)==0) LengthUnits=5;
|
|
else if( _strnicmp(q,"meters",6)==0) LengthUnits=3;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Problem Type (planar or axisymmetric)
|
|
if( _strnicmp(q,"[problemtype]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if( _strnicmp(q,"planar",6)==0) ProblemType=0;
|
|
if( _strnicmp(q,"axisymmetric",3)==0) ProblemType=1;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Coordinates (cartesian or polar)
|
|
if( _strnicmp(q,"[coordinates]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%s",q);
|
|
if ( _strnicmp(q,"cartesian",4)==0) Coords=0;
|
|
if ( _strnicmp(q,"polar",5)==0) Coords=1;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Comments
|
|
if (_strnicmp(q,"[comment]",9)==0){
|
|
v=StripKey(s);
|
|
// put in carriage returns;
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if((v[i]=='\\') && (v[i+1]=='n')){
|
|
v[i]=13;
|
|
v[i+1]=10;
|
|
}
|
|
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
ProblemNote=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// name of previous solution file for AC incremental permeability solution
|
|
// Previous Solution File
|
|
if( _strnicmp(q,"[prevsoln]",10)==0){
|
|
int i;
|
|
v=StripKey(s);
|
|
|
|
// have to do this carefully to accept a filename with spaces
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
|
|
PrevSoln=v;
|
|
if (PrevSoln.GetLength()==0) PrevType=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Type of previous solution file
|
|
if (_strnicmp(q, "[prevtype]", 10) == 0) {
|
|
v = StripKey(s);
|
|
sscanf(v, "%i", &PrevType);
|
|
q[0] = NULL;
|
|
// 0 == None
|
|
// 1 == Incremental
|
|
// 2 == Frozen
|
|
}
|
|
|
|
// properties for axisymmetric external region
|
|
if( _strnicmp(q,"[extzo]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extZo);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"[extro]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extRo);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"[extri]",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&extRi);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Point Properties
|
|
if( _strnicmp(q,"<beginpoint>",11)==0){
|
|
PProp.PointName="New Point Property";
|
|
PProp.Jp=0;
|
|
PProp.Ap=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<pointname>",11)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
PProp.PointName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_re>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Ap.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_im>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Ap.im);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<I_re>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Jp.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<I_im>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.Jp.im);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endpoint>",9)==0){
|
|
nodeproplist.Add(PProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Boundary Properties;
|
|
if( _strnicmp(q,"<beginbdry>",11)==0){
|
|
BProp.BdryName="New Boundary";
|
|
BProp.BdryFormat=0;
|
|
BProp.A0=0.;
|
|
BProp.A1=0.;
|
|
BProp.A2=0.;
|
|
BProp.phi=0.;
|
|
BProp.Mu=0.;
|
|
BProp.Sig=0.;
|
|
BProp.c0=0.;
|
|
BProp.c1=0.;
|
|
BProp.InnerAngle=0;
|
|
BProp.OuterAngle=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<bdryname>",10)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
BProp.BdryName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<bdrytype>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&BProp.BdryFormat);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<mu_ssd>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.Mu);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<sigma_ssd>",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.Sig);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_0>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.A0);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_1>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.A1);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<A_2>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.A2);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.phi);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c0>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c0.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c1>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c1.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c0i>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c0.im);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c1i>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c1.im);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<innerangle>",12)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.InnerAngle);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<outerangle>",12)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.OuterAngle);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endbdry>",9)==0){
|
|
lineproplist.Add(BProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Block Properties;
|
|
if( _strnicmp(q,"<beginblock>",12)==0){
|
|
MProp.BlockName="New Material";
|
|
MProp.mu_x=1.;
|
|
MProp.mu_y=1.; // permeabilities, relative
|
|
MProp.H_c=0.; // magnetization, A/m
|
|
MProp.Jsrc=0; // applied current density, MA/m^2
|
|
MProp.Cduct=0.; // conductivity of the material, MS/m
|
|
MProp.Lam_d=0.; // lamination thickness, mm
|
|
MProp.Theta_hn=0.; // hysteresis angle, degrees
|
|
MProp.Theta_hx=0.;
|
|
MProp.Theta_hy=0.;
|
|
MProp.LamFill=1.; // lamination fill factor;
|
|
MProp.LamType=0; // type of lamination;
|
|
MProp.NStrands=0;
|
|
MProp.WireD=0;
|
|
MProp.BHpoints=0;
|
|
MProp.BHdata=NULL;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<blockname>",10)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
MProp.BlockName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<mu_x>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.mu_x);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<mu_y>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.mu_y);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<H_c>",5)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.H_c);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<J_re>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Jsrc.re);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<J_im>",6)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Jsrc.im);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<sigma>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Cduct);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi_h>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Theta_hn);
|
|
if(vers==30){
|
|
MProp.Theta_hx=MProp.Theta_hn;
|
|
MProp.Theta_hy=MProp.Theta_hn;
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi_hx>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Theta_hx);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<phi_hy>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Theta_hy);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<d_lam>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.Lam_d);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<LamFill>",8)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.LamFill);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<LamType>",9)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&MProp.LamType);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<NStrands>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&MProp.NStrands);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<WireD>",7)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.WireD);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<BHPoints>",10)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&MProp.BHpoints);
|
|
if (MProp.BHpoints>0)
|
|
{
|
|
MProp.BHdata=(CComplex *)calloc(MProp.BHpoints,sizeof(CComplex));
|
|
for(j=0;j<MProp.BHpoints;j++){
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%lf %lf",&MProp.BHdata[j].re,&MProp.BHdata[j].im);
|
|
}
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endblock>",9)==0){
|
|
blockproplist.Add(MProp);
|
|
MProp.BHpoints=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Circuit Properties
|
|
if( _strnicmp(q,"<begincircuit>",14)==0){
|
|
CProp.CircName="New Circuit";
|
|
CProp.Amps=0.;
|
|
CProp.CircType=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<circuitname>",13)==0){
|
|
v=StripKey(s);
|
|
k=(int) strlen(v);
|
|
for(i=0;i<k;i++)
|
|
if(v[i]=='\"'){
|
|
v=v+i+1;
|
|
i=k;
|
|
}
|
|
k=(int) strlen(v);
|
|
if(k>0) for(i=k-1;i>=0;i--){
|
|
if(v[i]=='\"'){
|
|
v[i]=0;
|
|
i=-1;
|
|
}
|
|
}
|
|
CProp.CircName=v;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<totalamps_re>",14)==0){
|
|
double inval;
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&inval);
|
|
CProp.Amps+=inval;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<totalamps_im>",14)==0){
|
|
double inval;
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&inval);
|
|
CProp.Amps+=(I*inval);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<circuittype>",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&CProp.CircType);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endcircuit>",12)==0){
|
|
circproplist.Add(CProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Points list;
|
|
if(_strnicmp(q,"[numpoints]",11)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
|
|
v=ParseDbl(s,&node.x);
|
|
v=ParseDbl(v,&node.y);
|
|
v=ParseInt(v,&t);
|
|
v=ParseInt(v,&node.InGroup);
|
|
if(t==0) node.BoundaryMarker="";
|
|
else if(t<=(int) nodeproplist.GetSize())
|
|
node.BoundaryMarker=nodeproplist[t-1].PointName;
|
|
nodelist.Add(node);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in segment list
|
|
if(_strnicmp(q,"[numsegments]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
|
|
// some defaults
|
|
segm.MaxSideLength=0;
|
|
t=0;
|
|
segm.Hidden=0;
|
|
segm.InGroup=0;
|
|
|
|
// scan in data
|
|
v=ParseInt(s,&segm.n0);
|
|
v=ParseInt(v,&segm.n1);
|
|
v=ParseDbl(v,&segm.MaxSideLength);
|
|
v=ParseInt(v,&t);
|
|
v=ParseInt(v,&segm.Hidden);
|
|
v=ParseInt(v,&segm.InGroup);
|
|
|
|
if(t==0) segm.BoundaryMarker="";
|
|
else if (t<=(int) lineproplist.GetSize())
|
|
segm.BoundaryMarker=lineproplist[t-1].BdryName;
|
|
linelist.Add(segm);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in arc segment list
|
|
if(_strnicmp(q,"[numarcsegments]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
|
|
// some defaults
|
|
asegm.Hidden=0;
|
|
asegm.MaxSideLength=-1.;
|
|
asegm.InGroup=0;
|
|
t=0;
|
|
|
|
// scan in data
|
|
v=ParseInt(s,&asegm.n0);
|
|
v=ParseInt(v,&asegm.n1);
|
|
v=ParseDbl(v,&asegm.ArcLength);
|
|
v=ParseDbl(v,&asegm.MaxSideLength);
|
|
v=ParseInt(v,&t);
|
|
v=ParseInt(v,&asegm.Hidden);
|
|
v=ParseInt(v,&asegm.InGroup);
|
|
asegm.mySideLength=asegm.MaxSideLength;
|
|
if(t==0) asegm.BoundaryMarker="";
|
|
else if (t<=(int) lineproplist.GetSize())
|
|
asegm.BoundaryMarker=lineproplist[t-1].BdryName;
|
|
arclist.Add(asegm);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
|
|
// read in list of holes;
|
|
if(_strnicmp(q,"[numholes]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
if(k>0)
|
|
{
|
|
blk.BlockType="<No Mesh>";
|
|
blk.MaxArea=0;
|
|
blk.InGroup=0;
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
v=ParseDbl(s,&blk.x);
|
|
v=ParseDbl(v,&blk.y);
|
|
v=ParseInt(v,&blk.InGroup);
|
|
|
|
blocklist.Add(blk);
|
|
}
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// read in regional attributes
|
|
if(_strnicmp(q,"[numblocklabels]",13)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&k);
|
|
for(i=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
|
|
//some defaults
|
|
t=0;
|
|
blk.MaxArea=0.;
|
|
blk.MagDir=0.;
|
|
blk.MagDirFctn.Empty();
|
|
blk.Turns=1;
|
|
blk.InCircuit="<None>";
|
|
blk.InGroup=0;
|
|
blk.IsExternal=0;
|
|
blk.IsDefault=0;
|
|
|
|
// scan in data
|
|
v=ParseDbl(s,&blk.x);
|
|
v=ParseDbl(v,&blk.y);
|
|
|
|
v=ParseInt(v,&t);
|
|
if (t==0) blk.BlockType="<None>";
|
|
else if(t<=(int) blockproplist.GetSize())
|
|
blk.BlockType=blockproplist[t-1].BlockName;
|
|
|
|
v=ParseDbl(v,&blk.MaxArea);
|
|
if (blk.MaxArea<0) blk.MaxArea=0;
|
|
else blk.MaxArea=PI*blk.MaxArea*blk.MaxArea/4.;
|
|
|
|
v=ParseInt(v,&t);
|
|
if (t==0) blk.InCircuit="<None>";
|
|
else if(t<=(int) circproplist.GetSize())
|
|
blk.InCircuit=circproplist[t-1].CircName;
|
|
|
|
v=ParseDbl(v,&blk.MagDir);
|
|
v=ParseInt(v,&blk.InGroup);
|
|
v=ParseInt(v,&blk.Turns);
|
|
v=ParseInt(v,&blk.IsExternal);
|
|
blk.IsDefault = blk.IsExternal & 2;
|
|
blk.IsExternal = blk.IsExternal & 1;
|
|
v=ParseString(v,&blk.MagDirFctn);
|
|
|
|
blocklist.Add(blk);
|
|
}
|
|
q[0]=NULL;
|
|
}
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
if(Depth==-1)
|
|
{
|
|
// if this is a v3.2 file we are importing, make the length
|
|
// equal to 1 meter, because 3.2 was all per-meter calculations
|
|
switch(LengthUnits)
|
|
{
|
|
case 1:
|
|
Depth=1000.; //mm
|
|
break;
|
|
case 2:
|
|
Depth=100.; //cm
|
|
break;
|
|
case 3:
|
|
Depth=1.; //m
|
|
break;
|
|
case 4:
|
|
Depth=1000./0.0254; // mils
|
|
break;
|
|
case 5:
|
|
Depth=1.e6; // microns
|
|
break;
|
|
default:
|
|
Depth=1./0.0254; // inches
|
|
break;
|
|
}
|
|
}
|
|
|
|
FirstDraw=TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL CFemmeDoc::OnSaveDocument(LPCTSTR lpszPathName)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
FILE *fp;
|
|
int i,j,k,t;
|
|
CString s;
|
|
|
|
// check to see if we are ready to write a datafile;
|
|
|
|
if ((fp=fopen(lpszPathName,"wt"))==NULL){
|
|
MsgBox("Couldn't write to specified file.\nPerhaps the file is write-protected?");
|
|
return FALSE;
|
|
}
|
|
|
|
fprintf(fp,"[Format] = 4.0\n");
|
|
fprintf(fp,"[Frequency] = %.17g\n",Frequency);
|
|
fprintf(fp,"[Precision] = %.17g\n",Precision);
|
|
fprintf(fp,"[MinAngle] = %.17g\n",MinAngle);
|
|
fprintf(fp,"[DoSmartMesh] = %i\n",SmartMesh);
|
|
fprintf(fp,"[Depth] = %.17g\n",Depth);
|
|
fprintf(fp,"[LengthUnits] = ");
|
|
switch(LengthUnits)
|
|
{
|
|
case 1:
|
|
fprintf(fp,"millimeters\n");
|
|
break;
|
|
case 2:
|
|
fprintf(fp,"centimeters\n");
|
|
break;
|
|
case 3:
|
|
fprintf(fp,"meters\n");
|
|
break;
|
|
case 4:
|
|
fprintf(fp,"mils\n");
|
|
break;
|
|
case 5:
|
|
fprintf(fp,"microns\n");
|
|
break;
|
|
default:
|
|
fprintf(fp,"inches\n");
|
|
break;
|
|
}
|
|
|
|
if (ProblemType==0) fprintf(fp,"[ProblemType] = planar\n");
|
|
else{
|
|
fprintf(fp,"[ProblemType] = axisymmetric\n");
|
|
if ((extRo!=0) && (extRi!=0))
|
|
{
|
|
fprintf(fp,"[extZo] = %.17g\n",extZo);
|
|
fprintf(fp,"[extRo] = %.17g\n",extRo);
|
|
fprintf(fp,"[extRi] = %.17g\n",extRi);
|
|
}
|
|
}
|
|
|
|
if (Coords==0) fprintf(fp,"[Coordinates] = cartesian\n");
|
|
else fprintf(fp,"[Coordinates] = polar\n");
|
|
|
|
s = ProblemNote;
|
|
for (i = 0;i<ProblemNote.GetLength();i++) {
|
|
if (s[i] == 13) s.SetAt(i, '\\');
|
|
if (s[i] == 10) s.SetAt(i, 'n');
|
|
}
|
|
|
|
fprintf(fp, "[ACSolver] = %i\n", ACSolver);
|
|
fprintf(fp, "[PrevType] = %i\n", PrevType);
|
|
fprintf(fp, "[PrevSoln] = \"%s\"\n", (const char *)PrevSoln);
|
|
fprintf(fp, "[Comment] = \"%s\"\n", (const char *)s);
|
|
|
|
// write out materials properties stuff...
|
|
fprintf(fp, "[PointProps] = %i\n", (int)nodeproplist.GetSize());
|
|
for (i = 0;i<nodeproplist.GetSize();i++)
|
|
{
|
|
fprintf(fp, " <BeginPoint>\n");
|
|
fprintf(fp, " <PointName> = \"%s\"\n", (const char *)nodeproplist[i].PointName);
|
|
fprintf(fp, " <I_re> = %.17g\n", nodeproplist[i].Jp.re);
|
|
fprintf(fp, " <I_im> = %.17g\n", nodeproplist[i].Jp.im);
|
|
fprintf(fp, " <A_re> = %.17g\n", nodeproplist[i].Ap.re);
|
|
fprintf(fp, " <A_im> = %.17g\n", nodeproplist[i].Ap.im);
|
|
fprintf(fp, " <EndPoint>\n");
|
|
}
|
|
|
|
fprintf(fp,"[BdryProps] = %i\n",(int) lineproplist.GetSize());
|
|
for(i=0;i<lineproplist.GetSize();i++)
|
|
{
|
|
fprintf(fp," <BeginBdry>\n");
|
|
fprintf(fp," <BdryName> = \"%s\"\n", (const char *) lineproplist[i].BdryName);
|
|
fprintf(fp," <BdryType> = %i\n",lineproplist[i].BdryFormat);
|
|
fprintf(fp," <A_0> = %.17g\n",lineproplist[i].A0);
|
|
fprintf(fp," <A_1> = %.17g\n",lineproplist[i].A1);
|
|
fprintf(fp," <A_2> = %.17g\n",lineproplist[i].A2);
|
|
fprintf(fp," <Phi> = %.17g\n",lineproplist[i].phi);
|
|
fprintf(fp," <c0> = %.17g\n",lineproplist[i].c0.re);
|
|
fprintf(fp," <c0i> = %.17g\n",lineproplist[i].c0.im);
|
|
fprintf(fp," <c1> = %.17g\n",lineproplist[i].c1.re);
|
|
fprintf(fp," <c1i> = %.17g\n",lineproplist[i].c1.im);
|
|
fprintf(fp," <Mu_ssd> = %.17g\n",lineproplist[i].Mu);
|
|
fprintf(fp," <Sigma_ssd> = %.17g\n",lineproplist[i].Sig);
|
|
fprintf(fp," <innerangle> = %.17g\n",lineproplist[i].InnerAngle);
|
|
fprintf(fp," <outerangle> = %.17g\n",lineproplist[i].OuterAngle);
|
|
fprintf(fp," <EndBdry>\n");
|
|
}
|
|
|
|
fprintf(fp,"[BlockProps] = %i\n",(int) blockproplist.GetSize());
|
|
for(i=0;i<blockproplist.GetSize();i++)
|
|
{
|
|
fprintf(fp," <BeginBlock>\n");
|
|
fprintf(fp," <BlockName> = \"%s\"\n", (const char *) blockproplist[i].BlockName);
|
|
fprintf(fp," <Mu_x> = %.17g\n",blockproplist[i].mu_x);
|
|
fprintf(fp," <Mu_y> = %.17g\n",blockproplist[i].mu_y);
|
|
fprintf(fp," <H_c> = %.17g\n",blockproplist[i].H_c);
|
|
fprintf(fp," <H_cAngle> = %.17g\n",blockproplist[i].Theta_m);
|
|
fprintf(fp," <J_re> = %.17g\n",blockproplist[i].Jsrc.re);
|
|
fprintf(fp," <J_im> = %.17g\n",blockproplist[i].Jsrc.im);
|
|
fprintf(fp," <Sigma> = %.17g\n",blockproplist[i].Cduct);
|
|
fprintf(fp," <d_lam> = %.17g\n",blockproplist[i].Lam_d);
|
|
fprintf(fp," <Phi_h> = %.17g\n",blockproplist[i].Theta_hn);
|
|
fprintf(fp," <Phi_hx> = %.17g\n",blockproplist[i].Theta_hx);
|
|
fprintf(fp," <Phi_hy> = %.17g\n",blockproplist[i].Theta_hy);
|
|
fprintf(fp," <LamType> = %i\n",blockproplist[i].LamType);
|
|
fprintf(fp," <LamFill> = %.17g\n",blockproplist[i].LamFill);
|
|
fprintf(fp," <NStrands> = %i\n",blockproplist[i].NStrands);
|
|
fprintf(fp," <WireD> = %.17g\n",blockproplist[i].WireD);
|
|
fprintf(fp," <BHPoints> = %i\n",blockproplist[i].BHpoints);
|
|
for(j=0;j<blockproplist[i].BHpoints;j++)
|
|
fprintf(fp," %.17g %.17g\n",blockproplist[i].BHdata[j].re,
|
|
blockproplist[i].BHdata[j].im);
|
|
fprintf(fp," <EndBlock>\n");
|
|
}
|
|
|
|
fprintf(fp,"[CircuitProps] = %i\n",(int) circproplist.GetSize());
|
|
for(i=0;i<circproplist.GetSize();i++)
|
|
{
|
|
fprintf(fp," <BeginCircuit>\n");
|
|
fprintf(fp," <CircuitName> = \"%s\"\n", (const char *) circproplist[i].CircName);
|
|
fprintf(fp," <TotalAmps_re> = %.17g\n",circproplist[i].Amps.Re());
|
|
fprintf(fp," <TotalAmps_im> = %.17g\n",circproplist[i].Amps.Im());
|
|
fprintf(fp," <CircuitType> = %i\n",circproplist[i].CircType);
|
|
fprintf(fp," <EndCircuit>\n");
|
|
}
|
|
|
|
// write out node list
|
|
fprintf(fp,"[NumPoints] = %i\n",(int) nodelist.GetSize());
|
|
for(i=0;i<nodelist.GetSize();i++)
|
|
{
|
|
for(j=0,t=0;j<nodeproplist.GetSize();j++)
|
|
if(nodeproplist[j].PointName==nodelist[i].BoundaryMarker) t=j+1;
|
|
fprintf(fp,"%.17g %.17g %i %i\n",nodelist[i].x,nodelist[i].y,t,
|
|
nodelist[i].InGroup);
|
|
}
|
|
|
|
// write out segment list
|
|
fprintf(fp,"[NumSegments] = %i\n",(int) linelist.GetSize());
|
|
for(i=0;i<linelist.GetSize();i++)
|
|
{
|
|
for(j=0,t=0;j<lineproplist.GetSize();j++)
|
|
if(lineproplist[j].BdryName==linelist[i].BoundaryMarker) t=j+1;
|
|
fprintf(fp,"%i %i ",linelist[i].n0,linelist[i].n1);
|
|
if(linelist[i].MaxSideLength<0) fprintf(fp,"-1 ");
|
|
else fprintf(fp,"%.17g ",linelist[i].MaxSideLength);
|
|
fprintf(fp,"%i %i %i\n",t,linelist[i].Hidden,linelist[i].InGroup);
|
|
}
|
|
|
|
// write out arc segment list
|
|
fprintf(fp,"[NumArcSegments] = %i\n",(int) arclist.GetSize());
|
|
for(i=0;i<arclist.GetSize();i++)
|
|
{
|
|
for(j=0,t=0;j<lineproplist.GetSize();j++)
|
|
if(lineproplist[j].BdryName==arclist[i].BoundaryMarker) t=j+1;
|
|
fprintf(fp,"%i %i %.17g %.17g %i %i %i %.17g\n",arclist[i].n0,arclist[i].n1,
|
|
arclist[i].ArcLength,arclist[i].MaxSideLength,t,
|
|
arclist[i].Hidden,arclist[i].InGroup,arclist[i].mySideLength);
|
|
}
|
|
|
|
// write out list of holes;
|
|
for(i=0,j=0;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].BlockType=="<No Mesh>") j++;
|
|
fprintf(fp,"[NumHoles] = %i\n",j);
|
|
for(i=0,k=0;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].BlockType=="<No Mesh>")
|
|
{
|
|
fprintf(fp,"%.17g %.17g %i\n",blocklist[i].x,blocklist[i].y,
|
|
blocklist[i].InGroup);
|
|
k++;
|
|
}
|
|
|
|
// write out regional attributes
|
|
fprintf(fp,"[NumBlockLabels] = %i\n",(int) blocklist.GetSize()-j);
|
|
for(i=0,k=0;i<blocklist.GetSize();i++)
|
|
if(blocklist[i].BlockType!="<No Mesh>")
|
|
{
|
|
fprintf(fp,"%.17g %.17g ",blocklist[i].x,blocklist[i].y);
|
|
for(j=0,t=0;j<blockproplist.GetSize();j++)
|
|
if(blockproplist[j].BlockName==blocklist[i].BlockType) t=j+1;
|
|
fprintf(fp,"%i ",t);
|
|
if (blocklist[i].MaxArea>0)
|
|
fprintf(fp,"%.17g ",sqrt(4.*blocklist[i].MaxArea/PI));
|
|
else fprintf(fp,"-1 ");
|
|
for(j=0,t=0;j<circproplist.GetSize();j++)
|
|
if(circproplist[j].CircName==blocklist[i].InCircuit) t=j+1;
|
|
fprintf(fp,"%i %.17g %i %i %i",t,blocklist[i].MagDir,
|
|
blocklist[i].InGroup,blocklist[i].Turns,
|
|
blocklist[i].IsExternal+blocklist[i].IsDefault);
|
|
if (blocklist[i].MagDirFctn.GetLength()>0)
|
|
fprintf(fp," \"%s\"", (const char *) blocklist[i].MagDirFctn);
|
|
fprintf(fp,"\n");
|
|
|
|
k++;
|
|
}
|
|
fclose(fp);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CFemmeDoc::LoadMesh()
|
|
{
|
|
int i,j,k,q,nl;
|
|
CString pathname,rootname,infile;
|
|
FILE *fp;
|
|
char s[1024];
|
|
|
|
// clear out the old mesh...
|
|
meshnode.RemoveAll();
|
|
meshline.RemoveAll();
|
|
greymeshline.RemoveAll();
|
|
|
|
pathname=GetPathName();
|
|
if (pathname.GetLength()==0){
|
|
MsgBox("No mesh to display");
|
|
return FALSE;
|
|
}
|
|
|
|
rootname=pathname.Left(pathname.ReverseFind('.'));
|
|
|
|
//read meshnodes;
|
|
infile=rootname+".node";
|
|
if((fp=fopen(infile,"rt"))==NULL){
|
|
MsgBox("No mesh to display");
|
|
return FALSE;
|
|
}
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k);
|
|
meshnode.SetSize(k);
|
|
CNode node;
|
|
for(i=0;i<k;i++){
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i %lf %lf",&j,&node.x,&node.y);
|
|
meshnode.SetAt(i,node);
|
|
}
|
|
fclose(fp);
|
|
|
|
//read meshlines;
|
|
infile=rootname+".edge";
|
|
if((fp=fopen(infile,"rt"))==NULL){
|
|
MsgBox("No mesh to display");
|
|
return FALSE;
|
|
}
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k);
|
|
meshline.SetSize(k);
|
|
fclose(fp);
|
|
|
|
infile=rootname+".ele";
|
|
if((fp=fopen(infile,"rt"))==NULL){
|
|
MsgBox("No mesh to display");
|
|
return FALSE;
|
|
}
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i",&k);
|
|
|
|
CPoint segm;
|
|
int n[3],p;
|
|
for(i=0,nl=0;i<k;i++)
|
|
{
|
|
fgets(s,1024,fp);
|
|
sscanf(s,"%i %i %i %i %i",&q,&n[0],&n[1],&n[2],&j);
|
|
for(q=0;q<3;q++)
|
|
{
|
|
p=q+1; if(p==3) p=0;
|
|
if (n[p]>n[q])
|
|
{
|
|
segm.x=n[p];
|
|
segm.y=n[q];
|
|
if (j!=0) meshline.SetAt(nl++,segm);
|
|
else greymeshline.Add(segm);
|
|
}
|
|
}
|
|
}
|
|
meshline.SetSize(nl);
|
|
fclose(fp);
|
|
|
|
// clear out temporary files
|
|
infile=rootname+".ele"; DeleteFile(infile);
|
|
infile=rootname+".node"; DeleteFile(infile);
|
|
infile=rootname+".edge"; DeleteFile(infile);
|
|
infile=rootname+".pbc"; DeleteFile(infile);
|
|
infile=rootname+".poly"; DeleteFile(infile);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CFemmeDoc::UpdateUndo()
|
|
{
|
|
|
|
int i;
|
|
|
|
undonodelist.RemoveAll();
|
|
undolinelist.RemoveAll();
|
|
undoarclist.RemoveAll();
|
|
undoblocklist.RemoveAll();
|
|
|
|
for(i=0;i<nodelist.GetSize();i++) undonodelist.Add(nodelist[i]);
|
|
for(i=0;i<linelist.GetSize();i++) undolinelist.Add(linelist[i]);
|
|
for(i=0;i<arclist.GetSize();i++) undoarclist.Add(arclist[i]);
|
|
for(i=0;i<blocklist.GetSize();i++) undoblocklist.Add(blocklist[i]);
|
|
}
|
|
|
|
void CFemmeDoc::Undo()
|
|
{
|
|
int i;
|
|
|
|
CArray< CNode, CNode&> tempnodelist;
|
|
CArray< CSegment, CSegment&> templinelist;
|
|
CArray< CArcSegment, CArcSegment&> temparclist;
|
|
CArray< CBlockLabel, CBlockLabel&> tempblocklist;
|
|
|
|
tempnodelist.RemoveAll();
|
|
templinelist.RemoveAll();
|
|
temparclist.RemoveAll();
|
|
tempblocklist.RemoveAll();
|
|
|
|
for(i=0;i<nodelist.GetSize();i++) tempnodelist.Add(nodelist[i]);
|
|
for(i=0;i<linelist.GetSize();i++) templinelist.Add(linelist[i]);
|
|
for(i=0;i<arclist.GetSize();i++) temparclist.Add(arclist[i]);
|
|
for(i=0;i<blocklist.GetSize();i++) tempblocklist.Add(blocklist[i]);
|
|
|
|
nodelist.RemoveAll();
|
|
linelist.RemoveAll();
|
|
arclist.RemoveAll();
|
|
blocklist.RemoveAll();
|
|
|
|
for(i=0;i<undonodelist.GetSize();i++) nodelist.Add(undonodelist[i]);
|
|
for(i=0;i<undolinelist.GetSize();i++) linelist.Add(undolinelist[i]);
|
|
for(i=0;i<undoarclist.GetSize();i++) arclist.Add(undoarclist[i]);
|
|
for(i=0;i<undoblocklist.GetSize();i++) blocklist.Add(undoblocklist[i]);
|
|
|
|
undonodelist.RemoveAll();
|
|
undolinelist.RemoveAll();
|
|
undoarclist.RemoveAll();
|
|
undoblocklist.RemoveAll();
|
|
|
|
for(i=0;i<tempnodelist.GetSize();i++) undonodelist.Add(tempnodelist[i]);
|
|
for(i=0;i<templinelist.GetSize();i++) undolinelist.Add(templinelist[i]);
|
|
for(i=0;i<temparclist.GetSize();i++) undoarclist.Add(temparclist[i]);
|
|
for(i=0;i<tempblocklist.GetSize();i++) undoblocklist.Add(tempblocklist[i]);
|
|
}
|
|
|
|
BOOL CFemmeDoc::ScanPreferences()
|
|
{
|
|
FILE *fp;
|
|
CString fname;
|
|
|
|
fname=BinDir+"femme.cfg";
|
|
|
|
fp=fopen(fname,"rt");
|
|
if (fp!=NULL)
|
|
{
|
|
BOOL flag=FALSE;
|
|
char s[1024];
|
|
char q[1024];
|
|
char *v;
|
|
|
|
// parse the file
|
|
while (fgets(s,1024,fp)!=NULL)
|
|
{
|
|
sscanf(s,"%s",q);
|
|
|
|
if( _strnicmp(q,"<Precision>",11)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&d_prec);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<MinAngle>",10)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&d_minangle);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<Frequency>",11)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&d_freq);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<Depth>",7)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&d_depth);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<Coordinates>",13)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&d_coord);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<LengthUnits>",13)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&d_length);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<ProblemType>",13)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&d_type);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<ACSolver>",8)==0)
|
|
{
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&d_solver);
|
|
q[0]=NULL;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
void CFemmeView::lnuMakeMesh()
|
|
{
|
|
OnMakeMesh();
|
|
}
|
|
|
|
void CFemmeView::lnu_purge_mesh()
|
|
{
|
|
OnPurgemesh();
|
|
}
|
|
|
|
void CFemmeView::lnu_show_mesh()
|
|
{
|
|
OnShowMesh();
|
|
}
|
|
|
|
void CFemmeView::lnu_analyze(int bShow)
|
|
{
|
|
if (bShow) bLinehook=HiddenLua;
|
|
else bLinehook=NormalLua;
|
|
OnMenuAnalyze();
|
|
}
|
|
|
|
void CFemmeView::lua_zoomnatural()
|
|
{
|
|
OnZoomNatural();
|
|
}
|
|
|
|
void CFemmeView::lua_zoomout()
|
|
{
|
|
OnZoomOut();
|
|
}
|
|
|
|
void CFemmeView::lua_zoomin()
|
|
{
|
|
OnZoomIn();
|
|
}
|
|
|
|
BOOL CFemmeDoc::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
|
|
{
|
|
// TODO: Add your specialized code here and/or call the base class
|
|
if (bLinehook!=FALSE) return TRUE;
|
|
return CDocument::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
|
|
}
|
|
|
|
void CFemmeDoc::OnEditExterior()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
CExteriorProps dlg;
|
|
|
|
dlg.m_Ro=extRo;
|
|
dlg.m_Ri=extRi;
|
|
dlg.m_Zo=extZo;
|
|
if(dlg.DoModal()==IDOK)
|
|
{
|
|
extRo=dlg.m_Ro;
|
|
extRi=dlg.m_Ri;
|
|
extZo=dlg.m_Zo;
|
|
}
|
|
}
|
|
|
|
BOOL CFemmeDoc::CanCreateRadius(int n)
|
|
{
|
|
// check to see if a selected point, specified by n, can be
|
|
// converted to a radius. To be able to be converted to a radius,
|
|
// the point must be an element of either 2 lines, 2 arcs, or
|
|
// 1 line and 1 arc.
|
|
|
|
int j,k;
|
|
|
|
for(k=0,j=0;k<linelist.GetSize();k++)
|
|
if ((linelist[k].n0==n) || (linelist[k].n1==n)) j++;
|
|
for(k=0;k<arclist.GetSize();k++)
|
|
if ((arclist[k].n0==n) || (arclist[k].n1==n)) j++;
|
|
|
|
if (j==2) return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CFemmeDoc::CreateRadius(int n, double r)
|
|
{
|
|
// replace the node indexed by n with a radius of r
|
|
|
|
if(r<=0) return FALSE;
|
|
|
|
int nseg=0;
|
|
int narc=0;
|
|
int k,arc[2],seg[2];
|
|
|
|
for(k=0;k<linelist.GetSize();k++)
|
|
if ((linelist[k].n0==n) || (linelist[k].n1==n)) seg[nseg++]=k;
|
|
for(k=0;k<arclist.GetSize();k++)
|
|
if ((arclist[k].n0==n) || (arclist[k].n1==n)) arc[narc++]=k;
|
|
if ((narc+nseg)!=2) return FALSE;
|
|
|
|
// there are three valid cases:
|
|
switch (nseg-narc)
|
|
{
|
|
case 0: // One arc and one line
|
|
{
|
|
CComplex c,u,p0,p1,q,p[4],v[8],i1[8],i2[8];
|
|
double rc,b,R[4],phi;
|
|
CArcSegment ar;
|
|
int j,m;
|
|
|
|
// inherit the boundary condition from the arc so that
|
|
// we can apply it to the newly created arc later;
|
|
ar.InGroup =arclist[arc[0]].InGroup;
|
|
ar.BoundaryMarker=arclist[arc[0]].BoundaryMarker;
|
|
|
|
// get the center and radius of the circle associated with the arc;
|
|
GetCircle(arclist[arc[0]],c,rc);
|
|
|
|
// get the locations of the endpoints of the segment;
|
|
p0=nodelist[n].CC();
|
|
if(linelist[seg[0]].n0==n)
|
|
p1=nodelist[linelist[seg[0]].n1].CC();
|
|
else
|
|
p1=nodelist[linelist[seg[0]].n0].CC();
|
|
|
|
u=(p1-p0)/abs(p1-p0); // unit vector along the line
|
|
q=p0 + u*Re((c-p0)/u); // closest point on line to center of circle
|
|
u=I*u; // unit normal to the line
|
|
|
|
p[0]=q+r*u; R[0]=rc+r;
|
|
p[1]=q-r*u; R[1]=rc+r;
|
|
p[2]=q+r*u; R[2]=rc-r;
|
|
p[3]=q-r*u; R[3]=rc-r;
|
|
|
|
for(j=0,k=0;k<4;k++)
|
|
{
|
|
b=R[k]*R[k]-abs(p[k]-c)*abs(p[k]-c);
|
|
if (b>=0){
|
|
b=sqrt(b);
|
|
v[j++]=p[k]+I*b*(p[k]-c)/abs(p[k]-c);
|
|
v[j++]=p[k]-I*b*(p[k]-c)/abs(p[k]-c);
|
|
}
|
|
}
|
|
|
|
// locations of the centerpoints that could be for the radius that
|
|
// we are looking for are stored in v. We now need to paw through
|
|
// them to find the one solution that we are after.
|
|
u=(p1-p0)/abs(p1-p0); // unit vector along the line
|
|
for(m=0,k=0;k<j;k++)
|
|
{
|
|
i1[m]=p0 +u*Re((v[k]-p0)/u); // intersection with the line
|
|
i2[m]=c + rc*(v[k]-c)/abs(v[k]-c); // intersection with the arc;
|
|
v[m]=v[k];
|
|
|
|
// add this one to the list of possibly valid solutions if
|
|
// both of the intersection points actually lie on the arc
|
|
if ( ShortestDistanceFromArc(i2[m],arclist[arc[0]])<(r/10000.) &&
|
|
ShortestDistance(Re(i1[m]),Im(i1[m]),seg[0])<(r/10000.)
|
|
&& abs(i1[m]-i2[m])>(r/10000.))
|
|
{
|
|
m++;
|
|
if (m==2) break;
|
|
}
|
|
|
|
}
|
|
|
|
if (m==0) return FALSE;
|
|
|
|
// But there are also special cases where there could be two answers.
|
|
// We then pick the solution that has the center point closest to the point to be removed.
|
|
if(m>1)
|
|
{
|
|
if (abs(v[0]-p0)<abs(v[1]-p0)) j=0;
|
|
else j=1;
|
|
}
|
|
else j=0; // The index of the winning case is in j....
|
|
|
|
UpdateUndo();
|
|
AddNode(Re(i1[j]),Im(i1[j]),r/10000.);
|
|
AddNode(Re(i2[j]),Im(i2[j]),r/10000.);
|
|
UnselectAll();
|
|
|
|
// delete the node that is to be replace by a radius;
|
|
n=ClosestNode(Re(p0),Im(p0));
|
|
nodelist[n].IsSelected=TRUE;
|
|
DeleteSelectedNodes();
|
|
|
|
// compute the angle spanned by the new arc;
|
|
phi=arg((i2[j]-v[j])/(i1[j]-v[j]));
|
|
if (phi<0)
|
|
{
|
|
c=i2[j]; i2[j]=i1[j]; i1[j]=c;
|
|
phi=fabs(phi);
|
|
}
|
|
|
|
// add in the new radius;
|
|
ar.n0=ClosestNode(Re(i1[j]),Im(i1[j]));
|
|
ar.n1=ClosestNode(Re(i2[j]),Im(i2[j]));
|
|
ar.ArcLength=phi/DEG;
|
|
AddArcSegment(ar);
|
|
|
|
return TRUE;
|
|
}
|
|
case 2: // Two lines
|
|
{
|
|
CComplex p0,p1,p2;
|
|
double phi,len;
|
|
CArcSegment ar;
|
|
|
|
if (linelist[seg[0]].n0==n) p1=nodelist[linelist[seg[0]].n1].CC();
|
|
else p1=nodelist[linelist[seg[0]].n0].CC();
|
|
|
|
if (linelist[seg[1]].n0==n) p2=nodelist[linelist[seg[1]].n1].CC();
|
|
else p2=nodelist[linelist[seg[1]].n0].CC();
|
|
|
|
p0=nodelist[n].CC();
|
|
|
|
// get the angle between the lines
|
|
phi=arg((p2-p0)/(p1-p0));
|
|
|
|
// check to see if this case is degenerate
|
|
if (fabs(phi)>(179.*DEG)) return FALSE;
|
|
|
|
// check to see if the points are in the wrong order
|
|
// and fix it if they are.
|
|
if (phi<0){
|
|
p0=p1; p1=p2; p2=p0; p0=nodelist[n].CC();
|
|
k=seg[0]; seg[0]=seg[1]; seg[1]=k;
|
|
phi=fabs(phi);
|
|
}
|
|
|
|
len = r/tan(phi/2.); // distance from p0 to the tangency point;
|
|
|
|
// catch the case where the desired radius is too big to fit;
|
|
if ((abs(p1-p0)<len) || (abs(p2-p0)<len)) return FALSE;
|
|
|
|
// compute the locations of the tangency points;
|
|
p1=len*(p1-p0)/abs(p1-p0)+p0;
|
|
p2=len*(p2-p0)/abs(p2-p0)+p0;
|
|
|
|
// inherit the boundary condition from one of the segments
|
|
// so that we can apply it to the newly created arc later;
|
|
ar.BoundaryMarker=linelist[seg[0]].BoundaryMarker;
|
|
ar.InGroup =linelist[seg[0]].InGroup;
|
|
|
|
// add new nodes at ends of radius
|
|
UpdateUndo();
|
|
AddNode(Re(p1),Im(p1),len/10000.);
|
|
AddNode(Re(p2),Im(p2),len/10000.);
|
|
UnselectAll();
|
|
|
|
// delete the node that is to be replace by a radius;
|
|
n=ClosestNode(Re(p0),Im(p0));
|
|
nodelist[n].IsSelected=TRUE;
|
|
DeleteSelectedNodes();
|
|
|
|
// add in the new radius;
|
|
ar.n0=ClosestNode(Re(p2),Im(p2));
|
|
ar.n1=ClosestNode(Re(p1),Im(p1));
|
|
ar.ArcLength=180.-phi/DEG;
|
|
AddArcSegment(ar);
|
|
|
|
return TRUE;
|
|
}
|
|
case -2: // Two arcs
|
|
{
|
|
int j;
|
|
CComplex c0,c1,c2,p[8],i1[8],i2[8];
|
|
double a[8],b[8],c,d[8],x[8],r0,r1,r2,phi;
|
|
CArcSegment ar;
|
|
|
|
r0=r;
|
|
GetCircle(arclist[arc[0]],c1,r1);
|
|
GetCircle(arclist[arc[1]],c2,r2);
|
|
c=abs(c2-c1);
|
|
|
|
// solve for all of the different possible cases;
|
|
a[0]=r1+r0; b[0]=r2+r0;
|
|
a[1]=r1+r0; b[1]=r2+r0;
|
|
a[2]=r1-r0; b[2]=r2-r0;
|
|
a[3]=r1-r0; b[3]=r2-r0;
|
|
a[4]=r1-r0; b[4]=r2+r0;
|
|
a[5]=r1-r0; b[5]=r2+r0;
|
|
a[6]=r1+r0; b[6]=r2-r0;
|
|
a[7]=r1+r0; b[7]=r2-r0;
|
|
for(k=0;k<8;k++){
|
|
x[k]=(b[k]*b[k]+c*c-a[k]*a[k])/(2.*c*c);
|
|
d[k]=sqrt(b[k]*b[k]-x[k]*x[k]*c*c);
|
|
}
|
|
for(k=0;k<8;k+=2)
|
|
{
|
|
// solve for the center point of the radius for each solution.
|
|
p[k] =((1-x[k])*c+I*d[k])*(c2-c1)/abs(c2-c1) + c1;
|
|
p[k+1]=((1-x[k])*c-I*d[k])*(c2-c1)/abs(c2-c1) + c1;
|
|
}
|
|
|
|
c0=nodelist[n].CC();
|
|
|
|
for(j=0,k=0;k<8;k++)
|
|
{
|
|
i1[j]=c1 + r1*(p[k]-c1)/abs(p[k]-c1); // compute possible intersection points
|
|
i2[j]=c2 + r2*(p[k]-c2)/abs(p[k]-c2); // with the arcs;
|
|
p[j] =p[k];
|
|
|
|
// add this one to the list of possibly valid solutions if
|
|
// both of the intersection points actually lie on the arc
|
|
if ( ShortestDistanceFromArc(i1[j],arclist[arc[0]])<(r0/10000.) &&
|
|
ShortestDistanceFromArc(i2[j],arclist[arc[1]])<(r0/10000.) &&
|
|
abs(i1[j]-i2[j])>(r0/10000.))
|
|
{
|
|
j++;
|
|
if (j==2) break;
|
|
}
|
|
|
|
}
|
|
|
|
// There could be no valid solutions...
|
|
if (j==0) return FALSE;
|
|
|
|
// But there are also special cases where there could be two answers.
|
|
// We then pick the solution that has the center point closest to the point to be removed.
|
|
if(j>1)
|
|
{
|
|
if (abs(p[0]-c0)<abs(p[1]-c0)) j=0;
|
|
else j=1;
|
|
}
|
|
else j=0; // The index of the winning case is in j....
|
|
|
|
// inherit the boundary condition from one of the segments
|
|
// so that we can apply it to the newly created arc later;
|
|
ar.BoundaryMarker=arclist[arc[0]].BoundaryMarker;
|
|
ar.InGroup=arclist[arc[0]].InGroup;
|
|
|
|
// add new nodes at ends of radius
|
|
UpdateUndo();
|
|
AddNode(Re(i1[j]),Im(i1[j]),c/10000.);
|
|
AddNode(Re(i2[j]),Im(i2[j]),c/10000.);
|
|
UnselectAll();
|
|
|
|
// delete the node that is to be replace by a radius;
|
|
n=ClosestNode(Re(c0),Im(c0));
|
|
nodelist[n].IsSelected=TRUE;
|
|
DeleteSelectedNodes();
|
|
|
|
// compute the angle spanned by the new arc;
|
|
phi=arg((i2[j]-p[j])/(i1[j]-p[j]));
|
|
if (phi<0)
|
|
{
|
|
c0=i2[j]; i2[j]=i1[j]; i1[j]=c0;
|
|
phi=fabs(phi);
|
|
}
|
|
|
|
// add in the new radius;
|
|
ar.n0=ClosestNode(Re(i1[j]),Im(i1[j]));
|
|
ar.n1=ClosestNode(Re(i2[j]),Im(i2[j]));
|
|
ar.ArcLength=phi/DEG;
|
|
AddArcSegment(ar);
|
|
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
} |