2562 lines
62 KiB
C++
2562 lines
62 KiB
C++
// beladrawDoc.cpp : implementation of the CbeladrawDoc class
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "femm.h"
|
|
#include "beladrawDoc.h"
|
|
#include "beladrawView.h"
|
|
#include "bd_probdlg.h"
|
|
#include "bd_PtProp.h"
|
|
#include "bd_OpBlkDlg.h"
|
|
#include "bd_OpNodeDlg.h"
|
|
#include "bd_OpSegDlg.h"
|
|
#include "bd_OpArcSegDlg.h"
|
|
#include "OpGrp.h"
|
|
#include "ArcDlg.h"
|
|
#include "ExteriorProps.h"
|
|
|
|
extern void *pBeladrawDoc;
|
|
extern lua_State *lua;
|
|
extern BOOL bLinehook;
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CbeladrawDoc
|
|
|
|
IMPLEMENT_DYNCREATE(CbeladrawDoc, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(CbeladrawDoc, CDocument)
|
|
//{{AFX_MSG_MAP(CbeladrawDoc)
|
|
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()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CbeladrawDoc construction/destruction
|
|
|
|
CbeladrawDoc::CbeladrawDoc()
|
|
{
|
|
// 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_depth=1;
|
|
d_coord=0;
|
|
d_length=0;
|
|
d_type=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();
|
|
}
|
|
|
|
CbeladrawDoc::~CbeladrawDoc()
|
|
{
|
|
if (pBeladrawDoc==this) pBeladrawDoc=NULL;
|
|
}
|
|
|
|
BOOL CbeladrawDoc::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;
|
|
Precision=d_prec;
|
|
MinAngle=d_minangle;
|
|
SmartMesh=theApp.d_SmartMesh;
|
|
Depth=d_depth;
|
|
LengthUnits=d_length;
|
|
ProblemType=d_type;
|
|
Coords=d_coord;
|
|
ProblemNote="Add comments here.";
|
|
extRo=extRi=extZo=0;
|
|
|
|
|
|
// reset view to default attributes
|
|
CbeladrawView *pView;
|
|
POSITION pos;
|
|
pos=GetFirstViewPosition();
|
|
if (pos!=NULL){
|
|
pView=(CbeladrawView *)GetNextView(pos);
|
|
if (pView!=NULL) pView->OnNewDocument();
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CbeladrawDoc serialization
|
|
|
|
void CbeladrawDoc::Serialize(CArchive& ar)
|
|
{
|
|
if (ar.IsStoring())
|
|
{
|
|
// TODO: add storing code here
|
|
}
|
|
else
|
|
{
|
|
// TODO: add loading code here
|
|
}
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CbeladrawDoc diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CbeladrawDoc::AssertValid() const
|
|
{
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void CbeladrawDoc::Dump(CDumpContext& dc) const
|
|
{
|
|
CDocument::Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CbeladrawDoc commands
|
|
|
|
void CbeladrawDoc::OnDefineProblem()
|
|
{
|
|
bdCProbDlg pDlg;
|
|
|
|
// Send present parameter values to the dialog
|
|
// pDlg.m_rji=TheDoc->vi[0];
|
|
pDlg.probtype = ProblemType;
|
|
pDlg.m_problem_note = ProblemNote;
|
|
pDlg.m_precision = Precision;
|
|
pDlg.m_minangle = MinAngle;
|
|
pDlg.bsmart = SmartMesh;
|
|
pDlg.m_depth = Depth;
|
|
pDlg.lengthunits = LengthUnits;
|
|
|
|
// Display dialog and collect data
|
|
if(pDlg.DoModal()==IDOK)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
|
|
void CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::AddSegment(int n0, int n1, double tol)
|
|
{
|
|
return AddSegment(n0,n1,NULL,tol);
|
|
}
|
|
|
|
BOOL CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::OnEditMatprops()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
bdCPtProp pProp;
|
|
|
|
pProp.pblockproplist=&blockproplist;
|
|
pProp.PropType=2;
|
|
pProp.ProblemType=ProblemType;
|
|
|
|
pProp.DoModal();
|
|
}
|
|
|
|
void CbeladrawDoc::OnEditPtprops()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
bdCPtProp pProp;
|
|
|
|
pProp.pnodeproplist=&nodeproplist;
|
|
pProp.PropType=0;
|
|
|
|
pProp.DoModal();
|
|
}
|
|
|
|
void CbeladrawDoc::OnEditSegprops()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
bdCPtProp pProp;
|
|
|
|
pProp.plineproplist=&lineproplist;
|
|
pProp.PropType=1;
|
|
pProp.ProblemType=ProblemType;
|
|
pProp.DoModal();
|
|
}
|
|
|
|
void CbeladrawDoc::OnEditCircprops()
|
|
{
|
|
bdCPtProp pProp;
|
|
|
|
pProp.pcircproplist=&circproplist;
|
|
pProp.ProblemType=ProblemType;
|
|
pProp.PropType=3;
|
|
|
|
pProp.DoModal();
|
|
}
|
|
|
|
BOOL CbeladrawDoc::OpBlkDlg()
|
|
{
|
|
int i,j,k,nselected;
|
|
double a;
|
|
bdCOpBlkDlg zDlg;
|
|
|
|
zDlg.ProblemType=ProblemType;
|
|
|
|
// check to see how many (if any) blocks are selected.
|
|
for(i=0,k=0,nselected=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(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 (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.;
|
|
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;
|
|
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 CbeladrawDoc::OpNodeDlg()
|
|
{
|
|
int i,k,nselected;
|
|
bdCOpNodeDlg 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;
|
|
zDlg.pcircproplist=&circproplist;
|
|
|
|
if (nselected==1){
|
|
for(i=0,zDlg.cursel=0;i<nodeproplist.GetSize();i++)
|
|
if (nodeproplist[i].PointName==nodelist[k].BoundaryMarker)
|
|
zDlg.cursel=i+1;
|
|
|
|
for(i=0,zDlg.condsel=0;i<circproplist.GetSize();i++)
|
|
if (circproplist[i].CircName==nodelist[k].InConductor)
|
|
zDlg.condsel=i+1;
|
|
}
|
|
else{
|
|
zDlg.cursel=0;
|
|
zDlg.condsel=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;
|
|
|
|
if (zDlg.condsel==0) nodelist[i].InConductor="<None>";
|
|
else nodelist[i].InConductor=circproplist[zDlg.condsel-1].CircName;
|
|
|
|
nodelist[i].InGroup=zDlg.m_ingroup;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CbeladrawDoc::OpSegDlg()
|
|
{
|
|
int i,j,k,nselected;
|
|
bdCOpSegDlg zDlg;
|
|
|
|
// check to see how many (if any) lines 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;
|
|
zDlg.pcircproplist=&circproplist;
|
|
|
|
if (nselected==1){
|
|
for(i=0,zDlg.cursel=0;i<lineproplist.GetSize();i++)
|
|
if (lineproplist[i].BdryName==linelist[k].BoundaryMarker)
|
|
zDlg.cursel=i+1;
|
|
|
|
for(i=0,zDlg.condsel=0;i<circproplist.GetSize();i++)
|
|
if (circproplist[i].CircName==linelist[k].InConductor)
|
|
zDlg.condsel=i+1;
|
|
}
|
|
else{
|
|
zDlg.cursel=0;
|
|
zDlg.condsel=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;
|
|
|
|
if (zDlg.condsel==0) linelist[i].InConductor="<None>";
|
|
else linelist[i].InConductor=circproplist[zDlg.condsel-1].CircName;
|
|
|
|
linelist[i].Hidden=zDlg.m_hide;
|
|
linelist[i].InGroup=zDlg.m_ingroup;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void CbeladrawDoc::OpArcSegDlg()
|
|
{
|
|
int i,j,k,nselected;
|
|
bdCOpArcSegDlg 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;
|
|
zDlg.pcircproplist=&circproplist;
|
|
|
|
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;
|
|
|
|
for(i=0,zDlg.condsel=0;i<circproplist.GetSize();i++)
|
|
if (circproplist[i].CircName==arclist[k].InConductor)
|
|
zDlg.condsel=i+1;
|
|
}
|
|
else{
|
|
zDlg.cursel=0;
|
|
zDlg.m_MaxSeg=ms;
|
|
zDlg.condsel=0;
|
|
}
|
|
|
|
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;
|
|
if (zDlg.condsel==0) arclist[i].InConductor="<None>";
|
|
else arclist[i].InConductor=circproplist[zDlg.condsel-1].CircName;
|
|
arclist[i].MaxSideLength=zDlg.m_MaxSeg;
|
|
arclist[i].Hidden=zDlg.m_hide;
|
|
arclist[i].InGroup=zDlg.m_ingroup;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CbeladrawDoc::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 CbeladrawDoc::OnOpenDocument(LPCTSTR lpszPathName)
|
|
{
|
|
if (!CDocument::OnOpenDocument(lpszPathName))
|
|
return FALSE;
|
|
|
|
// make sure old document is cleared out...
|
|
OnNewDocument();
|
|
|
|
FILE *fp;
|
|
int i,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 .fee file");
|
|
return FALSE;
|
|
}
|
|
|
|
// 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>33) MsgBox("File is from a newer version of FEMM\nThis file may contain attributes not\nsupported by this version of FEMM");
|
|
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;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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.V=0;
|
|
PProp.qp=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,"<vp>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.V);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qp>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&PProp.qp);
|
|
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.V=0;
|
|
BProp.qs=0;
|
|
BProp.c0=0;
|
|
BProp.c1=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,"<vs>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.V);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qs>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.qs);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c0>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c0);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<c1>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&BProp.c1);
|
|
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.ex=1.;
|
|
MProp.ey=1.; // permeabilities, relative
|
|
MProp.qv=0.;
|
|
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,"<ex>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.ex);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<ey>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.ey);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qv>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&MProp.qv);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endblock>",9)==0){
|
|
blockproplist.Add(MProp);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
// Circuit Properties
|
|
if( _strnicmp(q,"<beginconductor>",16)==0){
|
|
CProp.CircName="New Conductor";
|
|
CProp.V=0.;
|
|
CProp.q=0.;
|
|
CProp.CircType=0;
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<conductorname>",15)==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,"<vc>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&CProp.V);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<qc>",4)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%lf",&CProp.q);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<conductortype>",15)==0){
|
|
v=StripKey(s);
|
|
sscanf(v,"%i",&CProp.CircType);
|
|
q[0]=NULL;
|
|
}
|
|
|
|
if( _strnicmp(q,"<endconductor>",14)==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);
|
|
if(t==0) node.BoundaryMarker="";
|
|
else if(t<=(int) nodeproplist.GetSize())
|
|
node.BoundaryMarker=nodeproplist[t-1].PointName;
|
|
v=ParseInt(v,&node.InGroup);
|
|
v=ParseInt(v,&t);
|
|
if(t==0) node.InConductor="<None>";
|
|
else if(t<=(int) circproplist.GetSize())
|
|
node.InConductor=circproplist[t-1].CircName;
|
|
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);
|
|
if(t==0) segm.BoundaryMarker="";
|
|
else if (t<=(int) lineproplist.GetSize())
|
|
segm.BoundaryMarker=lineproplist[t-1].BdryName;
|
|
v=ParseInt(v,&segm.Hidden);
|
|
v=ParseInt(v,&segm.InGroup);
|
|
v=ParseInt(v,&t);
|
|
if(t==0) segm.InConductor="<None>";
|
|
else if(t<=(int) circproplist.GetSize())
|
|
segm.InConductor=circproplist[t-1].CircName;
|
|
|
|
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);
|
|
if(t==0) asegm.BoundaryMarker="";
|
|
else if (t<=(int) lineproplist.GetSize())
|
|
asegm.BoundaryMarker=lineproplist[t-1].BdryName;
|
|
v=ParseInt(v,&asegm.Hidden);
|
|
v=ParseInt(v,&asegm.InGroup);
|
|
v=ParseInt(v,&t);
|
|
if(t==0) asegm.InConductor="<None>";
|
|
else if(t<=(int) circproplist.GetSize())
|
|
asegm.InConductor=circproplist[t-1].CircName;
|
|
asegm.mySideLength=asegm.MaxSideLength;
|
|
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.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,&blk.InGroup);
|
|
v=ParseInt(v,&blk.IsExternal);
|
|
blk.IsDefault = blk.IsExternal & 2;
|
|
blk.IsExternal = blk.IsExternal & 1;
|
|
|
|
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 CbeladrawDoc::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] = 1\n");
|
|
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,"[Comment] = \"%s\"\n", (const char *) s);
|
|
|
|
// write out materials properties stuff...
|
|
fprintf(fp,"[PointProps] = %i\n",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," <Vp> = %.17g\n",nodeproplist[i].V);
|
|
fprintf(fp," <qp> = %.17g\n",nodeproplist[i].qp);
|
|
fprintf(fp," <EndPoint>\n");
|
|
}
|
|
|
|
fprintf(fp,"[BdryProps] = %i\n",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," <Vs> = %.17g\n",lineproplist[i].V);
|
|
fprintf(fp," <qs> = %.17g\n",lineproplist[i].qs);
|
|
fprintf(fp," <c0> = %.17g\n",lineproplist[i].c0);
|
|
fprintf(fp," <c1> = %.17g\n",lineproplist[i].c1);
|
|
fprintf(fp," <EndBdry>\n");
|
|
}
|
|
|
|
fprintf(fp,"[BlockProps] = %i\n",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," <ex> = %.17g\n",blockproplist[i].ex);
|
|
fprintf(fp," <ey> = %.17g\n",blockproplist[i].ey);
|
|
fprintf(fp," <qv> = %.17g\n",blockproplist[i].qv);
|
|
fprintf(fp," <EndBlock>\n");
|
|
}
|
|
|
|
fprintf(fp,"[ConductorProps] = %i\n",circproplist.GetSize());
|
|
for(i=0;i<circproplist.GetSize();i++)
|
|
{
|
|
fprintf(fp," <BeginConductor>\n");
|
|
fprintf(fp," <ConductorName> = \"%s\"\n", (const char *) circproplist[i].CircName);
|
|
fprintf(fp," <Vc> = %.17g\n",circproplist[i].V);
|
|
fprintf(fp," <qc> = %.17g\n",circproplist[i].q);
|
|
fprintf(fp," <ConductorType> = %i\n",circproplist[i].CircType);
|
|
fprintf(fp," <EndConductor>\n");
|
|
}
|
|
|
|
// write out node list
|
|
fprintf(fp,"[NumPoints] = %i\n",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 ",nodelist[i].x,nodelist[i].y,t,
|
|
nodelist[i].InGroup);
|
|
|
|
for(j=0,t=0;j<circproplist.GetSize();j++)
|
|
if(circproplist[j].CircName==nodelist[i].InConductor) t=j+1;
|
|
fprintf(fp,"%i\n",t);
|
|
}
|
|
|
|
// write out segment list
|
|
fprintf(fp,"[NumSegments] = %i\n",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 ",t,linelist[i].Hidden,linelist[i].InGroup);
|
|
|
|
for(j=0,t=0;j<circproplist.GetSize();j++)
|
|
if(circproplist[j].CircName==linelist[i].InConductor) t=j+1;
|
|
fprintf(fp,"%i\n",t);
|
|
}
|
|
|
|
// write out arc segment list
|
|
fprintf(fp,"[NumArcSegments] = %i\n",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 ",arclist[i].n0,arclist[i].n1,
|
|
arclist[i].ArcLength,arclist[i].MaxSideLength,t,
|
|
arclist[i].Hidden,arclist[i].InGroup);
|
|
|
|
for(j=0,t=0;j<circproplist.GetSize();j++)
|
|
if(circproplist[j].CircName==arclist[i].InConductor) t=j+1;
|
|
fprintf(fp,"%i %.17g\n",t,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",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 ");
|
|
|
|
fprintf(fp,"%i %i\n",blocklist[i].InGroup,
|
|
blocklist[i].IsExternal+blocklist[i].IsDefault);
|
|
k++;
|
|
}
|
|
fclose(fp);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::ScanPreferences()
|
|
{
|
|
FILE *fp;
|
|
CString fname;
|
|
|
|
fname=BinDir+"beladraw.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,"<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;
|
|
}
|
|
}
|
|
fclose(fp);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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 CbeladrawDoc::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;
|
|
} |