Diagram.java 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. import javax.swing.*;
  2. import java.awt.*;
  3. import java.awt.event.*;
  4. import java.awt.geom.*;
  5. import java.net.*;
  6. import java.io.*;
  7. import java.applet.*;
  8. class Node {
  9. //*********************************************
  10. //* *
  11. //* This class is needed for the class list. *
  12. //* A Node looks like an element of the list. *
  13. //* *
  14. //*********************************************
  15. private int value; //Value of the Node
  16. private Node next; //The next Node in the list
  17. private Node previous; //The previous Node in the list
  18. public Node(){
  19. value=0;
  20. }
  21. public Node(int _value){
  22. value=_value;
  23. }
  24. public void setValue(int _value){
  25. value=_value;
  26. }
  27. public void setPrevious(Node _previous){
  28. previous=_previous;
  29. }
  30. public void setNext(Node _next){
  31. next=_next;
  32. }
  33. public int getValue(){
  34. return value;
  35. }
  36. public Node getPrevious(){
  37. return previous;
  38. }
  39. public Node getNext(){
  40. return next;
  41. }
  42. }
  43. class List {
  44. //******************************************
  45. //* *
  46. //* This class decribe a bichained list. *
  47. //* I don't use the linkedList of java *
  48. //* because it need use of complex Object. *
  49. //* *
  50. //******************************************
  51. private Node first; //The first Node of the list
  52. private Node last; //The last Node of the list
  53. public Node current; //A Node we play the game of an iterator
  54. public int length; //The length of the list
  55. public List(){
  56. length=0;
  57. }
  58. public Node getFirst(){
  59. return first;
  60. }
  61. public Node getLast(){
  62. return last;
  63. }
  64. public void initCurrent(){
  65. current=first;
  66. }
  67. public void setCurrent(Node _current){
  68. current=_current;
  69. }
  70. public Node getCurrent(){
  71. return current;
  72. }
  73. public int isEnd(){
  74. if(current==last){
  75. return 1;
  76. }
  77. else{
  78. return 0;
  79. }
  80. }
  81. public void shift(){
  82. // ---------------------------------------
  83. //| Change the current node with the next |
  84. // ---------------------------------------
  85. current=current.getNext();
  86. }
  87. public void addLast(int value){
  88. // ----------------------------------------------------
  89. //| Add a Node of value 'value' at the end of the list |
  90. // ----------------------------------------------------
  91. Node node=new Node(value);
  92. if(length==0){
  93. first=node;
  94. last=node;
  95. }
  96. else{
  97. last.setNext(node);
  98. node.setPrevious(last);
  99. last=node;
  100. }
  101. length++;
  102. }
  103. public Node addBefore(int value){
  104. // -----------------------------------------------------------------
  105. //| Add a Node of value 'value' before the current Node of the list |
  106. //| and return the new Node |
  107. // -----------------------------------------------------------------
  108. Node node=new Node(value);
  109. if(current==first){
  110. first=node;
  111. node.setNext(current);
  112. current.setPrevious(node);
  113. }
  114. else {
  115. Node temp=current.getPrevious();
  116. temp.setNext(node);
  117. node.setPrevious(temp);
  118. current.setPrevious(node);
  119. node.setNext(current);
  120. }
  121. length++;
  122. return node;
  123. }
  124. public Node addAfter(int value){
  125. // ----------------------------------------------------------------
  126. //| Add a Node of value 'value' after the current Node of the list |
  127. //| and return the new Node |
  128. // ----------------------------------------------------------------
  129. Node node=new Node(value);
  130. if(current==last){
  131. last=node;
  132. node.setPrevious(current);
  133. current.setNext(node);
  134. }
  135. else{
  136. Node temp=current.getNext();
  137. temp.setPrevious(node);
  138. node.setNext(temp);
  139. current.setNext(node);
  140. node.setPrevious(current);
  141. }
  142. length++;
  143. return node;
  144. }
  145. public void remove(Node node){
  146. // ----------------------------------
  147. //| Remove the Node node of the list |
  148. // ----------------------------------
  149. if(length!=0){
  150. if(length==1){
  151. length=0;
  152. }
  153. else{
  154. if(node==first){
  155. first=node.getNext();
  156. node=first;
  157. }
  158. else if(node==last){
  159. last=node.getPrevious();
  160. current=last;
  161. }
  162. else{
  163. (node.getPrevious()).setNext(node.getNext());
  164. (node.getNext()).setPrevious(node.getPrevious());
  165. }
  166. length--;
  167. }
  168. }
  169. }
  170. public int value(){
  171. return current.getValue();
  172. }
  173. public int length(){
  174. return length;
  175. }
  176. }
  177. public class Diagram extends JApplet implements ActionListener{
  178. //*******************************************************
  179. //* *
  180. //* This class represent the window of the application. *
  181. //* *
  182. //*******************************************************
  183. public static final long serialVersionUID = 0;
  184. private Panel panel; //Will draw graphics on the panel
  185. private JTextField textField; //An area in which will enter a braid word
  186. public void init(){
  187. JLabel label=new JLabel("Enter a word :");
  188. label.setBounds(0,0,100,20);
  189. add(label);
  190. textField=new JTextField(10);
  191. textField.addActionListener(this); //Active the action listener of
  192. textField.setBounds(100,0,380,20);
  193. add(textField);
  194. panel=new Panel();
  195. panel.setBackground(Color.darkGray);
  196. panel.setBounds(0,20,480,600);
  197. add(panel);
  198. add(new JLabel(""));
  199. }
  200. public void actionPerformed (ActionEvent event){
  201. // ----------------------------------------------------------
  202. //| Specify what the action on the element of the windows do |
  203. // ----------------------------------------------------------
  204. if(event.getSource()==textField){
  205. StringBuffer word=new StringBuffer(event.getActionCommand());
  206. panel.writeBraidWord(word);
  207. }
  208. }
  209. public String getAppletInfo() {
  210. return "Handle reduction algorithm.";
  211. }
  212. }
  213. class Panel extends JPanel{
  214. //************************************************
  215. //* *
  216. //* This class is the key class of this program. *
  217. //* It contains algoritms and drawing tools. *
  218. //* *
  219. //************************************************
  220. public static final long serialVersionUID = 0;
  221. //=====> Braid variable
  222. private StringBuffer braidWord; //The initial braid word
  223. private int braidWordSet=0;
  224. private List braid; //The braid word as a list
  225. //=====> Strand variable
  226. private int strandNumber=5; //The number of strand
  227. private float strandStep; //The distance between two strand
  228. private float strandWidth; //The width of a strand
  229. private float strandLeft; //The x position of the leftmost strand
  230. private float[] xPos; //The x postion of strands
  231. private float[] xPosNext; //The next x position of strands
  232. private float yUp; //The y position of the first element of the braid
  233. //======> Color variable
  234. private Color[] strandColor; //The color of different strand
  235. private Color handleColor=Color.black; //The color of the handle
  236. private Color originalHandleStrandColor; //The original color of the handle strand
  237. //======> Way variable
  238. private GeneralPath[] continuousWay; //The currant continuous way of strands
  239. //======> Double Buffering variable
  240. private Image offScreenBuffer; //A buffer in wich we draw and after drawing we will show this buffer
  241. private int isDraw; //For not repeat drawing
  242. // =================
  243. //I I
  244. //I Braid functions I
  245. //I I
  246. // =================
  247. private void initBraid(){
  248. // -----------------------------------------------------
  249. //| Iniliasition of braid as a list and of strandNumber |
  250. // -----------------------------------------------------
  251. int length;
  252. int value;
  253. char letter;
  254. strandNumber=2;
  255. value=0;
  256. braid=new List();
  257. length=braidWord.length(); //get the length of the braid word
  258. braid.addLast(0); //add a trivial at the begin
  259. for(int i=0;i<length;i++){
  260. letter=braidWord.charAt(i);
  261. if(letter>='a' && letter<='z'){ //if we have a lower case letter
  262. value=(int)(letter-'a')+1; //value is 1 for 'a', 2 for 'b', ...
  263. if(value+1>strandNumber){ //update the strand number
  264. strandNumber=value+1;
  265. }
  266. }
  267. else if(letter>='A' && letter<='Z'){ //if we have an upper case letter
  268. value=-(int)(letter-'A')-1; //value is -1 for 'A', -2 for 'B', ...
  269. if(-value+1>strandNumber){ //update the strand number
  270. strandNumber=-value+1;
  271. }
  272. }
  273. else{
  274. value=0;
  275. }
  276. braid.addLast(value); //add the value at the list of the braid
  277. }
  278. braid.addLast(0); //add a trivial at th end
  279. }
  280. public void writeBraidWord(StringBuffer buffer){
  281. // -----------------------------------------------------
  282. //| Initialise the braid word and some other parameters |
  283. //------------------------------------------------------
  284. braidWord=buffer;
  285. initBraid(); //initialise the braid list
  286. isDraw=0; //we draw a new image
  287. braidWordSet=1;
  288. update(super.getGraphics()); //update draw
  289. }
  290. // =================
  291. //I I
  292. //I Color functions I
  293. //I I
  294. // =================
  295. public void initStrandColor(){
  296. // ---------------------------
  297. //| Init the color of strands |
  298. // ---------------------------
  299. strandColor=new Color[strandNumber]; //Make the table of strand color
  300. for(int strand=1;strand<strandNumber+1;strand++){
  301. if(strandNumber<10){
  302. strandColor[strand-1]=Color.getHSBColor((float)1-(float)strand/(float)10,(float)0.8,1);
  303. }
  304. else {
  305. strandColor[strand-1]=Color.getHSBColor((float)1-(float)strand/(float)strandNumber,(float)0.8,1);
  306. }
  307. }
  308. }
  309. // ==========================
  310. //I I
  311. //I Continuous way functions I
  312. //I I
  313. // ==========================
  314. public void initContinuousWay(){
  315. // -----------------------------------------
  316. //| Start the continuous way for all strand |
  317. // -----------------------------------------
  318. continuousWay=new GeneralPath[strandNumber]; //Make the table of continuous way
  319. xPos=new float[strandNumber]; //Make the table of x position of strands
  320. xPosNext=new float[strandNumber]; //Make the table of next x position of strands
  321. for(int strand=1;strand<strandNumber+1;strand++){
  322. continuousWay[strand-1]=new GeneralPath();
  323. xPos[strand-1]=strandLeft+strand*strandStep; //The xPos of n is strandLeft+n*strandStep
  324. continuousWay[strand-1].moveTo(xPos[strand-1],yUp); //Start the continuous way at the y position yUp
  325. }
  326. }
  327. public void closeContinuousWay(Graphics2D g,int strand){
  328. // -------------------------------------------
  329. //| Stop and draw the continous way of strand |
  330. // -------------------------------------------
  331. GeneralPath gp;
  332. gp=continuousWay[strand-1];
  333. g.setColor(strandColor[strand-1]); //Apply the color of strand
  334. g.draw(gp);
  335. gp=new GeneralPath(); //Make a new general path
  336. continuousWay[strand-1]=gp; //Start the new continuous way
  337. }
  338. public void permuteContinuousWay(int strand){
  339. // -----------------------------------------------------------------
  340. //| Echange the continuous way and the color of strand and strand+1 |
  341. // -----------------------------------------------------------------
  342. GeneralPath gp;
  343. Color color;
  344. //Echange continuous way
  345. gp=continuousWay[strand-1];
  346. continuousWay[strand-1]=continuousWay[strand];
  347. continuousWay[strand]=gp;
  348. //Echange color
  349. color=strandColor[strand-1];
  350. strandColor[strand-1]=strandColor[strand];
  351. strandColor[strand]=color;
  352. }
  353. // ================
  354. //I I
  355. //I Math functions I
  356. //I I
  357. // ================
  358. public double min(double a,double b){
  359. if(a<b){
  360. return a;
  361. }
  362. else{
  363. return b;
  364. }
  365. }
  366. public double max(double a,double b){
  367. if(a>b){
  368. return a;
  369. }
  370. else{
  371. return b;
  372. }
  373. }
  374. public double square(double a){
  375. return a*a;
  376. }
  377. // ===================
  378. //I I
  379. //I Position function I
  380. //I I
  381. // ===================
  382. public void calcXPosNext(){
  383. // ----------------------------------------
  384. //| Compute the nex x position of strands. |
  385. //| It's a key function for animation. |
  386. // ----------------------------------------
  387. for(int strand=0;strand<strandNumber;strand++){
  388. xPosNext[strand]=strandLeft+(strand+1)*strandStep; //The general case
  389. }
  390. }
  391. public void updateXPos(){
  392. // ------------------------------------------------------------------
  393. //| Update the x postion of strand with the nex x position of strand |
  394. // ------------------------------------------------------------------
  395. for(int strand=0;strand<strandNumber;strand++){
  396. xPos[strand]=xPosNext[strand];
  397. }
  398. }
  399. public float[] calculIntersection(int strand,float yPos,int type){
  400. // -----------------------------------------------------------------------
  401. //| Compute the two key point for draw the generator strand |
  402. // -----------------------------------------------------------------------
  403. float []res=new float[4];
  404. //res[0]<=res[1] is the x position of this points
  405. //res[2]<=res[3] is the y position of this points
  406. double decale=1.5*strandWidth; //Is distance of a strand with the other in the crossing
  407. double distance;
  408. if(type==1){ //If the crossing is positive
  409. //We compute the distance between the left-up point and then right-down
  410. distance=Math.sqrt(square(xPosNext[strand]-xPos[strand-1])+square(strandStep));
  411. }
  412. else { //If the crossing is negative
  413. //We compute the distance between the right-up and the left-down
  414. distance=Math.sqrt(square(xPos[strand]-xPosNext[strand-1])+square(strandStep));
  415. }
  416. double alpha=Math.acos(strandStep/distance); //The angle of the crossing
  417. double decalX=Math.sin(alpha)*decale; //The x coords of decale
  418. double decalY=Math.cos(alpha)*decale; //The y coords of decale
  419. //The straight line D1 of equation x=m1*y+p1 contains the left-up and the right-down point
  420. double m1=((double)strandStep)/((double)(xPosNext[strand]-xPos[strand-1]));
  421. double p1=yPos-m1*((double)xPos[strand-1]);
  422. //The straight line D2 of equation x=m2*y+p2 contains the right-up and the left-down point
  423. double m2=((double)strandStep)/((double)(xPosNext[strand-1]-xPos[strand]));
  424. double p2=yPos-m2*((double)xPos[strand]);
  425. double xInter=(p2-p1)/(m1-m2); //x coord of D1 inter D2
  426. double yInter=m1*xInter+p1; //y coord of D1 inter D2
  427. //Computaion of values of res, the min and max fonction are usefull for a good drawing
  428. res[0]=(float)max(xInter-decalX,xPosNext[strand-1]);
  429. res[1]=(float)min(xInter+decalX,xPosNext[strand]);
  430. res[2]=(float)max(yInter-decalY,yPos);
  431. res[3]=(float)min(yInter+decalY,yPos+strandStep);
  432. return res;
  433. }
  434. // ===================
  435. //I I
  436. //I Drawing functions I
  437. //I I
  438. // ===================
  439. public void drawTrivial(float yPos){
  440. // -------------------------------------
  441. //| Draw a not extrem trivial generator |
  442. // -------------------------------------
  443. for(int strand=0;strand<strandNumber;strand++){
  444. continuousWay[strand].lineTo(xPosNext[strand],yPos+strandStep);
  445. }
  446. }
  447. public void drawNoCrossing(Graphics2D g,int strand,float yPos){
  448. // ----------------------
  449. //| Draw straight strand |
  450. // ----------------------
  451. continuousWay[strand-1].lineTo(xPosNext[strand-1],yPos+strandStep);
  452. }
  453. public void drawPositiveCrossing(Graphics2D g,int strand,float yPos){
  454. // --------------------------
  455. //| Draw a positive crossing |
  456. // --------------------------
  457. float inter[]=calculIntersection(strand,yPos,1);
  458. continuousWay[strand-1].lineTo(inter[0],inter[2]);
  459. closeContinuousWay(g,strand);
  460. continuousWay[strand-1].moveTo(inter[1],inter[3]);
  461. continuousWay[strand-1].lineTo(xPosNext[strand],yPos+strandStep);
  462. continuousWay[strand].lineTo(xPosNext[strand-1],yPos+strandStep);
  463. permuteContinuousWay(strand);
  464. }
  465. public void drawNegativeCrossing(Graphics2D g,int strand,float yPos){
  466. // --------------------------
  467. //| Draw a negative crossing |
  468. // --------------------------
  469. float inter[]=calculIntersection(strand,yPos,-1);
  470. continuousWay[strand].lineTo(inter[1],inter[2]);
  471. closeContinuousWay(g,strand+1);
  472. continuousWay[strand].moveTo(inter[0],inter[3]);
  473. continuousWay[strand].lineTo(xPosNext[strand-1],yPos+strandStep);
  474. continuousWay[strand-1].lineTo(xPosNext[strand],yPos+strandStep);
  475. permuteContinuousWay(strand);
  476. }
  477. public void draw(Graphics g){
  478. // --------------------------------------------
  479. //| The main and first called drawing function |
  480. // --------------------------------------------
  481. Graphics2D g2=(Graphics2D) g; //A Graphics2D context is needed
  482. Rectangle r;
  483. int generator; //The absolute value of generator
  484. int exponent; //The sign of generator 1 or -1
  485. float yPos;
  486. //The current y position
  487. r=getBounds(); //The dimension of the graphics window
  488. g.setColor(Color.darkGray); //Background color
  489. g.clearRect(0,0,r.width,r.height); //Clear the drawing window
  490. g.drawRect(0,0,r.width-1,r.height-1); //Aply background color
  491. //Defintion of some strand parameter
  492. strandStep=(float)min((double)r.width/(double)(strandNumber+1),(double)r.height/((double)(braid.length())));
  493. strandWidth=strandStep/(float)5;
  494. strandLeft=((float)r.width-((float)(strandNumber+1)*(float)strandStep+strandWidth))/(float)2;
  495. yUp=(float)max((double)0,(double)((double)r.height-(double)strandStep*((double)(braid.length())))/(double)2);
  496. braid.initCurrent(); //Set current as braid.first
  497. initStrandColor(); //Init the strand color
  498. initContinuousWay(); //Init then continuous way
  499. g2.setStroke(new BasicStroke(strandWidth,BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL)); //Type of general path
  500. yPos=yUp; //Init current y position
  501. int stop=0; //stop is a flag for break the main while
  502. while(stop==0){
  503. generator=braid.value(); //Get braid value
  504. exponent=1;
  505. if(generator<0){ // \
  506. exponent=-1; // Computation of generator and exponent
  507. generator=-generator; // /
  508. }
  509. calcXPosNext();
  510. for(int strand=1;strand<strandNumber+1;strand++){
  511. if(strand==generator && exponent==1){ //If the generator is positive
  512. drawPositiveCrossing(g2,strand,yPos);
  513. strand++;
  514. }
  515. else if(strand==generator && exponent==-1){ //If the generato is negative
  516. drawNegativeCrossing(g2,strand,yPos);
  517. strand++;
  518. }
  519. else{
  520. drawNoCrossing(g2,strand,yPos);
  521. }
  522. }
  523. yPos+=strandStep; //Update yPos
  524. if(braid.isEnd()==1){ //Are we at the end of the braid ?
  525. stop=1;
  526. }
  527. else{
  528. braid.shift();
  529. }
  530. updateXPos(); //Update xPos
  531. } //Restart with the new generator
  532. for(int strand=1;strand<strandNumber+1;strand++){
  533. closeContinuousWay(g2,strand); //Close the continuous way
  534. }
  535. }
  536. // ===================
  537. //I I
  538. //I Graphics function I
  539. //I I
  540. // ===================
  541. public void paint(Graphics g){
  542. if(isDraw==0){
  543. update(g);
  544. isDraw=1;
  545. }
  546. else{
  547. g.drawImage(offScreenBuffer,0,0,this);
  548. }
  549. }
  550. public void update(Graphics g) {
  551. // -----------------------------------------------
  552. //| Graphic update function with double-buffering |
  553. // -----------------------------------------------
  554. if(braidWordSet==1){
  555. Graphics gr;
  556. if (offScreenBuffer==null||(!(offScreenBuffer.getWidth(this)==getBounds().width && offScreenBuffer.getHeight(this)==getBounds().height))){
  557. offScreenBuffer=this.createImage(getBounds().width,getBounds().height);
  558. }
  559. gr=offScreenBuffer.getGraphics();
  560. draw(gr);
  561. g.drawImage(offScreenBuffer,0,0,this);
  562. }
  563. }
  564. }