import java.applet.*; import java.awt.*; import java.lang.*; public class Surfaces extends java.applet.Applet { static int maxSides = 100 ; private int sides ; private int sequence[] = new int[maxSides]; // The arrows on the sides private int vertices[] = new int[maxSides]; // The labels for the vertices private String message ; private String description ; private String euler ; private boolean ready = true ; int labelled ; // Used in Step 4 int different ; // Used in Step 4 private Color color = new Color ( 0 , 0 , 127 ) ; private TextComponent textSequence = new TextField ( "" , 26 ) ; private TextComponent textResult = new TextField ( "" , 26 ) ; private TextComponent textDescription = new TextField ( "" , 26 ) ; private TextComponent textEuler = new TextField ( "" , 26 ) ; private Button buttonCalc = new Button ( "Calculate" ) ; private Button buttonClear = new Button ( "Clear" ) ; private Label label = new Label ( "Enter the sequence: " ) ; private Label labelr = new Label ( "Result: " ) ; private Label labeld = new Label ( "Description: " ) ; private Label labele = new Label ( "Euler characteristic: " ) ; private Checkbox show = new Checkbox ( "Show" ) ; private Panel cont = new Panel ( ) ; // Container for all private Panel pnl = new Panel ( ) ; // Input panel private Panel pnlb = new Panel ( ) ; // Buttons panel private Panel pnlr = new Panel ( ) ; // Result panel private Panel pnld = new Panel ( ) ; // Description panel private Panel pnle = new Panel ( ) ; // Euler panel public void init ( ) { // Put some initial picture sides = 4 ; sequence[0] = 1 ; sequence[1] = 2 ; sequence[2] = -1 ; sequence[3] = -2 ; vertices[0] = 1 ; vertices[1] = 1 ; vertices[2] = 1 ; vertices[3] = 1 ; message = "Torus" ; description = "Orientable surface of genus 1" ; euler = "X = 0" ; textSequence . setText ( "1, 2, -1, -2" ) ; pnl . setLayout ( new GridLayout ( 2 , 1 ) ) ; pnl . add ( label ) ; pnl . add ( textSequence ) ; pnlb . add ( buttonCalc ) ; pnlb . add ( buttonClear ) ; pnlb . add ( show ) ; pnlr . setLayout ( new GridLayout ( 2 , 1 ) ) ; pnlr . add ( labelr ) ; pnlr . add ( textResult ) ; pnld . setLayout ( new GridLayout ( 2 , 1 ) ) ; pnld . add ( labeld ) ; pnld . add ( textDescription ) ; pnle . setLayout ( new GridLayout ( 2 , 1 ) ) ; pnle . add ( labele ) ; pnle . add ( textEuler ) ; cont . setLayout ( new GridLayout ( 5 , 1 ) ) ; cont . add ( pnl ) ; cont . add ( pnlb ) ; cont . add ( pnlr ) ; cont . add ( pnld ) ; cont . add ( pnle ) ; pnl . setBackground ( color ) ; pnlb . setBackground ( color ) ; pnlr . setBackground ( color ) ; pnld . setBackground ( color ) ; pnle . setBackground ( color ) ; add ( cont ) ; label . setBackground ( color ) ; label . setForeground ( Color . yellow ) ; labelr . setBackground ( color ) ; labelr . setForeground ( Color . yellow ) ; labeld . setBackground ( color ) ; labeld . setForeground ( Color . yellow ) ; labele . setBackground ( color ) ; labele . setForeground ( Color . yellow ) ; show . setBackground ( color ) ; show . setForeground ( Color . yellow ) ; textSequence . setBackground ( Color . white ) ; textSequence . setForeground ( Color . black ) ; textResult . setBackground ( Color . white ) ; textResult . setForeground ( Color . black ) ; textResult . setEditable ( false ) ; textDescription . setBackground ( Color . white ) ; textDescription . setForeground ( Color . black ) ; textDescription . setEditable ( false ) ; textEuler . setBackground ( Color . white ) ; textEuler . setForeground ( Color . black ) ; textEuler . setEditable ( false ) ; } public boolean handleEvent(Event evt) { if (evt.target == buttonCalc && evt.id == Event.ACTION_EVENT ) { calculate ( ) ; repaint ( ) ; } if (evt.target == buttonClear && evt.id == Event.ACTION_EVENT ) textSequence . setText ( "" ) ; return false; } public void paint ( Graphics g ) { Dimension rect = new Dimension () ; int center_x , center_y ; int radius ; int sign ; int pointsX [] = new int [ 6 ]; int pointsY [] = new int [ 6 ]; rect = textResult . size () ; radius = rect . width ; rect = size () ; cont . move ( 445 - radius / 2 , 10 ) ; cont . setBackground ( color ) ; textResult . setText ( message ) ; textDescription . setText ( description ) ; textEuler . setText ( euler ) ; center_y = rect.height / 2 ; center_x = center_y ; radius = ( center_x < center_y ) ? center_x - 20 : center_y - 30 ; // Drawing the polygon section g.setColor ( color ) ; g.fillRect ( 0 , 0 , rect.height - 1 , rect.height - 1 ) ; g.setColor ( Color . lightGray ) ; pointsX [ 0 ] = 0 ; pointsY [ 0 ] = 0 ; pointsX [ 1 ] = rect.height - 1 ; pointsY [ 1 ] = 0 ; pointsX [ 2 ] = rect.height - 4 ; pointsY [ 2 ] = 3 ; pointsX [ 3 ] = 3 ; pointsY [ 3 ] = 3 ; pointsX [ 4 ] = 3 ; pointsY [ 4 ] = rect.height - 4 ; pointsX [ 5 ] = 0 ; pointsY [ 5 ] = rect.height ; g.fillPolygon ( pointsX , pointsY , 6 ) ; g.setColor ( Color . white ) ; pointsX [ 0 ] = 0 ; pointsY [ 0 ] = rect.height - 1 ; pointsX [ 1 ] = 3 ; pointsY [ 1 ] = rect.height - 4 ; pointsX [ 2 ] = rect.height - 4 ; pointsY [ 2 ] = rect.height - 4 ; pointsX [ 3 ] = rect.height - 4 ; pointsY [ 3 ] = 3 ; pointsX [ 4 ] = rect.height - 1 ; pointsY [ 4 ] = 0 ; pointsX [ 5 ] = rect.height - 1 ; pointsY [ 5 ] = rect.height - 1 ; g.fillPolygon ( pointsX , pointsY , 6 ) ; g.setColor ( Color . lightGray ) ; g.drawRect ( 0 , 0 , rect.height - 1 , rect.height - 1 ) ; g.drawLine ( rect.height - 4 , rect.height - 4 , rect.height - 1 , rect.height - 1 ) ; g.drawLine ( 0 , rect.height - 4 , rect.height - 4 , rect.height - 4 ) ; g.drawLine ( rect.height - 4 , 0 , rect.height - 4 , rect.height - 4 ) ; g.setColor ( Color . gray ) ; g.drawLine ( 0 , 0 , 3 , 3 ) ; // Drawing the poligon String current = "Torus" ; for ( int i = 0 ; i < sides ; i ++ ) { // Drawing the side of the polygon if ( ready ) { if ( sequence [ i ] == sequence [ ( i + 1 + 5 * sides ) % sides ] && i + 1 <= sides - 1 ) // Beginning of projective plane { g.setColor ( Color . red ) ; g.fillArc ( center_x + ( int ) ( radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) - 4, center_y - ( int ) ( radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) - 4, 8 , 8 , 0 , 360 ) ; current = "Plane" ; } if ( sequence [ i ] == - sequence [ ( i + 2 + 5 * sides ) % sides ] && sequence [ ( i + 1 + 5 * sides ) % sides ] == - sequence [ ( i + 3 + 5 * sides ) % sides ] && i + 3 <= sides - 1 ) // Beginning of torus { g.setColor ( Color . red ) ; g.fillArc ( center_x + ( int ) ( radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) - 4 , center_y - ( int ) ( radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) - 4 , 8, 8, 0 , 360 ) ; current = "Torus" ; } if ( current == "Torus" ) g.setColor ( Color . yellow ) ; else g.setColor ( Color . cyan ) ; g.drawLine ( center_x + ( int ) ( radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) , center_y - ( int ) ( radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) , center_x + ( int ) ( radius * Math . cos ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) , center_y - ( int ) ( radius * Math . sin ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) ; // Drawing the arrow sign = ( sequence [ i ] < 0 ) ? - 1 : 1 ; g.drawLine ( center_x + ( int ) ( ( radius * Math . cos ( Math . PI / sides ) + 5 ) * Math . cos ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_y - ( int ) ( ( radius * Math . cos ( Math . PI / sides ) + 5 ) * Math . sin ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_x + ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) , center_y - ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) ) ; g.drawLine ( center_x + ( int ) ( ( radius * Math . cos ( Math . PI / sides ) - 5 ) * Math . cos ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_y - ( int ) ( ( radius * Math . cos ( Math . PI / sides ) - 5 ) * Math . sin ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_x + ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) , center_y - ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) ) ; } else { g.setColor ( Color . yellow ) ; g.drawLine ( center_x + ( int ) ( radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) , center_y - ( int ) ( radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) , center_x + ( int ) ( radius * Math . cos ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) , center_y - ( int ) ( radius * Math . sin ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) ; // Drawing the arrow sign = ( sequence [ i ] < 0 ) ? - 1 : 1 ; g.drawLine ( center_x + ( int ) ( ( radius * Math . cos ( Math . PI / sides ) + 5 ) * Math . cos ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_y - ( int ) ( ( radius * Math . cos ( Math . PI / sides ) + 5 ) * Math . sin ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_x + ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) , center_y - ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) ) ; g.drawLine ( center_x + ( int ) ( ( radius * Math . cos ( Math . PI / sides ) - 5 ) * Math . cos ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_y - ( int ) ( ( radius * Math . cos ( Math . PI / sides ) - 5 ) * Math . sin ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) , center_x + ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . cos ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) , center_y - ( ( int ) ( ( 0.5 - sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) + ( int ) ( ( 0.5 + sign * 0.02 * sides ) * radius * Math . sin ( ( 2 * Math . PI * ( i + 1 ) ) / sides ) ) ) ) ; } // Drawing the vertex label if ( ( ! ready ) && ( vertices [ i ] != 0 ) ) { g.setColor ( Color . cyan ) ; g.setFont ( new Font ( "MSSansSerif" , Font . PLAIN , 12 ) ) ; g.drawString ( "" + vertices [ i ], center_x + ( int ) ( ( radius + 12 ) * Math . cos ( ( 2 * Math . PI * i ) / sides ) ) - g . getFontMetrics ( ) . stringWidth ( "" + vertices [ i ] ) / 2, center_y - ( int ) ( ( radius + 12 ) * Math . sin ( ( 2 * Math . PI * i ) / sides ) ) + 6 ) ; } // Drawing the letter g.setColor ( Color . red ) ; g.setFont ( new Font ( "MSSansSerif" , Font . PLAIN , 12 ) ) ; g.drawString ( "" + sequence [ i ] , center_x + ( int ) ( ( radius * Math . cos ( Math . PI / sides ) + 15 ) * Math . cos ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) - g . getFontMetrics ( ) . stringWidth ( "" + sequence [ i ] ) / 2 , center_y - ( int ) ( ( radius * Math . cos ( Math . PI / sides ) + 15 ) * Math . sin ( ( 2 * Math . PI * ( i + 0.5 ) ) / sides ) ) + 6 ) ; } // Drawing the non-polygon section g.setColor ( color ) ; g.fillRect ( rect.height , 0, rect.width - 1 , rect.height - 1 ) ; g.setColor ( Color . lightGray ) ; pointsX [ 0 ] = rect.height ; pointsY [ 0 ] = 0 ; pointsX [ 1 ] = rect.width - 1 ; pointsY [ 1 ] = 0 ; pointsX [ 2 ] = rect.width - 4 ; pointsY [ 2 ] = 3 ; pointsX [ 3 ] = 3 + rect.height ; pointsY [ 3 ] = 3 ; pointsX [ 4 ] = 3 + rect.height ; pointsY [ 4 ] = rect.height - 4 ; pointsX [ 5 ] = rect.height ; pointsY [ 5 ] = rect.height ; g.fillPolygon ( pointsX , pointsY , 6 ) ; g.setColor ( Color . white ) ; pointsX [ 0 ] = rect.height ; pointsY [ 0 ] = rect.height - 1 ; pointsX [ 1 ] = 3 + rect.height ; pointsY [ 1 ] = rect.height - 4 ; pointsX [ 2 ] = rect.width - 4 ; pointsY [ 2 ] = rect.height - 4 ; pointsX [ 3 ] = rect.width - 4 ; pointsY [ 3 ] = 3 ; pointsX [ 4 ] = rect.width - 1 ; pointsY [ 4 ] = 0 ; pointsX [ 5 ] = rect.width - 1 ; pointsY [ 5 ] = rect.height - 1 ; g.fillPolygon ( pointsX , pointsY , 6 ) ; g.setColor ( Color . lightGray ) ; g.drawRect ( rect.height , 0 , rect.width - 1 - rect.height , rect.height - 1 ) ; g.drawLine ( rect.width - 4 , rect.height - 4 , rect.width - 1 , rect.height - 1 ) ; g.drawLine ( rect.height , rect.height - 4 , rect.width - 4 , rect.height - 4 ) ; g.drawLine ( rect.width - 4 , 0 , rect.width - 4 , rect.height - 4 ) ; g.setColor ( Color . gray ) ; g.drawRect ( 0 , 0 , rect.width - 1 , rect.height - 1 ) ; g.drawLine ( rect.height , 0 , rect.height + 3 , 3 ) ; } // From here start not inherited methods private void delay ( long nn ) { long n = System . currentTimeMillis ( ) + nn ; while ( System . currentTimeMillis ( ) < n ) { } ; } private void showNow ( ) { if ( ! show . getState ( ) ) return ; paint ( getGraphics ( ) ) ; delay ( 1000 ) ; return ; } private void match ( int vertex ) // Labels all vertices that coinside with vertex [ i ] { labelled ++ ; int ourSide = vertex ; int j = 0 ; while ( ( sequence [ j ] != sequence [ ourSide ] && sequence [ j ] != - sequence [ ourSide ] ) || j == ourSide ) j ++ ; int otherVertex ; if (sequence [ ourSide ] == sequence [ j ]) otherVertex = j ; else otherVertex = j + 1 ; if ( otherVertex == sides ) otherVertex = 0 ; if ( vertices [ otherVertex ] == 0 ) { vertices [ otherVertex ] = vertices [ vertex ] ; match ( otherVertex ) ; } ourSide = vertex - 1; if ( ourSide == -1 ) ourSide = sides - 1 ; j = 0 ; while ( ( sequence [ j ] != sequence [ ourSide ] && sequence [ j ] != - sequence [ ourSide ] ) || j == ourSide ) j ++ ; if (sequence [ ourSide ] == sequence [ j ]) otherVertex = j + 1; else otherVertex = j ; if ( otherVertex == sides ) otherVertex = 0 ; if ( vertices [ otherVertex ] == 0 ) { vertices [ otherVertex ] = vertices [ vertex ] ; match ( otherVertex ) ; } } private int calcVertices ( ) { for ( int i = 0 ; i < sides ; i ++ ) if ( vertices [ i ] != 1 ) return 2 ; return 1 ; } private void step2 ( ) // Remove all sequences which are the same and replaces them with the first side { int i ; for ( int cycle = 0 ; cycle < sides ; cycle ++ ) { // The Cycle loop rotates the surface in order to // find repetitions passing through the beginning. // -------- This is NOT the best solution. If I have time I shall change it. for ( i = sides / 2 ; i >= 2 ; i -- ) { for ( int j = 0 ; j <= sides - i * 2 ; j ++ ) { boolean found = true ; for ( int k = j + i ; (k <= sides - i) && found && ( j <= sides - i * 2 ); k ++ ) { if ( sequence [ j ] == sequence [ k ] ) { boolean b = true ; for ( int l = 1 ; (l <= i - 1) && b ; l ++ ) { if ( ( sequence [ j + l ] != sequence [ k + l] ) && ( sequence [ j ] == sequence [ k ] ) ) b = false ; } if ( b ) { for ( int l = 1 ; l <= sides - k - i ; l ++ ) { sequence [ k + l] = sequence [ k + i + l - 1]; } sides -= ( i - 1 ); for ( int l = 1 ; l <= sides - j - i ; l ++ ) { sequence [ j + l] = sequence [ j + i + l - 1 ]; } sides -= ( i - 1 ); found = false ; showNow ( ) ; } } // if if ( sequence [ j ] == - sequence [ k + i - 1 ] ) { boolean b = true ; for ( int l = 1 ; (l <= i - 1) && b ; l ++ ) { if ( ( sequence [ j + l ] != ( - sequence [ k + i - 1 - l] ) ) ) b = false ; } if ( b ) { sequence [ k ] = sequence [ k + i - 1 ] ; for ( int l = 1 ; l <= sides - k - i ; l ++ ) { sequence [ k + l] = sequence [ k + i + l - 1]; } sides -= ( i - 1 ); for ( int l = 1 ; l <= sides - j - i ; l ++ ) { sequence [ j + l] = sequence [ j + i + l - 1 ]; } sides -= ( i - 1 ); found = false ; showNow ( ) ; } } // if } // k } // j } // i int mem = sequence [ 0 ] ; for ( int l = 0 ; l <= ( sides - 2 ) ; l ++ ) sequence [ l ] = sequence [ l + 1 ] ; sequence [ sides - 1 ] = mem ; } // Cycle return ; } private boolean step3 ( ) // Removing consequent opposing pairs { int i ; // Check if we have to finish at this point. if ( ( sides == 2 ) && ( sequence [ 0 ] == - sequence [ 1 ] ) ) { message = "S" ; description = "Orientable surface of genus 0" ; euler = "X = 2" ; return true ; } if ( ( sides == 2 ) && ( sequence [ 0 ] == sequence [ 1 ] ) ) { message = "P" ; description = "Non-orientable surface of genus 1" ; euler = "X = 1" ; return true ; } boolean b = true ; while ( b ) { b = false ; for ( i = 0 ; i <= sides - 2 ; i ++ ) { if ( sequence [ i ] == ( - sequence [ i + 1 ] ) ) { for ( int l = 0 ; l <= sides - 3 - i ; l ++ ) { sequence [ i + l ] = sequence [ i + l + 2 ]; } sides -= 2 ; b = true ; showNow ( ) ; } } // Check if we have to finish at this point. if ( ( sides == 2 ) && ( sequence [ 0 ] == - sequence [ 1 ] ) ) { message = "S" ; description = "Orientable surface of genus 0" ; euler = "X = 2" ; return true ; } if ( ( sides == 2 ) && ( sequence [ 0 ] == sequence [ 1 ] ) ) { message = "P" ; description = "Non-orientable surface of genus 1" ; euler = "X = 1" ; return true ; } if ( sequence [ 0 ] == ( - sequence [ sides - 1 ] ) ) { for ( int l = 0 ; l <= sides - 3 ; l ++ ) { sequence [ l ] = sequence [ l + 1]; } sides -= 2 ; b = true ; showNow ( ) ; } // Check if we have to finish at this point. if ( ( sides == 2 ) && ( sequence [ 0 ] == - sequence [ 1 ] ) ) { message = "S" ; description = "Orientable surface of genus 0" ; euler = "X = 2" ; return true ; } if ( ( sides == 2 ) && ( sequence [ 0 ] == sequence [ 1 ] ) ) { message = "P" ; description = "Non-orientable surface of genus 1" ; euler = "X = 1" ; return true ; } } return false ; } private void labelVertices ( ) { for ( int i = 0 ; i < sides ; i ++ ) vertices [ i ] = 0 ; labelled = 0 ; different = 0 ; // Label the vertices while ( labelled < sides ) { int i = 0 ; while ( vertices [ i ] != 0 ) i ++ ; different ++ ; vertices [ i ] = different ; // Label the next vertex match ( i ) ; // Label all vertices that must have the same label } } private boolean step4 ( ) // Changing the polygon so that there is only one vertex { int i ; labelVertices ( ) ; // Eliminate all vertices but '1' while ( calcVertices ( ) > 1 ) { int firstP , firstQ , firstR , secondP , secondQ , secondR , thirdQ; // Maybe these variables are not very clear - sorry. // I am just looking at a picture with vertices P, Q & R. // The following code is a complete mess - again sorry. // I hope it's working pretty good. firstP = 0 ; while ( vertices [ firstP ] != 1 && firstP < sides ) firstP ++ ; if ( firstP == sides ) return false ; if ( firstP != 0 ) firstQ = firstP - 1 ; else { firstQ = firstP + 1; while ( vertices [ firstQ % sides ] == 1 ) { firstP ++ ; firstQ ++ ; } } int a_1 = firstP < firstQ ? firstP : firstQ ; // This is the side int j = 0 ; while ( ( sequence [ j ] != sequence [ a_1 % sides ] && sequence [ j ] != - sequence [ a_1 % sides ] ) || j == a_1 % sides ) j ++ ; if ( sequence [ j ] == sequence [ a_1 % sides ] ) { secondP = firstP < firstQ ? j : j + 1 ; secondQ = firstP < firstQ ? j + 1 : j ; } else { secondP = firstP < firstQ ? j + 1 : j ; secondQ = firstP < firstQ ? j : j + 1 ; } int a_2 = j ; int b_1 ; if ( secondQ > secondP ) { b_1 = secondQ ; firstR = secondQ + 1 ; if ( firstR == sides ) firstR = 0 ; } else { b_1 = secondQ - 1; firstR = secondQ - 1 ; if ( firstR == -1 ) firstR = sides - 1 ; } j = 0; while ( ( sequence [ j ] != sequence [ b_1 % sides ] && sequence [ j ] != - sequence [ b_1 % sides ] ) || j == b_1 % sides ) j ++ ; if ( sequence [ j % sides ] == sequence [ b_1 % sides ] ) { secondR = ( firstR < secondQ ) ? j : j + 1 ; thirdQ = firstR < secondQ ? j + 1 : j ; } else { secondR = firstR > secondQ ? j : j + 1 ; thirdQ = firstR > secondQ ? j + 1 : j ; } int b_2 = j ; // Now performing the actual cut-and-pasting. int tempSequence [] = new int [ sides ] ; int tempVertices [] = new int [ sides ] ; int tIndex = 0 ; for ( i = 0 ; i < sides ; i ++ ) { if ( i != a_2 % sides && i != b_1 % sides && i != b_2 % sides ) { tempSequence [ tIndex ] = sequence [ i ] ; tIndex ++ ; } if ( i == a_2 % sides || i == b_1 % sides ) { tempSequence [ tIndex ] = sequence [ b_1 % sides ] ; tIndex ++ ; i ++ ; } if ( i == b_2 % sides ) { if ( a_2 < b_1 && sequence [ b_1 % sides ] == - sequence [ b_2 % sides ] ) { tempSequence [ tIndex ] = sequence [ b_2 % sides ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ a_2 % sides ] ; tIndex ++ ; } if ( a_2 < b_1 && sequence [ b_1 % sides ] == sequence [ b_2 % sides ] ) { tempSequence [ tIndex ] = - sequence [ a_2 % sides ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ b_2 % sides ] ; tIndex ++ ; } if ( a_2 > b_1 && sequence [ b_1 % sides ] == sequence [ b_2 % sides ] ) { tempSequence [ tIndex ] = sequence [ b_2 % sides ] ; tIndex ++ ; tempSequence [ tIndex ] = - sequence [ a_2 % sides ] ; tIndex ++ ; } if ( a_2 > b_1 && sequence [ b_1 % sides ] == - sequence [ b_2 % sides ] ) { tempSequence [ tIndex ] = sequence [ a_2 % sides ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ b_2 % sides ] ; tIndex ++ ; } } } tIndex = 0 ; for ( i = 0 ; i < sides ; i ++ ) { if ( i != a_2 % sides && i != b_1 % sides && i != b_2 % sides ) { tempVertices [ tIndex ] = vertices [ i ] ; tIndex ++ ; } if ( i == a_2 % sides && b_1 > a_2 ) { tempVertices [ tIndex ] = vertices [ i ] ; tIndex ++ ; } if ( i == b_1 % sides && b_1 < a_2 ) { tempVertices [ tIndex ] = vertices [ i ] ; tIndex ++ ; } if ( i == b_2 % sides ) { tempVertices [ tIndex ] = vertices [ i ] ; tIndex ++ ; tempVertices [ tIndex ] = vertices [ a_1 % sides ] ; tIndex ++ ; } } for ( i = 0 ; i < sides ; i ++ ) { vertices [ i ] = tempVertices [ i ] ; sequence [ i ] = tempSequence [ i ] ; } // Just to make sure if we're not finished step2 ( ) ; if ( step3 ( ) ) { labelVertices ( ) ; return true ; } labelVertices ( ) ; showNow ( ) ; } return false ; } private int twistedPair ( ) { for ( int i = 0 ; i < sides ; i ++ ) { for ( int j = 0 ; j < sides ; j ++ ) { if ( sequence [ j ] == sequence [ i ] && i != j && ( Math . abs ( i - j ) + 5 * sides ) % sides > 1 ) return i * sides + j ; } // j } // i return -1 ; } private boolean step5 ( ) // Collecting twisted pairs together { int i = twistedPair ( ) ; while ( i != -1 ) { int a_1 = i / sides ; int a_2 = i % sides ; // Now performing the actual cut-and-pasting. int tempSequence [] = new int [ sides ] ; int tIndex = 0 ; for ( i = 0 ; i < sides ; i ++ ) { if ( i < a_1 || i > a_2 ) { tempSequence [ tIndex ] = sequence [ i ] ; tIndex ++ ; } if ( i == a_1 ) { for ( int j = a_2 - 1 ; j > a_1 ; j -- ) { tempSequence [ tIndex ] = - sequence [ j ] ; tIndex ++ ; } // j tempSequence [ tIndex ] = sequence [ a_1 ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ a_1 ] ; tIndex ++ ; i = a_2 ; } // if i == a_1 } for ( i = 0 ; i < sides ; i ++ ) { sequence [ i ] = tempSequence [ i ] ; } showNow ( ) ; step2 ( ) ; if ( step3 ( ) ) { return true ; } i = twistedPair ( ) ; } return false ; } private int opposingPair ( ) { int i = 0 ; int firstP = -1 ; int secondP = -1 ; int firstD = 0 ; int secondD = 0 ; while ( i < sides - 3 ) { firstP = -1 ; secondP = -1 ; firstD = 0 ; secondD = 0 ; while ( i < sides && firstP == -1 ) { int j = i + 1 ; while ( j < sides && firstP == -1 ) { if ( sequence [ j ] == - sequence [ i ] ) { firstP = i * sides + j ; if ( i > j ) firstD = ( i - j + 5 * sides ) % sides ; else firstD = ( j - i + 5 * sides ) % sides ; } j ++ ; } // j i ++ ; } // i if ( firstP == -1 ) return -1 ; i = firstP / sides + 1 ; while ( i < sides && secondP == -1 ) { int j = i + 1 ; while ( j < sides && secondP == -1 ) { if ( sequence [ j ] == - sequence [ i ] ) { secondP = i * sides + j ; if ( i > j ) secondD = ( i - j + 5 * sides ) % sides ; else secondD = ( j - i + 5 * sides ) % sides ; } j ++ ; } // j i ++ ; } // i if ( secondP == -1 ) return -2 ; if ( firstD == 2 && secondD == 2 && firstP >= sides - 4 ) return -1 ; if ( firstD != 2 || secondD != 2 ) return firstP * sides * sides + secondP ; i = firstP ; } return -1 ; } private boolean step6 ( ) // Collecting opposing pairs together { int i = opposingPair ( ) ; if ( i == -2 ) { message = "Sorry, there seems to be somthing wrong with opposing pairs." ; return true ; } while ( i != -1 ) { int a_1 = i / ( sides * sides * sides ) ; int a_2 = ( i / ( sides * sides ) ) % sides ; int b_1 = ( i / sides ) % ( sides ) ; int b_2 = i % ( sides ) ; // Now performing the actual cut-and-pasting. int tempSequence [] = new int [ sides ] ; int tIndex = 0 ; for ( i = 0 ; i < sides ; i ++ ) { if ( i < a_1 ) { tempSequence [ tIndex ] = sequence [ i ] ; tIndex ++ ; } if ( i == a_1 ) { for ( int j = a_2 + 1 ; j < b_2 ; j ++ ) { tempSequence [ tIndex ] = sequence [ j ] ; tIndex ++ ; } // j for ( int j = b_1 + 1 ; j < a_2 ; j ++ ) { tempSequence [ tIndex ] = sequence [ j ] ; tIndex ++ ; } // j tempSequence [ tIndex ] = sequence [ a_1 ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ b_1 ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ a_2 ] ; tIndex ++ ; tempSequence [ tIndex ] = sequence [ b_2 ] ; tIndex ++ ; for ( int j = a_1 + 1 ; j < b_1 ; j ++ ) { tempSequence [ tIndex ] = sequence [ j ] ; tIndex ++ ; } // j for ( int j = b_2 + 1 ; j < sides ; j ++ ) { tempSequence [ tIndex ] = sequence [ j ] ; tIndex ++ ; } // j i = sides - 1 ; } // if i == a_1 } for ( i = 0 ; i < sides ; i ++ ) { sequence [ i ] = tempSequence [ i ] ; } showNow ( ) ; step2 ( ) ; if ( step3 ( ) ) { return true ; } i = opposingPair ( ) ; if ( i == -2 ) { message = "Sorry, there seems to be somthing wrong with opposing pairs." ; return true ; } } return false ; } private void step7 ( ) // Generate the message for the result // and replacing T#P with P#P#P { // The following code rotates the polygon if there is a // projective plane or torus via the beginning // Projective plane : if ( sequence [ 0 ] == sequence [ sides - 1 ] ) { int s = sequence [ 0 ] ; for ( int i = 0 ; i < sides - 1 ; i ++ ) sequence [ i ] = sequence [ i + 1 ] ; sequence [ sides - 1 ] = s ; showNow ( ) ; } // End of projective plane // Torus if ( sides > 2 ) { if ( sequence [ 1 ] == - sequence [ sides - 1 ] ) if ( sequence [ 0 ] == - sequence [ sides - 2 ] ) { int s = sequence [ 0 ] ; for ( int i = 0 ; i < sides - 1 ; i ++ ) sequence [ i ] = sequence [ i + 1 ] ; sequence [ sides - 1 ] = s ; s = sequence [ 0 ] ; for ( int i = 0 ; i < sides - 1 ; i ++ ) sequence [ i ] = sequence [ i + 1 ] ; sequence [ sides - 1 ] = s ; showNow ( ) ; } if ( sequence [ 1 ] == - sequence [ sides - 1 ] ) if ( sequence [ 0 ] == - sequence [ 2 ] ) { int s = sequence [ sides - 1 ] ; for ( int i = sides - 1 ; i > 0 ; i -- ) sequence [ i ] = sequence [ i - 1 ] ; sequence [ 0 ] = s ; showNow ( ) ; } if ( sequence [ 0 ] == - sequence [ sides - 2 ] ) if ( sequence [ sides - 1 ] == - sequence [ sides - 3 ] ) { int s = sequence [ 0 ] ; for ( int i = 0 ; i < sides - 1 ; i ++ ) sequence [ i ] = sequence [ i + 1 ] ; sequence [ sides - 1 ] = s ; showNow ( ) ; } } // if ( sides > 2 ) // End of torus // Preorienting arrows for more 'neaty' look of the picture for ( int i = 0 ; i < sides ; i ++ ) { if ( sequence [ i ] == sequence [ i + 1 ] && sequence [ i ] < 0 ) { sequence [ i ] = - sequence [ i ] ; sequence [ i + 1 ] = - sequence [ i + 1 ] ; i ++ ; } if ( sequence [ i ] == - sequence [ i + 2 ] && sequence [ i ] < 0 ) { sequence [ i ] = - sequence [ i ] ; sequence [ i + 2 ] = - sequence [ i + 2 ] ; if ( sequence [ i + 1 ] == - sequence [ i + 3 ] && sequence [ i + 1 ] < 0 ) { sequence [ i + 1 ] = - sequence [ i + 1 ] ; sequence [ i + 3 ] = - sequence [ i + 3 ] ; } i += 3 ; } } // Replacing the torus if needed // Checking if there are projective planes boolean found = false ; int i = 0 ; while ( i < sides - 1 ) { if ( sequence [ i ] == sequence [ i + 1 ] ) found = true ; i ++ ; } if ( found ) { for ( i = 0 ; i < sides - 3 ; i ++ ) { if ( sequence [ i ] == - sequence [ i + 2 ] ) { sequence [ i + 3 ] = ( sequence [ i + 2 ] = sequence [ i + 1 ] ) ; sequence [ i + 1 ] = sequence [ i ] ; i += 3 ; showNow ( ) ; } } } // Generating the messages message = "" ; int tor = 0 , proj = 0 ; for ( i = 0 ; i < sides ; i ++ ) { if ( i < sides - 1 ) if ( sequence [ i ] == sequence [ i + 1 ] ) { message += "P" ; proj ++ ; i ++ ; if ( i < sides - 1 ) message += "#" ; } if ( i < sides - 3 ) if ( sequence [ i ] == - sequence [ i + 2 ] ) { message += "T" ; tor ++ ; i += 3 ; if ( i < sides - 1 ) message += "#" ; } } if ( tor > 0 ) { description = "Orientable surface of genus " + tor ; euler = "X = " + 2 * ( 1 - tor ) ; } if ( proj > 0 ) { description = "Non-orientable surface of genus " + proj ; euler = "X = " + ( 1 - proj ) ; } } private void calculate ( ) { String expr ; int i ; message = "Processing ... " ; ready = false ; paint ( getGraphics ( ) ) ; expr = textSequence . getText ( ) ; for ( i = 0 ; i < sides ; i ++ ) vertices [ i ] = 0 ; // Removing intervals while ( expr . indexOf ( " " ) != -1 ) try { expr = expr . substring ( 0 , expr . indexOf ( " " ) ) + expr . substring ( expr . indexOf ( " " ) + 1 , expr . length ( ) ) ; } finally { } // Taking the string into array int k_b = 0 ; int k_e = expr . indexOf ( "," , k_b ) ; if ( k_e == -1 ) k_e = expr . length ( ) ; sides = 0 ; while ( k_e > k_b ) { Integer v ; try { v = new Integer ( expr . substring ( k_b , k_e ) ) ; } catch ( NumberFormatException e ) { message = "Wrong number." ; description = "Not a correct surface." ; euler = "" ; return ; } sequence [ sides ] = v . intValue ( ) ; if (++sides >= maxSides) { message = "Too many sides." ; description = "Too big surface." ; euler = "" ; return ; } k_b = k_e + 1 ; k_e = expr . indexOf ( "," , k_b ) ; if ( k_e == -1 ) k_e = expr . length ( ) ; } // Check if there are sides if (sides == 0) { message = "Nothing entered." ; description = "Not a surface." ; euler = "" ; sides = 2 ; return ; } // Check if sides are even if (sides % 2 != 0) { message = "Odd number of sides." ; description = "Not a closed surface." ; euler = "" ; return ; } // Checking for pairwise correctness for ( i = 0 ; i < sides ; i ++ ) { int n = 0 ; for ( int j = 0 ; j < sides ; j ++ ) { if ( ( j != i ) && ( ( sequence [ i ] == sequence [ j ] ) || ( sequence [ i ] == - sequence [ j ] ) ) ) n ++ ; } if (n != 1) { message = "Sides do not match pairwise." ; description = "Not a closed surface." ; euler = "" ; return ; } } labelVertices ( ) ; showNow ( ) ; step2 ( ) ; if ( ready = step3 ( ) ) return ; if ( ready = step4 ( ) ) return ; if ( ready = step5 ( ) ) return ; if ( ready = step6 ( ) ) return ; step7 ( ) ; ready = true ; return ; } }