ソースを参照

GlobalEnergy

- Adds GlobalEnergy
- Selection is now recursive
TomTroppmann 2 年 前
コミット
7bfae751ce

+ 6 - 6
src/algorithm/binary/AcoAlgorithm.java

@@ -6,7 +6,7 @@ import java.util.ListIterator;
 
 import javax.swing.JFrame;
 import api.AlgorithmFrameworkFlex;
-import utility.StringFormat;
+import utility.FormatFloat;
 
 public class AcoAlgorithm extends AlgorithmFrameworkFlex{
 	
@@ -78,7 +78,7 @@ public class AcoAlgorithm extends AlgorithmFrameworkFlex{
 		best.fitness = evaluatePosition(best.position);
 		List<Double> runList = new ArrayList<Double>();
 		runList.add(best.fitness);
-		console.print("Start with: " + StringFormat.doubleFixedPlaces(2, best.fitness));
+		console.print("Start with: " + FormatFloat.doubleFixedPlaces(2, best.fitness));
 		if(moreInformation)console.println("");
 		int problemSize = best.position.size();
 		if(problemSize == 0) return best;
@@ -91,7 +91,7 @@ public class AcoAlgorithm extends AlgorithmFrameworkFlex{
 			if(moreInformation)console.println("Generation" + generation + " start with Fitness: " + best.fitness);
 			for(Individual i : population) {
 				i.fitness = evaluatePosition(i.position);
-				if(moreInformation)console.println("Fitness" + StringFormat.doubleFixedPlaces(2, i.fitness));
+				if(moreInformation)console.println("Fitness" + FormatFloat.doubleFixedPlaces(2, i.fitness));
 				if(i.fitness < best.fitness) best = i;	
 			}
 			runList.add(best.fitness);
@@ -106,7 +106,7 @@ public class AcoAlgorithm extends AlgorithmFrameworkFlex{
 		}
 		
 		
-		console.println("   End With:" + StringFormat.doubleFixedPlaces(2, best.fitness));
+		console.println("   End With:" + FormatFloat.doubleFixedPlaces(2, best.fitness));
 		this.runList = runList;
 		return best;
 		
@@ -195,8 +195,8 @@ public class AcoAlgorithm extends AlgorithmFrameworkFlex{
 				+ " Rounds: " + rounds 
 				+ " Iterations: " + maxGenerations 
 				+ " Individuals: " +  popsize
-				+ " vaporization: " +  StringFormat.doubleAllPlaces(p)
-				+ " convergenceFactorReset: " +  StringFormat.doubleAllPlaces(convergenceFactorReset);
+				+ " vaporization: " +  FormatFloat.doubleAllPlaces(p)
+				+ " convergenceFactorReset: " +  FormatFloat.doubleAllPlaces(convergenceFactorReset);
 	}
 
 

+ 4 - 9
src/algorithm/topologie/PsoAlgorithm.java

@@ -9,6 +9,7 @@ import java.util.stream.Collectors;
 import algorithm.objectiveFunction.TopologieObjectiveFunction;
 import api.TopologieAlgorithmFramework;
 import ui.model.DecoratedState;
+import utility.Maths;
 import utility.Random;
 
 public class PsoAlgorithm extends TopologieAlgorithmFramework {
@@ -46,13 +47,7 @@ public class PsoAlgorithm extends TopologieAlgorithmFramework {
 	}
 	
 	
-	public static double linearInterpolate(double first, double second, double alpha) {
-		return first * (1.0 - alpha) + second * alpha;
-	}
-	public static double inverseLinearInterpolation(double min, double max, double value) {
-		if (max - min == 0) return max;
-		else return (value - min) / (max - min);
-	}
+
 	
 	@Override
 	protected double evaluateState(DecoratedState actualstate, int amountOfAddedSwitch, double addedCableMeters, boolean moreInformation) {
@@ -250,8 +245,8 @@ public class PsoAlgorithm extends TopologieAlgorithmFramework {
 	 */
 	private void decode(Particle particle, int index) {
 		double value = clamp(Random.nextGaussian(particle.xGenotype.get(index), deviation));
-		double alpha = inverseLinearInterpolation(-maxVelocity, +maxVelocity, value);
-		double result = linearInterpolate(0, this.getMaximumIndexObjects(index), alpha);
+		double alpha = Maths.inverseLinearInterpolation(-maxVelocity, +maxVelocity, value);
+		double result = Maths.linearInterpolate(0, this.getMaximumIndexObjects(index), alpha);
 		particle.xPhenotype.set(index, (int)Math.round(result));
 	}
 

+ 13 - 13
src/api/AlgorithmFrameworkFlex.java

@@ -62,7 +62,7 @@ import ui.model.DecoratedSwitch.SwitchState;
 import ui.view.component.Console;
 import ui.model.DecoratedNetwork;
 import utility.ImageImport;
-import utility.StringFormat;
+import utility.FormatFloat;
 
 public abstract class AlgorithmFrameworkFlex implements AddOn{
 	//Algo
@@ -613,12 +613,12 @@ public abstract class AlgorithmFrameworkFlex implements AddOn{
 			long executionTime = printElapsedTime();
 			setState(roundBest.position);
 			runPrinter.openStream();
-			runPrinter.println(runList.stream().map(value -> StringFormat.doubleFixedPlaces(2,value)).collect(Collectors.joining(", ")));
+			runPrinter.println(runList.stream().map(value -> FormatFloat.doubleFixedPlaces(2,value)).collect(Collectors.joining(", ")));
 			RunValues val = getRunValuesFromActualState();
 			val.result = roundBest.fitness;
 			val.executionTime = executionTime;
 			avg.addRun(val);
-			runPrinter.println("Result: " + StringFormat.doubleFixedPlaces(2,roundBest.fitness) + " ExecutionTime:" + executionTime + " " + stringStatFromRunValues(val));
+			runPrinter.println("Result: " + FormatFloat.doubleFixedPlaces(2,roundBest.fitness) + " ExecutionTime:" + executionTime + " " + stringStatFromRunValues(val));
 			runPrinter.closeStream();
 			resetState();
 			if(roundBest.fitness < runBest.fitness) runBest = roundBest;
@@ -628,14 +628,14 @@ public abstract class AlgorithmFrameworkFlex implements AddOn{
 		this.extractPositionAndAccess();
 		setState(runBest.position);
 		updateVisual();
-		console.println("Start: " + StringFormat.doubleFixedPlaces(2,startFitness));
-		console.println("AlgoResult: " + StringFormat.doubleFixedPlaces(2,runBest.fitness));
+		console.println("Start: " + FormatFloat.doubleFixedPlaces(2,startFitness));
+		console.println("AlgoResult: " + FormatFloat.doubleFixedPlaces(2,runBest.fitness));
 		if(this.algoUseFlexes)calculateAndPrintFlexInfos(control.getSimManager().getActualDecorState());
 		runPrinter.openStream();
 		if(rounds > 1) {
 			RunValues avgRun = avg.getAverage();
 			
-			runPrinter.println("Average.Result: " + StringFormat.doubleFixedPlaces(2, avgRun.result) + " Average.ExecutionTime:" + avgRun.executionTime + " "  + this.stringStatFromRunValues(avg.getAverage(), "Average."));
+			runPrinter.println("Average.Result: " + FormatFloat.doubleFixedPlaces(2, avgRun.result) + " Average.ExecutionTime:" + avgRun.executionTime + " "  + this.stringStatFromRunValues(avg.getAverage(), "Average."));
 		}
 		runPrinter.println("");
 		runPrinter.closeStream();
@@ -921,12 +921,12 @@ public abstract class AlgorithmFrameworkFlex implements AddOn{
 			+ " " +	prefix +"Partially: " + percentage(val.partiallySupplied, val.objects)
 			+ " " +	prefix +"Over: " + percentage(val.overSupplied, val.objects)
 			+ " " +	prefix +"Supplied: " + percentage(val.supplied, val.objects)
-			+ " " +	prefix +"Partially.SupplyPercentage.Min: " + StringFormat.doubleFixedPlaces(2, val.partiallyMin) 
-			+ " " +	prefix +"Partially.SupplyPercentage.Max: "+ StringFormat.doubleFixedPlaces(2, val.partiallyMax) 
-			+ " " +	prefix +"Partially.SupplyPercentage.Average: " + StringFormat.doubleFixedPlaces(2, val.partiallyAverage)
-			+ " " + prefix +"Over.SupplyPercentage.Min: " + StringFormat.doubleFixedPlaces(2, val.overMin) 
-			+ " " +	prefix +"Over.SupplyPercentage.Max: "+ StringFormat.doubleFixedPlaces(2, val.overMax) 
-			+ " " +	prefix +"Over.SupplyPercentage.Average: " + StringFormat.doubleFixedPlaces(2, val.overAverage)
+			+ " " +	prefix +"Partially.SupplyPercentage.Min: " + FormatFloat.doubleFixedPlaces(2, val.partiallyMin) 
+			+ " " +	prefix +"Partially.SupplyPercentage.Max: "+ FormatFloat.doubleFixedPlaces(2, val.partiallyMax) 
+			+ " " +	prefix +"Partially.SupplyPercentage.Average: " + FormatFloat.doubleFixedPlaces(2, val.partiallyAverage)
+			+ " " + prefix +"Over.SupplyPercentage.Min: " + FormatFloat.doubleFixedPlaces(2, val.overMin) 
+			+ " " +	prefix +"Over.SupplyPercentage.Max: "+ FormatFloat.doubleFixedPlaces(2, val.overMax) 
+			+ " " +	prefix +"Over.SupplyPercentage.Average: " + FormatFloat.doubleFixedPlaces(2, val.overAverage)
 			+ " " +	prefix +"HolonElemnts.Active:" + percentage(val.activeElements, val.elements)
 			+ " " +	prefix +"Flexibilities.Essential: " + percentage(val.essentialFlex, val.flexebilities)
 			+ " " + prefix +"Flexibilities.High: " + percentage(val.highFlex, val.flexebilities)
@@ -945,7 +945,7 @@ public abstract class AlgorithmFrameworkFlex implements AddOn{
 		if((int)denominator == 0) {
 			return "-%";
 		}
-		return  StringFormat.doubleTwoPlaces(numerator)   + "/" + StringFormat.doubleTwoPlaces(denominator) + " "+ StringFormat.doubleFixedPlaces(2,(float)numerator /(float)denominator * 100) + "%";
+		return  FormatFloat.doubleTwoPlaces(numerator)   + "/" + FormatFloat.doubleTwoPlaces(denominator) + " "+ FormatFloat.doubleFixedPlaces(2,(float)numerator /(float)denominator * 100) + "%";
 	}
 	
 

+ 37 - 7
src/ui/view/inspector/Inspector.java

@@ -1,11 +1,12 @@
 package ui.view.inspector;
 
 import java.awt.BorderLayout;
+import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.event.ItemEvent;
-import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.swing.Box;
 import javax.swing.GrayFilter;
@@ -21,20 +22,23 @@ import javax.swing.JToolBar;
 
 import classes.HolonElement;
 import classes.HolonSwitch;
-import interfaces.GraphEditable;
 import interfaces.TimelineDependent;
 import ui.controller.Control;
+import utility.FormatFloat;
 import utility.ImageImport;
 
 public class Inspector extends JSplitPane {
 	private final UnitGraph unitGraph;
 	private final InspectorTable table;
 	private final Control control;
-	private final JScrollPane scrollGraph = new JScrollPane();
+	private final JPanel scrollGraph = new JPanel();
 	private final JPanel graphLabel = new JPanel();
 	private final JLabel maxGraph = new JLabel("100%");
 	private final JLabel medGraph = new JLabel("50%");
 	private final JLabel minGraph = new JLabel("0%");
+	private final JPanel globalCurveLabel = new JPanel();
+	private final JLabel minEnergy = new JLabel("0.0");
+	private final JLabel maxEnergy = new JLabel("0.0");
 	private final JToolBar toolBarGraph = new JToolBar();
 	private String[] comboContext = { "", "5", "10", "20", "100", "1000" };
 	private JComboBox<String> localPeriodInput = new JComboBox<String>(comboContext);
@@ -51,7 +55,7 @@ public class Inspector extends JSplitPane {
 		unitGraph = new UnitGraph(control);
 		table.OnElementSelectionChanged.addListener(this::updateUnitGraph);
 		initUI();
-
+		control.OnSelectionChanged.addListener(this::updateGlobalCurve);
 	}
 
 	private void initUI() {
@@ -61,7 +65,8 @@ public class Inspector extends JSplitPane {
 		this.setTopComponent(scrollPane);
 		this.setBottomComponent(scrollGraph);
 		this.setDividerLocation(1000);
-		scrollGraph.setViewportView(unitGraph);
+		scrollGraph.setLayout(new BorderLayout());
+		scrollGraph.add(unitGraph, BorderLayout.CENTER);
 		// Set up of the Properties section
 
 		graphLabel.setLayout(new BorderLayout(0, 10));
@@ -69,6 +74,14 @@ public class Inspector extends JSplitPane {
 		graphLabel.add(medGraph, BorderLayout.CENTER);
 		graphLabel.add(minGraph, BorderLayout.SOUTH);
 
+		
+		globalCurveLabel.setLayout(new BorderLayout(0, 10));
+		maxEnergy.setForeground(Color.red);
+		minEnergy.setForeground(Color.red);
+		globalCurveLabel.add(maxEnergy, BorderLayout.NORTH);
+		globalCurveLabel.add(minEnergy, BorderLayout.SOUTH);
+		
+		
 		toolBarGraph.setFloatable(false);
 		toolBarGraph.setAlignmentY(Component.RIGHT_ALIGNMENT);
 
@@ -98,8 +111,9 @@ public class Inspector extends JSplitPane {
 		resetButton.setToolTipText("Reset");
 		resetButton.addActionListener(actionEvent -> unitGraph.reset());
 		toolBarGraph.add(resetButton);
-		scrollGraph.setRowHeaderView(graphLabel);
-		scrollGraph.setColumnHeaderView(toolBarGraph);
+		scrollGraph.add(graphLabel, BorderLayout.WEST);
+		scrollGraph.add(globalCurveLabel, BorderLayout.EAST);
+		scrollGraph.add(toolBarGraph, BorderLayout.NORTH);
 
 	}
 
@@ -138,11 +152,14 @@ public class Inspector extends JSplitPane {
 		for (TimelineDependent element : elements) {
 			unitGraph.addNewSeries(element);
 		}
+			
 		
 		if(elements.isEmpty()) {
 			control.getModel().getSelectedObjects().stream().filter(obj -> obj instanceof HolonSwitch)
 			.forEach(obj -> unitGraph.addNewSeries((HolonSwitch) obj));			
 		}
+		
+		
 //		if (elements.isEmpty()) {
 //			this.setDividerLocation(1.0);
 //		}
@@ -152,6 +169,19 @@ public class Inspector extends JSplitPane {
 				.setItem(unitGraph.isLocalPeriedDifferentInSeries() ? "-" : unitGraph.getFirstLocalPeriod());
 	}
 
+	
+	
+	private void updateGlobalCurve() {
+		Set<HolonElement> elements = InspectorTable.extractElements(control.getModel().getSelectedObjects()).collect(Collectors.toSet());
+		unitGraph.setGlobalCurve(elements);
+		double maxEnergy = elements.stream().map(ele -> ele.getEnergy()).filter(energy -> energy > 0).reduce(0.0f,
+				Float::sum);
+		double minEnergy = elements.stream().map(ele -> ele.getEnergy()).filter(energy -> energy < 0).reduce(0.0f,
+				Float::sum);
+		this.minEnergy.setText(FormatFloat.doubleTwoPlaces(minEnergy));		
+		this.maxEnergy.setText(FormatFloat.doubleTwoPlaces(maxEnergy));	
+	}
+	
 	/**
 	 * Displayed the actual LocalModeState.
 	 * 

+ 8 - 4
src/ui/view/inspector/InspectorTable.java

@@ -27,11 +27,10 @@ import javax.swing.JFormattedTextField;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JTextField;
-import javax.swing.UIManager;
-import javax.swing.border.Border;
 import javax.swing.text.NumberFormatter;
 
 import classes.AbstractCanvasObject;
+import classes.GroupNode;
 import classes.HolonElement;
 import classes.HolonElement.Priority;
 import classes.HolonObject;
@@ -221,13 +220,18 @@ public class InspectorTable extends JPanel {
 	}
 
 	// Extract elements from a list of AbstractCanvasObjects
-	private Stream<HolonElement> extractElements(Collection<AbstractCanvasObject> toInspect) {
-		return toInspect.stream().filter(obj -> obj instanceof HolonObject).flatMap(obj -> {
+	static Stream<HolonElement>  extractElements(Collection<AbstractCanvasObject> toInspect) {
+		Stream<HolonElement> recursiveLayer = toInspect.stream().filter(object ->object instanceof GroupNode).flatMap(obj -> extractElements(((GroupNode)obj).getNodes()));
+		Stream<HolonElement> thisLayer = toInspect.stream().filter(obj -> obj instanceof HolonObject).flatMap(obj -> {
 			HolonObject ho = (HolonObject) obj;
 			return ho.getElements().stream();
 		});
+		return Stream.concat(thisLayer, recursiveLayer);
 	}
 	
+	
+	
+	
 	private class ElementRow {
 		HolonElement element;
 		private JCheckBox selectionBox;

+ 83 - 22
src/ui/view/inspector/UnitGraph.java

@@ -15,18 +15,19 @@ import java.awt.geom.Path2D;
 import java.awt.geom.Point2D;
 import java.util.ArrayList;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.ListIterator;
 import java.util.Optional;
+import java.util.Set;
 
 import javax.swing.JPanel;
 
 import classes.HolonElement;
-import interfaces.GraphEditable;
 import interfaces.GraphEditable.GraphType;
-import interfaces.LocalMode;
 import interfaces.TimelineDependent;
 import ui.controller.Control;
 import ui.model.Model;
+import utility.Maths;
 import utility.Vector2Int;
 
 /**
@@ -52,6 +53,7 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 	private static final Color editDotColor = new Color(255, 119, 0);
 	private static final Color[] seriesColorArray = { Color.blue, Color.cyan, Color.black, Color.green, Color.gray,
 			Color.magenta, Color.yellow, Color.PINK, Color.red };
+	private static final Color globalCurveColor = new Color(255, 30, 30);
 
 	// Intern Variables
 	private class Series {
@@ -64,8 +66,17 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 	private ArrayList<Series> seriesList = new ArrayList<Series>();
 	private Vector2Int editPosition;
 	private Optional<Series> actualSeries;
-	private boolean editMode = false;
 
+	private class GlobalCurve {
+		public LinkedList<UnitGraphPoint> points = new LinkedList<UnitGraphPoint>();
+		public float minEnergy;
+		public float maxEnergy;
+	}
+
+	private Optional<GlobalCurve> globalCurve = Optional.empty();
+	private boolean editMode = false;
+	private Set<HolonElement> elements;
+	
 	private enum EditPointType {
 		Normal, StartPoint, EndPoint
 	};
@@ -112,6 +123,46 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 		repaint();
 	}
 
+	public void setGlobalCurve(Set<HolonElement> elements) {
+		// TODO debug timing -> if to long async
+		if(elements.isEmpty()) {
+			this.globalCurve = Optional.empty();
+			return;
+		}
+		GlobalCurve curve = new GlobalCurve();
+		curve.maxEnergy = elements.stream().map(ele -> ele.getEnergy()).filter(energy -> energy > 0).reduce(0.0f,
+				Float::sum);
+		curve.minEnergy = elements.stream().map(ele -> ele.getEnergy()).filter(energy -> energy < 0).reduce(0.0f,
+				Float::sum);
+		
+		float[] sample = new float[model.getMaxIterations()];
+		// sample energy
+		for (HolonElement element : elements) {
+			for (int i = 0; i < model.getMaxIterations(); i++) {
+				sample[i] += element.getEnergyAtTimeStep(i);
+			}
+		}
+		
+		// sample curve
+		for (int i = 0; i < model.getMaxIterations(); i++) {
+			curve.points.add(new UnitGraphPoint((double) i / (double)model.getMaxIterations(),
+					Maths.inverseLinearInterpolation(curve.minEnergy, curve.maxEnergy, sample[i]), false));
+		}
+		// update displayPosition
+		for (UnitGraphPoint p : curve.points) {
+			p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+		}
+		// set global curve
+		this.globalCurve = Optional.of(curve);
+		this.elements = elements;
+	}
+
+	private void updateGlobalCurve() {
+		setGlobalCurve(this.elements);
+	}
+	
+	
+	
 	/**
 	 * Paints the Graph, the Grid, the actual Line from the currentIteration
 	 * 
@@ -134,6 +185,10 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 		g2D.setColor(dotColor);
 		g2D.setStroke(new BasicStroke(1));
 		drawCurrentIterartionLine(g2D);
+		this.globalCurve.ifPresent(curve -> {
+			g2D.setColor(globalCurveColor);
+			drawDoubleGraph(g2D, curve.points);
+		});
 	}
 
 	// Draw Methods only to let the User see the changes. Nothing its saved here or
@@ -154,25 +209,24 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 			case boolGraph:
 				if (editMode) {
 					drawBoolGraphInEditMode(g, series);
-					drawSnappingHintFlag = true;					
-				}
-				else
+					drawSnappingHintFlag = true;
+				} else
 					drawBoolGraph(g, series);
 				break;
 			case doubleGraph:
 				if (editMode)
 					drawDoubleGraphInEditMode(g, series);
 				else
-					drawDoubleGraph(g, series);
+					drawDoubleGraph(g, series.points);
 				break;
 			default:
 				throw new UnsupportedOperationException();
 			}
 		}
-		if(drawSnappingHintFlag) {
+		if (drawSnappingHintFlag) {
 			drawSnappingHint(g);
 		}
-			
+
 	}
 
 	/**
@@ -238,8 +292,8 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 	private void drawCurrentIterartionLine(Graphics2D g) {
 		int cur = model.getCurrentIteration();
 		int max = model.getMaxIterations();
-		if(isLocalPeriedDifferentInSeries()){
-			for(Series series: seriesList) {
+		if (isLocalPeriedDifferentInSeries()) {
+			for (Series series : seriesList) {
 				double where;
 				if (!series.element.isUsingLocalPeriod()) {
 					where = ((double) cur) / ((double) max);
@@ -248,12 +302,12 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 					where = ((double) cur % lPeriod) / ((double) lPeriod);
 				}
 				Vector2Int oben = new Vector2Int(border + (int) (where * widthWithBorder), 0);
-				Vector2Int unten = new Vector2Int(border + (int) (where * widthWithBorder), 2 * border + heightWithBorder);
+				Vector2Int unten = new Vector2Int(border + (int) (where * widthWithBorder),
+						2 * border + heightWithBorder);
 				g.setColor(series.color);
 				drawLine(g, oben, unten);
 			}
-		}
-		else {
+		} else {
 			double where;
 			if (!isUsingLocalPeriod()) {
 				where = ((double) cur) / ((double) max);
@@ -266,7 +320,7 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 			g.setColor(dotColor);
 			drawLine(g, oben, unten);
 		}
-		
+
 	}
 
 	/**
@@ -463,10 +517,10 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 	 * 
 	 * @param g2D to draw.
 	 */
-	private void drawDoubleGraph(Graphics2D g, Series series) {
-		if (series.points.isEmpty())
+	private void drawDoubleGraph(Graphics2D g, List<UnitGraphPoint> points) {
+		if (points.isEmpty())
 			return;
-		ListIterator<UnitGraphPoint> iter = series.points.listIterator();
+		ListIterator<UnitGraphPoint> iter = points.listIterator();
 		Vector2Int actual = iter.next().displayedPosition;
 		Path2D.Double path = this.initBezier(actual);
 		while (iter.hasNext()) {
@@ -546,6 +600,12 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 				p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
 			}
 		}
+		this.globalCurve.ifPresent(curve -> {
+			for (UnitGraphPoint p : curve.points) {
+				p.calcDisplayedPosition(border, widthWithBorder, heightWithBorder);
+			}
+		});
+		
 	}
 
 	/**
@@ -767,6 +827,7 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 	public void mouseDragged(MouseEvent e) {
 		actualSeries.ifPresent(series -> {
 			updateEditPointPosition(new Vector2Int(e.getPoint().x, e.getPoint().y), this.editPointType, series.type);
+			updateGlobalCurve();
 			repaint();
 		});
 
@@ -830,9 +891,10 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 				this.insertNewGraphPoint(series, editPosition);
 			}
 			editMode = false;
-			repaint();
 		}
 		saveGraph();
+		updateGlobalCurve();
+		repaint();
 	}
 
 	/**
@@ -887,10 +949,9 @@ public class UnitGraph extends JPanel implements MouseListener, MouseMotionListe
 	public boolean isLocalPeriedDifferentInSeries() {
 		return seriesList.stream().map(series -> series.element.getLocalPeriod()).distinct().count() > 1;
 	}
+
 	public int getFirstLocalPeriod() {
-		int period = 0;
-		//seriesList.stream().findFirst().ifPresentOrElse(series -> return series.element.getLocalPeriod(), () -> period = LocalMode.STANDARD_GRAPH_ACCURACY);
-		return period;
+		return seriesList.isEmpty() ? 0 : seriesList.get(0).element.getLocalPeriod();
 	}
 
 	public boolean isUsingLocalPeriod() {

+ 1 - 1
src/utility/StringFormat.java → src/utility/FormatFloat.java

@@ -5,7 +5,7 @@ import java.text.DecimalFormat;
 import java.text.NumberFormat;
 import java.util.Locale;
 
-public class StringFormat {
+public class FormatFloat {
 	
 	private static DecimalFormat formatter;
 	private static DecimalFormat twoFormatter;

+ 13 - 0
src/utility/Maths.java

@@ -0,0 +1,13 @@
+package utility;
+
+public class Maths {
+	private final static double EPSILON = 1E-6;
+	
+	public static double linearInterpolate(double first, double second, double alpha) {
+		return first * (1.0 - alpha) + second * alpha;
+	}
+	public static double inverseLinearInterpolation(double min, double max, double value) {
+		if (Math.abs(max - min) < EPSILON) return max;
+		else return (value - min) / (max - min);
+	}
+}