Skip to content
Snippets Groups Projects
Commit 93f0cd9b authored by LABOUREL Arnaud's avatar LABOUREL Arnaud
Browse files

Version finale du template formula

parent 0d5f9b4c
Branches
No related tags found
No related merge requests found
Showing
with 287 additions and 296 deletions
......@@ -14,7 +14,7 @@ repositories {
dependencies {
testImplementation('org.junit.jupiter:junit-jupiter-api:5.7.2',
'org.hamcrest:hamcrest-library:2.2', 'net.obvj:junit-utils:1.3.1')
'org.assertj:assertj-core:3.11.1')
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.2'
}
......@@ -23,5 +23,5 @@ test {
}
application {
mainClassName = "viewer.Main"
mainClassName = "viewer.MainAppLauncher"
}
\ No newline at end of file
rootProject.name = 'color-image'
rootProject.name = 'formula'
package formula;
public interface Formula {
/**
* Compute the value of the formula
*
* @param xValue the value of the variable x
* @return the value of the function when the variable x has value {@code xValue}
*/
double eval(double xValue);
/**
* Compute a {@code String} representation of the formula.
* @return the formula as a {@code String}
*/
String toString();
/**
* Compute the derivative of the formula.
* @return the derivative of the formula
*/
Formula derivative();
}
package image;
import javafx.scene.paint.Color;
public class BlankImage implements Image{
private final int width;
private final int height;
public BlankImage(int width, int height) {
this.width = width;
this.height = height;
}
@Override
public Color getPixelColor(int x, int y) {
return Color.WHITE;
}
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
}
package image;
public class BlankImageFactory implements ImageFactory {
@Override
public Image makeImage() {
return new BlankImage(1000, 800);
}
}
package image;
import javafx.scene.paint.Color;
/**
* Created by Arnaud Labourel on 09/11/2018.
*/
public interface Image {
Color getPixelColor(int x, int y);
int getWidth();
int getHeight();
}
package image;
/**
* Created by Arnaud Labourel on 23/11/2018.
*/
public interface ImageFactory {
Image makeImage();
}
package image;
import javafx.scene.paint.Color;
/**
* Created by Arnaud Labourel on 09/11/2018.
*/
public class Pixel extends Point{
private Color color;
Pixel(int x, int y, Color color) {
super(x, y);
this.color = color;
}
public Color getColor() {
return color;
}
}
package image;
import java.util.Objects;
/**
* Created by Arnaud Labourel on 09/11/2018.
*/
public class Point {
public final int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public final boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Point point)) return false;
return x == point.x &&
y == point.y;
}
@Override
public final int hashCode() {
return Objects.hash(x, y);
}
}
package image;
import javafx.scene.paint.Color;
public interface Shape {
/**
* Tests if a specified Point is inside the boundary of the Shape.
*
* @return true if the point is inside the shape and false otherwise.
*/
boolean contains(Point point);
/**
* Return the color of the interior of the Shape.
*
* @return the color of the shape.
*/
Color getColor();
}
package util;
import java.util.Objects;
/**
* Created by Arnaud Labourel on 23/11/2018.
*/
public class Matrices {
/**
* Ensures that the given matrix does not have null parts : itself being null, having null row or having
* null values.
*
* @throws NullPointerException if there are null parts in the matrix.
* @param matrix the matrix to be tested.
*/
public static void requiresNonNull(Object[][] matrix) {
Objects.requireNonNull(matrix, "The matrix must not be null.");
for (int x = 0; x < getRowCount(matrix); x++) {
Objects.requireNonNull(matrix[x], "The matrix must not have rows equals to null.");
for (int y = 0; y < matrix[x].length; y++) {
Objects.requireNonNull(matrix[x][y], "The matrix must not have values equals to null.");
}
}
}
/**
* Ensures that the given matrix (assumed to be rectangular) does not have zero rows or zero columns.
*
* @throws IllegalArgumentException if the matrix have zero rows or zero columns.
* @param matrix the matrix to be tested.
*/
public static void requiresNonZeroDimensions(Object[][] matrix) {
if (getRowCount(matrix) == 0) {
throw new IllegalArgumentException("The matrix must not have zero rows.");
}
if (getColumnCount(matrix) == 0) {
throw new IllegalArgumentException("The matrix must not have zero columns.");
}
}
/**
* Ensures that the given matrix is rectangular, i.e., all rows have the same size.
*
* @throws IllegalArgumentException if the matrix have rows with different sizes.
* @param matrix the matrix to be tested.
*/
public static void requiresRectangularMatrix(Object[][] matrix) {
for (int x = 1; x < getRowCount(matrix); x++) {
if (matrix[x].length != matrix[0].length)
throw new IllegalArgumentException("The matrix must be rectangular.");
}
}
/**
* Give the number of rows of a matrix.
*
* @param matrix the matrix.
* @return the number of rows of the matrix.
*/
public static int getRowCount(Object[][] matrix){
return matrix.length;
}
/**
* Give the number of columns of a matrix (assumed to be rectangular).
*
* @param matrix the matrix.
* @return the number of rows of the matrix.
*/
public static int getColumnCount(Object[][] matrix){
return matrix[0].length;
}
}
package viewer;
import image.*;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.PixelWriter;
import javafx.scene.paint.Color;
import java.net.URL;
import java.util.ResourceBundle;
/**
* Created by Arnaud Labourel on 04/10/2018.
*/
public class Display implements Initializable {
@FXML
private Canvas canvas;
private Image image;
@Override
public void initialize(URL location, ResourceBundle resources) {
ImageFactory imageFactory = new BlankImageFactory();
// TODO : changer la fabrique d'image pour construire des images.
this.image = imageFactory.makeImage();
render();
}
private void render() {
int pixelWidth = image.getWidth();
int pixelHeight = image.getHeight();
canvas.setWidth(pixelWidth);
canvas.setHeight(pixelHeight);
GraphicsContext graphicsContext = canvas.getGraphicsContext2D();
PixelWriter pixelWriter = graphicsContext.getPixelWriter();
for (int i = 0; i < pixelWidth; i++) {
for (int j = 0; j < pixelHeight; j++) {
renderPixel(i, j, pixelWriter);
}
}
}
private void renderPixel(int x, int y, PixelWriter pixelWriter) {
pixelWriter.setColor(x, y, image.getPixelColor(x, y));
}
}
package viewer;
import javafx.geometry.Side;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
class FunctionChart extends LineChart<Number, Number> {
private static final int TICK_UNIT = 1;
private static final int LOWER_BOUND = -10;
private static final int UPPER_BOUND = 10;
int getLowerBound() {
return LOWER_BOUND;
}
int getUpperBound() {
return UPPER_BOUND;
}
FunctionChart(){
super(new NumberAxis(LOWER_BOUND, UPPER_BOUND, TICK_UNIT), new NumberAxis(LOWER_BOUND, UPPER_BOUND, TICK_UNIT));
getXAxis().setSide(Side.BOTTOM);
getYAxis().setSide(Side.LEFT);
setPrefWidth(900);
setPrefHeight(900);
setCreateSymbols(false);
}
private Series<Number, Number> getSeries(String name){
for (Series<Number, Number> series : getData())
if(series.getName().equals(name)){
return series;
}
return null;
}
void removeSeries(String name){
Series<Number, Number> series = getSeries(name);
if(series != null){
getData().remove(series);
}
}
}
package viewer;
import javafx.scene.chart.XYChart;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
class FunctionList {
private final List<PlottableFunction> functions = new ArrayList<>();
private final FunctionChart functionChart;
private final double lowerBound;
private final double upperBound;
FunctionList(FunctionChart functionChart) {
this.functionChart = functionChart;
this.lowerBound = functionChart.getLowerBound();
this.upperBound = functionChart.getUpperBound();
// TODO: add functions
}
void toggleFunction(PlottableFunction function) {
if (function.isPlotted()){
unplot(function);
}
else{
plot(function);
}
}
private void unplot(PlottableFunction function) {
functionChart.removeSeries(function.toString());
function.setPlotted(false);
}
List<PlottableFunction> getFunctions(){
return functions;
}
private void plot(PlottableFunction function){
XYChart.Series<Number, Number> series = function.getData(lowerBound, upperBound);
series.setName(function.toString());
functionChart.getData().add(series);
function.setPlotted(true);
}
private void addFunctionsAndTheirDerivative(Collection<PlottableFunction> functions){
for(PlottableFunction function: functions){
addFunctionAndItsDerivative(function);
}
}
private void addFunctionAndItsDerivative(PlottableFunction function){
add(function);
add(function.derivative());
}
private void add(PlottableFunction function) {
functions.add(function);
}
void clear() {
functionChart.getData().clear();
for(PlottableFunction function: functions){
function.setPlotted(false);
}
}
}
package viewer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
import java.util.Objects;
public class Main extends Application
{
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws IOException {
Parent root =FXMLLoader.load(Objects.requireNonNull(getClass().getClassLoader().getResource("fxml/Display.fxml")));
primaryStage.setTitle("Image display");
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
package viewer;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import java.net.URL;
import java.util.ResourceBundle;
public class MainAppController implements Initializable {
private static final int BUTTON_WIDTH = 500;
@FXML
private AnchorPane anchorPane;
@FXML
private VBox vBox;
private FunctionList functionList;
@Override
public void initialize(final URL url, final ResourceBundle rb) {
FunctionChart functionChart = new FunctionChart();
functionList = new FunctionList(functionChart);
anchorPane.getChildren().add(functionChart);
addFunctionButtons();
addClearButton();
}
private void addClearButton() {
Button clearButton = new Button("Clear");
clearButton.setOnAction(event -> functionList.clear());
addButton(clearButton);
}
private void addFunctionButtons() {
for(PlottableFunction function : functionList.getFunctions()){
addFunctionButton(function);
}
}
private void addFunctionButton(PlottableFunction function) {
Button button = new Button(function.toString());
addButton(button);
button.setOnAction(event -> toggleFunction(function));
}
private void toggleFunction(PlottableFunction function){
functionList.toggleFunction(function);
}
private void addButton(Button button) {
button.setPrefWidth(BUTTON_WIDTH);
vBox.getChildren().add(button);
}
}
package viewer;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.util.Objects;
public class MainAppLauncher extends Application {
public static void main(String[] args) {
Application.launch(MainAppLauncher.class, args);
}
@Override
public void start(Stage stage) {
try {
Parent root = FXMLLoader.load(Objects.requireNonNull(getClass().getClassLoader()
.getResource("MainApp.fxml")));
stage.setScene(new Scene(root));
stage.setTitle("Formulas");
stage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package viewer;
import formula.Formula;
import javafx.scene.chart.XYChart;
public class PlottableFunction {
private final Formula formula;
private final String name;
private static final double PRECISION = 0.01;
private boolean isPlotted = false;
PlottableFunction(Formula formula, String name) {
this.formula = formula;
this.name = name;
}
@Override
public String toString() {
return name + "(x) = " + formula;
}
public PlottableFunction derivative(){
return new PlottableFunction(formula.derivative(), name + "'");
}
XYChart.Series<Number, Number> getData(double lowerBound, double upperBound) {
final XYChart.Series<Number, Number> series = new XYChart.Series<>();
for (int index = 0; index <= 2 * (upperBound-lowerBound) / PRECISION; index++) {
double x = lowerBound + index * PRECISION;
series.getData().add(new XYChart.Data<>(x, formula.eval(x)));
}
return series;
}
boolean isPlotted() {
return isPlotted;
}
void setPlotted(boolean plotted) {
isPlotted = plotted;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane maxHeight="900.0" maxWidth="1200.0" minHeight="900.0" minWidth="1400.0"
prefHeight="900.0" prefWidth="1000.0"
styleClass="root" stylesheets="stylesheet.css"
xmlns:fx="http://javafx.com/fxml"
fx:controller="viewer.MainAppController">
<AnchorPane layoutX="900.0" minHeight="0.0" minWidth="0.0" prefHeight="900.0" prefWidth="300.0">
<VBox fx:id="vBox" prefHeight="800.0" prefWidth="500.0"/>
</AnchorPane>
<AnchorPane fx:id="anchorPane" layoutX="-7.0" prefHeight="900.0" prefWidth="900.0"/>
</AnchorPane>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.canvas.Canvas?>
<AnchorPane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="viewer.Display">
<Canvas fx:id="canvas"/>
</AnchorPane>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment