diff --git a/src/main/java/com/ugsbo/gui/BasicGuiController.java b/src/main/java/com/ugsbo/gui/BasicGuiController.java index 3d2a48e..a34ee08 100644 --- a/src/main/java/com/ugsbo/gui/BasicGuiController.java +++ b/src/main/java/com/ugsbo/gui/BasicGuiController.java @@ -5,9 +5,9 @@ import javafx.scene.control.*; public class BasicGuiController { - //Hier werden die fx:id Attribute verknuepft. + // Hier werden die fx:id Attribute verknuepft. @FXML - private Button app1; //Fuer ToDoManager. + private Button matrixCalc; @FXML private Button app2; //Fuer VokabelKartenSchreiber @FXML @@ -19,7 +19,7 @@ public class BasicGuiController { * Konstructor is called before initialize() */ public BasicGuiController() { - //Setup of some Fields could be defined here. + // Setup of some Fields could be defined here. } /** @@ -28,9 +28,9 @@ public class BasicGuiController { */ @FXML public void initialize() { - app1.setOnMouseClicked((event) -> { - //MainApp.startToDoMainGui(); - System.out.println(event); + matrixCalc.setOnMouseClicked((event) -> { + MainApp.startMatrixCalcGUI(); + // System.out.println(event); }); app2.setOnMouseClicked((event) -> { //System.out.println(event); diff --git a/src/main/java/com/ugsbo/gui/MainApp.java b/src/main/java/com/ugsbo/gui/MainApp.java index f7282e6..04c0635 100644 --- a/src/main/java/com/ugsbo/gui/MainApp.java +++ b/src/main/java/com/ugsbo/gui/MainApp.java @@ -35,7 +35,7 @@ public class MainApp extends Application { /** * Loades the FXML file and the Default CSS. * - * @param stage The Stage will be passed over from fxml + * @param stage The Stage will be passed over from JavaFx * @param fxmlFileName Only the Filename of the fxml file wich sould be loaded */ private void createStageFromFXML(Stage stage, String fxmlFileName) { @@ -64,4 +64,14 @@ public class MainApp extends Application { MainApp main = new MainApp(); main.createStageFromFXML(stage, "Voabelkartenschreiber"); } + + /** + * Startet eine Instanz der MatrixCalcGui. + */ + public static void startMatrixCalcGUI() { + Stage stage = new Stage(); + MainApp app = new MainApp(); + app.createStageFromFXML(stage, "matrixCalcGui"); + } + } diff --git a/src/main/java/com/ugsbo/matrixcalc/MatrixCalcController.java b/src/main/java/com/ugsbo/matrixcalc/MatrixCalcController.java new file mode 100644 index 0000000..f857eb0 --- /dev/null +++ b/src/main/java/com/ugsbo/matrixcalc/MatrixCalcController.java @@ -0,0 +1,273 @@ +package com.ugsbo.matrixcalc; + +import javafx.fxml.FXML; +import javafx.scene.control.*; +import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; + +import java.util.ArrayList; + +public class MatrixCalcController { + + private static final String MULTIPLICATION_STRING = "multiplication"; + private static final String ADDITION_STRING = "addition"; + private static final String SUBSTRACTION_STRING = "substract"; + private static final String TRANPOSE_STRING = "transpose"; + private static final String CALCDETERMINAT_STRING = "calcDeterminate"; + + // The fx:id Attributes will be bind here. + @FXML + private Button multiplyButton, addButton, DetAButton, DetBButton, substractButton, transposeButton; + @FXML + private Text errorText, outputText; + @FXML + private TextArea matrixATextArea, matrixBTextArea; + + private MatrixCalcMath math = new MatrixCalcMath(); + private MatrixCalcIOUtils util = new MatrixCalcIOUtils(); + + /** + * Konstructor is called before initialize() + */ + public MatrixCalcController() { + // Setup of some Fields could be defined here. + } + + /** + * Initializes the controller class. This method is automatically called after + * the fxml file has been loaded. + */ + @FXML + public void initialize() { + /** + * Convert Strings to matricies, multiply them and output the result. + */ + multiplyButton.setOnMouseClicked((event) -> { + String stringMatrixA = matrixATextArea.getText(); + String stringMatrixB = matrixBTextArea.getText(); + String[] stringMatrix = { stringMatrixA, stringMatrixB }; + + checkInputAndDisplayIfInputIsNotValid(stringMatrix, 2); + + ArrayList matricies = new ArrayList(); + matricies.add(util.stringToMatrix(stringMatrixA)); + matricies.add(util.stringToMatrix(stringMatrixB)); + + invokeOperation(matricies, MULTIPLICATION_STRING); + }); + + /** + * Convert a String to a matrix, transpose it and output the result. + */ + transposeButton.setOnMouseClicked((event) -> { + String stringMatrixA = matrixATextArea.getText(); + String[] stringMatrix = { stringMatrixA, "" }; + + checkInputAndDisplayIfInputIsNotValid(stringMatrix, 1); + + ArrayList matricies = new ArrayList(); + matricies.add(util.stringToMatrix(stringMatrixA)); + + invokeOperation(matricies, TRANPOSE_STRING); + }); + + /** + * Convert Strings to matricies, add them and output the result. + */ + addButton.setOnMouseClicked((event) -> { + String stringMatrixA = matrixATextArea.getText(); + String stringMatrixB = matrixBTextArea.getText(); + String[] stringMatrix = { stringMatrixA, stringMatrixB }; + + checkInputAndDisplayIfInputIsNotValid(stringMatrix, 2); + + ArrayList matricies = new ArrayList(); + matricies.add(util.stringToMatrix(stringMatrixA)); + matricies.add(util.stringToMatrix(stringMatrixB)); + + invokeOperation(matricies, ADDITION_STRING); + }); + + /** + * Convert Strings to matricies, substract them and output the result. + */ + substractButton.setOnMouseClicked((event) -> { + String stringMatrixA = matrixATextArea.getText(); + String stringMatrixB = matrixBTextArea.getText(); + String[] stringMatrix = { stringMatrixA, stringMatrixB }; + + checkInputAndDisplayIfInputIsNotValid(stringMatrix, 2); + + ArrayList matricies = new ArrayList(); + matricies.add(util.stringToMatrix(stringMatrixA)); + matricies.add(util.stringToMatrix(stringMatrixB)); + + invokeOperation(matricies, SUBSTRACTION_STRING); + }); + + /** + * Convert the String of the left inputField to a matrix, calculate the Determinate and output it. + */ + DetAButton.setOnMouseClicked((event) -> { + String stringMatrixA = matrixATextArea.getText(); + String[] stringMatrix = { stringMatrixA, "" }; + + checkInputAndDisplayIfInputIsNotValid(stringMatrix, 1); + + ArrayList matricies = new ArrayList(); + matricies.add(util.stringToMatrix(stringMatrixA)); + + invokeOperation(matricies, CALCDETERMINAT_STRING); + }); + + /** + * Convert the String of the right inputField to a matrix, calculate the Determinate and output it. + */ + DetBButton.setOnMouseClicked((event) -> { + String stringMatrixB = matrixBTextArea.getText(); + String[] stringMatrix = { "", stringMatrixB }; + + checkInputAndDisplayIfInputIsNotValid(stringMatrix, 1); + + ArrayList matricies = new ArrayList(); + matricies.add(util.stringToMatrix(stringMatrixB)); + + invokeOperation(matricies, CALCDETERMINAT_STRING); + }); + } + + /** + * Invokes the needed operations form the MatrixCalcMath class + * @param matricies Contains both Matricies or onely one Matrix + * @param operation One of the global Constats to select wich Operation is needed. + */ + private void invokeOperation(ArrayList matricies, String operation) { + if (matricies.size() == 2) { + if (operation.equals(MULTIPLICATION_STRING)) { + try { + double[][] result = math.matrixMultiplication(matricies.get(0), matricies.get(1)); + + String DisplayableString = util.outputMatrixToOutputText(result); + + outputText.setText(DisplayableString); + outputText.setTextAlignment(TextAlignment.CENTER); + } catch (IllegalArgumentException e) { + + outputText.setText(e.getMessage()); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } else if (operation.equals(ADDITION_STRING)) { + try { + double[][] result = math.matrixAddition(matricies.get(0), matricies.get(1)); + + String DisplayableString = util.outputMatrixToOutputText(result); + + outputText.setText(DisplayableString); + outputText.setTextAlignment(TextAlignment.CENTER); + } catch (IllegalArgumentException e) { + + outputText.setText(e.getMessage()); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } else if (operation.equals(SUBSTRACTION_STRING)) { + try { + double[][] result = math.matrixSubstraction(matricies.get(0), matricies.get(1)); + + String DisplayableString = util.outputMatrixToOutputText(result); + + outputText.setText(DisplayableString); + outputText.setTextAlignment(TextAlignment.CENTER); + } catch (IllegalArgumentException e) { + + outputText.setText(e.getMessage()); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } + }else if (matricies.size() == 1) { + if (operation.equals(TRANPOSE_STRING)) { + try { + double[][] result = math.matrixTransponation(matricies.get(0)); + + String DisplayableString = util.outputMatrixToOutputText(result); + + outputText.setText(DisplayableString); + outputText.setTextAlignment(TextAlignment.CENTER); + } catch (IllegalArgumentException e) { + + outputText.setText(e.getMessage()); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } + if (operation.equals(CALCDETERMINAT_STRING)) { + try { + double result = math.calcDeterminat(matricies.get(0)); + + String DisplayableString = Double.toString(result); + + outputText.setText(DisplayableString); + outputText.setTextAlignment(TextAlignment.CENTER); + } catch (IllegalArgumentException e) { + + outputText.setText(e.getMessage()); + outputText.setTextAlignment(TextAlignment.CENTER); + } catch (Exception e){ + + outputText.setText(e.getMessage()); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } + } + } + + /** + * Checks the Input and Displays it if the Input is valid. + * + * @param stringMatrix Contains both input matrices if + * numberOfMarriciesToMatch is 2. If the number + * is 1 than one of them has to be a empty String + * @param numberOfMatricesToMatch If the number is 1 onely one Marix will be + * verifyed and the other one needs to be an empty + * String in the stringMatrix + */ + private void checkInputAndDisplayIfInputIsNotValid(String[] stringMatrix, int numberOfMatricesToMatch) { + if (numberOfMatricesToMatch == 1 && !stringMatrix[0].equals("")) { + try { + util.checkInput(stringMatrix[0]); + } catch (Exception e) { + outputText.setText(e.getMessage() + "A"); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } else if (numberOfMatricesToMatch == 1 && !stringMatrix[1].equals("")) { + try { + util.checkInput(stringMatrix[1]); + } catch (Exception e) { + outputText.setText(e.getMessage() + "B"); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } else if (numberOfMatricesToMatch == 2 && !stringMatrix[0].equals("") && !stringMatrix[1].equals("")) { + try { + util.checkInput(stringMatrix[0]); + } catch (Exception e) { + outputText.setText(e.getMessage() + "A"); + outputText.setTextAlignment(TextAlignment.CENTER); + } + + try { + util.checkInput(stringMatrix[1]); + } catch (Exception e) { + outputText.setText(e.getMessage() + "B"); + outputText.setTextAlignment(TextAlignment.CENTER); + } + } else if (stringMatrix[0].equals("")) { + + outputText.setText("Pease insert MatrixA"); + outputText.setTextAlignment(TextAlignment.CENTER); + + } else if (stringMatrix[1].equals("")) { + + outputText.setText("Pease insert MatrixB"); + outputText.setTextAlignment(TextAlignment.CENTER); + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/ugsbo/matrixcalc/MatrixCalcIOUtils.java b/src/main/java/com/ugsbo/matrixcalc/MatrixCalcIOUtils.java new file mode 100644 index 0000000..e929081 --- /dev/null +++ b/src/main/java/com/ugsbo/matrixcalc/MatrixCalcIOUtils.java @@ -0,0 +1,97 @@ +package com.ugsbo.matrixcalc; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MatrixCalcIOUtils { + /** + * Prints a given 2D-Array to the output Textfield. + * + * @param output2DArray The Array that gets Displayed + */ + protected String outputMatrixToOutputText(double[][] output2DArray) { + // convert array to String + String DisplayableString = convertsArrayToStringInOrderToDisplayIt(output2DArray); + // Display output + return DisplayableString; + } + + /** + * Converts 2D-Array to String in order to Display it. + * + * @param array2D The array wich will be converted to an Displayable String + * @return The Displayable String + */ + protected String convertsArrayToStringInOrderToDisplayIt(double[][] array2D) { + String displayableString = ""; + for (int i = 0; i < array2D.length; i++) { + for (int j = 0; j < array2D[0].length; j++) { + displayableString += array2D[i][j] + " "; + } + displayableString += "\n\n"; + } + return displayableString; + } + + /** + * Checks if the Input is Valid, with Regex. Returns true if the Matrix can be + * matched by the regular Expression. + * + * @param matrix It is the InputMatrix + * @return True if the Matrix is valid Input. + */ + protected void checkInput(String matrix) throws IllegalArgumentException { + if (matrix.length() == 0) { + throw new IllegalArgumentException("Please insert a Matrix"); + } + + // Matches digits witch following spaces 1 to 3 times + String row1 = "(\\d*\\u0020*){1,3}"; + // Matches newlineCurrierReturn followed by digits witch following spaces 1 to + // 3 times + String row2 = "(\\n){0,3}(\\d*\\u0020*){0,3}"; + String row3 = "(\\n){0,3}(\\d*\\u0020*){0,3}"; + + // TODO for verion 2 get the input check more stricktly missing matrix slots are allowed. + + Pattern p = Pattern.compile(row1 + row2 + row3); + Matcher m = p.matcher(matrix); + + if(!m.matches()){ + throw new IllegalArgumentException("A Matrix is not in the right format, Matrix "); + } + } + + /** + * Converts a String form the Inputfield to an 2D-Array aka Matrix. + * + * @param stringMatrix The String form the Inputfield + * @return Matrix as a 2D-Array + */ + public double[][] stringToMatrix(String stringMatrix) { + + ArrayList singleNumbersArr = new ArrayList(); + + // Splitting the strings into their rows + String[] singleNumbers = null; + String[] rows = stringMatrix.split("\n"); + for (int i = 0; i < rows.length; i++) { + // Splitting rows into their Numbers + singleNumbers = rows[i].split("\\s"); + singleNumbersArr.add(singleNumbers); + } + + int rowlength = singleNumbersArr.get(0).length; + int columCount = singleNumbersArr.size(); + double[][] matrix = new double[columCount][rowlength]; + + for (int columIndex = 0; columIndex < columCount; columIndex++) { + for (int rowIndex = 0; rowIndex < singleNumbers.length; rowIndex++) { + matrix[columIndex][rowIndex] = Double.parseDouble(singleNumbersArr.get(columIndex)[rowIndex]); + } + } + return matrix; + } + +} \ No newline at end of file diff --git a/src/main/java/com/ugsbo/matrixcalc/MatrixCalcMath.java b/src/main/java/com/ugsbo/matrixcalc/MatrixCalcMath.java new file mode 100644 index 0000000..5cd807b --- /dev/null +++ b/src/main/java/com/ugsbo/matrixcalc/MatrixCalcMath.java @@ -0,0 +1,228 @@ +package com.ugsbo.matrixcalc; + +/** + * Contains all basic matrix math calculations. + */ +public class MatrixCalcMath { + + /** + * Mutliplys matrixA and matrixB. + * + * @param matrixA The Inputmatrix A (right TextArea in the GUI) + * @param matrixB The Inputmatrix B (left TextArea in the GUI) + * @return The Matrixproduct of the matricies A and B + */ + public double[][] matrixMultiplication(double[][] matrixA, double[][] matrixB) { + if (checkIfMatriciesAreLinked(matrixA, matrixB)) { + int rowOfResultMatrix = matrixA.length; + int columOfResultMatrix = matrixB[0].length; + int ColumsOfMatA = matrixA[0].length; + double[][] result = new double[rowOfResultMatrix][columOfResultMatrix]; + + for (int rowResult = 0; rowResult < rowOfResultMatrix; rowResult++) { + for (int columResult = 0; columResult < columOfResultMatrix; columResult++) { + for (int columOfA = 0; columOfA < ColumsOfMatA; columOfA++) { + result[rowResult][columResult] += matrixA[rowResult][columOfA] * matrixB[columOfA][columResult]; + } + } + } + return result; + } else { + throw new IllegalArgumentException("Matricies must be linked"); + } + } + + /** + * checks if matrixA and matrixB are linked to know if it is possible to + * multiply them. If they are linked it is possible. + * + * @param matrixA The Inputmatrix A (right TextArea in the GUI) + * @param matrixB The Inputmatrix B (left TextArea in the GUI) + * @return true if you can Muliply A with B false if not. + */ + public boolean checkIfMatriciesAreLinked(double[][] matrixA, double[][] matrixB) { + if (matrixA == null) { + return false; + } + if (matrixA.length == 0) { + return false; + } + if (matrixA[0].length == matrixB.length) { + return true; + } + return false; + } + + /** + * Adds two matroices A and B. Adding matrix A to matrix B is the same as adding + * B to A. + * + * @param matrixA The Inputmatrix A (right TextArea in the GUI) + * @param matrixB The Inputmatrix B (left TextArea in the GUI) + * @return The Matrixsum of matrix A and matrix B + */ + public double[][] matrixAddition(double[][] matrixA, double[][] matrixB) { + if (checkIfMatriciesAreTheSameDimension(matrixA, matrixB)) { + double[][] result = new double[matrixA.length][matrixA[0].length]; + for (int rows = 0; rows < matrixA.length; rows++) { + for (int colums = 0; colums < matrixA[0].length; colums++) { + result[rows][colums] = matrixA[rows][colums] + matrixB[rows][colums]; + } + } + return result; + } else { + throw new IllegalArgumentException("Matricies need to have the same Dimensions"); + } + } + + /** + * In order to adding two Matricies they must have the same Dimensions. This + * Methode checks if this is the case. + * + * @param matrixA The Inputmatrix A (right TextArea in the GUI) + * @param matrixB The Inputmatrix B (left TextArea in the GUI) + * @return true if the Dimensions of Matrix A equals the Dimensions Matrix B + */ + public boolean checkIfMatriciesAreTheSameDimension(double[][] matrixA, double[][] matrixB) { + if (matrixA == null || matrixA.length == 0) { + return false; + } + if (matrixA[0] == null) { + return false; + } + if (matrixA.length == matrixB.length && matrixA[0].length == matrixB[0].length) { + return true; + } else { + return false; + } + + } + + /** + * Substracts matrix A by the matrix B. Substaction for Matrices is just the + * substraction of each component with thier coorsponding component. + * + * @param matrixA The Inputmatrix A (right TextArea in the GUI) + * @param matrixB The Inputmatrix B (left TextArea in the GUI + * @return matrix A substracted by matrix B + */ + public double[][] matrixSubstraction(double[][] matrixA, double[][] matrixB) { + if (checkIfMatriciesAreTheSameDimension(matrixA, matrixB)) { + double[][] result = new double[matrixA.length][matrixA[0].length]; + for (int rows = 0; rows < matrixA.length; rows++) { + for (int colums = 0; colums < matrixA[0].length; colums++) { + result[rows][colums] = matrixA[rows][colums] - matrixB[rows][colums]; + } + } + return result; + } else { + throw new IllegalArgumentException("Matricies need to have the same Dimensions"); + } + } + + /** + * Transposes the Input Matrix. Swaps rows with colums. + * + * @param matrixA The Inputmatrix A wich will be Transposed + * @return The Transposed matrix of matrix A + */ + public double[][] matrixTransponation(double[][] matrixA) { + if (matrixA == null) { + throw new IllegalArgumentException("Matricies need to have the same Dimensions"); + } + if (matrixA.length == 0) { + throw new IllegalArgumentException("Matricies need to have the same Dimensions"); + } + if (matrixA[0] == null) { + throw new IllegalArgumentException("Matricies need to have the same Dimensions"); + } + int columCountResult = matrixA.length; + int rowCountResult = matrixA[0].length; + double[][] result = new double[rowCountResult][columCountResult]; + for (int row = 0; row < rowCountResult; row++) { + for (int colum = 0; colum < columCountResult; colum++) { + result[row][colum] = matrixA[colum][row]; + } + } + return result; + } + + /** + * Calculates the Determinant of a Matrix. + * + * @param matrixA The Inputmatrix + * @return The Determinant of the Matrix A + */ + public double calcDeterminat(double[][] matrixA) throws IllegalArgumentException{ + // checking if a Determinant can be calculated. + double result = 0.0; + if (checkIfMatrixIsQuadradtic(matrixA)) { + if (getMatrixRowCount(matrixA) == 2) { + result = calc2by2Determinant(matrixA); + } else if (getMatrixRowCount(matrixA) == 3) { + result = calc3by3Determinant(matrixA); + + } else { + throw new IllegalArgumentException("Matrix is not 2 by 2 or 3 by 3"); + } + + } else { + throw new IllegalArgumentException("Matrix must be Quadratic"); + } + return result; + } + + /** + * Calculates the Determinat of an three by three Matrix. + * + * @param matrixA The Inputmatrix form wich the Determinat will be calculated + * @return the Determinant of the Matrix + */ + private double calc3by3Determinant(double[][] matrixA) { + double result = matrixA[0][0] * matrixA[1][1] * matrixA[2][2] + matrixA[0][1] * matrixA[1][2] * matrixA[2][0] + + matrixA[0][2] * matrixA[1][0] * matrixA[2][1] - matrixA[0][0] * matrixA[1][2] * matrixA[2][1] + - matrixA[0][1] * matrixA[1][0] * matrixA[2][2] - matrixA[0][2] * matrixA[1][1] * matrixA[2][0]; + return result; + } + + /** + * Calculates the Determinat of an two by two Matrix. + * + * @param matrixA The Inputmatrix form wich the Determinat will be calculated + * @return the Determinant of the Matrix + */ + private double calc2by2Determinant(double[][] matrixA) { + double result = matrixA[0][0] * matrixA[1][1] - matrixA[0][1] * matrixA[1][0]; + return result; + } + + /** + * Returns the Number of rows of a Matrix. + * + * @param matrixA the Inputmatrix form wich the rows will be counted + * @return Number of rows + */ + private int getMatrixRowCount(double[][] matrixA) { + return matrixA.length; + } + + /** + * Checks if the rows and colums of an Matrix are equal. If they are equal the + * Matrix is Quadratic and the function will return true. + * + * @param matrixA the Inputmatrix for wich the rows and colums will be compared + * @return isQuadratic + */ + private boolean checkIfMatrixIsQuadradtic(double[][] matrixA) { + if (matrixA == null) { + return false; + } + if (matrixA[0] == null) { + return false; + } + if (matrixA.length == matrixA[0].length) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/src/main/resources/com/ugsbo/gui/BasicGui.fxml b/src/main/resources/com/ugsbo/gui/BasicGui.fxml index 275d454..d591c5a 100644 --- a/src/main/resources/com/ugsbo/gui/BasicGui.fxml +++ b/src/main/resources/com/ugsbo/gui/BasicGui.fxml @@ -27,8 +27,8 @@ -