Files
TempleOS-Rijn/SparrowOS/Demo/Graphics/Circuit.CPP
T
2018-09-08 21:45:28 +02:00

1191 lines
27 KiB
C++

$SP,"<1>",1$
$SP,"<2>",2$
$SP,"<3>",3$
$SP,"<4>",4$
$SP,"<5>",5$
$SP,"<6>",6$
#define A_EAST 0
#define A_NORTH 1
#define A_WEST 2
#define A_SOUTH 3
U0 OrthRot(I64 *_x,I64 *_y,I64 é)
{
nobound_switch (é&3) {
case A_EAST:
break;
case A_NORTH:
*_y=-*_y;
SwapU64(_x,_y);
break;
case A_WEST:
*_x=-*_x;
*_y=-*_y;
break;
case A_SOUTH:
*_x=-*_x;
SwapU64(_x,_y);
break;
}
}
#define MAX_TERMINALS 6
#define ET_R 0
#define ET_L 1
#define ET_C 2
#define ET_NUM_TYPES 3
class ElementType
{
U8 *black_img,*red_img;
I64 terminals;
CD2I64 term[MAX_TERMINALS];
I64 min_x,max_x,min_y,max_y;
};
ElementType et[ET_NUM_TYPES] =
{
{$IB,"<1>",1$,$IB,"<2>",2$,2,{{-12,1},{13,1},{0,0},{0,0},{0,0},{0,0}},0,0,0,0},
{$IB,"<3>",3$,$IB,"<4>",4$,2,{{-14,0},{15,0},{0,0},{0,0},{0,0},{0,0}},0,0,0,0},
{$IB,"<5>",5$,$IB,"<6>",6$,2,{{-4 ,0},{6 ,0},{0,0},{0,0},{0,0},{0,0}},0,0,0,0},
};
extern class Element;
class Terminal
{
Element *e;
I64 terminal;
};
#define Df_PROCESSED 0
#define Df_JUNCTION 1
#define Df_TERMINAL 2
#define Df_TERMINAL_LEFT 3
#define Df_TERMINAL_RIGHT 4
#define Df_TERMINAL_TOP 5
#define Df_TERMINAL_BOTTOM 6
class Dot //These are points on a node
{
Dot *next,*last;
I64 x,y,saved_x,saved_y;
Element *e;
U16 flags[4];
Dot *left,*right,*top,*bottom;
};
class Node
{
Node *next,*last;
I64 cnt;
Terminal *terms;
Dot *dot_root;
} node_root;
class Element
{
Element *next,*last;
ElementType *type;
I64 x,y,é,min_x,max_x,min_y,max_y;
Node *nodes[MAX_TERMINALS];
} el_root;
#define MD_CONNECT 0
#define MD_MOVE 1
#define MD_NUM_MODES 2
I64 mode;
Element *rubber_band;
I64 rubber_band_terminal,rubber_band_x,rubber_band_y;
U0 DotDel(Dot *root)
{
if (root) {
QueDel(root,TRUE);
Free(root);
}
}
U0 DotRst(Dot *root)
{
Dot *tempd;
if (root) {
Bts(root->flags,Df_PROCESSED);
tempd=root->next;
while (tempd!=root) {
Btr(tempd->flags,Df_PROCESSED);
tempd=tempd->next;
}
}
}
#define DIR_LT 0
#define DIR_CT 1
#define DIR_RT 2
#define DIR_LC 3
#define DIR_CC 4
#define DIR_RC 5
#define DIR_LB 6
#define DIR_CB 7
#define DIR_RB 8
I64 ElementSqrDist(Element *tempe,I64 x,I64 y)
{
I64 i,dx,dy;
if (x<tempe->min_x)
i=0;
else if (x<=tempe->max_x)
i=1;
else
i=2;
if (y>=tempe->min_y) {
if (y<=tempe->max_y)
i+=3;
else
i+=6;
}
switch (i) {
case DIR_LT:
dx=tempe->min_x-x;
dy=tempe->min_y-y;
break;
case DIR_CT:
dx=0;
dy=tempe->min_y-y;
break;
case DIR_RT:
dx=x-tempe->max_x;
dy=tempe->min_y-y;
break;
case DIR_LC:
dx=tempe->min_x-x;
dy=0;
break;
case DIR_CC:
dx=0;
dy=0;
break;
case DIR_RC:
dx=x-tempe->max_x;
dy=0;
break;
case DIR_LB:
dx=tempe->min_x-x;
dy=y-tempe->max_y;
break;
case DIR_CB:
dx=0;
dy=y-tempe->max_y;
break;
case DIR_RB:
dx=x-tempe->max_x;
dy=y-tempe->max_y;
break;
}
return SqrI64(dx)+SqrI64(dy);
}
#define SPACING 10
F64 DotNetScore(Dot *root)
{ //higher is better
F64 d,distdist1=0.1,distdist2=0.1,num=1.0,den=0.1;
I64 dx,dy,nonzero_cnt=1;
Element *tempe;
Dot *tempd,*tempd1;
if (root) {
tempd=root->next;
while (tempd!=root) {
//Calculate clearance from elements like parallel resistors
tempe=el_root.next;
while (tempe!=&el_root) {
if (tempd->e!=tempe) {
d=Sqrt(ElementSqrDist(tempe,tempd->x,tempd->y))+0.1;
if (d>SPACING) d=SPACING;
num*=d;
den+=d;
}
tempe=tempe->next;
}
//Calculate clearance from junctions like parallel resistors
if (Bt(tempd->flags,Df_TERMINAL)) {
tempd1=root->next;
while (tempd1!=root) {
if (tempd1!=tempd && Bt(tempd1->flags,Df_JUNCTION)) {
d=Sqrt(SqrI64(tempd->x-tempd1->x)+SqrI64(tempd->y-tempd1->y))+0.1;
if (d>SPACING) d=SPACING;
num*=d;
den+=d;
}
tempd1=tempd1->next;
}
}
if (tempd1=tempd->left) {
dx=SqrI64(tempd->x-tempd1->x);
dy=SqrI64(tempd->y-tempd1->y);
if (d=dx+dy) {
distdist1+=d;
nonzero_cnt++;
}
distdist2+=dy;
}
if (tempd1=tempd->right) {
dx=SqrI64(tempd->x-tempd1->x);
dy=SqrI64(tempd->y-tempd1->y);
if (d=dx+dy) {
distdist1+=d;
nonzero_cnt++;
}
distdist2+=dy;
}
if (tempd1=tempd->top) {
dx=SqrI64(tempd->x-tempd1->x);
dy=SqrI64(tempd->y-tempd1->y);
if (d=dx+dy) {
distdist1+=d;
nonzero_cnt++;
}
distdist2+=dx;
}
if (tempd1=tempd->bottom) {
dx=SqrI64(tempd->x-tempd1->x);
dy=SqrI64(tempd->y-tempd1->y);
if (d=dx+dy) {
distdist1+=d;
nonzero_cnt++;
}
distdist2+=dx;
}
tempd=tempd->next;
}
}
return num/(nonzero_cnt*nonzero_cnt*nonzero_cnt*distdist1*distdist2);
}
Bool NodeAdd(Node *tempn,Element *tempe,I64 terminal,CTask *mem_task=NULL)
{
I64 i;
Terminal *a;
for (i=0;i<tempn->cnt;i++)
if (tempn->terms[i].e==tempe&&tempn->terms[i].terminal==terminal)
return TRUE;
a=MAlloc((tempn->cnt+1)*sizeof(Terminal),mem_task);
if (tempn->terms) {
MemCpy(a,tempn->terms,tempn->cnt*sizeof(Terminal));
Free(tempn->terms);
}
tempn->terms=a;
i=tempn->cnt++;
tempn->terms[i].e=tempe;
tempn->terms[i].terminal=terminal;
return FALSE;
}
U0 NodeDel(Node *tempn)
{
if (tempn) {
QueRem(tempn);
Free(tempn->terms);
if (tempn->dot_root)
DotDel(tempn->dot_root);
Free(tempn);
}
}
extern Dot *DotNew(Node *tempn,CTask *mem_task=NULL);
U0 NodeReroute(Node *tempn=NULL,CTask *mem_task=NULL)
{
if (tempn) {
DotDel(tempn->dot_root);
tempn->dot_root=DotNew(tempn,mem_task);
} else {
tempn=node_root.next;
while (tempn!=&node_root) {
DotDel(tempn->dot_root);
tempn->dot_root=DotNew(tempn,mem_task);
tempn=tempn->next;
}
}
}
U0 ElementExtents(Element *tempe)
{
ElementType *tempt=tempe->type;
I64 x,y;
x=tempt->min_x; y=tempt->min_y;
OrthRot(&x,&y,tempe->é);
x+=tempe->x; y+=tempe->y;
tempe->min_x=tempe->max_x=x;
tempe->min_y=tempe->max_y=y;
x=tempt->max_x; y=tempt->max_y;
OrthRot(&x,&y,tempe->é);
x+=tempe->x; y+=tempe->y;
if (x<tempe->min_x) tempe->min_x=x;
if (x>tempe->max_x) tempe->max_x=x;
if (y<tempe->min_y) tempe->min_y=y;
if (y>tempe->max_y) tempe->max_y=y;
if (tempe==rubber_band) {
tempe->min_x+=ipx-rubber_band_x;
tempe->max_x+=ipx-rubber_band_x;
tempe->min_y+=ipy-rubber_band_y;
tempe->max_y+=ipy-rubber_band_y;
}
}
U0 ElementReroute(Element *tempe,CTask *mem_task=NULL)
{
I64 i;
ElementType *tempt;
if (tempe) {
tempt=tempe->type;
for (i=0;i<tempt->terminals;i++)
if (tempe->nodes[i])
NodeReroute(tempe->nodes[i],mem_task);
}
}
U0 ElementDel(Element *tempe,CTask *mem_task=NULL)
{
I64 i,cnt;
Terminal *src,*dst;
Node *tempn=node_root.next,*tempn1;
while (tempn!=&node_root) {
tempn1=tempn->next;
cnt=0;
dst=src=tempn->terms;
for (i=0;i<tempn->cnt;i++) {
if (src->e!=tempe) {
if (dst!=src)
MemCpy(dst,src,sizeof(Terminal));
cnt++;
dst++;
}
src++;
}
if (tempn->cnt!=cnt) {
tempn->cnt=cnt;
if (!cnt)
NodeDel(tempn);
else if (cnt==1) {
tempn->terms[0].e->nodes[tempn->terms[0].terminal]=NULL;
NodeDel(tempn);
} else {
DotDel(tempn->dot_root);
tempn->dot_root=NULL;
NodeReroute(tempn,mem_task);
}
}
tempn=tempn1;
}
QueRem(tempe);
Free(tempe);
}
Node *NodeNew(CTask *mem_task=NULL)
{
Node *result=CAlloc(sizeof(Node),mem_task);
QueIns(result,node_root.last);
return result;
}
Node *NodeCat(Node *dst,Node *src,CTask *mem_task=NULL)
{
I64 i;
if (!dst) dst=NodeNew(mem_task);
if (src && dst!=src) {
for (i=0;i<src->cnt;i++) {
NodeAdd(dst,src->terms[i].e,src->terms[i].terminal,mem_task);
src->terms[i].e->nodes[src->terms[i].terminal]=dst;
}
NodeDel(src);
}
return dst;
}
U0 TerminalXY(Element *tempe,I64 terminal,I64 *_x,I64 *_y)
{
ElementType *tempt=tempe->type;
I64 x=tempt->term[terminal].x,y=tempt->term[terminal].y;
OrthRot(&x,&y,tempe->é);
if (_x)
*_x=tempe->x+x;
if (_y)
*_y=tempe->y+y;
}
#define CT_NONE 0
#define CT_LEFT 1
#define CT_RIGHT 2
#define CT_TOP 3
#define CT_BOTTOM 4
I64 DotHVDecideConnect(Dot *tempd,Dot *tempd1)
{
I64 d;
d=tempd->x-tempd1->x;
if (d<0) {
if (!tempd->right && !tempd1->left ||
tempd->right==tempd1 && tempd1->left==tempd)
return CT_RIGHT;
} else if (d>0) {
if (!tempd->left && !tempd1->right ||
tempd->left==tempd1 && tempd1->right==tempd)
return CT_LEFT;
}
d=tempd->y-tempd1->y;
if (d<0) {
if (!tempd->bottom && !tempd1->top ||
tempd->bottom==tempd1 && tempd1->top==tempd)
return CT_BOTTOM;
} else if (d>0) {
if (!tempd->top && !tempd1->bottom ||
tempd->top==tempd1 && tempd->bottom==tempd)
return CT_TOP;
}
return CT_NONE;
}
Bool DotHVConnect(Dot *tempd,Dot *tempd1)
{
switch (DotHVDecideConnect(tempd,tempd1)) {
case CT_RIGHT:
tempd ->right=tempd1;
tempd1->left =tempd;
return TRUE;
case CT_LEFT:
tempd ->left =tempd1;
tempd1->right=tempd;
return TRUE;
case CT_BOTTOM:
tempd ->bottom=tempd1;
tempd1->top =tempd;
return TRUE;
case CT_TOP:
tempd ->top =tempd1;
tempd1->bottom=tempd;
return TRUE;
default:
return FALSE;
}
}
Dot *DotHVInterconnect(Dot *tempd,Dot *tempd1,CTask *mem_task=NULL)
{
I64 type;
Dot *result=CAlloc(sizeof(Dot),mem_task);
if (Bt(tempd ->flags,Df_TERMINAL_LEFT)||
Bt(tempd ->flags,Df_TERMINAL_RIGHT)) { //d horizontal
type=0;
if (Bt(tempd1->flags,Df_TERMINAL_TOP)||
Bt(tempd1->flags,Df_TERMINAL_BOTTOM)) {//d1 vertical
if (tempd->y<tempd1->y && Bt(tempd1->flags,Df_TERMINAL_TOP)||
tempd->y>tempd1->y && Bt(tempd1->flags,Df_TERMINAL_BOTTOM))
type=1;
} else {
if (tempd->x>tempd1->x && Bt(tempd1->flags,Df_TERMINAL_LEFT)||
tempd->x<tempd1->x && Bt(tempd1->flags,Df_TERMINAL_RIGHT))
type=1;
}
} else { //d vertical
type=1;
if (Bt(tempd1->flags,Df_TERMINAL_LEFT)||
Bt(tempd1->flags,Df_TERMINAL_RIGHT)) { //d1 horizontal
if (tempd->x<tempd1->x && Bt(tempd1->flags,Df_TERMINAL_LEFT)||
tempd->x>tempd1->x && Bt(tempd1->flags,Df_TERMINAL_RIGHT))
type=0;
} else {
if (tempd->y>tempd1->y && Bt(tempd1->flags,Df_TERMINAL_TOP)||
tempd->y<tempd1->y && Bt(tempd1->flags,Df_TERMINAL_BOTTOM))
type=0;
}
}
if (type==1) {
result->x=tempd1->x;
result->y=tempd ->y;
} else {
result->x=tempd ->x;
result->y=tempd1->y;
}
return result;
}
Dot *DotNearest(Dot *root,Dot *tempd,Bool just_processed)
{
I64 best_dd=MAX_I64,dx,dy,dd;
Dot *result=NULL,*tempd1,*tempd2;
if (root && tempd) {
tempd1=root->next;
while (tempd1!=root) {
if (tempd1!=tempd && (!just_processed||Bt(tempd1->flags,Df_PROCESSED))) {
dx=tempd->x-tempd1->x;
dy=tempd->y-tempd1->y;
dd=SqrI64(dx)+SqrI64(dy);
if (0<dd<best_dd) {
if (dx && dy) {
tempd2=DotHVInterconnect(tempd,tempd1);
if (DotHVDecideConnect(tempd ,tempd2) &&
DotHVDecideConnect(tempd2,tempd1)) {
best_dd=dd;
result=tempd1;
}
Free(tempd2);
} else {
if (DotHVDecideConnect(tempd ,tempd1)) {
best_dd=dd;
result=tempd1;
}
}
}
}
tempd1=tempd1->next;
}
}
return result;
}
Bool DotMarkConnected(Dot *tempd)
{
if (tempd && !Bts(tempd->flags,Df_PROCESSED)) {
DotMarkConnected(tempd->left);
DotMarkConnected(tempd->right);
DotMarkConnected(tempd->top);
DotMarkConnected(tempd->bottom);
return TRUE;
} else
return FALSE;
}
U0 DotSpacersAdd(Dot *root,CTask *mem_task=NULL)
{
Dot *tempd,*tempd1,*tempd2;
if (root) {
tempd=root->next;
if (tempd!=root) {
tempd2=root->last;
do {
if (Bt(tempd->flags,Df_TERMINAL)) {
tempd1=CAlloc(sizeof(Dot),mem_task);
tempd1->x=tempd->x;
tempd1->y=tempd->y;
tempd1->flags[0]=tempd->flags[0];
tempd1->e=tempd->e;
if (Bt(tempd->flags,Df_TERMINAL_LEFT)) {
tempd->right=tempd1;
tempd1->left=tempd;
tempd->x--;
}
if (Bt(tempd->flags,Df_TERMINAL_RIGHT)) {
tempd->left=tempd1;
tempd1->right=tempd;
tempd->x++;
}
if (Bt(tempd->flags,Df_TERMINAL_TOP)) {
tempd->bottom=tempd1;
tempd1->top=tempd;
tempd->y--;
}
if (Bt(tempd->flags,Df_TERMINAL_BOTTOM)) {
tempd->top=tempd1;
tempd1->bottom=tempd;
tempd->y++;
}
tempd->flags[0]=0;
tempd->e=NULL;
QueIns(tempd1,root->last);
}
tempd=tempd->next;
} while (tempd!=tempd2);
}
}
}
U0 DotAddSpace(Dot *root)
{
F64 score,best_score;
I64 i,x,y,best_x,best_y;
Dot *tempd,*tempd1;
if (root) {
tempd=root->next;
while (tempd!=root) {
tempd->saved_x=tempd->x;
tempd->saved_y=tempd->y;
tempd=tempd->next;
}
best_score=DotNetScore(root);
tempd=root->next;
while (tempd!=root) {
if (!Bt(tempd->flags,Df_TERMINAL)) {
best_x=0;
best_y=0;
for (i=0;i<4*SPACING;i++) {
nobound_switch (i&3) {
case A_EAST: x= i>>2; y=0; break;
case A_NORTH: y= i>>2; x=0; break;
case A_WEST: x=-i>>2; y=0; break;
case A_SOUTH: y=-i>>2; x=0; break;
}
tempd->x=tempd->saved_x+x;
tempd1=tempd->top;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->x=tempd1->saved_x+x;
tempd1=tempd1->top;
}
tempd1=tempd->bottom;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->x=tempd1->saved_x+x;
tempd1=tempd1->bottom;
}
tempd->y=tempd->saved_y+y;
tempd1=tempd->left;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->y=tempd1->saved_y+y;
tempd1=tempd1->left;
}
tempd1=tempd->right;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->y=tempd1->saved_y+y;
tempd1=tempd1->right;
}
score=DotNetScore(root);
if (score>best_score) {
best_score=score;
best_x=x;
best_y=y;
}
}
tempd->saved_x=tempd->x=tempd->saved_x+best_x;
tempd1=tempd->top;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->saved_x=tempd1->x=tempd1->saved_x+best_x;
tempd1=tempd1->top;
}
tempd1=tempd->bottom;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->saved_x=tempd1->x=tempd1->saved_x+best_x;
tempd1=tempd1->bottom;
}
tempd->saved_y=tempd->y=tempd->saved_y+best_y;
tempd1=tempd->left;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->saved_y=tempd1->y=tempd1->saved_y+best_y;
tempd1=tempd1->left;
}
tempd1=tempd->right;
while (tempd1 && !Bt(tempd1->flags,Df_TERMINAL)) {
tempd1->saved_y=tempd1->y=tempd1->saved_y+best_y;
tempd1=tempd1->right;
}
}
tempd=tempd->next;
}
}
}
U0 DotJunctions(Dot *root)
{
I64 cnt;
Dot *tempd;
tempd=root->next;
while (tempd!=root) {
if (Bt(tempd->flags,Df_TERMINAL))
cnt=1;
else
cnt=0;
if (tempd->left) cnt++;
if (tempd->right) cnt++;
if (tempd->top) cnt++;
if (tempd->bottom) cnt++;
BEqu(tempd->flags,Df_JUNCTION,cnt>2);
tempd=tempd->next;
}
}
Dot *DotTerminalsNew(Node *tempn,CTask *mem_task=NULL)
{
I64 i,min_x,max_x,min_y,max_y,dx,dy,x,y;
Element *tempe;
Dot *result=CAlloc(sizeof(Dot),mem_task),*tempd;
QueInit(result);
for (i=0;i<tempn->cnt;i++)
if (tempe=tempn->terms[i].e) {
tempd=CAlloc(sizeof(Dot),mem_task);
Bts(tempd->flags,Df_TERMINAL);
tempd->e=tempe;
TerminalXY(tempe,tempn->terms[i].terminal,&tempd->x,&tempd->y);
x=tempe->x;
y=tempe->y;
if (mode==MD_MOVE && tempe==rubber_band) {
tempd->x+=ipx-rubber_band_x;
tempd->y+=ipy-rubber_band_y;
x+=ipx-rubber_band_x;
y+=ipy-rubber_band_y;
}
min_x=AbsI64(tempd->x-tempe->min_x);
max_x=AbsI64(tempd->x-tempe->max_x);
if (min_x<max_x)
dx=min_x;
else
dx=max_x;
min_y=AbsI64(tempd->y-tempe->min_y);
max_y=AbsI64(tempd->y-tempe->max_y);
if (min_y<max_y)
dy=min_y;
else
dy=max_y;
if (dx<=dy) {
if (tempd->x<=x)
Bts(tempd->flags,Df_TERMINAL_LEFT);
else
Bts(tempd->flags,Df_TERMINAL_RIGHT);
} else {
if (tempd->y<=y)
Bts(tempd->flags,Df_TERMINAL_TOP);
else
Bts(tempd->flags,Df_TERMINAL_BOTTOM);
}
QueIns(tempd,result->last);
}
return result;
}
Dot *DotNew(Node *tempn,CTask *mem_task=NULL)
{
I64 cnt,pass=0,last_cnt=0;
Bool cont;
Dot *tempd,*tempd1,*tempd2,*tempd3;
Dot *result=DotTerminalsNew(tempn,mem_task);
do {
pass++;
tempd=result->next;
while (tempd!=result) {
if (!Bt(tempd->flags,Df_PROCESSED)) {
if (tempd1=DotNearest(result,tempd,pass>1)) {
if (tempd->x==tempd1->x || tempd->y==tempd1->y) {
if (tempd->x!=tempd1->x || tempd->y!=tempd1->y) {
if (DotHVConnect(tempd,tempd1))
DotMarkConnected(tempd);
}
}else {
tempd2=DotHVInterconnect(tempd,tempd1,mem_task);
tempd3=result->next;
while (tempd3!=result) {
if (tempd2->x==tempd3->x && tempd2->y==tempd3->y)
break;
tempd3=tempd3->next;
}
if (tempd3!=result) {
Free(tempd2);
tempd2=tempd3;
} else
QueIns(tempd2,result->last);
if (DotHVConnect(tempd,tempd2)) {
DotMarkConnected(tempd);
if (DotHVConnect(tempd2,tempd1))
DotMarkConnected(tempd1);
} else
DotHVConnect(tempd2,tempd1);
}
}
}
tempd=tempd->next;
}
tempd=result->next;
while (tempd!=result) {
tempd1=tempd->next;
while (tempd1!=result) {
if (tempd1->y==tempd->y) {
if ((tempd2=tempd->left ) && tempd2->x<tempd1->x<tempd ->x) {
tempd ->left =tempd1;
tempd1->right=tempd ;
tempd1->left =tempd2;
tempd2->right=tempd1;
}
if ((tempd2=tempd->right ) && tempd ->x<tempd1->x<tempd2->x) {
tempd2->left =tempd1;
tempd1->right=tempd2;
tempd1->left =tempd ;
tempd ->right=tempd1;
}
}
if (tempd1->x==tempd->x) {
if ((tempd2=tempd->top ) && tempd2->y<tempd1->y<tempd ->y) {
tempd ->top =tempd1;
tempd1->bottom=tempd ;
tempd1->top =tempd2;
tempd2->bottom=tempd1;
}
if ((tempd2=tempd->bottom) && tempd ->y<tempd1->y<tempd2->y) {
tempd2->top =tempd1;
tempd1->bottom=tempd2;
tempd1->top =tempd ;
tempd ->bottom=tempd1;
}
}
tempd1=tempd1->next;
}
tempd=tempd->next;
}
cont=FALSE;
DotRst(result);
cnt=0;
tempd=result->next;
if (tempd!=result) {
DotMarkConnected(tempd);
while (tempd!=result) {
if (Bt(tempd->flags,Df_PROCESSED))
cnt++;
else
cont=TRUE;
tempd=tempd->next;
}
if (last_cnt==cnt)
break;
last_cnt=cnt;
}
} while (cont);
DotJunctions(result);
DotSpacersAdd(result,mem_task);
DotAddSpace(result);
DotJunctions(result);
return result;
}
U0 DotDraw(CDC *dc,Dot *root)
{
Dot *tempd,*tempd1;
if (root) {
tempd=root->next;
while (tempd!=root) {
Bts(tempd->flags,Df_PROCESSED);
if ((tempd1=tempd->right) && !Bt(tempd1->flags,Df_PROCESSED))
GrLine(dc,tempd->x,tempd->y,tempd1->x,tempd1->y);
if ((tempd1=tempd->left) && !Bt(tempd1->flags,Df_PROCESSED))
GrLine(dc,tempd->x,tempd->y,tempd1->x,tempd1->y);
if ((tempd1=tempd->top) && !Bt(tempd1->flags,Df_PROCESSED))
GrLine(dc,tempd->x,tempd->y,tempd1->x,tempd1->y);
if ((tempd1=tempd->bottom) && !Bt(tempd1->flags,Df_PROCESSED))
GrLine(dc,tempd->x,tempd->y,tempd1->x,tempd1->y);
if (Bt(tempd->flags,Df_JUNCTION)) {
dc->pen_width=3;
GrPlot3(dc,tempd->x,tempd->y,0);
dc->pen_width=1;
}
tempd=tempd->next;
}
}
}
U0 DrawIt(CTask *task,CDC *dc)
{
I64 i,x1,y1,x2,y2;
U8 *img;
Bool old_preempt=Preempt(OFF);
Node *tempn=node_root.next;
Element *tempe=el_root.next;
while (tempe!=&el_root) {
x1=tempe->x;
y1=tempe->y;
if (mode==MD_MOVE && tempe==rubber_band) {
img=tempe->type->red_img;
x1+=ipx-rubber_band_x;
y1+=ipy-rubber_band_y;
} else
img=tempe->type->black_img;
CSpritePlotRotZ3b(dc,x1,y1,0,img,tempe->é*pi/2);
tempe=tempe->next;
}
while (tempn!=&node_root) {
dc->color=BLUE;
if (mode==MD_MOVE)
for (i=0;i<tempn->cnt;i++)
if (tempn->terms[i].e==rubber_band) {
dc->color=RED;
break;
}
DotRst(tempn->dot_root);
DotDraw(dc,tempn->dot_root);
tempn=tempn->next;
}
if (mode==MD_CONNECT && rubber_band && rubber_band_terminal>=0) {
TerminalXY(rubber_band,rubber_band_terminal,&x1,&y1);
x2=ipx-task->win_pixel_left-task->win_scroll_x;
y2=ipy-task->win_pixel_top -task->win_scroll_y;
dc->color=RED;
GrLine(dc,x1,y1,x2,y2);
}
Preempt(old_preempt);
dc->color=BLACK;
GrPutS(dc,0,0,"Right Mouse Change Modes");
switch (mode) {
case MD_CONNECT:
GrPutS(dc,20,FONT_HEIGHT,"Connect Components");
break;
case MD_MOVE:
GrPutS(dc,20,FONT_HEIGHT,"Move Components");
break;
}
}
U0 RubberReset()
{
rubber_band=NULL; rubber_band_terminal=-1;
rubber_band_x=0; rubber_band_y=0;
}
U0 Init()
{
I64 i;
ElementType *tempt;
for (i=0;i<ET_NUM_TYPES;i++) {
tempt=&et[i];
CSpriteExtents(tempt->black_img,&tempt->min_x,&tempt->max_x,&tempt->min_y,&tempt->max_y);
}
mode=MD_CONNECT;
RubberReset;
QueInit(&el_root);
QueInit(&node_root);
}
U0 CleanUp()
{
Element *tempe=el_root.next,*tempe1;
Node *tempn=node_root.next,*tempn1;
while (tempe!=&el_root) {
tempe1=tempe->next;
QueRem(tempe);
Free(tempe);
tempe=tempe1;
}
while (tempn!=&node_root) {
tempn1=tempn->next;
NodeDel(tempn);
tempn=tempn1;
}
}
Element *ElementNew(I64 t,CTask *mem_task=NULL)
{
Element *tempe=CAlloc(sizeof(Element),mem_task);
tempe->type=&et[t];
tempe->x=ipx-Fs->win_pixel_left-Fs->win_scroll_x;
tempe->y=ipy-Fs->win_pixel_top -Fs->win_scroll_y;
QueIns(tempe,el_root.last);
ElementExtents(tempe);
return tempe;
}
Element *ElementFind(I64 x,I64 y,I64 *_terminal)
{
I64 i,x2,y2,best_dd=MAX_I64,dd;
Element *result=NULL,*tempe=el_root.next;
if (_terminal) *_terminal=0;
while (tempe!=&el_root) {
for (i=0;i<tempe->type->terminals;i++) {
TerminalXY(tempe,i,&x2,&y2);
dd=SqrI64(x-x2)+SqrI64(y-y2);
if (dd<best_dd) {
best_dd=dd;
result=tempe;
if (_terminal) *_terminal=i;
}
}
tempe=tempe->next;
}
return result;
}
U0 Circuit()
{
I64 p1,p2,terminal1=-1,terminal2=-1;
Element *tempe1=NULL,*tempe2=NULL;
Node *tempn;
PopUpOk(
"This is not useful.\n"
"It just lets you draw\n"
"a circuit.\n");
SettingsPush; //See $LK,"SettingsPush","MN:SettingsPush"$
Preempt(OFF);
WordStat;
WinMax;
MenuPush(
"File {"
" New(,CH_NEW_LINE);"
" Abort(,CH_SHIFT_ESC);"
" Exit(,CH_ESC);"
"}"
"Edit {"
" Rotate(,CH_SPACE);"
" DelElement(,,SC_DELETE);"
"}"
"Mode {"
" Connect(,0,SC_F2);"
" Move(,0,SC_F3);"
"}"
"PlaceElement {"
" Resistor(,'r');"
" Inductor(,'l');"
" Capacitor(,'c');"
"}"
);
Init;
DocCursor;
DocClear;
Fs->draw_it=&DrawIt;
Fs->win_inhibit=WIF_ALL-WIF_BORDER-WIF_MENU-WIF_GRAB_SCROLL;
try {
while (TRUE) {
switch (GetMsg(&p1,&p2,1<<MSG_KEY_DOWN+1<<MSG_IP_MOVE+
1<<MSG_IP_L_DOWN+1<<MSG_IP_L_UP+
1<<MSG_IP_R_DOWN)) {
case MSG_KEY_DOWN:
switch (p1) {
case 0:
switch (p2.u8[0]) {
case SC_F2:
mode=MD_CONNECT;
tempe1=NULL; terminal1=-1;
tempe2=NULL; terminal2=-1;
RubberReset;
break;
case SC_F3:
mode=MD_MOVE;
tempe1=NULL; terminal1=-1;
tempe2=NULL; terminal2=-1;
RubberReset;
break;
case SC_DELETE:
tempe1=ElementFind(ipx-Fs->win_pixel_left-Fs->win_scroll_x,
ipy-Fs->win_pixel_top -Fs->win_scroll_y,&terminal1);
ElementDel(tempe1,Fs);
tempe1=NULL; terminal1=-1;
tempe2=NULL; terminal2=-1;
RubberReset;
break;
}
break;
case CH_NEW_LINE:
CleanUp;
Init;
break;
case CH_ESC:
case CH_SHIFT_ESC:
goto cs_done;
case 'r':
tempe1=ElementNew(ET_R);
terminal1=-1;
break;
case 'l':
tempe1=ElementNew(ET_L);
terminal1=-1;
break;
case 'c':
tempe1=ElementNew(ET_C);
terminal1=-1;
break;
case CH_SPACE:
if (tempe1) {
tempe1->é=(tempe1->é+1)&3;
ElementExtents(tempe1);
ElementReroute(tempe1,Fs);
}
break;
}
break;
case MSG_IP_MOVE:
if (tempe1) {
ElementExtents(tempe1);
ElementReroute(tempe1,Fs);
}
break;
case MSG_IP_L_DOWN:
tempe1=ElementFind(p1,p2,&terminal1);
rubber_band=tempe1; rubber_band_terminal=terminal1;
rubber_band_x=ipx; rubber_band_y=ipy;
break;
case MSG_IP_L_UP:
rubber_band=NULL;
switch (mode) {
case MD_CONNECT:
if (tempe1 && terminal1>=0) {
if ((tempe2=ElementFind(p1,p2,&terminal2)) &&
(tempe2!=tempe1 || terminal2!=terminal1)) {
if (!(tempn=tempe1->nodes[terminal1]) &&
!(tempn=tempe2->nodes[terminal2]))
tempn=NodeNew;
NodeAdd(tempn,tempe1,terminal1);
NodeAdd(tempn,tempe2,terminal2);
if (tempe1->nodes[terminal1])
NodeCat(tempn,tempe1->nodes[terminal1]);
tempe1->nodes[terminal1]=tempn;
if (tempe2->nodes[terminal2])
NodeCat(tempn,tempe2->nodes[terminal2]);
tempe2->nodes[terminal2]=tempn;
NodeReroute(tempn,Fs);
}
}
break;
case MD_MOVE:
if (tempe1 && terminal1>=0) {
tempe1->x+=ipx-rubber_band_x;
tempe1->y+=ipy-rubber_band_y;
ElementExtents(tempe1);
ElementReroute(tempe1,Fs);
}
break;
}
tempe1=NULL; terminal1=-1;
tempe2=NULL; terminal2=-1;
RubberReset;
break;
case MSG_IP_R_DOWN:
if (mode+1==MD_NUM_MODES)
mode=0;
else
mode++;
tempe1=NULL; terminal1=-1;
tempe2=NULL; terminal2=-1;
RubberReset;
break;
}
}
cs_done:
} catch
CatchAll;
SettingsPop;
CleanUp;
MenuPop;
}
Circuit;
œöÿÿÿùÿÿÿþÿÿÿùÿÿÿþÿÿÿüÿÿÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿÿÿ
þÿÿÿöÿÿÿôÿÿÿ
 òÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿXüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÿÿÿÿÿÿÿÿÿÿÿúÿÿÿœöÿÿÿùÿÿÿþÿÿÿùÿÿÿþÿÿÿüÿÿÿüÿÿÿÿÿÿÿþÿÿÿÿÿÿÿþÿÿÿýÿÿÿ
þÿÿÿöÿÿÿôÿÿÿ
 òÿÿÿýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿXüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúÿÿÿÿÿÿÿÿÿÿÿúÿÿÿ