/webtronics/script/connections.js

http://webtronics.googlecode.com/ · JavaScript · 581 lines · 499 code · 58 blank · 24 comment · 126 complexity · 4caaa8caa4e9d1aa5b95c63674343bc0 MD5 · raw file

  1. Schematic.prototype.getconnects=function(elem){
  2. var pins=[];
  3. var nodes=this.getwtxtagname(elem,"node");
  4. var matrix=this.parseMatrix(elem);
  5. var pin=this.svgRoot.createSVGPoint();
  6. for(var i=0;i<nodes.length;i++){
  7. pin.x=this.getwtxattribute(nodes[i],"x");
  8. pin.y=this.getwtxattribute(nodes[i],"y");
  9. pin = pin.matrixTransform(matrix);
  10. pins[i]={x:Math.round(pin.x),y:Math.round(pin.y)};
  11. }
  12. return pins;
  13. }
  14. Schematic.prototype.matrixxform=function(point,matrix){
  15. var pin=this.svgRoot.createSVGPoint();
  16. pin.x=point.x;
  17. pin.y=point.y;
  18. pin=pin.matrixTransform(matrix);
  19. return {x:Math.round(pin.x),y:Math.round(pin.y)};
  20. }
  21. /*tests if 2 point are within 3 pixels of each other*/
  22. Schematic.prototype.ispoint=function(point1,point2){
  23. return (Math.abs(point2.x-point1.x)<3)&&(Math.abs(point2.y-point1.y)<3);
  24. }
  25. Schematic.prototype.sortnetlist=function(list){
  26. var G=[];
  27. var A=[];
  28. var B=[];
  29. var C=[];
  30. var D=[];
  31. var I=[];
  32. var J=[];
  33. var K=[];
  34. var L=[];
  35. var M=[];
  36. var N=[];
  37. var P=[];
  38. var Q=[];
  39. var R=[];
  40. var U=[];
  41. var V=[];
  42. var wire=[];
  43. var other=[]
  44. for(var i=0;i<list.length;i++){
  45. if(list[i].type=='gnd'){
  46. G.push(list[i]);
  47. }
  48. else if(list[i].type=='v'){
  49. V.push(list[i]);
  50. }
  51. else if(list[i].type=='wire'){
  52. wire.push(list[i]);
  53. }
  54. else if(list[i].type=='b'){
  55. B.push(list[i]);
  56. }
  57. else if(list[i].type=='c'){
  58. C.push(list[i]);
  59. }
  60. else if(list[i].type=='d'){
  61. D.push(list[i]);
  62. }
  63. else if(list[i].type=='i'){
  64. J.push(list[i]);
  65. }
  66. else if(list[i].type=='j'){
  67. J.push(list[i]);
  68. }
  69. else if(list[i].type=='k'){
  70. K.push(list[i]);
  71. }
  72. else if(list[i].type=='l'){
  73. L.push(list[i]);
  74. }
  75. else if(list[i].type=='m'){
  76. M.push(list[i]);
  77. }
  78. else if(list[i].type=='n'){
  79. N.push(list[i]);
  80. }
  81. else if(list[i].type=='plot'){
  82. P.push(list[i]);
  83. }
  84. else if(list[i].type=='q'){
  85. Q.push(list[i]);
  86. }
  87. else if(list[i].type=='r'){
  88. R.push(list[i]);
  89. }
  90. else if(list[i].type=='u'){
  91. U.push(list[i]);
  92. }
  93. /* this is the best way I could think to tell if a part i digital */
  94. else if(list[i].category=="digital"){
  95. A.push(list[i]);
  96. }
  97. else {
  98. list[i].error='unknown device';
  99. other.push(list[i]);
  100. }
  101. }
  102. var sortfunction=function(a,b){
  103. var apart=a.id.replace(a.type,"");
  104. var bpart=b.id.replace(b.type,"");
  105. if(!apart)apart=0;
  106. if(!bpart)bpart=0;
  107. return (apart>bpart);
  108. };
  109. V.sort(sortfunction);
  110. wire.sort(sortfunction);
  111. B.sort(sortfunction);
  112. C.sort(sortfunction);
  113. D.sort(sortfunction);
  114. I.sort(sortfunction);
  115. J.sort(sortfunction);
  116. K.sort(sortfunction);
  117. L.sort(sortfunction);
  118. M.sort(sortfunction);
  119. N.sort(sortfunction);
  120. P.sort(sortfunction);
  121. Q.sort(sortfunction);
  122. R.sort(sortfunction);
  123. U.sort(sortfunction);
  124. A.sort(sortfunction);
  125. var newlist=[];
  126. G.each(function(item){newlist.push(item)});
  127. G.reverse();
  128. V.each(function(item){newlist.push(item)});
  129. wire.each(function(item){newlist.push(item)});
  130. B.each(function(item){newlist.push(item)});
  131. C.each(function(item){newlist.push(item)});
  132. D.each(function(item){newlist.push(item)});
  133. I.each(function(item){newlist.push(item)});
  134. J.each(function(item){newlist.push(item)});
  135. K.each(function(item){newlist.push(item)});
  136. L.each(function(item){newlist.push(item)});
  137. M.each(function(item){newlist.push(item)});
  138. N.each(function(item){newlist.push(item)});
  139. Q.each(function(item){newlist.push(item)});
  140. R.each(function(item){newlist.push(item)});
  141. U.each(function(item){newlist.push(item)});
  142. A.each(function(item){newlist.push(item)});
  143. other.each(function(item){newlist.push(item)});
  144. /*plots go last*/
  145. P.each(function(item){newlist.push(item)});
  146. return newlist;
  147. }
  148. /* draws wires to namewire ports with the same id*/
  149. Schematic.prototype.connectwires=function(list){
  150. for(var i=0;i<list.length;i++){
  151. if(list[i].type=="wire"){
  152. for(var j=i;j<list.length;j++){
  153. if((list[i]!=list[j])&&(list[i].id==list[j].id)){
  154. var node1=this.getwtxtagname(list[i].elem,"node")[0];
  155. var node2=this.getwtxtagname(list[j].elem,"node")[0];
  156. var point1={x:this.getwtxattribute(node1,"x"),y:this.getwtxattribute(node1,"y")}
  157. point1=this.matrixxform(point1,this.parseMatrix(list[i].elem));
  158. var point2={x:this.getwtxattribute(node2,"x"),y:this.getwtxattribute(node2,"y")}
  159. point2=this.matrixxform(point2,this.parseMatrix(list[j].elem));
  160. var line= this.createline('yellow',1,point1.x,point1.y,point2.x,point2.y);
  161. line.setAttributeNS(null,'class','namewire');
  162. this.info.appendChild(line);
  163. //console.log(line);
  164. break;
  165. }
  166. }
  167. }
  168. }
  169. }
  170. /* test if wires are connected anywhere*/
  171. Schematic.prototype.getconnected=function(wirelist,wire){
  172. for(var i=0;i<wirelist.length;i++){
  173. for(var j=0;j<wirelist[i].length;j++){
  174. for(var k=0;k<wire.length;k++){
  175. if(this.ispoint(wirelist[i][j],wire[k])){
  176. return i;
  177. }
  178. }
  179. }
  180. }
  181. return -1;
  182. }
  183. /*check for vectors and convert them*/
  184. Schematic.prototype.tovector=function(pin,nodenumber){
  185. var v ="";
  186. if(pin.parentNode.tagName=="wtx:vector"){
  187. var vector=Element.descendants(pin.parentNode);
  188. if(pin==vector[0]){v+="["}
  189. v+="a"+nodenumber;
  190. if(pin==vector[vector.length-1]){v+="]";}
  191. }
  192. else{
  193. v+="a"+nodenumber;
  194. }
  195. return v;
  196. }
  197. Schematic.prototype.getwtxdata=function(parts){
  198. list=[];
  199. for(var i=0;i<parts.length;i++){
  200. var part={error:"", elem:{}, type:"", name:"", category:"", value:"", spice:"", model:""}
  201. /*
  202. try{
  203. part.nodes=this.getwtxpins(part[i]);
  204. }
  205. catch{part.error="wtx:pins not found"}
  206. */
  207. part.elem=parts[i];
  208. try{
  209. part.id=this.readwtx(parts[i],'id');
  210. }
  211. catch(e){part.error="wtx:id not found";}
  212. try{
  213. part.type=this.readwtx(parts[i],'type');
  214. }
  215. catch(e){
  216. part.error="wtx:type not found";
  217. }
  218. try{
  219. part.name=this.readwtx(parts[i],'name');
  220. }
  221. catch(e){part.error="wtx:name not found";}
  222. try{
  223. part.category=this.readwtx(parts[i],'category');
  224. }
  225. catch(e){part.error="wtx:category not found";}
  226. try{
  227. part.value=this.readwtx(parts[i],'value');
  228. }
  229. catch(e){part.error="wtx:value not found";}
  230. try{
  231. part.spice=this.readwtx(parts[i],'spice');
  232. }
  233. catch(e){part.error="wtx:spice not found";}
  234. try{
  235. part.model=this.readwtx(parts[i],'model');
  236. }
  237. catch(e){part.error="wtx:model not found";}
  238. list.push(part);
  239. }
  240. return list;
  241. }
  242. /*detect analog and digital mix*/
  243. Schematic.prototype.mixedsignals=function(analogwires,digitalwires){
  244. for(var j=1;j<analogwires.length;j++){
  245. var crossed=this.getconnected(digitalwires,analogwires[j]);
  246. if(crossed>-1){
  247. return true;
  248. }
  249. }
  250. return false;
  251. }
  252. /* creates all netlist data from parts data*/
  253. Schematic.prototype.getnodes=function(parts){
  254. var sections={netlist:[],firstdir:[],simulation:[],lastdir:[]};
  255. var trannodes=[];
  256. var digitalcount=1;
  257. var analogcount=1;
  258. var digitalwires=[];
  259. var analogwires=[];
  260. for(var i=0;i<parts.length; i++){
  261. if(parts[i].type=="wire")continue;
  262. // check what type of simulation to use
  263. if(parts[i].type=="plot"){
  264. if(sections.simulation.length==0 && parts[i].model.length){
  265. sections.simulation.push(parts[i].model);
  266. }
  267. }
  268. else if(parts[i].type=="v"){
  269. if(sections.simulation.length==0 && parts[i].model.length){
  270. sections.simulation.push(".op");
  271. sections.simulation.push(".print ac i("+parts[i].id+")");
  272. sections.simulation.push(parts[i].model);
  273. }
  274. }
  275. else{
  276. if(parts[i].model.match(/\.mod/i) && !parts[i].id.match(/^x/))parts[i].id="x"+parts[i].id;
  277. if(parts[i].model.length)sections.firstdir.push(parts[i].model);
  278. }
  279. var net={error:parts[i].error,partid:parts[i].id,pins:[],model:parts[i].value};
  280. var nodes=this.getwtxtagname(parts[i].elem,"node");
  281. //node numbering loop
  282. for(var j=0;j<nodes.length;j++){
  283. var point={x:this.getwtxattribute(nodes[j],"x"),y:this.getwtxattribute(nodes[j],"y")};
  284. point=this.matrixxform(point,this.parseMatrix(parts[i].elem));
  285. var wire=this.followwires(null,point);
  286. if(nodes[j].parentNode.tagName=="wtx:analog"){
  287. var found=this.getconnected(analogwires,wire);
  288. if(parts[i].type=='gnd'){
  289. if(!analogwires[0])analogwires[0]=[];
  290. for(var k=0;k<wire.length;k++)analogwires[0].push(wire[k])
  291. /* add analog ground to digital wirelist*/
  292. if(!digitalwires[0])digitalwires.push(analogwires[0]);
  293. net=null;
  294. }
  295. else if(found<0){
  296. net.pins.push(analogcount);
  297. analogwires.push(wire);
  298. analogcount++;
  299. }
  300. else{
  301. net.pins.push(found);
  302. }
  303. }
  304. else{
  305. if(digitalwires.length==0){
  306. net.error="no ground node";
  307. }
  308. var found=this.getconnected(digitalwires,wire);
  309. if(found<0){
  310. var v=this.tovector(nodes[j],digitalcount);
  311. net.pins.push(v);
  312. digitalwires.push(wire);
  313. digitalcount++;
  314. }
  315. else{
  316. var v=this.tovector(nodes[j],found);
  317. net.pins.push(v);
  318. }
  319. }
  320. }
  321. //after all wires are numbered check which ones are plotted
  322. if(parts[i].type=="plot"){
  323. var point={x:this.getwtxattribute(nodes[0],"x"),y:this.getwtxattribute(nodes[0],"y")};
  324. point=this.matrixxform(point,this.parseMatrix(parts[i].elem));
  325. var wire=this.followwires(null,point);
  326. var found=this.getconnected(analogwires,wire);
  327. if(found>-1){trannodes.push(found);}
  328. else {
  329. var found=this.getconnected(digitalwires,wire);
  330. if(found>-1){trannodes.push("a"+found);}
  331. }
  332. }
  333. else if(net!=null)sections.netlist.push(net);
  334. }
  335. //create tran print nodes
  336. if(sections.simulation.length==1){
  337. for(var i=0;i<trannodes.length;i++){
  338. var command=".print tran"
  339. for(var i=0;i<trannodes.length;i++){
  340. /*digital*/
  341. if(trannodes[i].toString().match('a')){
  342. command+=" "+trannodes[i];
  343. }
  344. /*analog*/
  345. else{command+=" v("+trannodes[i]+")"}
  346. }
  347. }
  348. if(command!=null){
  349. sections.simulation.unshift(command);
  350. sections.simulation.unshift(".op");
  351. }
  352. }
  353. if(this.mixedsignals(analogwires,digitalwires)){
  354. return {firstdir:[],netlist:[{error:"pin is both analog and digital"}],lastdir:[],plot:[]};
  355. }
  356. return sections;
  357. }
  358. /* organizes data into netlist*/
  359. Schematic.prototype.createnetlist=function(responsefunc){
  360. var parts=$$('#webtronics_drawing > g');
  361. if(parts.length<1){
  362. responsefunc("no parts found\n");
  363. return;
  364. }
  365. var partswtx=this.sortnetlist(this.getwtxdata(parts));
  366. if(partswtx[0].type.toLowerCase()!='gnd'){
  367. responsefunc('no ground node');
  368. return;
  369. }
  370. this.connectwires(partswtx);
  371. var spice=".title webtronics\n";
  372. var sections=this.getnodes(partswtx);
  373. //dump models into spice
  374. var modelloader={
  375. modeltext:"",
  376. modelcount:0,
  377. responsecount:0,
  378. download:function(name){
  379. openfile( "../spice/"+ name.split(' ')[1],modelloader.responder);
  380. modelloader.modelcount++;
  381. },
  382. finish:function(){
  383. spice+=modelloader.modeltext;
  384. if(sections.simulation.length){
  385. var command=".print tran"
  386. for(var i=0;i<sections.simulation.length;i++){
  387. if(sections.simulation[i]!="")spice+=sections.simulation[i]+"\n";
  388. }
  389. }
  390. if(sections.lastdir.length){
  391. sections.lastdir=sections.lastdir.uniq();
  392. for(var i=0;i<sections.lastdir.length;i++){
  393. if(sections.lastdir[i]!="")spice+=sections.lastdir[i]+"\n";
  394. }
  395. }
  396. spice=spice.concat(".end \n");
  397. var connector=$$('#information > .namewire')
  398. for(var i=0;i<connector.length;i++)connector[i].parentNode.removeChild(connector[i]);
  399. responsefunc(spice.toLowerCase());
  400. },
  401. responder:function(text){
  402. modelloader.modeltext+=text;
  403. modelloader.responsecount++;
  404. if(modelloader.responsecount==modelloader.modelcount){
  405. modelloader.finish();
  406. }
  407. }
  408. }
  409. if(sections.netlist.length){
  410. var command="";
  411. for(var i=0;i<sections.netlist.length;i++){
  412. if(sections.netlist[i].error!=""){
  413. spice+=sections.netlist[i].error+'\n';
  414. continue;
  415. }
  416. command=sections.netlist[i].partid;
  417. for(var j=0;j<sections.netlist[i].pins.length;j++)command+=" "+sections.netlist[i].pins[j];
  418. command+=" "+sections.netlist[i].model;
  419. if(command!="")spice+=command+'\n';
  420. }
  421. }
  422. if(sections.firstdir.length){
  423. sections.firstdir=sections.firstdir.uniq();
  424. for(var i=0;i<sections.firstdir.length;i++){
  425. console.log(sections.firstdir[i]);
  426. if(sections.firstdir[i].length){
  427. modelloader.download(sections.firstdir[i]);
  428. }
  429. }
  430. }
  431. else modelloader.finish();
  432. }
  433. Schematic.prototype.followwires=function(wirelist,pin){
  434. if(wirelist==null)wirelist=[];
  435. var points=[];
  436. points.push(pin);
  437. var lines =$$('#webtronics_drawing > line, #information > .namewire');
  438. for(var i =0 ;i<lines.length;i++){
  439. var point1={x:lines[i].getAttribute('x1')-0,y:lines[i].getAttribute('y1')-0};
  440. var point2={x:lines[i].getAttribute('x2')-0,y:lines[i].getAttribute('y2')-0};
  441. if(wirelist.indexOf(lines[i])<0){
  442. if(this.ispoint(point1,pin)){
  443. wirelist.push(lines[i]);
  444. var p=this.followwires(wirelist,point2);
  445. for(var j=0;j<p.length;j++)points.push(p[j]);
  446. }
  447. else if(this.ispoint(point2,pin)){
  448. wirelist.push(lines[i]);
  449. var p=this.followwires(wirelist,point1);
  450. for(var j=0;j<p.length;j++)points.push(p[j]);
  451. }
  452. }
  453. }
  454. return points;
  455. }
  456. Schematic.prototype.addconnects=function(elem,pin){
  457. var pins=this.getconnects(elem);
  458. var str;
  459. if(!pins){
  460. str=pin.x+','+pin.y;
  461. elem.setAttribute('connects',str);
  462. }
  463. else {
  464. str=this.writeconnects(pins);
  465. str+=';'+pin.x+','+pin.y;
  466. elem.setAttribute('connects',str);
  467. }
  468. }
  469. Schematic.prototype.writeconnects=function(pins){
  470. var str=[];
  471. for(var i=0;i<pins.length;i++){
  472. str[i] = pins[i].x +','+pins[i].y;
  473. }
  474. return str.join(';');
  475. }
  476. Schematic.prototype.isconnect=function(pin,radius,x,y){
  477. return ((pin.x+radius)>x)&&((pin.x-radius)<x)&&
  478. ((pin.y+radius)>y)&&((pin.y-radius)<y);
  479. }
  480. Schematic.prototype.isconnects=function(radius,x,y){
  481. var parts=this.drawing.childNodes;
  482. for(var i=0; i<parts.length; i++){
  483. if(parts[i].tagName=='g'){
  484. var pins=this.getconnects(parts[i]);
  485. if(pins){
  486. for(var j=0;j<pins.length;j++){
  487. if(this.isconnect(pins[j],radius,x,y)){
  488. return pins[j];
  489. }
  490. }
  491. }
  492. }
  493. }
  494. return null;
  495. }
  496. Schematic.prototype.showallconnects=function(){
  497. if(this.connections){
  498. var parts=$$('#webtronics_drawing > g');
  499. this.connectwires(this.getwtxdata(parts));
  500. for(var i=0 ;i<parts.length;i++){
  501. var nodes=this.getwtxtagname(parts[i],"node");
  502. for(var j=0;j<nodes.length;j++){
  503. var x=this.getwtxattribute(nodes[j],"x");
  504. var y=this.getwtxattribute(nodes[j],"y");
  505. var point=this.matrixxform({x:x,y:y},this.parseMatrix(parts[i]));
  506. if(nodes[j].parentNode.tagName=="wtx:analog"){
  507. var circle=this.createdot('red',point.x,point.y);
  508. circle.setAttribute('class',"schematic_connector");
  509. this.info.appendChild(circle);
  510. }
  511. else{
  512. var rect=this.createrect('green',100,point.x-3,point.y-3,6,6);
  513. rect.setAttribute('class',"schematic_connector");
  514. this.info.appendChild(rect);
  515. }
  516. }
  517. }
  518. }
  519. }
  520. Schematic.prototype.hideconnects=function(){
  521. var connector=$$('#information .schematic_connector,#information .namewire')
  522. for(var i=0;i<connector.length;i++)connector[i].parentNode.removeChild(connector[i]);
  523. }