Troppmann, Tom 3 years ago
parent
commit
49c9cf2044
91 changed files with 6383 additions and 626 deletions
  1. 80 0
      Metaheuristics/BinaryAntColonyAlgoritm.cpp
  2. 31 0
      Metaheuristics/BinaryAntColonyAlgoritm.h
  3. 18 0
      Metaheuristics/BinaryHeuristic.cpp
  4. 21 0
      Metaheuristics/BinaryHeuristic.h
  5. 100 0
      Metaheuristics/GeneticAlgorithm.cpp
  6. 25 0
      Metaheuristics/GeneticAlgorithm.h
  7. 114 0
      Metaheuristics/Metaheuristics.cpp
  8. 169 0
      Metaheuristics/Metaheuristics.vcxproj
  9. 54 0
      Metaheuristics/Metaheuristics.vcxproj.filters
  10. 120 0
      Metaheuristics/ObjectiveFunction.cpp
  11. 42 0
      Metaheuristics/ObjectiveFunction.h
  12. 20 0
      Metaheuristics/Random.cpp
  13. 16 0
      Metaheuristics/Random.h
  14. 99 0
      metavis/BitInspector.cpp
  15. 27 0
      metavis/BitInspector.h
  16. 78 0
      metavis/BitInspectorPanel.cpp
  17. 24 0
      metavis/BitInspectorPanel.h
  18. 143 0
      metavis/Bitfield.cpp
  19. 20 0
      metavis/Bitfield.h
  20. 88 0
      metavis/BitfieldControlPanel.cpp
  21. 29 0
      metavis/BitfieldControlPanel.h
  22. 0 3
      metavis/ColorButton.cpp
  23. 234 48
      metavis/ColorGradient.cpp
  24. 24 3
      metavis/ColorGradient.h
  25. 65 0
      metavis/Concurrent.cpp
  26. 28 0
      metavis/Concurrent.h
  27. 3 2
      metavis/DockableGraphView.cpp
  28. 1 1
      metavis/DockableGraphView.h
  29. 358 0
      metavis/GraphPlott.cpp
  30. 79 0
      metavis/GraphPlott.h
  31. 5 6
      metavis/GraphView.cpp
  32. 1 1
      metavis/GraphView.h
  33. 11 9
      metavis/GraphViewSettingDialog.cpp
  34. 4 6
      metavis/GraphViewSettingDialog.h
  35. 15 16
      metavis/GraphViewSettingItem.cpp
  36. 8 5
      metavis/GraphViewSettingItem.h
  37. 27 0
      metavis/HoverButton.cpp
  38. 24 0
      metavis/HoverButton.h
  39. 27 0
      metavis/InformationPopUp.cpp
  40. 17 0
      metavis/InformationPopUp.h
  41. 520 0
      metavis/Plott.cpp
  42. 83 0
      metavis/Plott.h
  43. 24 10
      metavis/Project.cpp
  44. 8 16
      metavis/Project.h
  45. 179 53
      metavis/ProjectManager.cpp
  46. 26 20
      metavis/ProjectManager.h
  47. 0 2
      metavis/QTestGraph.cpp
  48. 0 7
      metavis/QTestGraph.h
  49. 125 23
      metavis/RangeSlider.cpp
  50. 15 5
      metavis/RangeSlider.h
  51. 7 0
      metavis/Resources/3-up-triangle.svg
  52. 45 0
      metavis/Resources/arrow_right.svg
  53. 70 0
      metavis/Resources/binaryIcon.svg
  54. 67 0
      metavis/Resources/csv.svg
  55. 75 0
      metavis/Resources/csv_remove.svg
  56. 39 0
      metavis/Resources/file.svg
  57. 52 0
      metavis/Resources/frame.svg
  58. 53 0
      metavis/Resources/frame_hovered.svg
  59. 52 0
      metavis/Resources/gridIcon.svg
  60. 54 0
      metavis/Resources/gridIcon_hovered.svg
  61. 51 0
      metavis/Resources/information_icon.svg
  62. 53 0
      metavis/Resources/information_icon_hovered.svg
  63. 49 0
      metavis/Resources/rubbish.svg
  64. 54 0
      metavis/Resources/rubbish_hovered.svg
  65. 5 0
      metavis/Resources/up-triangle.svg
  66. 230 89
      metavis/RunData.cpp
  67. 46 20
      metavis/RunData.h
  68. 48 0
      metavis/Scratchpad.cpp
  69. 22 0
      metavis/Scratchpad.h
  70. 51 0
      metavis/SearchSpacePlott.cpp
  71. 25 0
      metavis/SearchSpacePlott.h
  72. 144 0
      metavis/TsneControlPanel.cpp
  73. 48 0
      metavis/TsneControlPanel.h
  74. 172 0
      metavis/TsnePlott.cpp
  75. 33 0
      metavis/TsnePlott.h
  76. 125 0
      metavis/TsneSettings.cpp
  77. 34 0
      metavis/TsneSettings.h
  78. 5 2
      metavis/main.cpp
  79. 260 89
      metavis/metavis.cpp
  80. 51 17
      metavis/metavis.h
  81. BIN
      metavis/metavis.ico
  82. 19 7
      metavis/metavis.qrc
  83. 11 76
      metavis/metavis.ui
  84. 112 4
      metavis/metavis.vcxproj
  85. 92 5
      metavis/metavis.vcxproj.filters
  86. 23 0
      metavis/settings.ini
  87. 691 0
      metavis/tSneAlgo.cpp
  88. 37 0
      metavis/tSneAlgo.h
  89. 61 37
      metavis/tsneIteractive.cpp
  90. 6 3
      metavis/tsneIteractive.h
  91. 82 41
      metavis/tsneIteractive.ui

+ 80 - 0
Metaheuristics/BinaryAntColonyAlgoritm.cpp

@@ -0,0 +1,80 @@
+#include "BinaryAntColonyAlgoritm.h"
+#include <algorithm>
+#include <limits>
+#include <functional>
+#include <numeric>
+#include <iostream>
+BinaryAntColonyOptimization::BinaryAntColonyOptimization(std::ostream& outstream, int iteration, int population, double vaporization, double resetThreshold):
+	maxIteration(std::max(iteration, 1)), amountOfPopulation(std::max(1, population)), vaporization(std::clamp(vaporization, 0.0, 1.0)), 
+	resetThreshold(std::clamp(resetThreshold, 0.0, 1.0)), BinaryHeuristic(outstream)
+{
+
+}
+Solution BinaryAntColonyOptimization::execute(int rounds, int n, std::function<double(const std::vector<bool>&)> objectiveFunction, ObjectiveFunctionGoal goal)
+{
+	outstream << "Iteration,populationNumber,objectiveFunction,binary,convergenceFactor" << std::endl;
+	std::function<bool(double, double)> op = getOperatorFromGoal(goal);
+	Solution bestFound;
+	bestFound.objectiveFunctionValue = (goal == ObjectiveFunctionGoal::min) ? std::numeric_limits<double>::max() : std::numeric_limits<double>::min();
+	
+
+	for (int r = 0; r < rounds; r++) {
+		Solution bestFoundInRun;
+		//init with Worst Value
+		bestFoundInRun.objectiveFunctionValue = (goal == ObjectiveFunctionGoal::min) ? std::numeric_limits<double>::max() : std::numeric_limits<double>::min();
+		//Init Pheromons with 0.5
+		std::vector<double> pheromons(n);
+		std::fill(pheromons.begin(), pheromons.end(), 0.5);
+
+		std::vector<Solution> population(amountOfPopulation);
+		for (int i = 0; i < maxIteration; i++) {
+			//Geneartion Population
+			for (Solution& sol : population) {
+				std::vector<bool> bitstring(n);
+				std::transform(pheromons.begin(), pheromons.end(), bitstring.begin(),
+					[this](double pheromon)->bool {return rand.doubleRandom() < pheromon; });
+				sol.bitstring = bitstring;
+				sol.objectiveFunctionValue = objectiveFunction(sol.bitstring);
+				//UpdateBest
+				if (op(sol.objectiveFunctionValue, bestFoundInRun.objectiveFunctionValue)) {
+					bestFoundInRun = sol;
+				}
+			}
+			//Reset
+			double convergenceFactor = calculateConvergenceFactor(pheromons);
+			if (convergenceFactor >= resetThreshold) {
+				std::fill(pheromons.begin(), pheromons.end(), 0.5);
+			}
+			for (int k = 0; k < population.size() - 1; k++) {
+				outstream << r << ","  << i << "," << k << "," << population[k].objectiveFunctionValue << ","
+					<< population[k].bitstringToStdString() << "," << convergenceFactor << std::endl;
+			}
+			//UpdatePheromons
+			std::cout << "BestFound:" << bestFoundInRun.bitstringToStdString() << " with value:" << bestFoundInRun.objectiveFunctionValue << " cF:" << convergenceFactor << std::endl;
+			for (int bit = 0; bit < n; bit++) {
+				bool bestDecision = bestFoundInRun.bitstring[bit];
+				pheromons[bit] = (1.0 - vaporization) * pheromons[bit] + (bestDecision ? vaporization : 0.0);
+			}
+
+		}
+		//update best run
+		if (op(bestFoundInRun.objectiveFunctionValue, bestFound.objectiveFunctionValue)) {
+			bestFound = bestFoundInRun;
+		}
+	}
+	
+
+	return bestFound;
+}
+
+
+
+
+
+
+double BinaryAntColonyOptimization::calculateConvergenceFactor(std::vector<double> pheromons)
+{
+	//Sums the proportion to the marginal values
+	double sum = std::transform_reduce(pheromons.begin(), pheromons.end(), 0.0, std::plus<double>(), [](double value) {return std::abs(2*value - 1.0);});
+	return sum/(double)pheromons.size();
+}

+ 31 - 0
Metaheuristics/BinaryAntColonyAlgoritm.h

@@ -0,0 +1,31 @@
+#pragma once
+#include "ObjectiveFunction.h"
+#include "BinaryHeuristic.h"
+#include "Random.h"
+#include <ostream>
+#include <functional>
+
+class BinaryAntColonyOptimization;
+typedef BinaryAntColonyOptimization Baco;
+
+
+
+
+
+class BinaryAntColonyOptimization : BinaryHeuristic
+{
+public:
+	BinaryAntColonyOptimization(std::ostream& outstream, int iteration, int population, double vaporization = 0.3, double resetThreshold = 0.99);
+	Solution execute(int round, int n, std::function<double(const std::vector<bool>&)> objectiveFunction, ObjectiveFunctionGoal goal) override;
+protected:
+
+private:
+	//Params:
+	int maxIteration;
+	int amountOfPopulation;
+	double vaporization;
+	double resetThreshold;
+	//Methods 
+	double calculateConvergenceFactor(std::vector<double> pheromons);
+};
+

+ 18 - 0
Metaheuristics/BinaryHeuristic.cpp

@@ -0,0 +1,18 @@
+#include "BinaryHeuristic.h"
+
+BinaryHeuristic::BinaryHeuristic(std::ostream& outstream):
+outstream(outstream)
+{
+
+}
+
+std::function<bool(double, double)> BinaryHeuristic::getOperatorFromGoal(ObjectiveFunctionGoal goal)
+{
+	switch (goal) {
+	case ObjectiveFunctionGoal::min:
+		return std::less<double>();
+	case ObjectiveFunctionGoal::max:
+	default:
+		return std::greater<double>();
+	}
+}

+ 21 - 0
Metaheuristics/BinaryHeuristic.h

@@ -0,0 +1,21 @@
+#pragma once
+#include "ObjectiveFunction.h"
+#include <functional>
+#include <ostream>
+#include "Random.h"
+
+class BinaryHeuristic
+{
+public:
+	BinaryHeuristic(std::ostream& outstream);
+	enum class ObjectiveFunctionGoal { min, max };
+	virtual Solution execute(int rounds, int n, std::function<double(const std::vector<bool>&)> objectiveFunction, ObjectiveFunctionGoal goal) = 0;
+protected:
+	//Interfaces
+	PseudoRandom rand;
+	std::ostream& outstream;
+	std::function<bool(double, double)> getOperatorFromGoal(ObjectiveFunctionGoal goal);
+private:
+	
+};
+

+ 100 - 0
Metaheuristics/GeneticAlgorithm.cpp

@@ -0,0 +1,100 @@
+#include "GeneticAlgorithm.h"
+#include <iostream>
+
+GeneticAlgorithm::GeneticAlgorithm(std::ostream& outstream, int iteration, int population, double mutateProbability, double swapProbability, double tournamentSize):
+	iteration(iteration), populationSize(population), mutateProbability(mutateProbability), swapProbability(swapProbability), tournamentSize(tournamentSize), BinaryHeuristic(outstream)
+{
+}
+
+Solution GeneticAlgorithm::execute(int rounds, int n, std::function<double(const std::vector<bool>&)> objectiveFunction, ObjectiveFunctionGoal goal)
+{
+	outstream << "round,iteration,populationNumber,objectiveFunction,binary" << std::endl;
+	std::function<bool(double, double)> op = getOperatorFromGoal(goal);
+	Solution bestFound;
+	//init with Worst Value
+	bestFound.objectiveFunctionValue = (goal == ObjectiveFunctionGoal::min) ? std::numeric_limits<double>::max() : std::numeric_limits<double>::min();
+	for (int r = 0; r < rounds; r++) {
+		Solution bestFoundInRun;
+		//init with Worst Value
+		bestFoundInRun.objectiveFunctionValue = (goal == ObjectiveFunctionGoal::min) ? std::numeric_limits<double>::max() : std::numeric_limits<double>::min();
+		//Init populattion
+		std::vector<Solution> population(populationSize);
+		std::vector<Solution> childList(populationSize);
+		for (Solution& sol : population) {
+			std::vector<bool> bitstring(n);
+			std::generate(bitstring.begin(), bitstring.end(), [this]() {return rand.doubleRandom() < 0.5; });
+			sol.bitstring = bitstring;
+		}
+
+		for (int i = 0; i < iteration; i++) {
+			//Evaluate
+			for (Solution& sol : population) {
+				sol.objectiveFunctionValue = objectiveFunction(sol.bitstring);
+				//UpdateBest
+				if (op(sol.objectiveFunctionValue, bestFoundInRun.objectiveFunctionValue)) {
+					bestFoundInRun = sol;
+				}
+			}
+			for (int k = 0; k < population.size() - 1; k++) {
+				outstream << r << "," << i << "," << k << "," << population[k].objectiveFunctionValue << ","
+					<< population[k].bitstringToStdString() << std::endl;
+			}
+			//GenerateChildren
+			for (int k = 0; k < populationSize / 2; k++) {
+				childList[2 * k] = selectAParent(population, op);
+				childList[2 * k + 1] = selectAParent(population, op);
+				crossover(childList[2 * k], childList[2 * k + 1]);
+				mutate(childList[2 * k]);
+				mutate(childList[2 * k + 1]);
+			}
+			//Exchange generations
+			std::swap(population, childList);
+			std::cout << "BestFound:" << bestFoundInRun.bitstringToStdString() << " with value:" << bestFoundInRun.objectiveFunctionValue << std::endl;
+		}
+		//update best run
+		if (op(bestFoundInRun.objectiveFunctionValue, bestFound.objectiveFunctionValue)) {
+			bestFound = bestFoundInRun;
+		}
+	}
+	
+	return bestFound;
+}
+
+Solution& GeneticAlgorithm::selectAParent(std::vector<Solution>& population, std::function<bool(double, double)> op)
+{
+	Solution* tournamentBest = &population[rand.randomIntegerInRange(0, populationSize)];
+	double participants;
+	for (participants = tournamentSize; participants >= 2; participants -= 1.0) {
+		Solution& next = population[rand.randomIntegerInRange(0, populationSize)];
+		if (op(next.objectiveFunctionValue,tournamentBest->objectiveFunctionValue)) tournamentBest = &next;
+	}
+	//if decimal participant stays in tournament its a chance to play another
+	if (participants > 1) {
+		if (rand.doubleRandom() < participants - 1.0) {
+			Solution& next = population[rand.randomIntegerInRange(0, populationSize)];
+			if (op(next.objectiveFunctionValue, tournamentBest->objectiveFunctionValue)) tournamentBest = &next;
+		}
+	}
+	return *tournamentBest;
+}
+
+void GeneticAlgorithm::crossover(Solution& parentA, Solution& parentB)
+{
+	std::vector<bool>::iterator iterA= parentA.bitstring.begin();
+	std::vector<bool>::iterator iterB= parentB.bitstring.begin();
+	for (int i = 0; i < parentA.bitstring.size(); i++) {
+		if (rand.doubleRandom() <= swapProbability) {
+			//Swap 
+			std::iter_swap(iterA, iterB);
+		}
+		iterA++;
+		iterB++;
+	}
+}
+
+void GeneticAlgorithm::mutate(Solution& individual)
+{
+	std::transform(individual.bitstring.begin(), individual.bitstring.end(), individual.bitstring.begin(), [this](bool bit) {
+		return (rand.doubleRandom() < mutateProbability) ? !bit : bit;
+	});
+}

+ 25 - 0
Metaheuristics/GeneticAlgorithm.h

@@ -0,0 +1,25 @@
+#pragma once
+#include "ObjectiveFunction.h"
+#include "BinaryHeuristic.h"
+#include <ostream>
+
+
+class GeneticAlgorithm : BinaryHeuristic
+{
+public:
+	GeneticAlgorithm(std::ostream& outstream, int iteration, int population, double mutateProbability = 0.01, double swapProbability = 0.5, double tournamentSize = 2.0);
+	Solution execute(int round, int n, std::function<double(const std::vector<bool>&)> objectiveFunction, ObjectiveFunctionGoal goal) override;
+protected:
+private:
+	//params:
+	int iteration;
+	int populationSize;
+	double mutateProbability;
+	double swapProbability;
+	double tournamentSize;
+	//methods:
+	Solution& selectAParent(std::vector<Solution>& population, std::function<bool(double, double)> op);
+	void crossover(Solution& childA, Solution& childB);
+	void mutate(Solution& individual);
+};
+

+ 114 - 0
Metaheuristics/Metaheuristics.cpp

@@ -0,0 +1,114 @@
+// Metaheuristics.cpp : This file contains the 'main' function. Program execution begins and ends there.
+//
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <thread>
+#include <chrono>
+#include <random>
+#include "ObjectiveFunction.h"
+#include "BinaryAntColonyAlgoritm.h"
+#include "GeneticAlgorithm.h"
+#include <fstream>
+#include <functional>
+#include <algorithm>
+#include <iterator>
+
+
+void onemax() {
+    std::fstream file("ga_setting3.csv", std::ios::out);
+    if (!file.is_open()) {
+        std::cout << "Cant open file";
+    }
+    objective::OneMax onemax(100, 1);
+    auto f = std::bind(&objective::OneMax::function, &onemax, std::placeholders::_1);
+
+
+    ///*Baco instance with parameter: iteration, population, vaporization, resetThreshhold, ostream*/
+    //Baco instance(file, 1000, 100, 0.05, 0.99);
+    /*GeneticAlgorithm instance with parameter: iteration, population, mutateProbability, swapProbability, tournamentsize*/
+    GeneticAlgorithm instance(file, 101, 20, 0.005, 0.7, 2.0);
+    Solution sol = instance.execute(10, 100, f, BinaryHeuristic::ObjectiveFunctionGoal::max);
+    std::cout << "Value: " << sol.objectiveFunctionValue << std::endl;
+    file.close();
+}
+void knapsack() {
+    std::fstream file("ga_setting1.csv", std::ios::out);
+    if (!file.is_open()) {
+        std::cout << "Cant open file";
+    }
+    /*GeneticAlgorithm instance with parameter: iteration, population, mutateProbability, swapProbability, tournamentsize*/
+    GeneticAlgorithm instance(file, 100, 20, 0.01, 0.7, 2.0);
+
+    //Generate Problem
+    objective::KnapsackProblem knapsack(275.0, 2000);
+    //generate Items
+    double value = 5;
+    double weight = 0;
+    for (int i = 0; i < 100; i++) {
+        if (i % 10 == 0) {
+            value++;
+            weight++;
+        }
+        objective::Item item;
+        item.value = value;
+        item.weight = weight;
+        knapsack.itemVec.push_back(item);
+    }
+    //Bind as callable object
+    auto f1 = std::bind(&objective::KnapsackProblem::function, &knapsack, std::placeholders::_1);
+    std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
+    Solution sol = instance.execute(10, 100, f1, BinaryHeuristic::ObjectiveFunctionGoal::max);
+    std::cout << "Value: " << sol.objectiveFunctionValue << std::endl;
+    std::chrono::high_resolution_clock::time_point endPoint = std::chrono::high_resolution_clock::now();
+    std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(endPoint - start);
+    std::cout << "Time: " << time.count() << "ms";
+    file.close();
+}
+
+void knapsack2() {
+    std::fstream file("onemaxtrigger.csv", std::ios::out);
+    if (!file.is_open()) {
+        std::cout << "Cant open file";
+    }
+    /*GeneticAlgorithm instance with parameter: iteration, population, mutateProbability, swapProbability, tournamentsize*/
+    GeneticAlgorithm instance(file, 100, 20, 0.01, 0.6, 7);
+    /*Baco instance with parameter : iteration, population, vaporization, resetThreshhold, ostream */
+    //Baco instance(file, 1000, 20, 0.10, 0.999);
+    //Generate Problem
+    objective::KnapsackProblem knapsack(275.0, 2000);
+    //generate Items
+    double value = 5;
+    double weight = 0;
+    for (int i = 1; i < 99; i++) {
+        objective::Item item;
+        bool trigger = false;
+        //item.value = normal_pdf(i/100.0, 0.5, 0.5) * 10.0 * (trigger? 0:1);
+
+        //std::cout << item.value << " ";
+        item.weight = weight;
+        knapsack.itemVec.push_back(item);
+    }
+    //Bind as callable object
+    auto f1 = std::bind(&objective::KnapsackProblem::function, &knapsack, std::placeholders::_1);
+    Solution sol = instance.execute(10, 100, objective::onemaxTrigger, BinaryHeuristic::ObjectiveFunctionGoal::max);
+    std::cout << "Value: " << sol.objectiveFunctionValue << std::endl;
+    file.close();
+}
+
+int main()
+{
+    onemax();
+    return 0;
+}
+// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
+// Debug program: F5 or Debug > Start Debugging menu
+
+// Tips for Getting Started: 
+//   1. Use the Solution Explorer window to add/manage files
+//   2. Use the Team Explorer window to connect to source control
+//   3. Use the Output window to see build output and other messages
+//   4. Use the Error List window to view errors
+//   5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
+//   6. In the future, to open this project again, go to File > Open > Project and select the .sln file

+ 169 - 0
Metaheuristics/Metaheuristics.vcxproj

@@ -0,0 +1,169 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Debug|x64">
+      <Configuration>Debug</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <ProjectGuid>{5C72CD50-6274-4B64-93B1-68DC780190ED}</ProjectGuid>
+    <Keyword>Win32Proj</Keyword>
+    <RootNamespace>Metaheuristics</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>true</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v142</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <LinkIncremental>true</LinkIncremental>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <LinkIncremental>false</LinkIncremental>
+  </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <PrecompiledHeader>
+      </PrecompiledHeader>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>true</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+    </ClCompile>
+    <Link>
+      <SubSystem>Console</SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <ItemGroup>
+    <ClCompile Include="BinaryAntColonyAlgoritm.cpp" />
+    <ClCompile Include="BinaryHeuristic.cpp" />
+    <ClCompile Include="GeneticAlgorithm.cpp" />
+    <ClCompile Include="Metaheuristics.cpp" />
+    <ClCompile Include="ObjectiveFunction.cpp" />
+    <ClCompile Include="Random.cpp" />
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="BinaryAntColonyAlgoritm.h" />
+    <ClInclude Include="BinaryHeuristic.h" />
+    <ClInclude Include="GeneticAlgorithm.h" />
+    <ClInclude Include="ObjectiveFunction.h" />
+    <ClInclude Include="Random.h" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 54 - 0
Metaheuristics/Metaheuristics.vcxproj.filters

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup>
+    <Filter Include="Source Files">
+      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+    </Filter>
+    <Filter Include="Header Files">
+      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+      <Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
+    </Filter>
+    <Filter Include="Resource Files">
+      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+    </Filter>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="Metaheuristics.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="ObjectiveFunction.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="BinaryAntColonyAlgoritm.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Random.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="GeneticAlgorithm.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="BinaryHeuristic.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+  </ItemGroup>
+  <ItemGroup>
+    <ClInclude Include="ObjectiveFunction.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="BinaryAntColonyAlgoritm.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Random.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="GeneticAlgorithm.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="BinaryHeuristic.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+  </ItemGroup>
+</Project>

+ 120 - 0
Metaheuristics/ObjectiveFunction.cpp

@@ -0,0 +1,120 @@
+#include "ObjectiveFunction.h"
+#include <algorithm>
+#include <iostream>
+
+double objective::onemaxLinear(const std::vector<bool>& bitstring)
+{
+	return (double)std::count(bitstring.begin(), bitstring.end(), true);
+}
+
+double objective::onemaxWithTrap(const std::vector<bool>& bitstring)
+{
+	int x = std::count(bitstring.begin(), bitstring.end(), true);
+	if (x < 70) {
+		return x;
+	}
+	else if (70 <= x && x < 80) {
+		return x;//70 + x*0.000000001;//return 140.0 - x;
+	}
+	else if (80 <= x && x < 90) {
+		return x;//70 + x*0.000000001;//return x - 20.0;
+	}
+	else {
+		return 3.0*x -200.0;
+	}
+
+	
+}
+float normal_pdf(float x, float m, float s)
+{
+	static const float inv_sqrt_2pi = 0.3989422804014327;
+	float a = (x - m) / s;
+
+	return inv_sqrt_2pi / s * std::exp(-0.5f * a * a);
+}
+double objective::onemaxTrigger(const std::vector<bool>& bitstring)
+{
+	if (bitstring.size() != 100) {
+		return 0;
+	}
+	double sum = 0;
+	if (bitstring[0]) sum += normal_pdf(0 / 100.0, 0.5, 0.5);
+	if (bitstring[99]) sum += normal_pdf(99 / 100.0, 0.5, 0.5);
+	for (int i = 1; i < 99; i++) {
+		bool trigger = bitstring[i-1] && bitstring[i] && bitstring[i+1];
+		if(bitstring[i]) sum += (1 - normal_pdf(i / 100.0, 0.5, 0.5)) * (trigger ? 0 : 1);
+	}
+	return sum;
+}
+
+
+
+
+
+
+Solution::Solution()
+{
+}
+
+Solution::Solution(std::vector<bool> bitstring, double objectiveFunctionValue):
+	bitstring(bitstring), objectiveFunctionValue(objectiveFunctionValue)
+{
+}
+
+std::string Solution::bitstringToStdString()
+{
+	std::string str(bitstring.size(), 0);
+	std::transform(bitstring.begin(), bitstring.end(), str.begin(),
+		[](bool b) -> char { return b?'1':'0'; });
+	return str;
+}
+
+objective::KnapsackProblem::KnapsackProblem(double weightLimit, double limitPenalty) : weightLimit(weightLimit), limitPenalty(limitPenalty)
+{
+}
+
+double objective::KnapsackProblem::function(const std::vector<bool>& bitstring)
+{
+	double value = 0, weight = 0;
+	int lastIndex = std::min(itemVec.size(), bitstring.size());
+	for (int i = 0; i < lastIndex; i++) {
+		if (bitstring[i]) {
+			value += itemVec[i].value;
+			weight += itemVec[i].weight;
+		}
+	}
+	if (weight < weightLimit) {
+		return value;
+	}
+	return value -limitPenalty;
+}
+
+objective::OneMax::OneMax(int n, int k): results(n+1)
+{
+	generateKStep(k);
+}
+
+void objective::OneMax::generateKStep(int step)
+{
+	std::cout << "Results:";
+	int result = 0;
+	for(int i = 0; i < results.size(); i++) {
+		results[i] = result;
+		std::cout << result << " ";
+		if (i % step == 0) {
+			result++;
+		}
+	}
+	std::cout << std::endl;
+}
+
+double objective::OneMax::function(const std::vector<bool>& bitstring)
+{
+	int x = std::count(bitstring.begin(), bitstring.end(), true);
+	if (x < results.size()) {
+		return results[x];
+	}
+	else {
+		return results[results.size() - 1];
+	}
+}

+ 42 - 0
Metaheuristics/ObjectiveFunction.h

@@ -0,0 +1,42 @@
+#pragma once
+#include<vector>
+#include<string>
+
+
+
+struct Solution {
+    std::vector<bool> bitstring;
+    double objectiveFunctionValue;
+    Solution();
+    Solution(std::vector<bool> bitstring, double objectiveFunctionValue);
+    std::string bitstringToStdString();
+};
+namespace objective {
+	double onemaxLinear(const std::vector<bool>& bitstring);
+    double onemaxWithTrap(const std::vector<bool>& bitstring);
+    double onemaxTrigger(const std::vector<bool>& bitstring);
+    class OneMax{
+    public:
+        std::vector<int> results;
+        OneMax(int n, int k);
+        void generateKStep(int k);
+        double function(const std::vector<bool>&);
+    };
+    // 
+    struct Item {
+        double value;
+        double weight;
+    };
+    class KnapsackProblem {
+    public:
+        KnapsackProblem(double weightLimit,double limitPenalty);
+        // List of items that can be selected
+        std::vector<Item> itemVec;
+        // Limit of the maximum weight that will apply the penalty
+        double weightLimit;
+        // The penalty for exceeding the limit
+        double limitPenalty;
+        double function(const std::vector<bool>&);
+    };
+}
+

+ 20 - 0
Metaheuristics/Random.cpp

@@ -0,0 +1,20 @@
+#include "Random.h"
+
+PseudoRandom::PseudoRandom(): generator(rd()), boolDistribution(0.5), doubleDistribution(0,1)
+{
+}
+
+bool PseudoRandom::randomBool()
+{
+	return boolDistribution(generator);
+}
+
+double PseudoRandom::doubleRandom()
+{
+	return doubleDistribution(generator);
+}
+
+int PseudoRandom::randomIntegerInRange(int min, int max)
+{
+	return std::uniform_int_distribution(min,max-1)(generator);
+}

+ 16 - 0
Metaheuristics/Random.h

@@ -0,0 +1,16 @@
+#pragma once
+#include <random>
+class PseudoRandom
+{
+public:
+	PseudoRandom();
+	bool randomBool();
+	double doubleRandom();
+	int randomIntegerInRange(int min, int max);
+private:
+	std::random_device rd;  //Will be used to obtain a seed for the random number engine
+	std::mt19937 generator; //Standard mersenne_twister_engine seeded with rd()
+	std::bernoulli_distribution boolDistribution;
+	std::uniform_real_distribution<double> doubleDistribution;
+};
+

+ 99 - 0
metavis/BitInspector.cpp

@@ -0,0 +1,99 @@
+#include "pch.h"
+#include "BitInspector.h"
+
+#define ItemWidth 20
+#define FieldStart 170
+#define EmptySpaceRight 5
+#define EmptySpaceBottom 40
+#define HeaderSpace 0
+
+BitInspector::BitInspector(QWidget* parent)
+	: QWidget(parent)
+{
+	//DummyData
+	//std::vector< SolutionPointData>* dummyVec = new std::vector< SolutionPointData>();
+	//SolutionPointData data;
+	//data.iteration = 20;
+	//data.bitVec.push_back(true);
+	//data.objectiveFunction = 230.234;
+	//data.particleNumber = 120;
+	//dummyVec->push_back(data);
+	//begin = dummyVec->begin();
+	//end = dummyVec->end();
+}
+
+BitInspector::~BitInspector()
+{
+	
+}
+
+void BitInspector::updateData(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end)
+{
+	this->begin = begin;
+	this->end = end;
+	setMinimumSize(FieldStart + begin->bitVec.size() * 1 + EmptySpaceRight, std::distance(begin, end) * ItemWidth + EmptySpaceBottom + HeaderSpace);
+	update();
+}
+
+void BitInspector::clear()
+{
+	begin = std::vector<SolutionPointData>::iterator();
+	end = std::vector<SolutionPointData>::iterator();
+	update();
+}
+
+
+void BitInspector::keyPressEvent(QKeyEvent* event)
+{
+
+}
+
+void BitInspector::paintEvent(QPaintEvent* event)
+{
+	if (begin == end) {
+		return;
+	}
+	int value = (parentWidget()->size().width() - FieldStart - EmptySpaceRight) / begin->bitVec.size();
+
+	if (value > 1) {
+		sizePerBit = value;
+	}
+	else {
+		sizePerBit = 1;
+	}
+	//PaintList
+	QPainter painter(this);
+	painter.setRenderHint(QPainter::RenderHint::HighQualityAntialiasing);
+	painter.setFont(QFont("Arial", 8));
+	painter.setPen(QColor(0, 0, 0));
+	QRect rect(event->rect());
+	rect.moveTop(rect.top() - parentWidget()->size().height());
+	int minimumY = rect.top() - parentWidget()->size().height();
+	int maximumY = rect.bottom() + parentWidget()->size().height();
+
+	QPen blackPen(QColor(0, 0, 0));
+	QPen whitePen(QColor(255, 255, 255));
+	int iteration = 0;
+	int drawSize = (sizePerBit > 1)? sizePerBit - 1: 1;
+	if (begin != end) {
+		painter.fillRect(QRect(FieldStart -1 , 0, begin->bitVec.size() * sizePerBit, std::distance(begin, end) * ItemWidth), Qt::lightGray);
+		int width = FieldStart + begin->bitVec.size() * sizePerBit;
+		for (auto iter = begin; iter != end; iter++) {
+			int startY = (iteration++) * ItemWidth + HeaderSpace;
+			if (startY <= minimumY) continue;
+			if (startY >= maximumY) break;
+			QRect textRect(0, startY, 40, ItemWidth);
+			painter.drawText(textRect, Qt::AlignCenter, QString::number(iter->iteration));
+			textRect.moveLeft(40);
+			painter.drawText(textRect, Qt::AlignCenter, QString::number(iter->particleNumber));
+			textRect.moveLeft(80);
+			textRect.setWidth(90);
+			painter.drawText(textRect, Qt::AlignCenter, QString::number(iter->objectiveFunction, 'f', 1));
+			//painter.setPen(blackPen);
+			for (int j = 0; j < iter->bitVec.size(); j++) {
+				painter.fillRect(FieldStart + j * sizePerBit, startY, drawSize, ItemWidth, (iter->bitVec[j]) ? blackPen.color() : whitePen.color());
+			}
+			painter.fillRect(FieldStart, startY, width - FieldStart, 1 ,QColor(140,140,140));
+		}
+	}
+}

+ 27 - 0
metavis/BitInspector.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include <QWidget>
+#include "RunData.h"
+#include <QString>
+#include <vector>
+
+
+
+class BitInspector : public QWidget
+{
+	Q_OBJECT
+
+public:
+	std::vector<SolutionPointData>::iterator begin;
+	std::vector<SolutionPointData>::iterator end;
+	int sizePerBit = 3;
+
+	QPixmap map;
+	BitInspector(QWidget *parent);
+	~BitInspector();
+	void updateData(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end);
+	void clear();
+private:
+	void keyPressEvent(QKeyEvent* event) override;
+	void paintEvent(QPaintEvent* event) override;
+};

+ 78 - 0
metavis/BitInspectorPanel.cpp

@@ -0,0 +1,78 @@
+#include "pch.h"
+#include "BitInspectorPanel.h"
+#include <QScrollArea>
+#include <QPushButton>
+#include <QVBoxLayout>
+#include <QHBoxLayout>
+#include <QSettings>
+#include <QApplication>
+#include <QDesktopWidget>
+
+BitInspectorPanel::BitInspectorPanel(QWidget *parent)
+	: QWidget(parent), inspector(new BitInspector(this))
+{
+	QScrollArea* scrollArea = new QScrollArea(this);
+	scrollArea->setWidget(inspector);
+	scrollArea->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+	scrollArea->setWidgetResizable(true);
+	QVBoxLayout* layout = new QVBoxLayout(this);
+	layout->setContentsMargins(0, 0, 0, 0);
+	layout->setSpacing(0);
+	topPanel = new QHBoxLayout();
+	topPanel->setContentsMargins(0, 0, 0, 0);
+	topPanel->setSpacing(0);
+	topPanel->addWidget(new QLabel("Iteration"));
+	topPanel->addSpacing(2);
+	topPanel->addWidget(new QLabel("Number"));
+	topPanel->addSpacing(2);
+	topPanel->addWidget(new QLabel("ObjectiveFunction"));
+	topPanel->addSpacing(2);
+	topPanel->addWidget(new QLabel("Binary"));
+	topPanel->addStretch();
+	runNameLabel = new QLabel("");
+	topPanel->addWidget(runNameLabel);
+
+	layout->addLayout(topPanel);
+	layout->addWidget(scrollArea);
+	popupWidget->setInformation("<h3><u>Inspector</u></h3> Shows all solution of a repetition. Each solution gets displayed in a row.<br><br><b>Iteration:</b> Show the iteration in which the solution is generated.<br><b>Number:</b> Shows which individual in the population is represented.<br><b>Objective Function:</b> Objective Function: Describes how optimal the solution is. Depending on the problem, a low or high value is desired.<br><b>Binary:</b> Shows the bitstring of the solution. White rectangle represents the bit is <i>false<i> and black <i>true<i>.");
+	informationButton->setMinimumSize(20, 20);
+	informationButton->setMaximumSize(20, 20);
+	informationButton->setIcon(QIcon(":/metavis/Resources/information_icon.svg"));
+	informationButton->setHoveredIcon(QIcon(":/metavis/Resources/information_icon_hovered.svg"));
+	informationButton->setAttribute(Qt::WA_TranslucentBackground);
+	informationButton->setStyleSheet(informationButton->styleSheet() + "border: none;");
+	informationButton->setToolTip("Information");
+	connect(informationButton, &QPushButton::released, this, &BitInspectorPanel::showInformation);
+	topPanel->addWidget(informationButton);
+}
+
+BitInspectorPanel::~BitInspectorPanel()
+{
+}
+
+void BitInspectorPanel::setRunName(std::string& string)
+{
+	runNameLabel->setText("\"" + QString::fromStdString(string) + "\"");
+}
+
+void BitInspectorPanel::removeRun()
+{
+	inspector->clear();
+	runNameLabel->setText("");
+}
+
+void BitInspectorPanel::showInformation()
+{
+	QPoint position = QCursor::pos();
+	popupWidget->width();
+	QRect screen = QApplication::desktop()->screenGeometry();
+	if (position.x() + popupWidget->width() > screen.width()) {
+		popupWidget->move(screen.width() - popupWidget->width(), position.y());
+	}
+	else {
+		popupWidget->move(position.x(), position.y());
+
+	}
+	popupWidget->show();
+
+}

+ 24 - 0
metavis/BitInspectorPanel.h

@@ -0,0 +1,24 @@
+#pragma once
+
+#include <QWidget>
+#include "BitInspector.h"
+#include <string>
+#include "HoverButton.h"
+#include "InformationPopUp.h"
+class BitInspectorPanel : public QWidget
+{
+	Q_OBJECT
+
+public:
+	BitInspectorPanel(QWidget *parent);
+	~BitInspectorPanel();
+	BitInspector* inspector;
+	QLabel* runNameLabel;
+	void setRunName(std::string& string);
+	void removeRun();
+	void showInformation();
+protected:
+	HoverButton* informationButton = new HoverButton();
+	InformationPopUp* popupWidget = new InformationPopUp(nullptr);
+	QHBoxLayout* topPanel;
+};

+ 143 - 0
metavis/Bitfield.cpp

@@ -0,0 +1,143 @@
+#include "pch.h"
+#include "Bitfield.h"
+#include <QSlider>
+#include <QTimer>
+#include <QCursor>
+
+
+Bitfield::Bitfield(QWidget *parent)
+	: SearchSpacePlott(parent)
+{
+	setAxisLegend("Position", "#SetBits");
+}
+
+Bitfield::~Bitfield()
+{
+	
+}
+
+void Bitfield::frameGraphInView()
+{
+	setVisibleWindow(0, 1, 0, maxAmountOfSetBits);
+	window.ZoomOut(0.05);
+	update();
+}
+
+
+
+void Bitfield::drawData(QPainter& painter)
+{
+	painter.setPen(Qt::lightGray);
+	painter.setBrush(Qt::Dense4Pattern);
+	painter.drawRect(this->getDisplayRect());
+	painter.setPen(Qt::black);
+	painter.setBrush(Qt::NoBrush);
+	painter.fillRect(QRectF(transformGraphToView(QPointF(0, maxAmountOfSetBits)), transformGraphToView(QPointF(1, 0))), Qt::white);
+	painter.drawRect(QRectF(transformGraphToView(QPointF(0, maxAmountOfSetBits)), transformGraphToView(QPointF(1, 0))));
+
+	//Draw Dots
+	QPen linePen;
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+
+	for (const GraphPlottSeries& graphSeries : seriesVec) {
+		if (!graphSeries.data) {
+			qDebug() << "Pointer to nothing pls help";
+			continue;
+		}
+		if (graphSeries.data->empty() || graphSeries.hide) continue;
+		linePen.setWidth(2);
+		linePen.setColor(Qt::transparent);
+		painter.setPen(linePen);
+		for (auto data : *graphSeries.data) {
+			if (data.orginalPoint->iteration < minIter) {
+				continue;
+			}
+			if (data.orginalPoint->iteration > maxIter) {
+				break;
+			}
+			QColor color = data.color;
+			color.setAlphaF(this->transparentAlphaValue);
+			linePen.setColor(Qt::transparent);
+			painter.setPen(linePen);
+			painter.setBrush(color);
+			if (window.inBound(data.toQPointF())) {
+				painter.drawEllipse(transformGraphToView(data.toQPointF(), stregth_factorX, stregth_factorY, translation), circleSize, circleSize);
+			}
+		}
+		painter.setBrush(Qt::BrushStyle::NoBrush);
+	}
+}
+
+
+
+
+
+void Bitfield::searchForPointUnderCursor()
+{
+	//check if mouse stayed still
+	QPoint globalPosition = QCursor::pos();
+	QPointF pos = this->mapFromGlobal(globalPosition);
+
+	if (pos != lastPosition){
+		return;
+	}
+	if (seriesVec.empty() || seriesVec[0].data->empty()) {
+		return;
+	}
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+
+	const GraphDataPoint* min = &seriesVec[0].data->at(0);
+	double minSqaredDistance = sqaredDistance(transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation), pos);
+	std::vector<GraphPlottSeries>::iterator actualBestSeries = seriesVec.begin();
+	for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) {
+		for (const GraphDataPoint& point : *seriesIter->data) {
+			if (point.orginalPoint->iteration < minIter) {
+				continue;
+			}
+			if (point.orginalPoint->iteration > maxIter) {
+				break;
+			}
+			double distance = sqaredDistance(transformGraphToView(point.toQPointF(), stregth_factorX, stregth_factorY, translation), pos);
+			if (distance < minSqaredDistance) {
+				minSqaredDistance = distance;
+				min = &point;
+				actualBestSeries = seriesIter;
+			}
+		}
+	}
+	//if curser is radius + 3pixel away
+	if (minSqaredDistance <= circleSize * circleSize + 9) {
+		QPointF pointInWidget = transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation);
+		QToolTip::showText(this->mapToGlobal(QPoint(pointInWidget.x(), pointInWidget.y())) - QPoint(0, 35), QString::fromStdString(min->orginalPoint->bitstringToStdString()));
+	}
+}
+
+void Bitfield::addPointsInWindowToScratchPad(VisibleWindow& window)
+{
+	if (!pad) {
+		qDebug() << "NoPad";
+		return;
+	}
+	for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) {
+		if (seriesIter->hide) continue;
+		for (const GraphDataPoint& point : *seriesIter->data) {
+			if (point.orginalPoint->iteration < minIter) {
+				continue;
+			}
+			if (point.orginalPoint->iteration > maxIter) {
+				break;
+			}
+			if (window.inBound(point.toQPointF()) && point.existLink()) {
+				pad->addPoint(*point.orginalPoint);
+			}
+		}
+	}
+}
+
+

+ 20 - 0
metavis/Bitfield.h

@@ -0,0 +1,20 @@
+#pragma once
+#include "SearchSpacePlott.h"
+
+class Bitfield : public SearchSpacePlott
+{
+	Q_OBJECT
+
+public:
+	unsigned int maxAmountOfSetBits = 5;
+	Bitfield(QWidget *parent);
+	~Bitfield();
+	void frameGraphInView() override;
+protected:
+	void drawData(QPainter& painter) override;
+	void searchForPointUnderCursor() override;
+	void addPointsInWindowToScratchPad(VisibleWindow& window) override;
+private:
+	
+
+};

+ 88 - 0
metavis/BitfieldControlPanel.cpp

@@ -0,0 +1,88 @@
+#include "pch.h"
+#include "BitfieldControlPanel.h"
+#include <QSettings>
+
+BitfieldControlPanel::BitfieldControlPanel(QWidget *parent)
+	: QWidget(parent)
+{
+	QVBoxLayout* layout = new QVBoxLayout(this);
+	layout->setContentsMargins(0, 0, 0, 0);
+
+	layout->addWidget(field);
+	field->setAxisLegend("Position", "#SetBits");
+	showOptionsButton = new QPushButton("Hide Options");
+	layout->addWidget(showOptionsButton);
+	connect(showOptionsButton, &QPushButton::pressed, this, &BitfieldControlPanel::toggleOptions);
+	layout->addWidget(slider);
+	slider->setTitle("Iteration:");
+	
+	//Connect slider with field
+	connect(slider, &RangeSlider::maxChanged, field, &Bitfield::setMaximumIterationToDispaly);
+	connect(slider, &RangeSlider::minChanged, field, &Bitfield::setMinimumIterationToDispaly);
+	connect(gradient, &ColorGradient::gradientChanged, this, &BitfieldControlPanel::updateDotColorsFromDisplayedRun);
+
+	layout->addWidget(gradient);
+	field->frameGraphInView();
+
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("BitField");
+	if (settings.value("hideOptions", true).toBool()) {
+		toggleOptions();
+	}
+	settings.endGroup();
+}
+
+BitfieldControlPanel::~BitfieldControlPanel()
+{
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("BitField");
+	settings.setValue("hideOptions",this->isOptionHidden);
+	settings.endGroup();
+}
+
+void BitfieldControlPanel::updateDotColorsFromDisplayedRun()
+{
+	if (!displayedRun || displayedRun->dotsForBitField.empty() || !displayedRun->dotsForBitField.back().existLink()) {
+		return;
+	}
+	for (GraphDataPoint& dot : displayedRun->dotsForBitField) {
+		dot.color = gradient->getColorFromValue(dot.orginalPoint->objectiveFunction);
+	}
+	field->update();
+}
+
+void BitfieldControlPanel::displaySingleRun(SingleRun* run)
+{
+	displayedRun = run;
+	updateDotColorsFromDisplayedRun();
+	field->removeAll();
+	field->addSeries(&run->dotsForBitField, run->name, "", QColor(Qt::black), GraphPlottSeries::SeriesType::Dot);
+	if (!run->dotsForBitField.empty() && run->dotsForBitField.back().existLink()) {
+		field->maxAmountOfSetBits = run->dotsForBitField.back().orginalPoint->bitVec.size();
+		if (run->dotsForBitField.front().orginalPoint->iteration < slider->getMinRange()) {
+			slider->setMinRange(run->dotsForBitField.front().orginalPoint->iteration);
+		}
+		if (run->dotsForBitField.back().orginalPoint->iteration > slider->getMaxRange()) {
+			slider->setMaxRange(run->dotsForBitField.back().orginalPoint->iteration);
+		}
+		
+	}
+	
+	field->frameGraphInView();
+}
+
+void BitfieldControlPanel::clearRun()
+{
+	displayedRun = nullptr;
+	field->removeAll();
+}
+
+void BitfieldControlPanel::toggleOptions()
+{
+	this->isOptionHidden = !this->isOptionHidden;
+	showOptionsButton->setText(this->isOptionHidden ? "More Options" : "Hide Options");
+	this->slider->setHidden(this->isOptionHidden);
+	this->gradient->setHidden(this->isOptionHidden);
+}

+ 29 - 0
metavis/BitfieldControlPanel.h

@@ -0,0 +1,29 @@
+#pragma once
+#include <QWidget>
+#include <QPushButton>
+#include "Bitfield.h"
+#include "RangeSlider.h"
+#include "ColorGradient.h"
+#include "RunData.h"
+
+
+class BitfieldControlPanel : public QWidget
+{
+	Q_OBJECT
+
+public:
+	BitfieldControlPanel(QWidget *parent);
+	~BitfieldControlPanel();
+	void updateDotColorsFromDisplayedRun();
+	void displaySingleRun(SingleRun* run);
+	void clearRun();
+	Bitfield* field = new Bitfield(this);
+protected:
+	RangeSlider* slider = new RangeSlider(this);
+	ColorGradient* gradient = new ColorGradient(this);
+	bool isOptionHidden = false;
+	void toggleOptions();
+private:
+	QPushButton* showOptionsButton;
+	SingleRun* displayedRun = nullptr;
+};

+ 0 - 3
metavis/ColorButton.cpp

@@ -35,13 +35,10 @@ void ColorButton::updateVisual()
 
 void ColorButton::resizeEvent(QResizeEvent* event)
 {
-	qDebug() << "Hello Resize";
-	qDebug() << "New Size: " << height() << "," << width();
 }
 
 void ColorButton::openColorMenu()
 {
-	qDebug() << "Hello World";
 	QColor color = QColorDialog::getColor(this->color, this, "Set Color", QColorDialog::ShowAlphaChannel);
 	if (!color.isValid()) return;
 	this->color = color;

+ 234 - 48
metavis/ColorGradient.cpp

@@ -1,8 +1,8 @@
 #include "pch.h"
 #include <QLayout>
+#include <QDoubleValidator>
 #include "ColorGradient.h"
 #include "util.h"
-
 #define LeftRightGap 10
 #define ColorExampleStart 30
 #define ColorExmapleHeight 80
@@ -24,31 +24,86 @@ ColorGradient::ColorGradient(QWidget *parent)
 	modeCombobox->addItem("Discrete");
 	connect(modeCombobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
 		this, [this](int index) {this->setMode((ColorGradient::ColorMode)index);});
-	label = new QLabel("Gradient", this);
-	colorbutton = new ColorButton(this, QColor(0,0,0));
-	connect(colorbutton, &ColorButton::colorChanged, this, [this](QColor color) {
-		if (selected != nullptr) selected->color = color;
+	colorButton = new ColorButton(this, QColor(0,0,0));
+	
+	connect(colorButton, &ColorButton::colorChanged, this, [this](QColor color) {
+		if (selected != nullptr) setColorPointColor(*selected, color);
 		});
-
-	QGridLayout* layout = new QGridLayout(this);
-	layout->setContentsMargins(0, 0, 0, 0);
-	layout->setAlignment(Qt::AlignTop);
+	QVBoxLayout* vBoxLayout = new QVBoxLayout(this);
+	vBoxLayout->setContentsMargins(0,0,0,0);
+	QGridLayout* layoutTop = new QGridLayout();
+	vBoxLayout->addLayout(layoutTop);
+	layoutTop->setContentsMargins(0, 0, 0, 0);
+	layoutTop->setAlignment(Qt::AlignTop);
 	spacerH = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
-	layout->addWidget(label, 0, 0);
-	layout->addItem(spacerH, 0, 1);
-	layout->addWidget(colorbutton, 0, 2);
-	layout->addWidget(modeCombobox, 0, 3);
-	layout->addWidget(interpolationCombobox, 0, 4);
-	//layout->(spacer);
+	layoutTop->addWidget(new QLabel("ObjectiveFunction-Gradient:", this), 0, 0);
+	layoutTop->addItem(spacerH, 0, 1);
+
+	layoutTop->addWidget(modeCombobox, 0, 6);
+	layoutTop->addWidget(interpolationCombobox, 0, 7);
+	QGridLayout* layoutBottom = new QGridLayout();
+	vBoxLayout->addLayout(layoutBottom);
+	layoutBottom->setContentsMargins(0, 0, 0, 0);
+	layoutBottom->setAlignment(Qt::AlignBottom);
+	layoutBottom->addItem(new QSpacerItem(10, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 0);
+	colorLabel = new QLabel("Color:");
+	layoutBottom->addWidget(colorLabel, 0, 1);
+	layoutBottom->addWidget(colorButton, 0, 2);
+	alphaLabel = new QLabel("Alpha:");
+	layoutBottom->addWidget(alphaLabel, 0, 3);
 	
-	this->setLayout(layout);
-	pointList.push_back(ColorPoint(0.0, QColor(0, 100, 200)));
-	pointList.push_back(ColorPoint(0.5, QColor(0, 100, 50)));
-	pointList.push_back(ColorPoint(0.7, QColor(200, 10, 10)));
-	this->setMinimumHeight(150);
+	
+
+	layoutTop->addWidget(new QLabel("ValueRange:"), 0, 2);
+	minEdit = new  QLineEdit();
+	minEdit->setMaximumWidth(80);
+	layoutTop->addWidget(minEdit, 0, 3);
+	layoutTop->addWidget(new QLabel(":"), 0, 4);
+	maxEdit = new  QLineEdit();
+	maxEdit->setMaximumWidth(80);
+	layoutTop->addWidget(maxEdit, 0, 5);
+	valueLabel = new QLabel("Value:");
+	layoutBottom->addWidget(valueLabel, 0,5);
+
+
+	QRegExp rxMinMax("[+-]?[0-9]*(\\.[0-9]{0,6})?");
+	QRegExpValidator* validatorMinMax = new QRegExpValidator(rxMinMax, 0);
+	minEdit->setValidator(validatorMinMax);
+	maxEdit->setValidator(validatorMinMax);
+	minEdit->setText(QString::number(minValue));
+	maxEdit->setText(QString::number(maxValue));
+	connect(minEdit, &QLineEdit::editingFinished, this, &ColorGradient::minEditChangeEvent);	
+	connect(maxEdit, &QLineEdit::editingFinished, this, &ColorGradient::maxEditChangeEvent);
+
+	alphaLineEdit = new QLineEdit(this);
+	alphaLineEdit->setMaximumWidth(80);
+	layoutBottom->addWidget(alphaLineEdit, 0, 4);
+
+	valueEdit = new  QLineEdit();
+	valueEdit->setMaximumWidth(80);
+	valueEdit->setValidator(validatorMinMax);
+	connect(valueEdit, &QLineEdit::editingFinished, this, &ColorGradient::setValueOfSelected);
+	layoutBottom->addWidget(valueEdit, 0, 6);
+
+	QRegExp rx("0(\\.[0-9]{0,6})?|1(\\.0*)?");
+	QRegExpValidator* v = new QRegExpValidator(rx, 0);
+	alphaLineEdit->setValidator(v);
+	connect(alphaLineEdit, &QLineEdit::editingFinished, this, &ColorGradient::setAlphaOfSelected);
+
+
+	layoutBottom->addItem(new QSpacerItem(10, 20, QSizePolicy::Expanding, QSizePolicy::Minimum), 0, 7);
+
 	//this->setMinimumHeight(150);
 	this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
-
+	
+	this->setMinimumHeight(150);
+	//Dummy Data
+	//TODO(ColorGradient #1) get gradient from last time or save project
+	pointList.push_back(ColorPoint(0.0, QColor(0, 100, 200)));
+	pointList.push_back(ColorPoint(0.5, QColor(0, 100, 50)));
+	pointList.push_back(ColorPoint(1.0, QColor(200, 10, 10)));
+	//select first
+	selectColorPoint(&pointList.front());
 }
 
 ColorGradient::~ColorGradient()
@@ -56,7 +111,7 @@ ColorGradient::~ColorGradient()
 
 }
 
-QColor ColorGradient::getColor(double alpha)
+QColor ColorGradient::getColorFromAlpha(double alpha)
 {
 	alpha = std::clamp(alpha, 0.0, 1.0);
 	switch(mode) {
@@ -99,6 +154,12 @@ QColor ColorGradient::getColor(double alpha)
 	
 }
 
+QColor ColorGradient::getColorFromValue(double value)
+{
+	double alpha = util::inverseLinearInterpolation(minValue, maxValue, value);
+	return getColorFromAlpha(alpha);
+}
+
 void ColorGradient::addColorPoint(double alpha)
 {
 	auto iter = pointList.begin();
@@ -107,9 +168,7 @@ void ColorGradient::addColorPoint(double alpha)
 			break;
 		}
 	}
-	selected = &*pointList.insert(iter, ColorPoint(alpha, getColor(alpha)));
-	colorbutton->setVisible(true);
-	colorbutton->setColor(selected->color);
+	selectColorPoint(&*pointList.insert(iter, ColorPoint(alpha, getColorFromAlpha(alpha))));
 	emit gradientChanged();
 }
 
@@ -117,10 +176,36 @@ void ColorGradient::removeColorPoint(ColorPoint& pointToRemove)
 {
 	pointList.erase(std::remove_if(pointList.begin(), pointList.end(),
 			[&pointToRemove](ColorPoint& point) {return &point == &pointToRemove; }));
+	//colorButton->setVisible(false);
 	selected = nullptr;
+	hideSelectionEdit(true);
 	emit gradientChanged();
 }
 
+void ColorGradient::setColorPointAlpha(ColorPoint& point, double alpha)
+{
+	alpha = std::clamp(alpha, 0.0, 1.0);
+	if (alpha == point.alpha) return;
+	point.alpha = alpha;
+	pointList.sort([](ColorPoint& a, ColorPoint& b) {
+		return a.alpha < b.alpha;
+		});
+	if (&point == selected) {
+		alphaLineEdit->setText(QString::number(alpha));
+		valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, alpha)));
+	}
+	emit gradientChanged();
+	update();
+}
+
+void ColorGradient::setColorPointColor(ColorPoint& point, QColor newColor)
+{
+	if (newColor == point.color) return;
+	point.color = newColor;
+	emit gradientChanged();
+	update();
+}
+
 void ColorGradient::setMode(ColorMode mode)
 {
 	this->mode = mode;
@@ -136,14 +221,96 @@ void ColorGradient::setInterpolationMode(ColorInterpolationMode mode)
 	emit gradientChanged();
 }
 
+void ColorGradient::setMinValue(double value)
+{
+	if (value > maxValue) {
+		minValue = maxValue;
+		maxValue = value;
+		minEdit->setText(QString::number(minValue));
+		maxEdit->setText(QString::number(maxValue));
+	}
+	else {
+		minValue = value;
+		minEdit->setText(QString::number(minValue));
+	}
+	if (selected != nullptr) {
+		valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, selected->alpha)));
+	}
+	emit gradientChanged();
+}
+
+void ColorGradient::setMaxValue(double value)
+{
+	if (value < minValue) {
+		maxValue = minValue;
+		minValue = value;
+		minEdit->setText(QString::number(minValue));
+		maxEdit->setText(QString::number(maxValue));
+	}
+	else {
+		maxValue = value;
+		maxEdit->setText(QString::number(maxValue));
+	}
+	if (selected != nullptr) {
+		valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, selected->alpha)));
+	}
+	emit gradientChanged();
+}
+
+void ColorGradient::hideSelectionEdit(bool value)
+{
+	colorButton->setHidden(value);
+	alphaLineEdit->setHidden(value);
+	alphaLabel->setHidden(value);
+	colorLabel->setHidden(value);
+	valueEdit->setHidden(value);
+	valueLabel->setHidden(value);
+}
+
+void ColorGradient::setAlphaOfSelected()
+{
+	if (selected == nullptr) return;
+	bool success = false;
+	double alpha = alphaLineEdit->text().toDouble(&success);
+	if (success) {
+		setColorPointAlpha(*selected, alpha);
+	}
+
+}
+
+void ColorGradient::setValueOfSelected()
+{
+	if (selected == nullptr) return;
+	bool success = false;
+	double value = valueEdit->text().toDouble(&success);
+	
+	if (success) {
+		if (value < minValue) {
+			value = minValue;
+		}
+		else if (value > maxValue) {
+			value = maxValue;
+		}
+		setColorPointAlpha(*selected, util::inverseLinearInterpolation(minValue, maxValue, value));
+	}
+}
+
+void ColorGradient::selectColorPoint(ColorPoint* point)
+{
+	selected = point;
+	colorButton->setColor(selected->color);
+	alphaLineEdit->setText(QString::number(selected->alpha));
+	valueEdit->setText(QString::number(util::linearInterpolate(minValue, maxValue, selected->alpha)));
+	hideSelectionEdit(false);
+}
+
 void ColorGradient::paintEvent(QPaintEvent* event)
 {
 	QPainter painter(this);
 	painter.setRenderHint(QPainter::RenderHint::HighQualityAntialiasing);
 	QRect colorExampleRect(QPoint(rect().left() + LeftRightGap, ColorExampleStart), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight));
 	painter.drawRect(colorExampleRect);
-	//painter.drawRect()
-	//drawSlider
+	//drawSliders
 	QPen sliderPen;
 	sliderPen.setWidth(2);
 	painter.setPen(Qt::NoPen);
@@ -170,14 +337,11 @@ void ColorGradient::paintEvent(QPaintEvent* event)
 	}
 	for (int pixelX = colorExampleRect.left() + 1; pixelX < colorExampleRect.right()+1; pixelX++) {
 		double alpha = util::inverseLinearInterpolation(colorExampleRect.left(), colorExampleRect.right()+1, pixelX);
-		QColor color = getColor(alpha);
+		QColor color = getColorFromAlpha(alpha);
 		painter.setPen(color);
 		painter.drawLine(pixelX, colorExampleRect.top() + 1, pixelX, colorExampleRect.bottom());
 	}
-	if (selected != nullptr) {
-		QRect currentSelected(QPoint(rect().right()/2 , SelectedHeight), QPoint(rect().right() / 2 + SelectedPreview, SelectedHeight + SelectedPreview));
-		painter.fillRect(currentSelected, selected->color);
-	}
+	
 
 
 
@@ -186,9 +350,13 @@ void ColorGradient::paintEvent(QPaintEvent* event)
 
 void ColorGradient::mousePressEvent(QMouseEvent* event)
 {
+	if (childAt(event->pos()) != nullptr) {
+		return;
+	}
 	QPoint mousePos = event->pos();
 	QRect area(QPoint(rect().left() + LeftRightGap, ColorExmapleHeight), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight+SliderBody+SliderPeak));
-	if (area.contains(mousePos)) {
+	QRect responisveArea(QPoint(area.left() - SliderPeak * 2, area.top()), QPoint(area.right() + SliderPeak * 2, area.bottom()));
+	if (responisveArea.contains(mousePos)) {
 
 		// Check for existing color point
 		// Select with left mouse Button
@@ -197,13 +365,11 @@ void ColorGradient::mousePressEvent(QMouseEvent* event)
 			double posX = util::linearInterpolate(area.left(), area.right() + 1, point.alpha);
 			if (posX - SliderPeak * 2 < mousePos.x() && mousePos.x() < posX + SliderPeak * 2) {
 				if (event->buttons() & Qt::LeftButton) {
-					selected = &point;
-					colorbutton->setVisible(true);
-					colorbutton->setColor(selected->color);
+					selectColorPoint(&point);
 				}
 				else if(event->buttons() & Qt::RightButton){
 					removeColorPoint(point);
-					colorbutton->setVisible(false);
+					
 				}
 				update();
 				return;
@@ -211,28 +377,48 @@ void ColorGradient::mousePressEvent(QMouseEvent* event)
 		}
 		
 
-
 		// Insert new Color Point
-		double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
-		addColorPoint(alpha);
-		update();
+		if (event->buttons() & Qt::LeftButton) {
+			double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
+			addColorPoint(alpha);
+
+			update();
+		}
 	}
 }
 
 void ColorGradient::mouseMoveEvent(QMouseEvent* event)
 {
 	if (selected == nullptr) return;
+	if (childAt(event->pos()) != nullptr) {
+		return;
+	}
 	//TODO(Bug #1) when mouse press button mouse move gets emitted and move the selected
 	//currently a workarround to not move the selected colorpoint when selecting a button
-	if (event->pos().y() < ColorExmapleHeight) return;
+	//if (event->pos().y() < ColorExmapleHeight) return;
+
 	QPoint mousePos = event->pos();
 	QRect area(QPoint(rect().left() + LeftRightGap, ColorExmapleHeight), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight + SliderBody + SliderPeak));
 	double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
-	selected->alpha = std::clamp(alpha, 0.0, 1.0);
+	this->setColorPointAlpha(*selected, alpha);
 
-	pointList.sort([](ColorPoint& a, ColorPoint& b) {
-		return a.alpha < b.alpha;
-		});
-	emit gradientChanged();
-	update();
+
+}
+
+void ColorGradient::minEditChangeEvent()
+{
+	bool success = false;
+	double value = minEdit->text().toDouble(&success);
+	if (success) {
+		this->setMinValue(value);
+	}
+}
+
+void ColorGradient::maxEditChangeEvent()
+{
+	bool success = false;
+	double value = maxEdit->text().toDouble(&success);
+	if (success) {
+		this->setMaxValue(value);
+	}
 }

+ 24 - 3
metavis/ColorGradient.h

@@ -4,6 +4,7 @@
 #include <QColor>
 #include <QComboBox>
 #include <list>
+#include <QLineEdit>
 #include "ColorButton.h"
 
 struct ColorPoint {
@@ -22,26 +23,46 @@ public:
 	enum ColorMode{ Interpolate, Discrete};
 	ColorGradient(QWidget *parent);
 	~ColorGradient();
-	QColor getColor(double alpha);
+	QColor getColorFromAlpha(double alpha);
+	QColor getColorFromValue(double value);
 	void addColorPoint(double alpha);
 	void removeColorPoint(ColorPoint& point);
+	void setColorPointAlpha(ColorPoint& point, double newAlpha);
+	void setColorPointColor(ColorPoint& point, QColor newColor);
 	void setMode(ColorMode mode);
 	void setInterpolationMode(ColorInterpolationMode mode);
+	void setMinValue(double value);
+	void setMaxValue(double value);
 private:
+	double minValue = 0, maxValue = 100;
 	ColorMode mode = ColorMode::Interpolate;
 	ColorInterpolationMode interpolationMode = ColorInterpolationMode::RGB;
 	std::list<ColorPoint> pointList;
 	//UI
+	QLineEdit* minEdit;
+	QLineEdit* maxEdit;
 	ColorPoint* selected = nullptr;
 	QComboBox* interpolationCombobox = nullptr;
 	QComboBox* modeCombobox = nullptr;
 	QSpacerItem* spacerH = nullptr;
-	QLabel* label = nullptr;
-	ColorButton* colorbutton = nullptr;
+	QLineEdit* alphaLineEdit = nullptr;
+	ColorButton* colorButton = nullptr;
+	QLineEdit* valueEdit;
+	QLabel* colorLabel;
+	QLabel* alphaLabel; 
+	QLabel* valueLabel;
+	void hideSelectionEdit(bool value);
+	void setAlphaOfSelected();
+	void setValueOfSelected();
+	void selectColorPoint(ColorPoint* point);
 	void paintEvent(QPaintEvent* event) override;
 	void mousePressEvent(QMouseEvent* event) override;
 	void mouseMoveEvent(QMouseEvent* event) override;
 
+	void minEditChangeEvent();
+	void maxEditChangeEvent();
+
+
 signals:
 	void gradientChanged();
 };

+ 65 - 0
metavis/Concurrent.cpp

@@ -0,0 +1,65 @@
+#include "pch.h"
+#include "Concurrent.h"
+#include <QDebug>
+
+Concurrent::Concurrent()
+{
+}
+
+Concurrent::~Concurrent()
+{
+	reset();
+}
+
+void Concurrent::start()
+{
+	qDebug() << "Hello Start";
+	if (thread != nullptr) reset();
+	qDebug() << "Start after reset";
+	thread = new std::thread(&Concurrent::run, this);
+	qDebug() << "Start end";
+}
+
+void Concurrent::pause()
+{
+	paused = !paused;
+	cv.notify_one();
+}
+
+void Concurrent::reset()
+{
+	qDebug() << "Hello Reset";
+	cancel = true;
+	paused = false;
+	cv.notify_one();
+	if (thread != nullptr) {
+		thread->join();
+		delete thread;
+		thread = nullptr;
+	}
+	cancel = false;
+}
+
+
+
+void Concurrent::run()
+{
+	for (;false;) {
+		checkPaused();
+		if (checkCancel()) { break; }
+	}
+}
+
+bool Concurrent::checkCancel()
+{
+	return cancel;
+}
+
+void Concurrent::checkPaused()
+{
+	std::unique_lock<std::mutex> lck(mutex);
+	while (paused) {
+		qDebug() << "while";
+		cv.wait(lck);
+	}
+}

+ 28 - 0
metavis/Concurrent.h

@@ -0,0 +1,28 @@
+#pragma once
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+
+class Concurrent
+{
+public:
+	Concurrent();
+	~Concurrent();
+	void start();
+	void pause();
+	void reset();
+
+protected:
+	bool checkCancel();
+	void checkPaused();
+
+
+private:
+	bool paused = false;
+	bool cancel = false;
+	std::thread* thread = nullptr;
+	std::mutex mutex;
+	std::condition_variable cv;
+	void virtual run();
+};
+

+ 3 - 2
metavis/DockableGraphView.cpp

@@ -13,7 +13,7 @@ DockableGraphView::DockableGraphView(QWidget *parent, QString title)
 	view = new GraphView(this, Bound(0, 100, -1.0, 101.0));
 	view->setUseFixedBound(true);
 	view->setMinimumSize(200, 200);
-	dialog = new GraphViewSettingDialog(view, title + " Settings", this);
+	//dialog = new GraphViewSettingDialog(view, title + " Settings", this);
 	QWidget* widget = new QWidget(this);
 	QGridLayout* layout = new QGridLayout;
 	QPushButton* button = new QPushButton();
@@ -23,7 +23,8 @@ DockableGraphView::DockableGraphView(QWidget *parent, QString title)
 	button->setAttribute(Qt::WA_TranslucentBackground);
 	button->setStyleSheet(button->styleSheet() + "border: none;");
 	button->setToolTip("Settings");
-	connect(button, &QPushButton::released, dialog, &GraphViewSettingDialog::openDialog);
+	
+	//connect(button, &QPushButton::released, dialog, &GraphViewSettingDialog::openDialog);
 	layout->addWidget(view, 0, 0, 4, 4);
 	layout->addWidget(button,0, 3, 1, 1);
 	layout->setContentsMargins(0, 0, 0, 0);

+ 1 - 1
metavis/DockableGraphView.h

@@ -8,7 +8,7 @@ class DockableGraphView : public QDockWidget
 	Q_OBJECT
 public:
 	GraphView* view;
-	GraphViewSettingDialog* dialog = nullptr;
+	//GraphViewSettingDialog* dialog = nullptr;
 public:
 	DockableGraphView(QWidget *parent, QString title);
 	~DockableGraphView();

+ 358 - 0
metavis/GraphPlott.cpp

@@ -0,0 +1,358 @@
+#include "pch.h"
+#include "GraphPlott.h"
+#include <QDebug>
+#include <QPen>
+#include <QPushButton>
+#include <QLayout>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include "HoverButton.h"
+#include <QApplication>
+#include <QDesktopWidget>
+
+
+GraphPlott::GraphPlott(QWidget* parent, bool showSettingsButton, bool showInformationButton, bool showGridButton)
+	: Plott(parent)
+{
+	QVBoxLayout* layoutOuter = new QVBoxLayout(this);
+	buttonPanel = new QHBoxLayout();
+	dialog = new GraphViewSettingDialog(this, "Settings");
+	this->setMouseTracking(true);
+
+
+	buttonPanel->insertStretch(0);
+	displayLabel = new QLabel("");
+	buttonPanel->addWidget(displayLabel);
+
+	HoverButton* frameButton = new HoverButton();
+	frameButton->setMinimumSize(20, 20);
+	frameButton->setMaximumSize(20, 20);
+	frameButton->setIcon(QIcon(":/metavis/Resources/frame.svg"));
+	frameButton->setHoveredIcon(QIcon(":/metavis/Resources/frame_hovered.svg"));
+	frameButton->setAttribute(Qt::WA_TranslucentBackground);
+	frameButton->setStyleSheet(frameButton->styleSheet() + "border: none;");
+	frameButton->setToolTip("Frame");
+	buttonPanel->addWidget(frameButton);
+	connect(frameButton, &QPushButton::released, this, &GraphPlott::frameGraphInView);
+
+
+	if (showGridButton) {
+		HoverButton* gridButton = new HoverButton();
+		gridButton->setMinimumSize(20, 20);
+		gridButton->setMaximumSize(20, 20);
+		gridButton->setIcon(QIcon(":/metavis/Resources/gridIcon.svg"));
+		gridButton->setHoveredIcon(QIcon(":/metavis/Resources/gridIcon_hovered.svg"));
+		gridButton->setAttribute(Qt::WA_TranslucentBackground);
+		gridButton->setStyleSheet(gridButton->styleSheet() + "border: none;");
+		gridButton->setToolTip("Toggle Grid");
+		buttonPanel->addWidget(gridButton);
+		connect(gridButton, &QPushButton::released, this, [this]() {this->enableGrid = !this->enableGrid; update(); });
+	}
+	if (showInformationButton) {
+		
+		informationButton->setMinimumSize(20, 20);
+		informationButton->setMaximumSize(20, 20);
+		informationButton->setIcon(QIcon(":/metavis/Resources/information_icon.svg"));
+		informationButton->setHoveredIcon(QIcon(":/metavis/Resources/information_icon_hovered.svg"));
+		informationButton->setAttribute(Qt::WA_TranslucentBackground);
+		informationButton->setStyleSheet(informationButton->styleSheet() + "border: none;");
+		informationButton->setToolTip("Information");
+		connect(informationButton, &QPushButton::released, this, &GraphPlott::showInformation);
+		buttonPanel->addWidget(informationButton);
+	}
+	
+	if (showSettingsButton) {
+		HoverButton* settingsButton = new HoverButton();
+		settingsButton->setMinimumSize(20, 20);
+		settingsButton->setMaximumSize(20, 20);
+		settingsButton->setIcon(QIcon(":/metavis/Resources/settingIcon.svg"));
+		settingsButton->setHoveredIcon(QIcon(":/metavis/Resources/settingIcon_hovered.svg"));
+		settingsButton->setAttribute(Qt::WA_TranslucentBackground);
+		settingsButton->setStyleSheet(settingsButton->styleSheet() + "border: none;");
+		settingsButton->setToolTip("Settings");
+		buttonPanel->addWidget(settingsButton);
+		connect(settingsButton, &QPushButton::released, dialog, &GraphViewSettingDialog::openDialog);
+	}
+
+
+
+
+	buttonPanel->setSpacing(0);
+	buttonPanel->setContentsMargins(0, 0, 0, 0);
+	layoutOuter->addLayout(buttonPanel);
+	layoutOuter->insertStretch(1);
+	layoutOuter->setContentsMargins(0, 0, 0, 0);
+
+	//QMenu
+	selectMenu->addAction(displayAreaAction);
+	selectMenu->addAction(scratchpadAction);
+	displayAreaAction->setShortcut(QKeySequence(Qt::CTRL));
+	scratchpadAction->setShortcut(QKeySequence(Qt::ALT));
+	scratchpadAction->setEnabled(false);
+	//setUpTimer
+	timer->setSingleShot(true);
+	connect(timer, &QTimer::timeout, this, &GraphPlott::searchForPointUnderCursor);
+
+}
+
+GraphPlott::~GraphPlott()
+{
+}
+
+void GraphPlott::addSeries(std::vector<GraphDataPoint>* line, std::string runName, QString description, QColor color, GraphPlottSeries::SeriesType type)
+{
+	if (line->empty()) {
+		qDebug() << "Series is empty!";
+		return;
+	}
+	GraphPlottSeries lgs;
+	lgs.runName = runName;
+	lgs.description = description;
+	lgs.data = line;
+	lgs.type = type;
+	lgs.color = color;
+	//set min max x y
+	auto pairX = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.x < b.x; });
+	lgs.xMin = pairX.first->x;
+	lgs.xMax = pairX.second->x;
+	auto pairY = std::minmax_element(lgs.data->begin(), lgs.data->end(), [](const GraphDataPoint& a, const GraphDataPoint& b) -> bool {return a.y < b.y; });
+	lgs.yMin = pairY.first->y;
+	lgs.yMax = pairY.second->y;
+	seriesVec.push_back(lgs);
+}
+
+
+
+
+void GraphPlott::removeRunData(RunData* run)
+{
+	//Remove all series with this rundata
+	auto iter = std::remove_if(seriesVec.begin(), seriesVec.end(), [run](GraphPlottSeries& series) {return (run->name == series.runName); });
+	seriesVec.erase(iter, seriesVec.end());
+	displayLabel->setText("");
+}
+
+void GraphPlott::removeAll()
+{
+	seriesVec.clear();
+}
+
+void GraphPlott::setInformation(QString information)
+{
+	this->informationButtonString = information;
+	popupWidget->setInformation(information);
+}
+
+std::vector<GraphPlottSeries>& GraphPlott::getSeriesVector()
+{
+	return seriesVec;
+}
+
+void GraphPlott::resetToDefaultWindow()
+{
+	frameGraphInView();
+}
+
+void GraphPlott::frameGraphInView()
+{
+	if(seriesVec.empty()) return;
+	window.xMin = std::min_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.xMin < b.xMin; })->xMin;
+	window.xMax = std::max_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.xMax < b.xMax; })->xMax;
+	window.yMin = std::min_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.yMin < b.yMin; })->yMin;
+	window.yMax = std::max_element(std::begin(seriesVec), std::end(seriesVec), [](const GraphPlottSeries& a, const GraphPlottSeries& b) -> bool {return a.yMax < b.yMax; })->yMax;
+	window.ZoomOut(0.05);
+	update();
+}
+
+void GraphPlott::setDisplayLabel(QString file)
+{
+	displayLabel->setText("\"" + file + "\"   ");
+}
+
+void GraphPlott::setScratchpad(Scratchpad* pad)
+{
+	this->pad = pad;
+	scratchpadAction->setEnabled(true);
+}
+
+
+void GraphPlott::showInformation()
+{
+	QPoint position = QCursor::pos();
+	popupWidget->setInformation(informationButtonString + graphplottInformation);
+	popupWidget->width();
+	QRect screen = QApplication::desktop()->screenGeometry();
+	if (position.x() + popupWidget->width() > screen.width()) {
+		popupWidget->move(screen.width() - popupWidget->width(), position.y());
+	}
+	else {
+		popupWidget->move(position.x(), position.y());
+
+	}
+	popupWidget->show();
+
+}
+
+void GraphPlott::drawData(QPainter& painter)
+{
+	QPen linePen;
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+
+	for (const GraphPlottSeries& graphSeries : seriesVec) {
+		if (!graphSeries.data) {
+			qDebug() << "Pointer to nothing pls help";
+		}
+		if (graphSeries.data->empty() || graphSeries.hide) continue;
+		linePen.setColor(graphSeries.color);
+
+		if (graphSeries.type == GraphPlottSeries::SeriesType::Line || graphSeries.type == GraphPlottSeries::SeriesType::LineDot) {
+			linePen.setWidth(graphSeries.lineWidth/* + ((&graphSeries == highlightSeries) ? 5 : 0)*/);
+			painter.setPen(linePen);
+			QPainterPath painterPath;
+
+			QPointF oldpoint = graphSeries.data->at(0).toQPointF();
+			painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation));
+			for (int i = 1; i < graphSeries.data->size(); i++) {
+				QPointF newpoint = graphSeries.data->at(i).toQPointF();
+				bool inBoundOldPoint = window.inBoundX(oldpoint);
+				bool inBoundNewPoint = window.inBoundX(newpoint);
+				if (!inBoundOldPoint && !inBoundNewPoint) {
+
+				}
+				else if (!inBoundOldPoint && inBoundNewPoint) {
+					painterPath.moveTo(transformGraphToView(oldpoint, stregth_factorX, stregth_factorY, translation));
+					painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
+				}
+				else if (inBoundOldPoint && inBoundNewPoint) {
+					painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
+				}
+				else if (inBoundOldPoint && !inBoundNewPoint) {
+					painterPath.lineTo(transformGraphToView(newpoint, stregth_factorX, stregth_factorY, translation));
+					break;
+				}
+				oldpoint = newpoint;
+			}
+
+			//painterPath.translate(translation);
+			painter.drawPath(painterPath);
+		}
+		if (graphSeries.type == GraphPlottSeries::SeriesType::Dot || graphSeries.type == GraphPlottSeries::SeriesType::LineDot) {
+			linePen.setWidth(2);
+			linePen.setColor(Qt::transparent);
+			painter.setPen(linePen);
+			painter.setBrush(graphSeries.color);
+			const bool useColor = graphSeries.useDataPointColor;
+			for (auto data : *graphSeries.data) {
+				if (useColor){
+					linePen.setColor(data.color);
+					painter.setPen(linePen);
+					painter.setBrush(data.color);
+				}
+				if (window.inBound(data.toQPointF())) {
+					painter.drawEllipse(transformGraphToView(data.toQPointF(), stregth_factorX, stregth_factorY, translation), graphSeries.circleRadius, graphSeries.circleRadius);
+				}
+			}
+			painter.setBrush(Qt::BrushStyle::NoBrush);
+		}
+	}
+}
+
+void GraphPlott::mouseMoveEvent(QMouseEvent* event)
+{
+	Plott::mouseMoveEvent(event);
+	lastPosition = event->pos();
+	timer->start(stayStillTimeMS);
+	QToolTip::hideText();
+}
+
+void GraphPlott::handleSelectedWindow(VisibleWindow& window, QMouseEvent* event)
+{
+	if (event->modifiers() & Qt::ControlModifier) {
+		setWindow(window);
+	}
+	else if (event->modifiers() & Qt::AltModifier) {
+		addPointsInWindowToScratchPad(window);
+	}
+	else {
+		QAction* used = selectMenu->exec(this->mapToGlobal(event->pos()));
+		if(used == displayAreaAction){
+			setWindow(window);
+		}
+		else if (used == scratchpadAction) {
+			addPointsInWindowToScratchPad(window);
+		}
+	}
+	
+}
+
+void GraphPlott::searchForPointUnderCursor()
+{
+	//check if mouse stayed still
+	QPoint globalPosition = QCursor::pos();
+	QPointF pos = this->mapFromGlobal(globalPosition);
+	if (pos != lastPosition) {
+		return;
+	}
+	if (seriesVec.empty() || seriesVec[0].data->empty()) {
+		return;
+	}
+
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+
+	const GraphDataPoint* min = &seriesVec[0].data->at(0);
+	double minSqaredDistance = sqaredDistance(transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation), pos);
+	std::vector<GraphPlottSeries>::iterator actualBestSeries = seriesVec.begin();
+	for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) {
+		for (const GraphDataPoint& point : *seriesIter->data) {
+			double distance = sqaredDistance(transformGraphToView(point.toQPointF(), stregth_factorX, stregth_factorY, translation), pos);
+			if (distance <= minSqaredDistance) {
+				minSqaredDistance = distance;
+				min = &point;
+				actualBestSeries = seriesIter;
+			}
+		}
+	}
+	if (minSqaredDistance <= 20) {
+		QPointF pointInWidget = transformGraphToView(min->toQPointF(), stregth_factorX, stregth_factorY, translation);
+		QToolTip::showText(this->mapToGlobal(QPoint(pointInWidget.x(), pointInWidget.y())) - QPoint(0, 35), actualBestSeries->description);
+	}
+}
+
+double GraphPlott::sqaredDistance(const QPointF& a, const QPointF& b)
+{
+	return std::pow(a.x() - b.x(), 2) + std::pow(a.y() - b.y(), 2);
+}
+
+void GraphPlott::addPointsInWindowToScratchPad(VisibleWindow& window)
+{
+	if (!pad) {
+		qDebug() << "NoPad";
+		return;
+	}
+	for (auto seriesIter = seriesVec.begin(); seriesIter != seriesVec.end(); seriesIter++) {
+		if (seriesIter->hide) continue;
+		for (const GraphDataPoint& point : *seriesIter->data) {
+			if (window.inBound(point.toQPointF()) && point.existLink()) {
+				pad->addPoint(*point.orginalPoint);
+			}
+		}
+	}
+}
+
+void GraphPlott::keyPressEvent(QKeyEvent* event)
+{
+	Plott::keyPressEvent(event);
+	switch (event->key()) {
+	case Qt::Key_T:
+		frameGraphInView();
+		break;
+	default:
+		break;
+	}
+}

+ 79 - 0
metavis/GraphPlott.h

@@ -0,0 +1,79 @@
+#pragma once
+#include <vector>
+
+#include "Plott.h"
+#include "RunData.h"
+#include "GraphViewSettingDialog.h"
+#include <QString>
+#include <QLabel>
+#include <string>
+#include "Scratchpad.h"
+#include "HoverButton.h"
+#include "InformationPopUp.h"
+class GraphViewSettingDialog;
+
+struct GraphPlottSeries {
+	std::vector<GraphDataPoint>* data;
+	double xMin, xMax;
+	double yMin, yMax;
+	std::string runName;
+
+
+
+	//Settings for visual
+	QString description;
+	QColor color;
+	int lineWidth = 2;
+	double circleRadius = 2.0;
+	enum class SeriesType { Line, Dot, LineDot };
+	bool useDataPointColor = false;
+	SeriesType type;
+	bool hide = false;
+};
+
+class GraphPlott : public Plott
+{
+	Q_OBJECT
+
+public:
+
+	GraphPlott(QWidget *parent,bool settingsButton = true, bool informationButton = true, bool gridButton = true);
+	~GraphPlott();
+	void addSeries(std::vector<GraphDataPoint>* line, std::string runName, QString description, QColor color, GraphPlottSeries::SeriesType type);
+	void removeRunData(RunData* run);
+	void removeAll();
+	void setInformation(QString information);
+	std::vector<GraphPlottSeries>& getSeriesVector();
+	void virtual resetToDefaultWindow() override;
+	void virtual frameGraphInView();
+	void setDisplayLabel(QString file);
+	void setScratchpad(Scratchpad* pad);
+protected:
+	QHBoxLayout* buttonPanel;
+	void showInformation();
+	void drawData(QPainter& painter) override;
+	void mouseMoveEvent(QMouseEvent* event) override;
+	std::vector<GraphPlottSeries> seriesVec;
+	virtual void handleSelectedWindow(VisibleWindow& window, QMouseEvent* event) override;
+
+	int stayStillTimeMS = 300;
+	virtual void searchForPointUnderCursor();
+	virtual void addPointsInWindowToScratchPad(VisibleWindow& window);
+	//Help Function:
+	double sqaredDistance(const QPointF& a, const QPointF& b);
+	QPoint lastPosition;
+	QTimer* timer = new QTimer(this);
+	Scratchpad* pad = nullptr;
+	HoverButton* informationButton = new HoverButton();
+	InformationPopUp* popupWidget = new InformationPopUp(nullptr);
+private:
+	QMenu* selectMenu = new QMenu(this);
+	QAction* displayAreaAction = new QAction("Display this area", this);
+	QAction* scratchpadAction = new QAction("Add points to Scratchpad", this);
+	GraphViewSettingDialog* dialog;
+	QString displayNameOfDataThatIsDisplayed = "";
+	QString informationButtonString = "No information.";
+	QString graphplottInformation = "<h3><u>Control:</u></h3><b>Scrolling:</b> Zooms in and out.<br><b>Scrolling + CTRL:</b> Zooms only horizontally.<br><b>Scrolling + SHIFT:</b> Zooms only vertically.<br><b>Drag & Drop LMB:</b> Moves the visible area.<br><b>Drag & Drop RMB:</b> Selects area to display or add solutions to Scratchpad.<br><b>Drag & Drop RMB + CTRL:</b> Selects area to display.<br><b>Drag & Drop RMB + ALT:</b> Adds solutions to Scratchpad.<br><b>Arrow Keys:</b> Moves the visible area<br><b>Page Up:</b> Zooms in.<br><b>Page Down:</b> Zooms out.<br><b>CTRL + R:</b> Resets the visible area.<br>";
+	QLabel* displayLabel;
+	virtual void keyPressEvent(QKeyEvent* event) override;
+};

+ 5 - 6
metavis/GraphView.cpp

@@ -135,6 +135,7 @@ void GraphView::paintEvent(QPaintEvent* event)
 		linePen.setWidth(2);
 		linePen.setColor(QColor(0,100,200, 0));
 		painter.setPen(linePen);
+		painter.setBrush(QColor(0, 100, 200, 0));
 		for (int i = 0; i < yDoubleDoubleValuesAmount; i++) {
 			painter.setBrush(pointColors[i]);
 			painter.drawEllipse(transformGraphToView(QPointF(yArray[2 * i], yArray[2 * i + 1]), stregth_factorX, stregth_factorY, translation), 3, 3);
@@ -168,8 +169,6 @@ void GraphView::paintEvent(QPaintEvent* event)
 	painter.drawRect(rightRect);
 	painter.setBrush(Qt::BrushStyle::NoBrush);
 	
-	//painter.drawRect(yAxisRect);
-	
 	
 	
 	
@@ -637,12 +636,12 @@ QColor interpolate(QColor& first, QColor& second, double alpha)
 
 
 
-void GraphView::addYMatrix(double* yArray, int length, std::vector<SolutionPointData>& solVec)
+void GraphView::addYMatrix(double* yArray, std::vector<SolutionPointData>& solVec)
 {
-	this->yArray = yArray; yDoubleDoubleValuesAmount = length;
+	this->yArray = yArray; yDoubleDoubleValuesAmount = solVec.size();
 	this->solVec = &solVec;
 	if (pointColors != nullptr) delete pointColors;
-	pointColors = new QColor[length];
+	pointColors = new QColor[yDoubleDoubleValuesAmount];
 }
 void GraphView::autoZoomOut()
 {
@@ -669,7 +668,7 @@ void GraphView::updateGraphColors(ColorGradient& gradient)
 	double bestValue = 0;
 	double worstValue = 100;
 	for (int i = 0; i < solVec->size(); i++) {
-		pointColors[i] = gradient.getColor( std::clamp(util::inverseLinearInterpolation(bestValue, worstValue, solVec->at(i).objectiveFunction), 0.0, 1.0));
+		pointColors[i] = gradient.getColorFromAlpha( std::clamp(util::inverseLinearInterpolation(bestValue, worstValue, solVec->at(i).objectiveFunction), 0.0, 1.0));
 	}
 }
 

+ 1 - 1
metavis/GraphView.h

@@ -104,7 +104,7 @@ public:
 	void setDrawBound(bool value);
 	QColor generateNextColorForGraph();
 	void resetBound();
-	void addYMatrix(double* yArray, int length, std::vector<SolutionPointData>& solVec);
+	void addYMatrix(double* yArray, std::vector<SolutionPointData>& solVec);
 	void autoZoomOut();
 	void updateGraphColors(ColorGradient& gradient);
 

+ 11 - 9
metavis/GraphViewSettingDialog.cpp

@@ -7,13 +7,11 @@
 
 
 
-GraphViewSettingDialog::GraphViewSettingDialog(GraphView* view, QString title ,QWidget *parent)
-	: QDialog(parent), view(view)
+GraphViewSettingDialog::GraphViewSettingDialog(GraphPlott* view, QString title)
+	: QDialog(view, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowType::WindowCloseButtonHint), view(view)
 {
 	ui.setupUi(this);
 	setWindowTitle(title);
-	this->graphVec = &view->graphSeriesVec;
-	vecsize = graphVec->size();
 	QWidget* toScroll = new QWidget(this);
 	layout = new QVBoxLayout(this);
 	layout->setContentsMargins(3, 0, 3, 0);
@@ -33,18 +31,22 @@ GraphViewSettingDialog::~GraphViewSettingDialog()
 
 void GraphViewSettingDialog::openDialog()
 {
-	//Generate Buttons;
-
-	if (vecsize == graphVec->size()) {
+	//Generate Buttons
+	//qDebug() << "vecsize " << vecsize << "     view->getSeriesVector().size() " << view->getSeriesVector().size();
+	if (vecsize == view->getSeriesVector().size()) {
 		this->activateWindow();
+		this->setFocus();
 		this->show();
 		return;
 	}
 	else {
-		vecsize = graphVec->size();
+		vecsize = view->getSeriesVector().size();
+		QLayoutItem* item;
+		while ((item = layout->takeAt(0)))
+			delete item;
 	}
 
-	for (auto iter = graphVec->begin(); iter != graphVec->end(); iter++) {
+	for (auto iter = view->getSeriesVector().begin(); iter != view->getSeriesVector().end(); iter++) {
 		GraphViewSettingItem* handle = new GraphViewSettingItem(view, &*iter, this);
 		layout->addWidget(handle);
 	}

+ 4 - 6
metavis/GraphViewSettingDialog.h

@@ -1,9 +1,9 @@
 #pragma once
 
 #include <QDialog>
-#include "GraphView.h"
+#include "GraphPlott.h"
 #include "ui_GraphViewSettingDialog.h"
-
+class GraphPlott;
 
 
 class GraphViewSettingDialog : public QDialog
@@ -11,10 +11,8 @@ class GraphViewSettingDialog : public QDialog
 	Q_OBJECT
 
 public:
-	GraphView* view;
-	std::vector<GraphSeries>* graphVec;
-public:
-	GraphViewSettingDialog(GraphView* view, QString title , QWidget *parent = Q_NULLPTR);
+	GraphPlott* view;
+	GraphViewSettingDialog(GraphPlott* view, QString title);
 	~GraphViewSettingDialog();
 public slots:
 	void openDialog();

+ 15 - 16
metavis/GraphViewSettingItem.cpp

@@ -2,18 +2,18 @@
 #include "GraphViewSettingItem.h"
 #include <QColorDialog>
 
-GraphViewSettingItem::GraphViewSettingItem(GraphView* view, GraphSeries* series, QWidget *parent) : QWidget(parent), series(series), view(view)
+GraphViewSettingItem::GraphViewSettingItem(GraphPlott* view, GraphPlottSeries* series, QWidget *parent) : QWidget(parent), series(series), view(view), colorButton(new ColorButton(this, series->color))
 {
 	ui.setupUi(this);
 	// Init
 	switch (series->type) {
-	case GraphSeries::SeriesType::Dot:
+	case GraphPlottSeries::SeriesType::Dot:
 		ui.SytleComboBox->setCurrentIndex(1);
 		break;
-	case GraphSeries::SeriesType::LineDot:
+	case GraphPlottSeries::SeriesType::LineDot:
 		ui.SytleComboBox->setCurrentIndex(2);
 		break;
-	case GraphSeries::SeriesType::Line:
+	case GraphPlottSeries::SeriesType::Line:
 	default:
 		ui.SytleComboBox->setCurrentIndex(0);
 		break;
@@ -22,7 +22,7 @@ GraphViewSettingItem::GraphViewSettingItem(GraphView* view, GraphSeries* series,
 	ui.CircleSlider->setValue(series->circleRadius);
 	dissableSlidersOnType();
 	updateGroupBoxTitle();
-
+	ui.RightFormLayout->setWidget(1, QFormLayout::FieldRole, colorButton);
 
 	
 	//Connect
@@ -31,7 +31,8 @@ GraphViewSettingItem::GraphViewSettingItem(GraphView* view, GraphSeries* series,
 	connect(ui.SytleComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [=](const int& newValue) { setType(newValue);dissableSlidersOnType();view->update(); });
 	connect(ui.HideCheckbox, &QCheckBox::stateChanged, [=](const int& newValue) { series->hide = (newValue==2); view->update(); });
 	//connect(ui.SetColorButton, &QPushButton::pressed, this, &GraphViewSettingItem::setColor);
-	connect(ui.NameEdit, &QLineEdit::textChanged, [=](const QString& text) { series->name = text; updateGroupBoxTitle(); });
+	connect(colorButton, &ColorButton::colorChanged, this, &GraphViewSettingItem::setColor);
+	connect(ui.NameEdit, &QLineEdit::textChanged, [=](const QString& text) { series->description = text; updateGroupBoxTitle(); });
 }
 
 GraphViewSettingItem::~GraphViewSettingItem()
@@ -41,15 +42,15 @@ GraphViewSettingItem::~GraphViewSettingItem()
 void GraphViewSettingItem::dissableSlidersOnType()
 {
 	switch (series->type) {
-	case GraphSeries::SeriesType::Line:
+	case GraphPlottSeries::SeriesType::Line:
 		ui.LineSlider->setEnabled(true);
 		ui.CircleSlider->setEnabled(false);
 		break;
-	case GraphSeries::SeriesType::Dot:
+	case GraphPlottSeries::SeriesType::Dot:
 		ui.LineSlider->setEnabled(false);
 		ui.CircleSlider->setEnabled(true);
 		break;
-	case GraphSeries::SeriesType::LineDot:
+	case GraphPlottSeries::SeriesType::LineDot:
 		ui.LineSlider->setEnabled(true);
 		ui.CircleSlider->setEnabled(true);
 		break;
@@ -62,23 +63,21 @@ void GraphViewSettingItem::setType(int type)
 {
 	switch (type) {
 	case 0:
-		series->type = GraphSeries::SeriesType::Line;
+		series->type = GraphPlottSeries::SeriesType::Line;
 		break;
 	case 1:
-		series->type = GraphSeries::SeriesType::Dot;
+		series->type = GraphPlottSeries::SeriesType::Dot;
 		break;
 	case 2:
-		series->type = GraphSeries::SeriesType::LineDot;
+		series->type = GraphPlottSeries::SeriesType::LineDot;
 		break;
 	default:
 		break;
 	}
 }
 
-void GraphViewSettingItem::setColor()
+void GraphViewSettingItem::setColor(QColor color)
 {
-	QColor color = QColorDialog::getColor(series->color, this, "Set Series Color", QColorDialog::ShowAlphaChannel);
-	if (!color.isValid()) return;
 	series->color = color;
 	updateGroupBoxTitle();
 	view->update();
@@ -86,7 +85,7 @@ void GraphViewSettingItem::setColor()
 
 void GraphViewSettingItem::updateGroupBoxTitle()
 {
-	ui.GroupBox->setTitle("Series: " + series->name);
+	ui.GroupBox->setTitle("Series: " + series->description);
 	QString style = "QGroupBox { color: rgb(%1, %2, %3); };";
 	ui.GroupBox->setStyleSheet(style.arg(series->color.red()).arg(series->color.green()).arg(series->color.blue()));
 }

+ 8 - 5
metavis/GraphViewSettingItem.h

@@ -2,22 +2,25 @@
 
 #include <QWidget>
 #include "ui_GraphViewSettingItem.h"
-#include "GraphView.h"
+#include "GraphPlott.h"
+#include "ColorButton.h"
+class GraphPlott;
 
 class GraphViewSettingItem : public QWidget
 {
 	Q_OBJECT
 
 public:
-	GraphViewSettingItem(GraphView* view, GraphSeries* series, QWidget *parent = Q_NULLPTR);
+	GraphViewSettingItem(GraphPlott* view, GraphPlottSeries* series, QWidget *parent = Q_NULLPTR);
 	~GraphViewSettingItem();
 
 private:
 	Ui::GraphViewSettingItem ui;
-	GraphSeries* series;
-	GraphView* view;
+	GraphPlottSeries* series;
+	GraphPlott* view;
+	ColorButton* colorButton;
 	void dissableSlidersOnType();
 	void setType(int type);
-	void setColor();
+	void setColor(QColor color);
 	void updateGroupBoxTitle();
 };

+ 27 - 0
metavis/HoverButton.cpp

@@ -0,0 +1,27 @@
+#include "pch.h"
+#include "HoverButton.h"
+
+HoverButton::HoverButton(QWidget *parent)
+	: QPushButton(parent)
+{
+}
+
+HoverButton::~HoverButton()
+{
+}
+
+void HoverButton::setHoveredIcon(const QIcon& icon)
+{
+	hoveredIcon = icon;
+}
+
+void HoverButton::enterEvent(QEvent*)
+{
+	normalIcon = this->icon();
+	this->setIcon(hoveredIcon);
+}
+
+void HoverButton::leaveEvent(QEvent*)
+{
+	this->setIcon(normalIcon);
+}

+ 24 - 0
metavis/HoverButton.h

@@ -0,0 +1,24 @@
+#pragma once
+
+#include <QPushButton>
+#include <QPalette>
+#include <QColor>
+#include <QDebug>
+#include <QIcon>
+
+class HoverButton : public QPushButton
+{
+	Q_OBJECT
+
+public:
+	HoverButton(QWidget *parent = nullptr);
+	~HoverButton();
+	void setHoveredIcon(const QIcon& icon);
+
+protected:
+    virtual void enterEvent(QEvent*);
+	virtual void leaveEvent(QEvent*);
+private:
+	QIcon normalIcon;
+	QIcon hoveredIcon;
+};

+ 27 - 0
metavis/InformationPopUp.cpp

@@ -0,0 +1,27 @@
+#include "pch.h"
+#include "InformationPopUp.h"
+
+InformationPopUp::InformationPopUp(QWidget *parent)
+	: QWidget(parent)
+{
+	this->setWindowFlag(Qt::Popup);
+	QVBoxLayout* layout = new QVBoxLayout(this);
+	setContentsMargins(3, 3, 3, 3);
+	informationLabel->setTextFormat(Qt::RichText);
+	layout->addWidget(informationLabel);
+}
+
+InformationPopUp::~InformationPopUp()
+{
+}
+
+void InformationPopUp::setInformation(QString information)
+{
+	informationLabel->setText(information);
+	update();
+}
+
+QString InformationPopUp::getInformation() const
+{
+	return informationLabel->text();
+}

+ 17 - 0
metavis/InformationPopUp.h

@@ -0,0 +1,17 @@
+#pragma once
+
+#include <QWidget>
+#include <QString>
+#include <QLabel>
+class InformationPopUp : public QWidget
+{
+	Q_OBJECT
+
+public:
+	InformationPopUp(QWidget *parent);
+	~InformationPopUp();
+	void setInformation(QString information);
+	QString getInformation() const;
+private:
+	QLabel* informationLabel = new QLabel();
+};

+ 520 - 0
metavis/Plott.cpp

@@ -0,0 +1,520 @@
+#include "pch.h"
+#include "Plott.h"
+#include "util.h"
+
+
+
+#include <chrono>
+
+#define X_AXIS_GAP_AMOUNT 5
+#define Y_AXIS_GAP_AMOUNT 10
+#define X_AXIS_NUMBER_LINE_LENGTH 5
+#define Y_AXIS_NUMBER_LINE_LENGTH 5
+#define X_AXIS_NUMBER_GAP_LENGTH 10
+#define Y_AXIS_NUMBER_GAP_LENGTH 30
+#define X_AXIS_LEGEND_TOP_BEGIN 12
+#define Y_AXIS_LEGEND_LEFT_BEGIN 12
+
+#define MARGIN_TOP 20
+#define MARGIN_BOTTOM 25
+#define MARGIN_LEFT 50
+#define MARGIN_RIGHT 10
+
+
+
+Plott::Plott(QWidget *parent)
+	: QWidget(parent)
+{
+	setFocusPolicy(Qt::ClickFocus);
+}
+
+Plott::~Plott()
+{
+}
+void Plott::setVisibleWindow(double xMin, double xMax, double yMin, double yMax)
+{
+	window.xMin = xMin;
+	window.xMax = xMax;
+	window.yMin = yMin;
+	window.yMax = yMax;
+}
+void Plott::setDefaultVisibleWindow(double xMin, double xMax, double yMin, double yMax)
+{
+	defaultWindow.xMin = xMin;
+	defaultWindow.xMax = xMax;
+	defaultWindow.yMin = yMin;
+	defaultWindow.yMax = yMax;
+}
+void Plott::resetToDefaultWindow()
+{
+	window.xMin = defaultWindow.xMin;
+	window.xMax = defaultWindow.xMax;
+	window.yMin = defaultWindow.yMin;
+	window.yMax = defaultWindow.yMax;
+}
+void Plott::setAxisLegend(QString xAxisLegend, QString yAxisLegend)
+{
+	this->xAxisLegend = xAxisLegend;
+	this->yAxisLegend = yAxisLegend;
+}
+QPointF Plott::transformGraphToView(QPointF graphpoint) const
+{
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+	return QPointF((graphpoint.x() - window.xMin) * stregth_factorX, (window.yMax - graphpoint.y()) * stregth_factorY) + translation;
+}
+QPointF Plott::transformGraphToView(QPointF graphpoint, double stregth_factorX, double stregth_factorY, QPointF translation) const
+{
+	return QPointF((graphpoint.x() - window.xMin) * stregth_factorX, (window.yMax - graphpoint.y()) * stregth_factorY) + translation;
+}
+QPointF Plott::transformViewToGraph(QPointF viewpoint) const
+{
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+	return QPointF(((viewpoint.x() - translation.x()) / stregth_factorX) + window.xMin, window.yMax - ((viewpoint.y() - translation.y()) / stregth_factorY));
+}
+
+QPointF Plott::transformViewToGraph(QPointF viewpoint, double stregth_factorX, double stregth_factorY, QPointF translation) const
+{
+	return QPointF(((viewpoint.x() - translation.x()) / stregth_factorX) + window.xMin, window.yMax - ((viewpoint.y() - translation.y()) / stregth_factorY));
+}
+
+
+
+
+void Plott::drawData(QPainter& painter)
+{
+}
+
+QRect Plott::getDisplayRect() const
+{
+	QRect graphDisplayRect(rect());
+
+	graphDisplayRect.setBottom(graphDisplayRect.bottom() - MARGIN_BOTTOM);
+	graphDisplayRect.setLeft(graphDisplayRect.left() + MARGIN_LEFT);
+	graphDisplayRect.setTop(graphDisplayRect.top() + MARGIN_TOP);
+	graphDisplayRect.setRight(graphDisplayRect.right() - MARGIN_RIGHT);
+	graphDisplayRect.setWidth(graphDisplayRect.width() - (graphDisplayRect.width() % X_AXIS_GAP_AMOUNT) + 1);
+	graphDisplayRect.setHeight(graphDisplayRect.height() - (graphDisplayRect.height() % Y_AXIS_GAP_AMOUNT) + 1);
+	return graphDisplayRect;
+}
+
+
+// Draws the axis
+void Plott::paintEvent(QPaintEvent* event)
+{
+	std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
+	QPainter painter(this);
+	painter.setRenderHint(QPainter::RenderHint::HighQualityAntialiasing);
+	
+	QRect graphDisplayRect = getDisplayRect();
+	int xGap = graphDisplayRect.width() / X_AXIS_GAP_AMOUNT;
+	int yGap = graphDisplayRect.height() / Y_AXIS_GAP_AMOUNT;
+	if(enableGrid){
+		QPainterPath gridPath;
+		for (int i = 1; i < X_AXIS_GAP_AMOUNT; i++) {
+			gridPath.moveTo(graphDisplayRect.left() + i * xGap, graphDisplayRect.top());
+			gridPath.lineTo(graphDisplayRect.left() + i * xGap, graphDisplayRect.bottom());
+		}
+		
+		for (int i = 0; i < Y_AXIS_GAP_AMOUNT + 1; i++) {
+			gridPath.moveTo(graphDisplayRect.left(), graphDisplayRect.bottom() - i * yGap);
+			gridPath.lineTo(graphDisplayRect.right(), graphDisplayRect.bottom() - i * yGap);
+		}
+		QPen graypen(QColor(150, 150, 150));
+		painter.setPen(graypen);
+		painter.drawPath(gridPath);
+	}
+	
+	drawData(painter);
+	
+	//Draw White Rect for axis
+	QPen blackpen(QColor(0, 0, 0));
+	blackpen.setWidth(1);
+	QPen whitePen(QColor(255, 255, 255));
+	whitePen.setWidth(1);
+	painter.setPen(whitePen);
+	painter.setBrush(whitePen.color());
+	QRect leftRect(rect().topLeft(), QPoint(graphDisplayRect.left() - 1, rect().bottom()));
+	QRect topRect(rect().topLeft(), QPoint(rect().right(), graphDisplayRect.top() - 1));
+	QRect bottomRect(QPoint(rect().left(), graphDisplayRect.bottom()), rect().bottomRight());
+	QRect rightRect(QPoint(graphDisplayRect.right(), rect().top()), rect().bottomRight());
+	painter.drawRect(leftRect);
+	painter.drawRect(topRect);
+	painter.drawRect(bottomRect);
+	painter.drawRect(rightRect);
+	painter.setBrush(Qt::BrushStyle::NoBrush);
+
+
+
+
+	//Font for Axis;
+	painter.setFont(QFont("Arial", 8));
+	//draw X-Axis
+	painter.setPen(blackpen);
+	QRect xAxisRect(QPoint(graphDisplayRect.left(), graphDisplayRect.bottom()), QPoint(graphDisplayRect.right(), rect().bottom()));
+	QPainterPath xAxisPath;
+	xAxisPath.moveTo(xAxisRect.left(), xAxisRect.top());
+	xAxisPath.lineTo(xAxisRect.right(), xAxisRect.top());
+
+	QRect textRect(0, 0, 40, 9);
+
+	for (int i = 0; i < X_AXIS_GAP_AMOUNT + 1; i++) {
+		xAxisPath.moveTo(xAxisRect.left() + i * xGap, xAxisRect.top() + X_AXIS_NUMBER_LINE_LENGTH);
+		xAxisPath.lineTo(xAxisRect.left() + i * xGap, xAxisRect.top());
+		textRect.moveCenter(QPoint(xAxisRect.left() + i * xGap, xAxisRect.top() + X_AXIS_NUMBER_GAP_LENGTH));
+		painter.drawText(textRect, Qt::AlignCenter, QString::number(util::linearInterpolate(window.xMin, window.xMax, (1/ (double)X_AXIS_GAP_AMOUNT )*i), 'f', 1));
+	}
+	
+	painter.drawPath(xAxisPath);
+	//Draw XAxisLegend
+	QRect xAxisLegendRect(QPoint(xAxisRect.left(), rect().bottom() - X_AXIS_LEGEND_TOP_BEGIN), rect().bottomRight());
+	painter.drawText(xAxisLegendRect, Qt::AlignCenter, xAxisLegend);
+
+	//draw Y-Axis
+	QRect yAxisRect(QPoint(rect().left(), graphDisplayRect.top()), QPoint(graphDisplayRect.left(), graphDisplayRect.bottom()));
+	QPainterPath yAxisPath;
+	yAxisPath.moveTo(yAxisRect.right(), yAxisRect.bottom());
+	yAxisPath.lineTo(yAxisRect.right(), yAxisRect.top());
+	
+	for (int i = 0; i < Y_AXIS_GAP_AMOUNT + 1; i++) {
+		yAxisPath.moveTo(yAxisRect.right() - Y_AXIS_NUMBER_LINE_LENGTH, yAxisRect.bottom() - i * yGap);
+		yAxisPath.lineTo(yAxisRect.right(), yAxisRect.bottom() - i * yGap);
+		textRect.moveCenter(QPoint(yAxisRect.right() - Y_AXIS_NUMBER_GAP_LENGTH, yAxisRect.bottom() - i * yGap));
+		painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, QString::number(util::linearInterpolate(window.yMin, window.yMax, (1 / (double)Y_AXIS_GAP_AMOUNT) * i), 'f', 1));
+	}
+	painter.drawPath(yAxisPath);
+	//Draw YAxisLegend
+	//to draw vertical the painter have to translated and rotated (order is crucial)
+	QRect yAxisLegendRect(0, 0, graphDisplayRect.bottom(), Y_AXIS_LEGEND_LEFT_BEGIN);
+	painter.translate(0,graphDisplayRect.bottom());
+	painter.rotate(-90.0);
+	painter.drawText(yAxisLegendRect, Qt::AlignCenter, yAxisLegend);
+	painter.rotate(+90.0);
+	painter.translate(0, -graphDisplayRect.bottom());
+
+
+
+	if (isLeftMousePressed) {
+		QColor blue(0, 122, 204);
+		QColor gray(120, 120, 120);
+		//QPointF value = transformViewToGraph(oldPositionForMouseEvent);
+		QPointF viewPoint = transformGraphToView(mousePressedValue);
+		if (graphDisplayRect.top() <= viewPoint.y() && viewPoint.y() <= graphDisplayRect.bottom()) {
+			painter.setPen(gray);
+			painter.drawLine(QPointF(graphDisplayRect.left() - Y_AXIS_NUMBER_LINE_LENGTH, viewPoint.y()), QPointF(graphDisplayRect.right(), viewPoint.y()));
+			textRect.moveCenter(QPoint(graphDisplayRect.left() - Y_AXIS_NUMBER_GAP_LENGTH, viewPoint.y()));
+			painter.fillRect(textRect, whitePen.color());
+			painter.setPen(blue);
+			painter.drawText(textRect, Qt::AlignRight | Qt::AlignVCenter, QString::number(mousePressedValue.y(), 'f', 1));
+		}
+		if (graphDisplayRect.left() <= viewPoint.x() && viewPoint.x() <= graphDisplayRect.right()) {
+			painter.setPen(gray);
+			painter.drawLine(QPointF(viewPoint.x(), graphDisplayRect.top()), QPointF(viewPoint.x(), graphDisplayRect.bottom() + X_AXIS_NUMBER_LINE_LENGTH));
+			textRect.moveCenter(QPoint(viewPoint.x(), graphDisplayRect.bottom() + X_AXIS_NUMBER_GAP_LENGTH));
+			painter.fillRect(textRect, whitePen.color());
+			painter.setPen(blue);
+			painter.drawText(textRect, Qt::AlignCenter, QString::number(mousePressedValue.x(), 'f', 1));
+		}
+	}
+	if (isRightMousePressed) {
+		QColor blue(0, 122, 204);
+		painter.setPen(blue);
+		painter.drawRect(QRectF(transformGraphToView(this->mousePressedValue), oldPositionForMouseEvent));
+	}
+	std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
+	std::chrono::milliseconds timeElapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+	
+}
+
+void Plott::keyPressEvent(QKeyEvent* event)
+{
+	double percent = 0.1;
+	switch (event->key()) {
+	case Qt::Key_Up:
+		window.moveUp(percent);
+		break;
+	case Qt::Key_Right:
+		window.moveRight(percent);
+		break;
+	case Qt::Key_Left:
+		window.moveLeft(percent);
+		break;
+	case Qt::Key_Down:
+		window.moveDown(percent);
+		break;
+	case Qt::Key_PageUp:
+	case Qt::Key_Plus:
+		if (event->modifiers() & Qt::ShiftModifier) {
+			//ZoomInY
+			window.ZoomInY(percent);
+		}
+		else if (event->modifiers() & Qt::ControlModifier) {
+			//ZoomInX
+			window.ZoomInX(percent);
+		}
+		else {
+			//Zoom
+			window.ZoomIn(percent);
+		}
+		break;
+	case Qt::Key_PageDown:
+	case Qt::Key_Minus:
+		if (event->modifiers() & Qt::ShiftModifier) {
+			//ZoomOutX
+			window.ZoomOutY(percent);
+		}
+		else if (event->modifiers() & Qt::ControlModifier) {
+			//ZoomOutX
+			window.ZoomOutX(percent);
+		}
+		else {
+			//ZoomOut
+			window.ZoomOut(percent);
+		}
+		break;
+	case Qt::Key_R:
+		resetToDefaultWindow();
+	default:
+		QWidget::keyPressEvent(event);
+	}
+	update();
+}
+
+void Plott::wheelEvent(QWheelEvent* event)
+{
+	double percent = 0.1;
+	QPoint numDegrees = event->angleDelta() / 8;
+	if (!numDegrees.isNull()) {
+		QPoint numSteps = numDegrees / 15;
+		switch (numSteps.y()) {
+		case 1:
+			if (event->modifiers() & Qt::ShiftModifier) {
+				window.ZoomInY(percent);
+			}
+			else if (event->modifiers() & Qt::ControlModifier) {
+				window.ZoomInX(percent);
+			}
+			else {
+				window.ZoomIn(percent);
+			}
+			break;
+		case -1:
+			if (event->modifiers() & Qt::ShiftModifier) {
+				window.ZoomOutY(percent);
+			}
+			else if (event->modifiers() & Qt::ControlModifier) {
+				window.ZoomOutX(percent);
+			}
+			else {
+				window.ZoomOut(percent);
+			}
+			break;
+		default:
+			break;
+		}
+		update();
+	}
+
+	event->accept();
+}
+
+void Plott::mouseMoveEvent(QMouseEvent* event)
+{
+	if (isLeftMousePressed) {
+		//Move window by calculating the change in visibleWindow
+		QPointF delta = event->pos() - oldPositionForMouseEvent;
+		oldPositionForMouseEvent = event->pos();
+		double rangeX = window.rangeX();
+		int width = (rect().right() - 10) - (rect().left() + 50);
+		width -= (width % X_AXIS_GAP_AMOUNT) + 1;
+		double pixelWidthX = rangeX / (double)width;
+		double rangeY = window.rangeY();
+		int height = (rect().bottom() - 20) - (rect().top() + 20);
+		height -= (height % Y_AXIS_GAP_AMOUNT) + 1;
+		double pixelWidthY = rangeY / (double)height;
+	
+		window.xMin += -delta.x() * pixelWidthX;
+		window.xMax += -delta.x() * pixelWidthX;
+		window.yMin += delta.y() * pixelWidthY;
+		window.yMax += delta.y() * pixelWidthY;
+		update();
+	}
+	else if (isRightMousePressed) {
+
+		oldPositionForMouseEvent = event->pos();
+		update();
+	}
+	
+}
+
+void Plott::mousePressEvent(QMouseEvent* event)
+{
+	if (event->buttons() == Qt::LeftButton) {
+		isLeftMousePressed = true;
+	}
+	else if (event->buttons() == Qt::RightButton) {
+		isRightMousePressed = true;
+	}
+	//To calculate the delta for mouse move  event
+	oldPositionForMouseEvent = event->pos();
+	mousePressedValue = transformViewToGraph(oldPositionForMouseEvent);
+	update();
+}
+
+void Plott::mouseReleaseEvent(QMouseEvent* event)
+{
+	if (isRightMousePressed) {
+		QPointF mouseViewPostion = transformGraphToView(mousePressedValue);
+		if (std::abs(mouseViewPostion.x() - oldPositionForMouseEvent.x()) > 0 || std::abs(mouseViewPostion.y() - oldPositionForMouseEvent.y()) > 0) {
+					//set visible window to selection 
+					VisibleWindow selectedWindow(0,0,0,0);
+					QPointF endPosition = transformViewToGraph(oldPositionForMouseEvent);
+					bool pressedIsLowerX = mousePressedValue.x() < endPosition.x();
+					selectedWindow.xMin = pressedIsLowerX? mousePressedValue.x() : endPosition.x();
+					selectedWindow.xMax = pressedIsLowerX ? endPosition.x() : mousePressedValue.x();
+
+					bool pressedIsLowerY = mousePressedValue.y() < endPosition.y();
+					selectedWindow.yMin = pressedIsLowerY ? mousePressedValue.y() : endPosition.y();
+					selectedWindow.yMax = pressedIsLowerY ? endPosition.y() : mousePressedValue.y();
+					handleSelectedWindow(selectedWindow, event);
+		}
+	}
+	isLeftMousePressed = false;
+	isRightMousePressed = false;
+	
+	update();
+}
+
+void Plott::handleSelectedWindow(VisibleWindow& window, QMouseEvent* event)
+{
+	setWindow(window);
+}
+
+void Plott::setWindow(VisibleWindow& window)
+{
+	this->window = window;
+	update();
+}
+
+void VisibleWindow::moveUp(double percent)
+{
+	double range = rangeY();
+	yMin += percent * range;
+	yMax += percent * range;
+
+}
+
+void VisibleWindow::moveDown(double percent)
+{
+	double range = rangeY();
+	yMin -= percent * range;
+	yMax -= percent * range;
+}
+
+void VisibleWindow::moveLeft(double percent)
+{
+	double range = rangeX();
+	xMin -= percent * range;
+	xMax -= percent * range;
+}
+
+void VisibleWindow::moveRight(double percent)
+{
+	double range = rangeX();
+	xMin += percent * range;
+	xMax += percent * range;
+}
+
+void VisibleWindow::ZoomIn(double percent)
+{
+	//Both sides same percentage
+	percent /= 2; 
+	double Xrange = rangeX();
+	if (Xrange == 0) Xrange = 1.0;
+	xMin += percent * Xrange;
+	xMax -= percent * Xrange;
+	double Yrange = rangeY();
+	if (Yrange == 0) Yrange = 1.0;
+	yMin += percent * Yrange;
+	yMax -= percent * Yrange;
+}
+
+void VisibleWindow::ZoomInX(double percent)
+{
+	percent /= 2;
+	double Xrange = rangeX();
+	if (Xrange == 0) Xrange = 1.0;
+	xMin += percent * Xrange;
+	xMax -= percent * Xrange;
+}
+
+void VisibleWindow::ZoomInY(double percent)
+{
+	percent /= 2;
+	double Yrange = rangeY();
+	if (Yrange == 0) Yrange = 1.0;
+	yMin += percent * Yrange;
+	yMax -= percent * Yrange;
+}
+
+void VisibleWindow::ZoomOut(double percent)
+{
+	//Both sides same percentage
+	percent /= 2;
+	double Xrange = rangeX();
+	if (Xrange == 0) Xrange = 1.0;
+	xMin -= percent * Xrange;
+	xMax += percent * Xrange;
+	double Yrange = rangeY();
+	if (Yrange == 0) Yrange = 1.0;
+	yMin -= percent * Yrange;
+	yMax += percent * Yrange;
+}
+
+void VisibleWindow::ZoomOutX(double percent)
+{
+	percent /= 2;
+	double Xrange = rangeX();
+	if (Xrange == 0) Xrange = 1.0;
+	xMin -= percent * Xrange;
+	xMax += percent * Xrange;
+}
+
+void VisibleWindow::ZoomOutY(double percent)
+{
+	percent /= 2;
+	double Yrange = rangeY();
+	if (Yrange == 0) Yrange = 1.0;
+	yMin -= percent * Yrange;
+	yMax += percent * Yrange;
+}
+
+double VisibleWindow::rangeX() const
+{
+	return xMax - xMin;
+}
+
+double VisibleWindow::rangeY() const
+{
+	return yMax - yMin;
+}
+
+bool VisibleWindow::inBoundX(QPointF point) const
+{
+	return point.x() >= xMin && point.x() <= xMax;
+}
+
+bool VisibleWindow::inBoundY(QPointF point) const
+{
+	return point.y() >= yMin && point.y() <= yMax;
+}
+
+bool VisibleWindow::inBound(QPointF point) const
+{
+	return inBoundX(point) && inBoundY(point);
+}

+ 83 - 0
metavis/Plott.h

@@ -0,0 +1,83 @@
+#pragma once
+
+#include <QWidget>
+#include <QPointF>
+#include <QPainter>
+#include <QMenu>
+
+
+
+struct VisibleWindow {
+	double xMin, xMax, yMin, yMax;
+	VisibleWindow(double xMin, double xMax, double yMin, double yMax):
+	xMin(xMin), xMax(xMax), yMin(yMin), yMax(yMax){}
+	void moveUp(double percent);
+	void moveDown(double percent);
+	void moveLeft(double percent);
+	void moveRight(double percent);
+	void ZoomIn(double percent);
+	void ZoomInX(double percent);
+	void ZoomInY(double percent);
+	void ZoomOut(double percent);
+	void ZoomOutX(double percent);
+	void ZoomOutY(double percent);
+	double rangeX() const;
+	double rangeY() const;
+	bool inBoundX(QPointF point) const;
+	bool inBoundY(QPointF point) const;
+	bool inBound(QPointF point) const;
+};
+
+class Plott : public QWidget
+{
+	Q_OBJECT
+
+public:
+	//Grid
+	bool enableGrid = false;
+
+	Plott(QWidget *parent);
+	~Plott();
+	//Setter
+	void setVisibleWindow(double xMin, double xMax, double yMin, double yMax);
+	void setDefaultVisibleWindow(double xMin, double xMax, double yMin, double yMax);
+	void setAxisLegend(QString xAxisLegend, QString yAxisLegend);
+	//sets the window to the default window
+	void virtual resetToDefaultWindow();
+
+	QPointF transformGraphToView(QPointF graphpoint) const;
+	QPointF transformGraphToView(QPointF graphpoint, double stregth_factorX, double stregth_factorY, QPointF translation) const;
+	QPointF transformViewToGraph(QPointF viewpoint) const;
+	QPointF transformViewToGraph(QPointF viewpoint, double stregth_factorX, double stregth_factorY, QPointF translation) const;
+protected:
+	//Represent the visual area in graph space that is shown in view space
+	VisibleWindow window = VisibleWindow(0.0, 10, 0, 10);
+	VisibleWindow defaultWindow = VisibleWindow(0.0, 10, 0, 10);
+
+
+
+	virtual void drawData(QPainter& painter);
+	//Returns the area in view space where 
+	QRect getDisplayRect() const;
+	
+	//Display
+	virtual void paintEvent(QPaintEvent* event) override;
+	//Process user input events
+	virtual void keyPressEvent(QKeyEvent* event) override;
+	virtual void wheelEvent(QWheelEvent* event) override;
+	virtual void mouseMoveEvent(QMouseEvent* event) override;
+	virtual void mousePressEvent(QMouseEvent* event) override;
+	virtual void mouseReleaseEvent(QMouseEvent* event) override;
+
+	virtual void handleSelectedWindow(VisibleWindow& window, QMouseEvent* event);
+	void setWindow(VisibleWindow& window);
+private:
+	
+	//Axis Legends
+	QString xAxisLegend = "X Legende", yAxisLegend = "Y Legend";
+	//MouseControl
+	bool isLeftMousePressed = false;
+	bool isRightMousePressed = false;
+	QPointF oldPositionForMouseEvent;
+	QPointF mousePressedValue;
+};

+ 24 - 10
metavis/Project.cpp

@@ -1,29 +1,43 @@
 #include "pch.h"
 #include "Project.h"
 
-void Project::addMetalogFile(std::string metaLogFile)
+void Project::addFile(std::string metaLogFile)
 {
 	//If file exist and can be open
-	runVec.push_back(Wrapper(metaLogFile));
+	runList.push_back(metaLogFile);
 }
 
 void Project::removeRunData(RunData* data)
 {
-	auto wrapperIter = std::find_if(runVec.begin(), runVec.end(), [&data](Wrapper& wrap) -> bool {return(&wrap.data == data); });
-	//Remove RunData from all GraphVec
-	//TODO
+	//Remove all series with this rundata
+	auto iter = std::remove_if(runList.begin(), runList.end(), [data](RunData& run) {return (data == &run); });
+	runList.erase(iter, runList.end());
+}
+
 
-	//remove from list -> delete itself;
-	//TODO
 
+void Project::removeLastData()
+{
+	if(!runList.empty()) runList.pop_back();
 }
 
-void Project::addGraphView(GraphView* view)
+void Project::removeIndex(int index)
 {
-	viewVec.push_back(view);
+	//TODO 
 }
 
-void Project::assignRunDataPointVecToView(RunData* data, std::vector<GraphDataPoint>* vec, GraphView* view)
+void Project::removeName(std::string fileName)
 {
+	auto iter = std::remove_if(runList.begin(), runList.end(), [fileName](RunData& series) {return (fileName == series.name); });
+	runList.erase(iter, runList.end());
+}
 
+void Project::clearDataList()
+{	
+	runList.clear();
+}
+
+std::list<RunData>& Project::getRunList()
+{
+	return runList;
 }

+ 8 - 16
metavis/Project.h

@@ -1,28 +1,20 @@
 #pragma once
 #include <vector>
 #include <string>
-
 #include "RunData.h"
-#include "GraphView.h"
-
-
-struct Wrapper {
-	RunData data;
-	Wrapper(std::string metaLogFile) : data(metaLogFile){}
-	std::vector<GraphView*> viewVec;
-};
 
 
 class Project
 {
-private:
-	std::vector<Wrapper> runVec;
-	std::vector<GraphView*> viewVec;
 public:	
-	void addMetalogFile(std::string metaLogFile);
+	void addFile(std::string fileName);
 	void removeRunData(RunData* data);
-	void addGraphView(GraphView* view);
-	//TODO what assigned
-	void assignRunDataPointVecToView(RunData* data, std::vector<GraphDataPoint>* vec, GraphView* view);
+	void removeLastData();
+	void removeIndex(int index);
+	void removeName(std::string fileName);
+	void clearDataList();
+	std::list<RunData>& getRunList();
+private:
+	std::list<RunData> runList;
 };
 

+ 179 - 53
metavis/ProjectManager.cpp

@@ -3,9 +3,10 @@
 #include <QAction>
 #include <QMenu>
 #include "ProjectManager.h"
+#include <QtConcurrent>
 
-ProjectManager::ProjectManager(QWidget *parent, metavis* owner)
-	: QWidget(parent), owner(owner)
+ProjectManager::ProjectManager(metavis* owner)
+	: QWidget(owner), owner(owner)
 {
 	QGridLayout* gridlayout = new QGridLayout();
 	gridlayout->setContentsMargins(0, 0, 0, 0);
@@ -14,90 +15,215 @@ ProjectManager::ProjectManager(QWidget *parent, metavis* owner)
 	treeWidget->setHeaderHidden(true);
 	treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
 	connect(treeWidget, &QTreeWidget::customContextMenuRequested, this, &ProjectManager::prepareMenu);
-
-	QTreeWidgetItem* projectItem = new QTreeWidgetItem(treeWidget, QStringList("Project"), ProjectManager::Types::Project);
+	connect(treeWidget, &QTreeWidget::itemActivated, this, &ProjectManager::itemClicked);
+	projectItem = new QTreeWidgetItem(treeWidget, QStringList("Project"), ProjectManager::Types::ProjectHeader);
 	projectItem->setExpanded(true);
-	QTreeWidgetItem* filesItem = new QTreeWidgetItem(projectItem, QStringList("Metalog Files"), ProjectManager::Types::LogManger);
-	new QTreeWidgetItem(filesItem, QStringList("run.metalog"), ProjectManager::Types::LogFile);
-	new QTreeWidgetItem(filesItem, QStringList("run2.metalog"), ProjectManager::Types::LogFile);
-	new QTreeWidgetItem(filesItem, QStringList("run3.metalog"), ProjectManager::Types::LogFile);
-	new QTreeWidgetItem(filesItem, QStringList("run4.metalog"), ProjectManager::Types::LogFile);
-	new QTreeWidgetItem(filesItem, QStringList("run5.metalog"), ProjectManager::Types::LogFile);
-	filesItem->setExpanded(true);
-	QTreeWidgetItem* graphItem = new QTreeWidgetItem(projectItem, QStringList("Graph Views"), ProjectManager::Types::GraphManger);
-	new QTreeWidgetItem(graphItem, QStringList("Best vs Avg"), ProjectManager::Types::Graph);
-	new QTreeWidgetItem(graphItem, QStringList("Mean Hamming Distance"), ProjectManager::Types::Graph);
-	new QTreeWidgetItem(graphItem, QStringList("Min Max Average"), ProjectManager::Types::Graph);
-	new QTreeWidgetItem(graphItem, QStringList("Particle"), ProjectManager::Types::Graph);
-	graphItem->setExpanded(true);
 	gridlayout->addWidget(treeWidget);
 	this->setLayout(gridlayout);
 
 
-
 	//Create Menus
-	filesMenu = new QMenu(this);
-	QAction* metaLogAddAction = new QAction("Add new .metalog-File...");
-	connect(metaLogAddAction, &QAction::triggered, owner, &metavis::openFile);
-	QAction* removeAllFilesAction = new QAction("Remove all metalog-Files");
-	filesMenu->addAction(metaLogAddAction);
-	filesMenu->addAction(removeAllFilesAction);
+	projectMenu = new QMenu(this);
+	QAction* metaLogAddAction = new QAction("Add .csv-File...");
+	QIcon test(":/metavis/Resources/file.svg");
+	metaLogAddAction->setIcon(test);
+	connect(metaLogAddAction, &QAction::triggered, this, &ProjectManager::openFileDialog);
+	//connect(metaLogAddAction, &QAction::triggered, this, [this]() { project.addFile(); });
+	QAction* removeAllFilesAction = new QAction("Remove all .csv-Files");
+	removeAllFilesAction->setIcon(QIcon(":/metavis/Resources/csv_remove.svg"));
+	connect(removeAllFilesAction, &QAction::triggered, this, [this]() {
+		for (RunData& data : project.getRunList()) {
+			this->owner->removeRunDataFromAllViews(&data);
+		}
+		project.clearDataList();
+		createTreeWidget();
+		});
+	projectMenu->addAction(metaLogAddAction);
+	projectMenu->addAction(removeAllFilesAction);
 	
 	metalogFileMenu = new QMenu(this);
 	QIcon removeIcon(":/metavis/Resources/close_big_red.svg");
-	QAction* removeMetalogFileAction = new QAction("Remove");
+	removeMetalogFileAction = new QAction("Remove");
 	removeMetalogFileAction->setIcon(removeIcon);
-	QAction* assignToGraphAction = new QAction("Assign...");
+	//connect(removeMetalogFileAction, &QAction::triggered, this, [this]() {project.clearDataList(); });
+	selectAction = new QAction("Show");
+	selectAction->setIcon(QIcon(":/metavis/Resources/arrow_right.svg"));
+	metalogFileMenu->addAction(selectAction);
 	metalogFileMenu->addAction(removeMetalogFileAction);
-	metalogFileMenu->addAction(assignToGraphAction);
+	singleRunMenu = new QMenu(this);
+	singleRunMenu->addAction(selectAction);
+	connect(&watcher, &QFutureWatcher<void>::finished, this, &ProjectManager::displayNewFile);
+	
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("ProjectManager");
+	lastPath = settings.value("path", "").toString();
+	settings.endGroup();
+}
+
+ProjectManager::~ProjectManager()
+{
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("ProjectManager");
+	settings.setValue("path", lastPath);
+	settings.endGroup();
+}
+
 
 
-	graphMenu = new QMenu(this);
-	QAction* assignMetalogFileAction = new QAction("Remove");
-	assignMetalogFileAction->setIcon(removeIcon);
-	graphMenu->addAction(assignMetalogFileAction);
 
+void ProjectManager::openFileDialog()
+{
+	qDebug() << "openFile";
+	this->lastPath != "";
+	QStringList pathList = QFileDialog::getOpenFileNames(this, "Open logFile",(this->lastPath != "")? lastPath :QStandardPaths::displayName(QStandardPaths::DesktopLocation), "Logfile (*.csv)");
+	if (pathList.isEmpty()) {
+		qDebug() << "No file selected";
+		return;
+	}
+	QDir d = QFileInfo(pathList.front()).absoluteDir();
+	lastPath = d.absolutePath();
+	owner->showStatusBarLoading();
+	//this->loadingFuture = std::async(std::launch::async, static_cast<void(ProjectManager::*)(std::list<QString>)>(&ProjectManager::openFiles), this, stdList);
+	future = QtConcurrent::run(this, &ProjectManager::openFiles, pathList);
+	watcher.setFuture(future);
 }
 
-ProjectManager::~ProjectManager()
+
+void ProjectManager::openFiles(QStringList pathList)
 {
+	int size = project.getRunList().size();
+	for (QString& string: pathList) {
+		qDebug() << "file:" << string;
+		project.addFile(string.toStdString());
+	}
+	for (std::list<RunData>::iterator iter = std::next(project.getRunList().begin(), size); iter != project.getRunList().end(); iter++) {
+		//owner->addRunDataToCompareViews(&*iter);
+	}
 }
 
-void ProjectManager::prepareMenu(const QPoint& pos) {
-	qDebug() << "TestMenu";
-	QTreeWidgetItem* item = treeWidget->itemAt(pos);
-	qDebug() << item->text(0) << "  " << item->type();
+void ProjectManager::displayNewFile()
+{
+	owner->selectRunData(&project.getRunList().back());
+	owner->selectSingleRun(&project.getRunList().back().singleRunList.front());
+	createTreeWidget();
+	owner->clearStatusBar();
+}
+
+
+
+
+
+void ProjectManager::createTreeWidget()
+{
+	//remove all clidren
+	for (QTreeWidgetItem* item : projectItem->takeChildren()) {
+		delete item;
+	}
+	for (RunData& run : project.getRunList()) {
+		qDebug() << "RunList add" << QString::fromStdString(run.name);
+		QTreeWidgetItem* item = new QTreeWidgetItem(projectItem, QStringList(QString::fromStdString(run.name)), ProjectManager::Types::LogFile);
+		QVariant variant(QVariant::fromValue(static_cast<void*>(&run)));
+		item->setData(1, Qt::UserRole, variant);
+		item->setExpanded(true);
+		int count = 0;
+		for (SingleRun& srun : run.singleRunList) {
+			QTreeWidgetItem* runitem = new QTreeWidgetItem(item, QStringList(QString::fromStdString(run.name) + "[" + QString::number(count) + "]"), ProjectManager::Types::Run);
+			QVariant srunVariant(QVariant::fromValue(static_cast<void*>(&srun)));
+			runitem->setData(1, Qt::UserRole, srunVariant);
+			count++;
+		}
+	}
+	
+}
+
+void ProjectManager::showItem(QTreeWidgetItem* item)
+{
+	switch (item->type()) {
+	case LogFile:
+	{
+		RunData* data = static_cast<RunData*>(item->data(1, Qt::UserRole).value<void*>());
+		if (data != nullptr) {
+			owner->selectRunData(data);
+		}
+		break;
+	}
+	case Run:
+	{
+		SingleRun* data = static_cast<SingleRun*>(item->data(1, Qt::UserRole).value<void*>());
+		if (data != nullptr) {
+			owner->selectSingleRun(data);
+		}
+		break;
+	}		
+	default:
+		break;
+	}
+	
+}
+
+
+
+
+
+void ProjectManager::itemClicked(QTreeWidgetItem* item, int column)
+{
 	switch (item->type()) {
 	case Types::Graph:
-		graphMenu->exec(treeWidget->mapToGlobal(pos));
 		break;
 	case Types::GraphManger:
 		break;
 	case Types::LogFile:
-		metalogFileMenu->exec(treeWidget->mapToGlobal(pos));
+	case Types::Run:
+		showItem(item);
 		break;
 	case Types::LogManger:
-		filesMenu->exec(treeWidget->mapToGlobal(pos));
 		break;
 	default:
 		break;
 	}
-
 }
 
-FileTreeItem::FileTreeItem(QTreeWidget* parent, const QStringList& strings, RunData* rundata, std::list<RunData>* list, int type) 
-	: QTreeWidgetItem(parent, strings, type), list(list), rundata(rundata)
-{
-
-}
 
-void FileTreeItem::remove()
-{
-	qDebug() << "Remove";
-	// Remove from graphs
+void ProjectManager::prepareMenu(const QPoint& pos) {
+	QTreeWidgetItem* item = treeWidget->itemAt(pos);
+	if (item == nullptr) return;
+	switch (item->type()) {
+	case Types::Graph:
+		//graphMenu->exec(treeWidget->mapToGlobal(pos));
+		break;
+	case Types::GraphManger:
+		break;
+	case Types::Run:
+	{
+		QAction* used = singleRunMenu->exec(treeWidget->mapToGlobal(pos));
+		if (used == selectAction) {
+			showItem(item);
+		}
+		break;
+	}
+	case Types::LogFile:
+	{
+		QAction* used = metalogFileMenu->exec(treeWidget->mapToGlobal(pos));
+		if (used == removeMetalogFileAction) {
+			RunData* data = static_cast<RunData*>(item->data(1, Qt::UserRole).value<void*>());
+			owner->removeRunDataFromAllViews(data);
+			project.removeRunData(data);
+			createTreeWidget();
+		}
+		else if (used == selectAction) {
+			showItem(item);
+		}
+		break;
+	}
+	
+	case Types::ProjectHeader:
+		projectMenu->exec(treeWidget->mapToGlobal(pos));
+		break;
+	default:
+		break;
+	}
 
-	//Remove from List
-	//list->remove(*rundata);
-	//Delete self
-	delete this;
 }
+

+ 26 - 20
metavis/ProjectManager.h

@@ -3,37 +3,43 @@
 #include <QWidget>
 #include <list>
 #include "metavis.h"
-#include "RunData.h"
-
-class FileTreeItem : public QTreeWidgetItem{
-
-private:
-	RunData* rundata = nullptr;
-	std::list<RunData>* list;
-
-public:
-	FileTreeItem(QTreeWidget* parent, const QStringList& strings, RunData* rundata, std::list<RunData>* list , int type = Type);
-	void remove();
-};
+#include <future>
+#include <QStringList>
+#include <QFuture>
+#include <QFutureWatcher>
+#include "Project.h"
+class metavis;
 
 class ProjectManager : public QWidget
 {
 	Q_OBJECT
 
 public:
-	ProjectManager(QWidget *parent, metavis* owner);
+	ProjectManager(metavis* owner);
 	~ProjectManager();
+
+
+	Project project;
+	void openFileDialog();
+	void openFiles(QStringList pathlist);
+	QMenu* projectMenu;
 private:
+	std::future<void> loadingFuture = std::async(std::launch::async, []() {});
+	QFuture<void> future;
+	QFutureWatcher<void> watcher = QFutureWatcher<void>(this);
 	metavis* owner;
 	QTreeWidget* treeWidget;
-	QMenu* filesMenu;
+	QTreeWidgetItem* projectItem;
+	void displayNewFile();
 	QMenu* metalogFileMenu;
-	QMenu* graphMenu;
-
-
-
-
-	enum Types{ LogManger = 1001, LogFile, GraphManger, Graph, Project};
+	QMenu* singleRunMenu;
+	QAction* removeMetalogFileAction;
+	QAction* selectAction;
+	enum Types{ LogManger = 1001, LogFile, Run, GraphManger, Graph, ProjectHeader};
+	QString lastPath;
+	void createTreeWidget();
+	void showItem(QTreeWidgetItem* item);
 private slots:
 	void prepareMenu(const QPoint& pos);
+	void itemClicked(QTreeWidgetItem* item, int column);
 };

+ 0 - 2
metavis/QTestGraph.cpp

@@ -1,2 +0,0 @@
-#include "pch.h"
-#include "QTestGraph.h"

+ 0 - 7
metavis/QTestGraph.h

@@ -1,7 +0,0 @@
-#pragma once
-#include <qwidget.h>
-class QTestGraph :
-	public QWidget
-{
-};
-

+ 125 - 23
metavis/RangeSlider.cpp

@@ -1,11 +1,31 @@
 #include "pch.h"
 #include "RangeSlider.h"
 #include <QDebug>
+#include <QComboBox>
+
 #include "util.h"
 
 RangeSlider::RangeSlider(QWidget *parent)
 	: QWidget(parent), sliderRangeColor(200,200,200), rangeColor(0,122,204)
 {
+	QVBoxLayout* layoutOuter = new QVBoxLayout(this);
+	layoutOuter->setContentsMargins(0, 0, 0, 0);
+	QHBoxLayout* buttonPanelLayout = new QHBoxLayout();
+	buttonPanelLayout->setContentsMargins(0, 0, 0, 0);
+	layoutOuter->addLayout(buttonPanelLayout);
+	layoutOuter->insertStretch(1);
+	titleLabel = new QLabel("Title");
+	buttonPanelLayout->addWidget(titleLabel);
+	buttonPanelLayout->insertStretch(1);
+	
+	QComboBox* combobox = new QComboBox(this);
+	combobox->addItem("Range");
+	combobox->addItem("Iteration");
+	connect(combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+		this, [this](int index) {this->setMode((DisplayMode)index); });
+	buttonPanelLayout->addWidget(combobox);
+	this->setMaximumHeight(70);
+	this->setMinimumHeight(70);
 }
 
 RangeSlider::~RangeSlider()
@@ -42,6 +62,14 @@ void RangeSlider::setMaxSliderValue(int value)
 	}
 }
 
+void RangeSlider::setItertionSliderValue(int value)
+{
+	value = std::clamp(value, minRange, maxRange);
+	itertionSliderValue = value;
+	emit minChanged(itertionSliderValue);
+	emit maxChanged(itertionSliderValue);
+}
+
 void RangeSlider::setRange(int min, int max)
 {
 	if (min > max) {
@@ -51,6 +79,16 @@ void RangeSlider::setRange(int min, int max)
 	maxRange = max;
 }
 
+int RangeSlider::getMinRange() const
+{
+	return minRange;
+}
+
+int RangeSlider::getMaxRange() const
+{
+	return maxRange;
+}
+
 void RangeSlider::setMinRange(int value)
 {
 	if (value > maxRange) {
@@ -60,7 +98,7 @@ void RangeSlider::setMinRange(int value)
 	else {
 		minRange = value;
 	}
-
+	emit minChanged(minSliderValue);
 }
 
 void RangeSlider::setMaxRange(int value)
@@ -72,6 +110,29 @@ void RangeSlider::setMaxRange(int value)
 	else {
 		maxRange = value;
 	}
+	emit maxChanged(maxSliderValue);
+}
+
+void RangeSlider::setMode(DisplayMode mode)
+{
+	this->mode = mode;
+	switch (mode) {
+	case Iteration:
+		emit minChanged(itertionSliderValue);
+		emit maxChanged(itertionSliderValue);
+		break;
+	default:
+	case Range:
+		emit minChanged(minSliderValue);
+		emit maxChanged(maxSliderValue);
+		break;
+	}
+	update();
+}
+
+void RangeSlider::setTitle(QString string)
+{
+	titleLabel->setText(string);
 }
 
 void RangeSlider::paintEvent(QPaintEvent* event)
@@ -81,17 +142,17 @@ void RangeSlider::paintEvent(QPaintEvent* event)
 	painter.setPen(sliderRangeColor);
 	//painter.setBrush(sliderRangeColor);
 	//FindMiddle
-	int middle = rect().center().y();
+	int middle = 35;
 	painter.drawRect(QRect(QPoint(minPos(), middle + 2), QPoint(maxPos(), middle - 2)));
-
-	double minSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, minSliderValue);
-	double minSliderPos = util::linearInterpolate(minPos(), maxPos(), minSliderAlpha);
-
-	double maxSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, maxSliderValue);
-	double maxSliderPos = util::linearInterpolate(minPos(), maxPos(), maxSliderAlpha);
+	painter.setPen(Qt::black);
+	painter.setFont(QFont("Arial", 8));
+	QRect textRect(0, 0, 30, 9);
+	textRect.moveCenter(QPoint(minPos(), middle + 20));
+	painter.drawText(textRect, Qt::AlignCenter, QString::number(this->minRange, 'f', 0));
+	textRect.moveCenter(QPoint(maxPos(), middle + 20));
+	painter.drawText(textRect, Qt::AlignCenter, QString::number(this->maxRange, 'f', 0));
+	
 	
-	//DrawRange
-	painter.fillRect(QRectF(QPointF(minSliderPos, (double)middle - 2), QPointF(maxSliderPos, (double)middle + 2)), rangeColor);
 
 	
 	//DrawSlider
@@ -99,17 +160,53 @@ void RangeSlider::paintEvent(QPaintEvent* event)
 	pen.setWidth(2);
 	painter.setPen(pen);
 	painter.setBrush(sliderRangeColor);
-	painter.drawEllipse(QPointF(minSliderPos, (double)middle + 1), 10, 10);
-	painter.drawEllipse(QPointF(maxSliderPos, (double)middle + 1), 10, 10);
+	switch (mode) {
+	case Iteration:
+	{
+		double itertionSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, itertionSliderValue);
+		double itertionSliderPos = util::linearInterpolate(minPos(), maxPos(), itertionSliderAlpha);
+
+		painter.drawEllipse(QPointF(itertionSliderPos, (double)middle + 1), 10, 10);
+		painter.setPen(Qt::black);
+		textRect.moveCenter(QPoint(itertionSliderPos, middle + 20));
+		painter.drawText(textRect, Qt::AlignCenter, QString::number(this->itertionSliderValue, 'f', 0));
+		break;
+	}
+	default:
+	case Range:
+	{
+		double minSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, minSliderValue);
+		double minSliderPos = util::linearInterpolate(minPos(), maxPos(), minSliderAlpha);
+
+		double maxSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, maxSliderValue);
+		double maxSliderPos = util::linearInterpolate(minPos(), maxPos(), maxSliderAlpha);
+		//DrawRange
+		painter.fillRect(QRectF(QPointF(minSliderPos, (double)middle - 2), QPointF(maxSliderPos, (double)middle + 2)), rangeColor);
+		painter.drawEllipse(QPointF(minSliderPos, (double)middle + 1), 10, 10);
+		painter.drawEllipse(QPointF(maxSliderPos, (double)middle + 1), 10, 10);
+		painter.setPen(Qt::black);
+		textRect.moveCenter(QPoint(minSliderPos, middle + 20));
+		painter.drawText(textRect, Qt::AlignCenter, QString::number(this->minSliderValue, 'f', 0));
+		textRect.moveCenter(QPoint(maxSliderPos, middle + 20));
+		painter.drawText(textRect, Qt::AlignCenter, QString::number(this->maxSliderValue, 'f', 0));
+		break;
+	}
+	}
 }
 
 void RangeSlider::mouseMoveEvent(QMouseEvent* event)
 {
+	if (childAt(event->pos()) != nullptr) {
+		return;
+	}
 	updateSliderPosition(event);
 }
 
 void RangeSlider::mousePressEvent(QMouseEvent* event)
 {
+	if (childAt(event->pos()) != nullptr) {
+		return;
+	}
 	updateSliderPosition(event);
 }
 
@@ -124,21 +221,26 @@ void RangeSlider::updateSliderPosition(QMouseEvent* event)
 	double minSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, minSliderValue);
 	double maxSliderAlpha = util::inverseLinearInterpolation(minRange, maxRange, maxSliderValue);
 
-	if (minSliderAlpha < alpha && alpha < maxSliderAlpha) {
-
-	}
 
 
 	double value = util::linearInterpolate(minRange, maxRange, alpha);
-	
-	double distanceToMin = std::abs(minSliderValue - value);
-	double distanceToMax = std::abs(maxSliderValue - value);
-	if (distanceToMin < distanceToMax) {
-		setMinSliderValue(value);
-	}
-	else {
-		setMaxSliderValue(value);
+	switch (mode) {
+	case Iteration:
+		setItertionSliderValue(value);
+		break;
+	default:
+	case Range:
+		double distanceToMin = std::abs(minSliderValue - value);
+		double distanceToMax = std::abs(maxSliderValue - value);
+		if (distanceToMin < distanceToMax) {
+			setMinSliderValue(value);
+		}
+		else {
+			setMaxSliderValue(value);
+		}
+		break;
 	}
+	
 	update();
 }
 

+ 15 - 5
metavis/RangeSlider.h

@@ -1,35 +1,45 @@
 #pragma once
 #include <QColor>
 #include <QWidget>
+#include <QString>
+#include <QLabel>
+
+
 
 class RangeSlider : public QWidget
 {
 	Q_OBJECT
 
-	int minRange = 0, maxRange = 100, minSliderValue = 25, maxSliderValue = 75;
-	QColor rangeColor, sliderRangeColor;
+	
 public:
+	enum DisplayMode{ Range, Iteration};
 	RangeSlider(QWidget *parent);
 	~RangeSlider();
 	void setMinSliderValue(int value);
 	void setMaxSliderValue(int value);
+	void setItertionSliderValue(int value);
 	void setRange(int min, int max);
+	int getMinRange() const;
+	int getMaxRange() const;
 	void setMinRange(int value);
 	void setMaxRange(int value);
-
+	void setMode(DisplayMode mode);
+	void setTitle(QString string);
 	//Visual Settings:
 	void setRangeColor(QColor color);
 	void setSliderRangeColor(QColor color);
 private:
+	int minRange = 0, maxRange = 100, minSliderValue = 0, maxSliderValue = 100, itertionSliderValue = 50;
+	QColor rangeColor, sliderRangeColor;
+	DisplayMode mode = DisplayMode::Range;
 	void paintEvent(QPaintEvent* event) override;
 	void mouseMoveEvent(QMouseEvent* event) override;
 	void mousePressEvent(QMouseEvent* event) override;
 	void updateSliderPosition(QMouseEvent* event);
-
+	QLabel* titleLabel;
 	int maxPos();
 	int minPos();
 
-
 signals:
 	void maxChanged(int max);
 	void minChanged(int min);

+ 7 - 0
metavis/Resources/3-up-triangle.svg

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--U+25B3-->
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="-40 0 640 180">
+   <polygon points="20 153  90 38  160 153" fill="none" stroke="#000" stroke-width="20" />  
+   <polygon points="220 153  290 38  360 153" fill="none" stroke="#000" stroke-width="20" />
+   <polygon points="420 153  490 38  560 153" fill="none" stroke="#000" stroke-width="20" />
+</svg>

+ 45 - 0
metavis/Resources/arrow_right.svg

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="95.312px" height="95.312px" viewBox="0 0 95.312 95.312" style="enable-background:new 0 0 95.312 95.312;"
+	 xml:space="preserve">
+<g>
+	<path d="M63.408,89.924V77.131c0-1.021-0.828-1.849-1.849-1.849H33.137v0.006h-1.333c-8.453,0-15.33-6.875-15.33-15.33
+		c0-8.451,6.877-15.329,15.33-15.329l34.397-0.025L52.9,57.854c-0.688,0.686-0.688,1.901,0,2.588l8.267,8.266
+		c0.343,0.344,0.81,0.537,1.294,0.537s0.951-0.193,1.294-0.537l31.021-31.022c0.717-0.715,0.717-1.873,0-2.589L63.755,4.076
+		c-0.716-0.714-1.873-0.714-2.588,0L52.9,12.341c-0.344,0.343-0.537,0.809-0.537,1.294s0.193,0.951,0.537,1.295l13.301,13.202
+		l-34.396,0.023C14.268,28.155,0,42.422,0,59.958c0,17.537,14.268,31.806,31.805,31.806l29.756,0.009
+		C62.58,91.772,63.408,90.944,63.408,89.924z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 70 - 0
metavis/Resources/binaryIcon.svg

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 261.501 261.501" style="enable-background:new 0 0 261.501 261.501;" xml:space="preserve">
+<g>
+	<path d="M37.984,161.696c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5v-58.627c0-3.034-1.827-5.768-4.63-6.929
+		c-2.801-1.16-6.028-0.519-8.173,1.626L21.177,116.77c-2.929,2.929-2.929,7.678,0,10.606c2.929,2.929,7.678,2.929,10.606,0
+		l6.201-6.201V161.696z"/>
+	<path d="M82.279,31.807l6.201-6.201v40.521c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5V7.5c0-3.034-1.827-5.768-4.63-6.929
+		c-2.801-1.16-6.028-0.519-8.173,1.626L71.673,21.201c-2.929,2.929-2.929,7.678,0,10.606C74.602,34.736,79.351,34.736,82.279,31.807
+		z"/>
+	<path d="M167.815,96.14c-2.801-1.16-6.028-0.519-8.173,1.626l-19.004,19.004c-2.929,2.929-2.929,7.678,0,10.606
+		c2.929,2.929,7.678,2.929,10.606,0l6.201-6.201v40.521c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5v-58.627
+		C172.445,100.036,170.618,97.301,167.815,96.14z"/>
+	<path d="M135.217,188.445c-2.801-1.16-6.028-0.519-8.173,1.626l-19.004,19.004c-2.929,2.929-2.929,7.678,0,10.606
+		c2.929,2.929,7.678,2.929,10.606,0l6.201-6.201v22.197c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5v-40.303
+		C139.847,192.34,138.02,189.606,135.217,188.445z"/>
+	<path d="M122.504,143.42v-22.074c0-14.213-11.563-25.776-25.776-25.776h-0.369c-14.213,0-25.776,11.563-25.776,25.776v22.074
+		c0,14.213,11.563,25.776,25.776,25.776h0.369C110.941,169.196,122.504,157.633,122.504,143.42z M107.504,143.42
+		c0,5.942-4.834,10.776-10.776,10.776h-0.369c-5.942,0-10.776-4.834-10.776-10.776v-22.074c0-5.942,4.834-10.776,10.776-10.776
+		h0.369c5.942,0,10.776,4.834,10.776,10.776V143.42z"/>
+	<path d="M216.745,95.569h-0.369c-14.213,0-25.776,11.563-25.776,25.776v22.074c0,14.213,11.563,25.776,25.776,25.776h0.369
+		c14.213,0,25.776-11.563,25.776-25.776v-22.074C242.521,107.133,230.958,95.569,216.745,95.569z M227.521,143.42
+		c0,5.942-4.834,10.776-10.776,10.776h-0.369c-5.942,0-10.776-4.834-10.776-10.776v-22.074c0-5.942,4.834-10.776,10.776-10.776
+		h0.369c5.942,0,10.776,4.834,10.776,10.776V143.42z"/>
+	<path d="M147.224,0h-0.369c-14.213,0-25.776,11.563-25.776,25.776v22.074c0,14.213,11.563,25.776,25.776,25.776h0.369
+		c4.142,0,7.5-3.358,7.5-7.5s-3.358-7.5-7.5-7.5h-0.369c-5.942,0-10.776-4.834-10.776-10.776V25.776
+		c0-5.942,4.834-10.776,10.776-10.776h0.369c5.942,0,10.776,4.834,10.776,10.776c0,4.142,3.358,7.5,7.5,7.5s7.5-3.358,7.5-7.5
+		C173.001,11.563,161.438,0,147.224,0z"/>
+	<path d="M216.745,0h-0.369c-14.213,0-25.776,11.563-25.776,25.776v22.074c0,14.213,11.563,25.776,25.776,25.776h0.369
+		c14.213,0,25.776-11.563,25.776-25.776V25.776C242.521,11.563,230.958,0,216.745,0z M227.521,47.851
+		c0,5.942-4.834,10.776-10.776,10.776h-0.369c-5.942,0-10.776-4.834-10.776-10.776V25.776c0-5.942,4.834-10.776,10.776-10.776h0.369
+		c5.942,0,10.776,4.834,10.776,10.776V47.851z"/>
+	<path d="M61.682,187.874h-0.369c-14.213,0-25.776,11.563-25.776,25.776v22.074c0,14.213,11.563,25.776,25.776,25.776h0.369
+		c14.213,0,25.776-11.563,25.776-25.776V213.65C87.459,199.438,75.896,187.874,61.682,187.874z M72.459,235.725
+		c0,5.942-4.834,10.776-10.776,10.776h-0.369c-5.942,0-10.776-4.834-10.776-10.776V213.65c0-5.942,4.834-10.776,10.776-10.776h0.369
+		c5.942,0,10.776,4.834,10.776,10.776V235.725z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 67 - 0
metavis/Resources/csv.svg

@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 318.188 318.188" style="enable-background:new 0 0 318.188 318.188;" xml:space="preserve">
+<g>
+	<g>
+		<g>
+			
+			<polygon points="112.09,123.663 112.09,123.662 118.286,113.621 124.548,123.662 134.588,123.662 123.647,107.909 133.82,91.54 
+				123.911,91.54 118.33,101.472 112.53,91.54 102.906,91.54 112.925,107.228 102.269,123.663 			"/>
+			<path d="M201.02,249.514c-0.339,1.27-0.73,3.015-1.174,5.236c-0.445,2.222-0.741,4.073-0.889,5.555
+				c-0.127-2.053-0.847-5.691-2.158-10.918l-6.316-23.519h-14.092l15.139,46.401h14.759l15.202-46.401h-14.027L201.02,249.514z"/>
+			
+			<path d="M283.149,52.723L232.624,2.197C231.218,0.79,229.311,0,227.321,0H40.342c-4.142,0-7.5,3.358-7.5,7.5v303.188
+				c0,4.142,3.358,7.5,7.5,7.5h237.504c4.142,0,7.5-3.358,7.5-7.5V58.025C285.346,56.036,284.556,54.129,283.149,52.723z
+				 M234.821,25.606l24.918,24.919h-24.918V25.606z M47.842,15h171.979v10.263H47.842V15z M47.842,303.188V40.263h171.979v17.763
+				c0,4.143,3.358,7.5,7.5,7.5h43.024v237.662H47.842z"/>
+			
+			<path d="M122.372,235.484c1.969,0,3.809,0.275,5.523,0.826c1.713,0.55,3.428,1.227,5.141,2.031l3.841-9.871
+				c-4.57-2.18-9.362-3.27-14.378-3.27c-4.591,0-8.585,0.98-11.98,2.937c-3.396,1.957-5.999,4.755-7.808,8.395
+				c-1.81,3.64-2.714,7.86-2.714,12.663c0,7.682,1.867,13.553,5.602,17.615c3.734,4.063,9.104,6.094,16.107,6.094
+				c4.888,0,9.268-0.857,13.14-2.57v-10.602c-1.947,0.805-3.883,1.492-5.808,2.063c-1.926,0.571-3.915,0.857-5.967,0.857
+				c-6.793,0-10.188-4.464-10.188-13.393c0-4.295,0.836-7.665,2.507-10.109C117.062,236.707,119.39,235.484,122.372,235.484z"/>
+			<path d="M163.57,244.594c-4.169-1.904-6.724-3.216-7.665-3.936c-0.942-0.719-1.412-1.533-1.412-2.443
+				c-0.002-0.847,0.368-1.556,1.11-2.127c0.74-0.571,1.925-0.857,3.555-0.857c3.152,0,6.897,0.995,11.234,2.984l3.841-9.681
+				c-4.994-2.222-9.892-3.333-14.694-3.333c-5.439,0-9.713,1.196-12.822,3.587c-3.111,2.392-4.666,5.724-4.666,9.997
+				c0,2.285,0.365,4.264,1.095,5.936s1.851,3.152,3.364,4.443s3.782,2.624,6.809,3.999c3.343,1.503,5.4,2.497,6.173,2.983
+				c0.771,0.486,1.333,0.968,1.682,1.444c0.35,0.476,0.524,1.031,0.524,1.666c0,1.016-0.435,1.847-1.302,2.491
+				c-0.868,0.647-2.233,0.969-4.095,0.969c-2.158,0-4.527-0.344-7.109-1.032c-2.581-0.687-5.067-1.645-7.458-2.872v11.172
+				c2.264,1.079,4.443,1.836,6.538,2.27c2.095,0.434,4.687,0.65,7.775,0.65c3.703,0,6.93-0.619,9.681-1.856
+				c2.75-1.238,4.856-2.973,6.315-5.205c1.461-2.232,2.191-4.787,2.191-7.665c0-3.131-0.777-5.729-2.333-7.792
+				C170.346,248.323,167.569,246.393,163.57,244.594z"/>
+	
+		</g>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 75 - 0
metavis/Resources/csv_remove.svg

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 318.188 318.188" style="enable-background:new 0 0 318.188 318.188;" xml:space="preserve">
+<g>
+	<g>
+		<g>
+			<rect x="182.882" y="155.008" width="33.713" height="15"/>
+			<rect x="101.592" y="132.689" width="33.713" height="15"/>
+			<rect x="182.882" y="132.689" width="33.713" height="15"/>
+			<rect x="182.882" y="88.053" width="33.713" height="15"/>
+			<rect x="182.882" y="110.371" width="33.713" height="15"/>
+			<rect x="101.592" y="155.008" width="33.713" height="15"/>
+			<polygon points="112.09,123.663 112.09,123.662 118.286,113.621 124.548,123.662 134.588,123.662 123.647,107.909 133.82,91.54 
+				123.911,91.54 118.33,101.472 112.53,91.54 102.906,91.54 112.925,107.228 102.269,123.663 			"/>
+			<path d="M201.02,249.514c-0.339,1.27-0.73,3.015-1.174,5.236c-0.445,2.222-0.741,4.073-0.889,5.555
+				c-0.127-2.053-0.847-5.691-2.158-10.918l-6.316-23.519h-14.092l15.139,46.401h14.759l15.202-46.401h-14.027L201.02,249.514z"/>
+			<rect x="142.457" y="110.371" width="33.713" height="15"/>
+			<rect x="142.457" y="88.053" width="33.713" height="15"/>
+			<path d="M283.149,52.723L232.624,2.197C231.218,0.79,229.311,0,227.321,0H40.342c-4.142,0-7.5,3.358-7.5,7.5v303.188
+				c0,4.142,3.358,7.5,7.5,7.5h237.504c4.142,0,7.5-3.358,7.5-7.5V58.025C285.346,56.036,284.556,54.129,283.149,52.723z
+				 M234.821,25.606l24.918,24.919h-24.918V25.606z M47.842,15h171.979v10.263H47.842V15z M47.842,303.188V40.263h171.979v17.763
+				c0,4.143,3.358,7.5,7.5,7.5h43.024v237.662H47.842z"/>
+			<rect x="142.457" y="132.689" width="33.713" height="15"/>
+			<path d="M122.372,235.484c1.969,0,3.809,0.275,5.523,0.826c1.713,0.55,3.428,1.227,5.141,2.031l3.841-9.871
+				c-4.57-2.18-9.362-3.27-14.378-3.27c-4.591,0-8.585,0.98-11.98,2.937c-3.396,1.957-5.999,4.755-7.808,8.395
+				c-1.81,3.64-2.714,7.86-2.714,12.663c0,7.682,1.867,13.553,5.602,17.615c3.734,4.063,9.104,6.094,16.107,6.094
+				c4.888,0,9.268-0.857,13.14-2.57v-10.602c-1.947,0.805-3.883,1.492-5.808,2.063c-1.926,0.571-3.915,0.857-5.967,0.857
+				c-6.793,0-10.188-4.464-10.188-13.393c0-4.295,0.836-7.665,2.507-10.109C117.062,236.707,119.39,235.484,122.372,235.484z"/>
+			<path d="M163.57,244.594c-4.169-1.904-6.724-3.216-7.665-3.936c-0.942-0.719-1.412-1.533-1.412-2.443
+				c-0.002-0.847,0.368-1.556,1.11-2.127c0.74-0.571,1.925-0.857,3.555-0.857c3.152,0,6.897,0.995,11.234,2.984l3.841-9.681
+				c-4.994-2.222-9.892-3.333-14.694-3.333c-5.439,0-9.713,1.196-12.822,3.587c-3.111,2.392-4.666,5.724-4.666,9.997
+				c0,2.285,0.365,4.264,1.095,5.936s1.851,3.152,3.364,4.443s3.782,2.624,6.809,3.999c3.343,1.503,5.4,2.497,6.173,2.983
+				c0.771,0.486,1.333,0.968,1.682,1.444c0.35,0.476,0.524,1.031,0.524,1.666c0,1.016-0.435,1.847-1.302,2.491
+				c-0.868,0.647-2.233,0.969-4.095,0.969c-2.158,0-4.527-0.344-7.109-1.032c-2.581-0.687-5.067-1.645-7.458-2.872v11.172
+				c2.264,1.079,4.443,1.836,6.538,2.27c2.095,0.434,4.687,0.65,7.775,0.65c3.703,0,6.93-0.619,9.681-1.856
+				c2.75-1.238,4.856-2.973,6.315-5.205c1.461-2.232,2.191-4.787,2.191-7.665c0-3.131-0.777-5.729-2.333-7.792
+				C170.346,248.323,167.569,246.393,163.57,244.594z"/>
+			<rect x="142.457" y="155.008" width="33.713" height="15"/>
+			<polygon fill="#EF2D56" transform="translate(150.0 2.0), scale(0.3)" points="386.813,0 245,141.812 103.188,0 0,103.188 141.813,245 0,386.812 103.187,489.999 245,348.187 386.813,490 
+			490,386.812 348.187,244.999 490,103.187 "/>
+		</g>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 39 - 0
metavis/Resources/file.svg

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 450 450" style="enable-background:new 0 0 450 450;" xml:space="preserve">
+<g>
+	<path d="M281.213,0H60v450h330V108.787L281.213,0z M290,51.213L338.787,100H290V51.213z M90,420V30h170v100h100v290H90z"/>
+	
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 52 - 0
metavis/Resources/frame.svg

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<g>
+	<g>
+		<polygon points="426.056,79.367 466.119,79.367 406.387,19.664 346.669,79.367 386.728,79.367 386.728,287.698 346.669,287.698 
+			406.387,347.401 466.119,287.698 426.056,287.698 		"/>
+	</g>
+</g>
+<g>
+	<g>
+		<polygon points="314.626,452.282 254.922,392.55 254.922,432.613 112.139,432.613 112.139,392.55 52.436,452.282 112.139,512 
+			112.139,471.941 254.922,471.941 254.922,512 		"/>
+	</g>
+</g>
+<g>
+	<g>
+		<path d="M45.881,0v367.065H321.18V0H45.881z M281.852,327.737H85.21V39.328h196.642V327.737z"/>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 53 - 0
metavis/Resources/frame_hovered.svg

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
+<g>
+	<g>
+		<polygon points="426.056,79.367 466.119,79.367 406.387,19.664 346.669,79.367 386.728,79.367 386.728,287.698 346.669,287.698 
+			406.387,347.401 466.119,287.698 426.056,287.698 		"/>
+	</g>
+</g>
+<g>
+	<g>
+		<polygon points="314.626,452.282 254.922,392.55 254.922,432.613 112.139,432.613 112.139,392.55 52.436,452.282 112.139,512 
+			112.139,471.941 254.922,471.941 254.922,512 		"/>
+	</g>
+</g>
+<g>
+	<g>
+		<path d="M45.881,0v367.065H321.18V0H45.881z M281.852,327.737H85.21V39.328h196.642V327.737z"/>
+		<path fill="#ff9f00" d="M281.852,327.737H85.21V39.328h196.642V327.737z"/>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 52 - 0
metavis/Resources/gridIcon.svg

@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 460.002 460.002" style="enable-background:new 0 0 460.002 460.002;" xml:space="preserve">
+<g>
+	<g>
+		<path d="M427.137,0H32.865C14.743,0,0,14.743,0,32.865v394.272c0,18.122,14.743,32.865,32.865,32.865h394.272
+			c18.122,0,32.865-14.743,32.865-32.865V32.865C460.002,14.743,445.259,0,427.137,0z M137.305,399.443c0,8.284-6.716,15-15,15
+			H56.251c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V399.443z M137.305,263.028
+			c0,8.284-6.716,15-15,15H56.251c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V263.028z
+			 M137.305,126.613c0,8.284-6.716,15-15,15H56.251c-8.284-0.001-15-6.717-15-15.001V60.559c0-8.284,6.716-15,15-15h66.054
+			c8.284,0,15,6.716,15,15V126.613z M277.071,399.443c0,8.284-6.716,15-15,15h-66.054c-8.284,0-15-6.716-15-15v-66.054
+			c0-8.284,6.715-15,15-15h66.054c8.284,0,15,6.716,15,15V399.443z M277.071,263.028c0,8.284-6.716,15-15,15h-66.054
+			c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.715-15,15-15h66.054c8.284,0,15,6.716,15,15V263.028z M277.071,126.613
+			c0,8.284-6.716,15-15,15h-66.054c-8.285-0.001-15-6.717-15-15.001V60.559c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15
+			V126.613z M418.751,399.443c0,8.284-6.716,15-15,15h-66.054c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.716-15,15-15h66.054
+			c8.284,0,15,6.716,15,15V399.443z M418.751,263.028c0,8.284-6.716,15-15,15h-66.054c-8.284,0-15-6.716-15-15v-66.054
+			c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V263.028z M418.751,126.612c0,8.284-6.716,15-15,15h-66.054
+			c-8.284,0-15-6.716-15-15V60.559c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V126.612z"/>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 54 - 0
metavis/Resources/gridIcon_hovered.svg

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 460.002 460.002" style="enable-background:new 0 0 460.002 460.002;" xml:space="preserve">
+<g>
+	<g>
+		<path fill="#ff9f00" d="M427.137,0H32.865C14.743,0,0,14.743,0,32.865v394.272c0,18.122,14.743,32.865,32.865,32.865h394.272
+			c18.122,0,32.865-14.743,32.865-32.865V32.865C460.002,14.743,445.259,0,427.137,0z"/>
+		<path d="M427.137,0H32.865C14.743,0,0,14.743,0,32.865v394.272c0,18.122,14.743,32.865,32.865,32.865h394.272
+			c18.122,0,32.865-14.743,32.865-32.865V32.865C460.002,14.743,445.259,0,427.137,0z M137.305,399.443c0,8.284-6.716,15-15,15
+			H56.251c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V399.443z M137.305,263.028
+			c0,8.284-6.716,15-15,15H56.251c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V263.028z
+			 M137.305,126.613c0,8.284-6.716,15-15,15H56.251c-8.284-0.001-15-6.717-15-15.001V60.559c0-8.284,6.716-15,15-15h66.054
+			c8.284,0,15,6.716,15,15V126.613z M277.071,399.443c0,8.284-6.716,15-15,15h-66.054c-8.284,0-15-6.716-15-15v-66.054
+			c0-8.284,6.715-15,15-15h66.054c8.284,0,15,6.716,15,15V399.443z M277.071,263.028c0,8.284-6.716,15-15,15h-66.054
+			c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.715-15,15-15h66.054c8.284,0,15,6.716,15,15V263.028z M277.071,126.613
+			c0,8.284-6.716,15-15,15h-66.054c-8.285-0.001-15-6.717-15-15.001V60.559c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15
+			V126.613z M418.751,399.443c0,8.284-6.716,15-15,15h-66.054c-8.284,0-15-6.716-15-15v-66.054c0-8.284,6.716-15,15-15h66.054
+			c8.284,0,15,6.716,15,15V399.443z M418.751,263.028c0,8.284-6.716,15-15,15h-66.054c-8.284,0-15-6.716-15-15v-66.054
+			c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V263.028z M418.751,126.612c0,8.284-6.716,15-15,15h-66.054
+			c-8.284,0-15-6.716-15-15V60.559c0-8.284,6.716-15,15-15h66.054c8.284,0,15,6.716,15,15V126.612z"/>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 51 - 0
metavis/Resources/information_icon.svg

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	viewBox="0 0 490.318 490.318" style="enable-background:new 0 0 490.318 490.318;"
+	 xml:space="preserve">
+<g>
+	<g>
+		<g>
+			<path d="M245.148,0C109.967,0,0.009,109.98,0.009,245.162c0,135.182,109.958,245.156,245.139,245.156
+				c135.186,0,245.162-109.978,245.162-245.156C490.31,109.98,380.333,0,245.148,0z M245.148,438.415
+				c-106.555,0-193.234-86.698-193.234-193.253c0-106.555,86.68-193.258,193.234-193.258c106.559,0,193.258,86.703,193.258,193.258
+				C438.406,351.717,351.706,438.415,245.148,438.415z"/>
+			<path d="M270.036,221.352h-49.771c-8.351,0-15.131,6.78-15.131,15.118v147.566c0,8.352,6.78,15.119,15.131,15.119h49.771
+				c8.351,0,15.131-6.77,15.131-15.119V236.471C285.167,228.133,278.387,221.352,270.036,221.352z"/>
+			<path d="M245.148,91.168c-24.48,0-44.336,19.855-44.336,44.336c0,24.484,19.855,44.34,44.336,44.34
+				c24.485,0,44.342-19.855,44.342-44.34C289.489,111.023,269.634,91.168,245.148,91.168z"/>
+		</g>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 53 - 0
metavis/Resources/information_icon_hovered.svg

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	viewBox="0 0 490.318 490.318" style="enable-background:new 0 0 490.318 490.318;"
+	 xml:space="preserve">
+<g>
+	<g>
+		<g>
+			<path d="M245.148,0C109.967,0,0.009,109.98,0.009,245.162c0,135.182,109.958,245.156,245.139,245.156
+				c135.186,0,245.162-109.978,245.162-245.156C490.31,109.98,380.333,0,245.148,0z M245.148,438.415
+				c-106.555,0-193.234-86.698-193.234-193.253c0-106.555,86.68-193.258,193.234-193.258c106.559,0,193.258,86.703,193.258,193.258
+				C438.406,351.717,351.706,438.415,245.148,438.415z"/>
+			<path fill="#ff9f00" d="M245.148,438.415
+				c-106.555,0-193.234-86.698-193.234-193.253c0-106.555,86.68-193.258,193.234-193.258c106.559,0,193.258,86.703,193.258,193.258
+				C438.406,351.717,351.706,438.415,245.148,438.415z"/>
+			<path d="M270.036,221.352h-49.771c-8.351,0-15.131,6.78-15.131,15.118v147.566c0,8.352,6.78,15.119,15.131,15.119h49.771
+				c8.351,0,15.131-6.77,15.131-15.119V236.471C285.167,228.133,278.387,221.352,270.036,221.352z"/>
+			<path d="M245.148,91.168c-24.48,0-44.336,19.855-44.336,44.336c0,24.484,19.855,44.34,44.336,44.34
+				c24.485,0,44.342-19.855,44.342-44.34C289.489,111.023,269.634,91.168,245.148,91.168z"/>
+			</g>
+	</g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 49 - 0
metavis/Resources/rubbish.svg

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	  viewBox="0 0 372.693 372.693" style="enable-background:new 0 0 372.693 372.693;"
+	 xml:space="preserve">
+<g>
+	<path d="M322.248,51.317h-67.296v-18.09C254.952,14.904,240.047,0,221.727,0h-70.755c-18.323,0-33.233,14.904-33.233,33.228v18.084
+		H50.452c-18.324,0-33.237,14.906-33.237,33.218v35.38c0,9.535,7.755,17.285,17.297,17.285h23.476v202.274
+		c0,18.321,14.907,33.225,33.225,33.225h194.472c18.32,0,33.236-14.915,33.236-33.225V137.201h19.264
+		c9.535,0,17.294-7.75,17.294-17.285v-35.38C355.478,66.224,340.568,51.317,322.248,51.317z M152.308,34.576h68.067v16.741h-68.067
+		V34.576z M153.353,306.316c0,9.188-7.485,16.67-16.681,16.67c-9.206,0-16.696-7.482-16.696-16.67v-139.59
+		c0-9.196,7.491-16.693,16.696-16.693c9.196,0,16.681,7.497,16.681,16.693V306.316z M203.028,306.316
+		c0,9.188-7.481,16.67-16.681,16.67c-9.197,0-16.681-7.482-16.681-16.67v-139.59c0-9.196,7.484-16.693,16.681-16.693
+		c9.206,0,16.681,7.497,16.681,16.693V306.316z M252.723,306.316c0,9.188-7.493,16.67-16.692,16.67c-9.2,0-16.67-7.482-16.67-16.67
+		v-139.59c0-9.196,7.47-16.693,16.67-16.693c9.199,0,16.692,7.497,16.692,16.693V306.316z"/>
+	
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 54 - 0
metavis/Resources/rubbish_hovered.svg

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	  viewBox="0 0 372.693 372.693" style="enable-background:new 0 0 372.693 372.693;"
+	 xml:space="preserve">
+<g>
+	<path d="M322.248,51.317h-67.296v-18.09C254.952,14.904,240.047,0,221.727,0h-70.755c-18.323,0-33.233,14.904-33.233,33.228v18.084
+		H50.452c-18.324,0-33.237,14.906-33.237,33.218v35.38c0,9.535,7.755,17.285,17.297,17.285h23.476v202.274
+		c0,18.321,14.907,33.225,33.225,33.225h194.472c18.32,0,33.236-14.915,33.236-33.225V137.201h19.264
+		c9.535,0,17.294-7.75,17.294-17.285v-35.38C355.478,66.224,340.568,51.317,322.248,51.317z M152.308,34.576h68.067v16.741h-68.067
+		V34.576z M153.353,306.316c0,9.188-7.485,16.67-16.681,16.67c-9.206,0-16.696-7.482-16.696-16.67v-139.59
+		c0-9.196,7.491-16.693,16.696-16.693c9.196,0,16.681,7.497,16.681,16.693V306.316z M203.028,306.316
+		c0,9.188-7.481,16.67-16.681,16.67c-9.197,0-16.681-7.482-16.681-16.67v-139.59c0-9.196,7.484-16.693,16.681-16.693
+		c9.206,0,16.681,7.497,16.681,16.693V306.316z M252.723,306.316c0,9.188-7.493,16.67-16.692,16.67c-9.2,0-16.67-7.482-16.67-16.67
+		v-139.59c0-9.196,7.47-16.693,16.67-16.693c9.199,0,16.692,7.497,16.692,16.693V306.316z"/>
+	<path fill="#ff9f00" d="M153.353,306.316c0,9.188-7.485,16.67-16.681,16.67c-9.206,0-16.696-7.482-16.696-16.67v-139.59
+		c0-9.196,7.491-16.693,16.696-16.693c9.196,0,16.681,7.497,16.681,16.693V306.316z M203.028,306.316
+		c0,9.188-7.481,16.67-16.681,16.67c-9.197,0-16.681-7.482-16.681-16.67v-139.59c0-9.196,7.484-16.693,16.681-16.693
+		c9.206,0,16.681,7.497,16.681,16.693V306.316z M252.723,306.316c0,9.188-7.493,16.67-16.692,16.67c-9.2,0-16.67-7.482-16.67-16.67
+		v-139.59c0-9.196,7.47-16.693,16.67-16.693c9.199,0,16.692,7.497,16.692,16.693V306.316z"/>
+	<path fill="#ff9f00" d="M152.308,34.576h68.067v16.741h-68.067 V34.576z"/>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+<g>
+</g>
+</svg>

+ 5 - 0
metavis/Resources/up-triangle.svg

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--U+25B3-->
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="-40 10 240 170">
+   <polygon points="20 153  90 38  160 153" fill="none" stroke="#000" stroke-width="20" />
+</svg>

+ 230 - 89
metavis/RunData.cpp

@@ -4,7 +4,7 @@
 #include <QDebug>
 #include <QString>
 #include <regex>
-
+#include <algorithm>
 
 
 RunData::RunData()
@@ -14,7 +14,7 @@ RunData::RunData()
 RunData::RunData(std::string filePath) : fileStream(filePath), filePath(filePath)
 {
     
-    std::string file = filePath.substr(filePath.find_last_of("/\\")+1);
+    std::string file = filePath.substr(filePath.find_last_of("/\\") + 1);
     name = file.substr(0, file.rfind("."));
     if (!fileStream.is_open())
     {
@@ -22,6 +22,99 @@ RunData::RunData(std::string filePath) : fileStream(filePath), filePath(filePath
         badFileFlag = true;
         return;
     }
+    std::string buffer;
+    getLine(buffer);
+    qDebug() << QString::fromStdString(buffer);
+    /*bool retflag;
+    metalogFile(retflag);
+    if (retflag) return;*/
+    std::string integerRegexString = "([\\+\\-]?\\d+)";
+    std::string doubleRegexString = "([\\+\\-]?\\d+(?:\\.\\d+(?:E[\\+\\-]\\d+)?)?)";
+    std::string binaryRegexString = "([01]+)";
+    std::string seperator = ",";
+    std::regex regexLine(integerRegexString
+        + seperator + integerRegexString
+        + seperator + integerRegexString
+        + seperator + doubleRegexString
+        + seperator + binaryRegexString);
+    while (fileStream.peek() != EOF) {
+        std::string buffer;
+        getLine(buffer);
+        SolutionPointData sol;
+        std::smatch match;
+        if (!std::regex_search(buffer, match, regexLine)) {
+            qDebug() << "Bad formatatted Line[" << actualLine << "].";
+            qDebug() << "Failed to matched:";
+            qDebug() << QString::fromStdString(buffer);
+            return;
+        }
+        sol.round = std::stoi(match[1]);
+        sol.iteration = std::stoi(match[2]);
+        sol.particleNumber = std::stoi(match[3]);
+        sol.objectiveFunction = std::stod(match[4]);
+        sol.bitVec.resize(match[5].length());
+        std::string binaryString = match[5];
+        for (std::string::size_type i = 0; i < binaryString.size(); ++i) {
+            sol.bitVec[i] = (binaryString[i] == '1');
+        }
+        solutionVec.push_back(sol);
+    }
+    fileStream.close();
+    qDebug() << "Import done";
+   
+
+
+    //Set Runs apart
+    int count = 0;
+    std::vector<SolutionPointData>::iterator begin = solutionVec.begin();
+    for (auto iter = solutionVec.begin(); iter != solutionVec.end(); iter++) {
+        if (iter->round != begin->round) {
+            std::string endString("[");
+            endString += std::to_string(count++);
+            endString += "]";
+            singleRunList.push_back(SingleRun(name, begin, iter, name +  endString));
+            begin = iter;
+        }
+    }
+    std::string endString("[");
+    endString += std::to_string(count);
+    endString += "]";
+    singleRunList.push_back(SingleRun(name, begin, solutionVec.end(), name + endString));
+
+
+
+    //Generate PascalTriangle
+    std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
+
+    int amountOfBits = begin->bitVec.size();
+    int lines = amountOfBits + 1;
+    std::vector<boost::multiprecision::cpp_int> pascalTriangleVec(((lines + 1) / 2 * (lines / 2 + 1)));
+    for (int line = 0; line < lines; line++) {
+        for (int number = 0; number < line + 1; number++) {
+            if (number > line / 2) break;
+            if (number == 0 || number == line) {
+                pascalTriangleVec[binominalIndex(line, number)] = 1;
+            }
+            else {
+                pascalTriangleVec[binominalIndex(line, number)] = pascalTriangleVec[binominalIndex(line - 1, number)] + pascalTriangleVec[binominalIndex(line - 1, number - 1)];
+            }
+
+        }
+    }
+    std::chrono::high_resolution_clock::time_point endPoint = std::chrono::high_resolution_clock::now();
+    std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(endPoint - start);
+    qDebug() << "PascalTriangle: " << time.count() << "ms";
+    //Calculate Additional Data
+    for (SingleRun& srun : singleRunList) {
+        srun.calculateAdditionalData(pascalTriangleVec, amountOfBits);
+    }
+    calculateAverageOverRuns();
+
+}
+
+void RunData::metalogFile(bool& retflag)
+{
+    retflag = true;
     /* Start extracting */
     while (fileStream.peek() != EOF) {
         std::string buffer;
@@ -54,7 +147,7 @@ RunData::RunData(std::string filePath) : fileStream(filePath), filePath(filePath
         }
         sol.particleNumber = std::stoi(match[1]);
         std::regex regexBitVec("b:([01]+)");
-        if(!std::regex_search(buffer, match, regexBitVec)) {
+        if (!std::regex_search(buffer, match, regexBitVec)) {
             qDebug() << "Bad formatatted Line[" << actualLine << "].";
             qDebug() << "Failed to matched:";
             qDebug() << QString::fromStdString(buffer);
@@ -68,12 +161,7 @@ RunData::RunData(std::string filePath) : fileStream(filePath), filePath(filePath
         }
         solutionVec.push_back(sol);
     }
-    fileStream.close();
-    calculateBestAndAverageIter();
-    calculateParticleSolution();
-    calculateDotsForDistribution();
-    calculateBitFieldData();
-    calculateMeanHammingDistance();
+    retflag = false;
 }
 
 void RunData::getLine(std::string& bufferString)
@@ -82,22 +170,60 @@ void RunData::getLine(std::string& bufferString)
     actualLine++;
 }
 
-void RunData::calculateBestAndAverageIter()
+void RunData::calculateAverageOverRuns()
+{
+    qDebug() << "calculateAverageOverRuns";
+
+    {
+        std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
+        int iter = singleRunList.begin()->bestMaxSolutionFoundPerIteration.size();
+        double n = singleRunList.size();
+        bestAverageMaxSolutionFoundPerIteration.resize(iter);
+        for (int i = 0; i < iter; i++) {
+            double average = std::accumulate(singleRunList.begin(), singleRunList.end(), 0.0, [i](double a, const SingleRun& b) -> double
+                {return a + b.bestMaxSolutionFoundPerIteration[i].y; }) / n;
+            bestAverageMaxSolutionFoundPerIteration[i] = GraphDataPoint((double)i, average);
+        }
+        std::chrono::high_resolution_clock::time_point endPoint = std::chrono::high_resolution_clock::now();
+        std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(endPoint - start);
+        qDebug() << "Time" << time.count() << "ms";
+    }
+
+}
+
+SingleRun::SingleRun(std::string uniqueName, const std::vector<SolutionPointData>::iterator begin, const std::vector<SolutionPointData>::iterator end, std::string name = "")
+    :begin(begin), end(end), name(name), runDataName(uniqueName)
 {
-    if (solutionVec.empty()) {
+
+}
+
+void SingleRun::calculateAdditionalData(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, int amountOfBits)
+{
+    calculateBestAndAverageIter();
+    calculateParticleSolution();
+    calculateDotsForDistribution();
+    calculateBitFieldData(pascalTriangleVec, amountOfBits);
+    calculateMeanHammingDistance();
+}
+
+void SingleRun::calculateBestAndAverageIter()
+{
+    if (begin == end) {
         return;
     }
-    double minObjectiveFunctionInIter = solutionVec[0].objectiveFunction;
-    double maxObjectiveFunctionInIter = solutionVec[0].objectiveFunction;
-    double bestObjectiveFunctionFound = solutionVec[0].objectiveFunction;
-    double actualIterObjectiveFunctionAggregate = solutionVec[0].objectiveFunction;
-    int actualIter = solutionVec[0].iteration;
+    double minObjectiveFunctionInIter = begin->objectiveFunction;
+    double maxObjectiveFunctionInIter = begin->objectiveFunction;
+    double bestMinObjectiveFunctionFound = begin->objectiveFunction;
+    double bestMaxObjectiveFunctionFound = begin->objectiveFunction;
+    double actualIterObjectiveFunctionAggregate = begin->objectiveFunction;
+    int actualIter = begin->iteration;
     int foundSolutionInIteration = 1; 
-    for(int i = 1; i < solutionVec.size(); i++) {
-        SolutionPointData nextData = solutionVec[i];
+    for (auto iter = begin; iter != end; iter++) {
+        SolutionPointData& nextData = *iter;
         if (nextData.iteration != actualIter) {
             //save last
-            bestSolutionPerIteration.push_back(GraphDataPoint((double)actualIter, bestObjectiveFunctionFound));
+            bestMinSolutionFoundPerIteration.push_back(GraphDataPoint((double)actualIter, bestMinObjectiveFunctionFound));
+            bestMaxSolutionFoundPerIteration.push_back(GraphDataPoint((double)actualIter, bestMaxObjectiveFunctionFound));
             averageSolutionPerItertion.push_back(GraphDataPoint((double)actualIter, actualIterObjectiveFunctionAggregate / (double)foundSolutionInIteration));
             minSolutionPerItertion.push_back(GraphDataPoint((double)actualIter, minObjectiveFunctionInIter));
             maxSolutionPerItertion.push_back(GraphDataPoint((double)actualIter, maxObjectiveFunctionInIter));
@@ -114,8 +240,11 @@ void RunData::calculateBestAndAverageIter()
             actualIterObjectiveFunctionAggregate += nextData.objectiveFunction;
         }
         //update best min and max if better
-        if (nextData.objectiveFunction < bestObjectiveFunctionFound) {
-            bestObjectiveFunctionFound = nextData.objectiveFunction;
+        if (nextData.objectiveFunction < bestMinObjectiveFunctionFound) {
+            bestMinObjectiveFunctionFound = nextData.objectiveFunction;
+        }
+        if (nextData.objectiveFunction > bestMaxObjectiveFunctionFound) {
+            bestMaxObjectiveFunctionFound = nextData.objectiveFunction;
         }
         if (nextData.objectiveFunction < minObjectiveFunctionInIter) {
             minObjectiveFunctionInIter = nextData.objectiveFunction;
@@ -125,114 +254,97 @@ void RunData::calculateBestAndAverageIter()
         }
     }
     //save last iteration
-    bestSolutionPerIteration.push_back(GraphDataPoint((double)actualIter, bestObjectiveFunctionFound));
+    bestMinSolutionFoundPerIteration.push_back(GraphDataPoint((double)actualIter, bestMinObjectiveFunctionFound));
+    bestMaxSolutionFoundPerIteration.push_back(GraphDataPoint((double)actualIter, bestMaxObjectiveFunctionFound));
     averageSolutionPerItertion.push_back(GraphDataPoint((double)actualIter, actualIterObjectiveFunctionAggregate / (double)foundSolutionInIteration));
     minSolutionPerItertion.push_back(GraphDataPoint((double)actualIter, minObjectiveFunctionInIter));
     maxSolutionPerItertion.push_back(GraphDataPoint((double)actualIter, maxObjectiveFunctionInIter));
-
-
 }
 
-void RunData::calculateParticleSolution()
+void SingleRun::calculateParticleSolution()
 {
-    for (SolutionPointData sol : solutionVec) {
-        GraphDataPoint point(sol.iteration, sol.objectiveFunction, &sol);
-        auto iter = particleMap.find(sol.particleNumber);
-        if (iter == particleMap.end()) {
+    for (auto iter = begin; iter != end; iter++) {
+        GraphDataPoint point(iter->iteration, iter->objectiveFunction, &*iter);
+        auto treeIter = particleMap.find(iter->particleNumber);
+        if (treeIter == particleMap.end()) {
             //create new Entry
             std::vector<GraphDataPoint> vec;
             vec.push_back(point);
-            particleMap.insert({ sol.particleNumber, vec});
+            particleMap.insert({ iter->particleNumber, vec});
         }
         else {
             //append to vector in Entry
-            iter->second.push_back(point);
+            treeIter->second.push_back(point);
         }
     }
 }
 
-void RunData::calculateDotsForDistribution()
+void SingleRun::calculateDotsForDistribution()
 {
-    for (std::vector<SolutionPointData>::iterator it = solutionVec.begin(); it != solutionVec.end(); ++it) {
+    for (std::vector<SolutionPointData>::iterator it = begin; it != end; ++it) {
         dotsForDistribution.push_back(GraphDataPoint((double)it->iteration, it->objectiveFunction, &*it));
     }
 }
-int binominalIndex(const int n, int k)
-{
-    if (k > n / 2) k = n - k;
-    return ((n+1)/2) * (n/2 + 1) + k;
-}
-boost::multiprecision::cpp_int positionInPermutation2(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfSetBits)
+
+boost::multiprecision::cpp_int positionInPermutation2(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfUnsetBits)
 {
-    int amountOfBits = end - begin;
     //recursion base
-    if (amountOfSetBits == 0) return 1;
-    std::vector<bool>::iterator indexIter = std::find(begin, end, true);
+    if (amountOfUnsetBits == 0) return 1;
+    int amountOfBits = end - begin;
+    std::vector<bool>::iterator indexIter = std::find(begin, end, false);
     int index = indexIter - begin;
-    int amountOfBitsAfterIndex = amountOfBits - 1 - index;
+    int amountOfBitsAfterIndex = (amountOfBits - 1) - index;
     //recursion base
-    if (amountOfSetBits == 1) return amountOfBits - index;
+    if (amountOfUnsetBits == 1) return (amountOfBits - 1) - index;
     //Step 1 the amount of permutations with the rest amountOfBitsAfterIndex 
-    boost::multiprecision::cpp_int before = pascalTriangleVec[binominalIndex(amountOfBitsAfterIndex, amountOfSetBits)];
-    //Step 2 teh actual position of the rest
-    boost::multiprecision::cpp_int after = positionInPermutation2(pascalTriangleVec, ++indexIter, end, amountOfSetBits - 1);
-    //setp 3 add Step 1 and Step 2
+    boost::multiprecision::cpp_int before = (amountOfUnsetBits <= amountOfBitsAfterIndex) ? pascalTriangleVec[RunData::binominalIndex(amountOfBitsAfterIndex, amountOfUnsetBits)] : 0;
+    //Step 2 the actual position of the rest
+    boost::multiprecision::cpp_int after = positionInPermutation2(pascalTriangleVec, ++indexIter, end, amountOfUnsetBits - 1);
+    //Step 3 add Step 1 and Step 2
     return before + after;
 }
 
-void RunData::calculateBitFieldData()
+void SingleRun::calculateBitFieldData(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, int amountOfBits)
 {
+    
     std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
 
-    int amountOfBits = solutionVec[0].bitVec.size();
-    int lines = amountOfBits + 1;
-    std::vector<boost::multiprecision::cpp_int> pascalTriangleVec(((lines+1)/2 * (lines/2 + 1)));
-    for (int line = 0; line < lines; line++) {
-        for (int number = 0; number < line + 1; number++) {
-            if (number > line / 2) break;
-            if (number == 0 || number == line) {
-                pascalTriangleVec[binominalIndex(line, number)] = 1;
-            }
-            else {
-                pascalTriangleVec[binominalIndex(line, number)] = pascalTriangleVec[binominalIndex(line - 1, number)] + pascalTriangleVec[binominalIndex(line - 1, number - 1)];
-            }
-
-        }
-    }
-    std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
-    std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
-    qDebug() << "PascalTriangle: " << time.count() << "ms";
-
-    for (std::vector<SolutionPointData>::iterator it = solutionVec.begin(); it != solutionVec.end(); ++it) {
+    for (std::vector<SolutionPointData>::iterator it = begin; it != end; ++it) {
             int amountOfSetBits = std::count(it->bitVec.begin(), it->bitVec.end(), true);
-            boost::multiprecision::cpp_dec_float_100 position(positionInPermutation2(pascalTriangleVec, it->bitVec.begin(), it->bitVec.end(), amountOfSetBits) - 1);
-            boost::multiprecision::cpp_dec_float_100 maxAmountOfPermutaions (pascalTriangleVec[binominalIndex(amountOfBits, amountOfSetBits)] - 1);
+            int amountOfUnsetBits = it->bitVec.size() - amountOfSetBits;
+            boost::multiprecision::cpp_dec_float_100 position(positionInPermutation2(pascalTriangleVec, it->bitVec.begin(), it->bitVec.end(), amountOfUnsetBits));
+            boost::multiprecision::cpp_dec_float_100 maxAmountOfPermutaions (pascalTriangleVec[RunData::binominalIndex(amountOfBits, amountOfSetBits)] - 1);
 
             dotsForBitField.push_back(GraphDataPoint((position / maxAmountOfPermutaions).convert_to<double>(), amountOfSetBits, &*it));
     }
-    std::chrono::high_resolution_clock::time_point end2 = std::chrono::high_resolution_clock::now();
-    time = std::chrono::duration_cast<std::chrono::milliseconds>(end2 - end);
-    qDebug() << "BitFieldBerechnung: " << time.count() << "ms";
-
+   std::chrono::high_resolution_clock::time_point endPoint = std::chrono::high_resolution_clock::now();
+   std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(endPoint - start);
+   qDebug() << "BitFieldBerechnung: " << time.count() << "ms";
 }
 
-void RunData::calculateMeanHammingDistance()
+void SingleRun::calculateMeanHammingDistance()
 {
     std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
-    std::vector<SolutionPointData>::iterator iterBegin = solutionVec.begin();
-    for (std::vector<SolutionPointData>::iterator iter = solutionVec.begin(); iter != solutionVec.end(); iter++) {
+    std::vector<SolutionPointData>::iterator iterBegin = begin;
+    for (std::vector<SolutionPointData>::iterator iter = begin; iter != end; iter++) {
         if (iter->iteration != iterBegin->iteration) {
-            double mean = meanHammingDistance(iterBegin, iter);
+            double mean = RunData::meanHammingDistance(iterBegin, iter);
             meanHammingDistancePerIteration.push_back(GraphDataPoint(iterBegin->iteration, mean));
             iterBegin = iter;
         }
     }
-    std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
-    std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
+    std::chrono::high_resolution_clock::time_point endPoint = std::chrono::high_resolution_clock::now();
+    std::chrono::milliseconds time = std::chrono::duration_cast<std::chrono::milliseconds>(endPoint - start);
     qDebug() << "Mean: " << time.count() << "ms";
 }
 
 
+int RunData::binominalIndex(const int n, int k)
+{
+    if (k > n / 2) k = n - k;
+    return ((n + 1) / 2) * (n / 2 + 1) + k;
+}
+
 int RunData::hammingdistance(std::vector<bool>& bitVecA, std::vector<bool>& bitVecB)
 {
     //assert((bitVecA.size() == bitVecB.size()));
@@ -275,20 +387,43 @@ boost::multiprecision::cpp_int RunData::binominal(const int n,int k)
     return value;
 }
 
-boost::multiprecision::cpp_int RunData::positionInPermutation(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfSetBits)
+boost::multiprecision::cpp_int RunData::positionInPermutation(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int setBits)
 {
     int amountOfBits = end - begin;
     //recursion base
-    if (amountOfSetBits == 0) return 1;
+    if (setBits == 0) return 1;
     std::vector<bool>::iterator indexIter = std::find(begin, end, true);//TODO:false könnte andersrum sortieren!
     int index = indexIter - begin;
-    int amountOfBitsAfterIndex = amountOfBits - 1 - index;
+    int bitsAfterIndex = (amountOfBits - 1) - index;
     //recursion base
-    if (amountOfSetBits == 1) return amountOfBits - index;
+    if (setBits == 1) return (amountOfBits - 1) - index;
     //Step 1 the amount of permutations with the rest amountOfBitsAfterIndex 
-    boost::multiprecision::cpp_int before = binominal(amountOfBitsAfterIndex, amountOfSetBits);
+    boost::multiprecision::cpp_int before = binominal(bitsAfterIndex, setBits);
     //Step 2 teh actual position of the rest
-    boost::multiprecision::cpp_int after = positionInPermutation(++indexIter, end, amountOfSetBits - 1);
+    boost::multiprecision::cpp_int after = positionInPermutation(++indexIter, end, setBits - 1);
+    //setp 3 add Step 1 and Step 2
+    return before + after;
+}
+
+boost::multiprecision::cpp_int RunData::positionInPermutation_reversed(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfUnsetBits)
+{
+    qDebug() << "Method()";
+    int amountOfBits = end - begin;
+    //recursion base
+    if (amountOfUnsetBits == 0) return 1;
+    std::vector<bool>::iterator indexIter = std::find(begin, end, false);
+    int index = indexIter - begin;
+    qDebug() << "index: " << index;
+    int bitsAfterIndex = (amountOfBits - 1) - index;
+    //recursion base
+    if (amountOfUnsetBits == 1) return (amountOfBits - 1) - index;
+    //Step 1 the amount of permutations with the rest amountOfBitsAfterIndex 
+    boost::multiprecision::cpp_int before = (amountOfUnsetBits <= bitsAfterIndex)? binominal(bitsAfterIndex, amountOfUnsetBits):0;
+    qDebug() << "before: " << "binominal("<< bitsAfterIndex << "," << amountOfUnsetBits  << ")" << before.convert_to<int>();
+    //Step 2 teh actual position of the rest
+    boost::multiprecision::cpp_int after = positionInPermutation_reversed(++indexIter, end, amountOfUnsetBits - 1);
+    qDebug() << "after: " << after.convert_to<int>();
+    qDebug() << "return:" << before.convert_to<int>() << "+" << after.convert_to<int>();
     //setp 3 add Step 1 and Step 2
     return before + after;
 }
@@ -304,7 +439,7 @@ GraphDataPoint::GraphDataPoint(double x, double y, QColor color, SolutionPointDa
 {
 }
 
-bool GraphDataPoint::existLink()
+bool GraphDataPoint::existLink() const
 {
     return orginalPoint != nullptr;
 }
@@ -319,4 +454,10 @@ double GraphDataPoint::squaredDistance(QPointF& graphPoint) const
     return std::pow(graphPoint.x() - x, 2) + std::pow(graphPoint.y() - y, 2);
 }
 
-
+std::string SolutionPointData::bitstringToStdString()
+{
+    std::string str(bitVec.size(), 0);
+    std::transform(bitVec.begin(), bitVec.end(), str.begin(),
+        [](bool b) -> char { return b ? '1' : '0'; });
+    return str;
+}

+ 46 - 20
metavis/RunData.h

@@ -7,13 +7,15 @@
 #include <boost/multiprecision/cpp_int.hpp>
 #include <boost/multiprecision/cpp_dec_float.hpp>
 
-
+class RunData;
 
 struct SolutionPointData {
+	int round;
 	int iteration;
 	double objectiveFunction;
 	int particleNumber;
 	std::vector<bool> bitVec;
+	std::string bitstringToStdString();
 };
 struct GraphDataPoint {
 	double x;
@@ -23,11 +25,39 @@ struct GraphDataPoint {
 	GraphDataPoint() :x(0), y(0), orginalPoint(nullptr) {}
 	GraphDataPoint(double x, double y, SolutionPointData* orginalPoint = nullptr);
 	GraphDataPoint(double x, double y, QColor color, SolutionPointData* orginalPoint = nullptr);
-	bool existLink();
+	bool existLink() const;
 	QPointF toQPointF() const;
 	double squaredDistance(QPointF& graphPoint) const;
 };
 
+class SingleRun {
+public:
+	std::string name;
+	std::string runDataName;
+	const std::vector<SolutionPointData>::iterator begin;
+	const std::vector<SolutionPointData>::iterator end;
+	SingleRun(std::string uniqueName, const std::vector<SolutionPointData>::iterator begin, const std::vector<SolutionPointData>::iterator end, std::string name);
+	std::vector<GraphDataPoint> bestMinSolutionFoundPerIteration;
+	std::vector<GraphDataPoint> bestMaxSolutionFoundPerIteration;
+	std::vector<GraphDataPoint> averageSolutionPerItertion;
+	std::vector<GraphDataPoint> minSolutionPerItertion;
+	std::vector<GraphDataPoint> maxSolutionPerItertion;
+	std::vector<GraphDataPoint> dotsForDistribution;
+	std::vector<GraphDataPoint> dotsForBitField;
+	std::vector<GraphDataPoint> meanHammingDistancePerIteration;
+	std::map<int, std::vector<GraphDataPoint>> particleMap;
+
+	void calculateAdditionalData(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, int amountOfBits);
+private:
+	void calculateBestAndAverageIter();
+	void calculateParticleSolution();
+	void calculateDotsForDistribution();
+	void calculateBitFieldData(std::vector<boost::multiprecision::cpp_int>& pascalTriangleVec, int amountOfBits);
+	void calculateMeanHammingDistance();
+};
+
+
+
 class RunData
 {
 public:
@@ -35,33 +65,29 @@ public:
 	std::string information;
 	std::string filePath;
 	std::vector<SolutionPointData> solutionVec;
+	std::list<SingleRun> singleRunList;
+	std::vector<GraphDataPoint> bestAverageMaxSolutionFoundPerIteration;
+
+
+
 	RunData();
 	RunData(std::string filePath);
-	
 
-	std::vector<GraphDataPoint> bestSolutionPerIteration;
-	std::vector<GraphDataPoint> averageSolutionPerItertion;
-	std::vector<GraphDataPoint> minSolutionPerItertion;
-	std::vector<GraphDataPoint> maxSolutionPerItertion;
-	std::vector<GraphDataPoint> dotsForDistribution;
-	std::vector<GraphDataPoint> dotsForBitField;
-	std::vector<GraphDataPoint> meanHammingDistancePerIteration;
-	std::map<int, std::vector<GraphDataPoint>> particleMap;
+	void metalogFile(bool& retflag);
+
 private:
 	bool badFileFlag = false;
 	std::fstream fileStream;
 	int actualLine = 0;
 	void getLine(std::string& bufferString);
-
-	void calculateBestAndAverageIter();
-	void calculateParticleSolution();
-	void calculateDotsForDistribution();
-	void calculateBitFieldData();
-	void calculateMeanHammingDistance();
+	void calculateAverageOverRuns();
+	
+public:
+	static int binominalIndex(const int n, int k);
 	int static hammingdistance(std::vector<bool>& bitVecA, std::vector<bool>& bitVecB);
 	double static meanHammingDistance(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end);
-
-	boost::multiprecision::cpp_int binominal(const int n, const int k);
-	boost::multiprecision::cpp_int positionInPermutation(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfSetBits);
+	static boost::multiprecision::cpp_int binominal(const int n, const int k);
+	static boost::multiprecision::cpp_int positionInPermutation(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfSetBits);
+	static boost::multiprecision::cpp_int positionInPermutation_reversed(std::vector<bool>::iterator begin, std::vector<bool>::iterator end, int amountOfUnsetBits);
 };
 

+ 48 - 0
metavis/Scratchpad.cpp

@@ -0,0 +1,48 @@
+#include "pch.h"
+#include "Scratchpad.h"
+#include "HoverButton.h"
+#include <QAction>
+
+Scratchpad::Scratchpad(QWidget *parent)
+	: BitInspectorPanel(parent)
+{
+	HoverButton* rubbishButton = new HoverButton();
+	rubbishButton->setMinimumSize(20, 20);
+	rubbishButton->setMaximumSize(20, 20);
+	rubbishButton->setIcon(QIcon(":/metavis/Resources/rubbish.svg"));
+	rubbishButton->setHoveredIcon(QIcon(":/metavis/Resources/rubbish_hovered.svg"));
+	rubbishButton->setAttribute(Qt::WA_TranslucentBackground);
+	rubbishButton->setStyleSheet(rubbishButton->styleSheet() + "border: none;");
+	rubbishButton->setToolTip("Clear scratchpad");
+	qDebug() << topPanel->count();
+	topPanel->insertWidget(topPanel->count()-1, rubbishButton);
+	connect(rubbishButton, &QPushButton::released, this, &Scratchpad::clear);
+	
+	QAction* clearAction = new QAction("Clear");
+	this->contextMenu->addAction(clearAction);
+	connect(clearAction, &QAction::triggered, this, &Scratchpad::clear);
+
+	popupWidget->setInformation("<h3><u>Scratchpad</u></h3> Shows selected solution from search space visualizations or metrics. Each solution gets displayed in a row. To add solutions go in an different visualization and drag over the points you want to add while hold the RMB(Right-Mouse-Button).<br><b>Clear button:</b> Removes all solutions from this pad.<br> Alternative is press RMB and \"Clear\" in the scratchpad. <br><b>Iteration:</b> Shows the iteratioon in which the solution is generated.<br><b>Number:</b> Shows which individual in the population is represented.<br><b>Objective Function:</b> Describes how good the solution is, it depends on the problem if a low or high value is desired.<br><b>Binary:</b> Shows the bitstring of the solution. White rectangle represents the bit is <i>false<i> and black <i>true<i>.");
+}
+
+Scratchpad::~Scratchpad()
+{
+}
+
+void Scratchpad::addPoint(const SolutionPointData& point)
+{
+	inspector->clear();
+	points.push_back(point);
+	inspector->updateData(points.begin(), points.end());
+}
+
+void Scratchpad::clear()
+{
+	inspector->clear();
+	points.clear();
+}
+
+void Scratchpad::contextMenuEvent(QContextMenuEvent* event)
+{
+	contextMenu->exec(event->globalPos());
+}

+ 22 - 0
metavis/Scratchpad.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include "BitInspectorPanel.h"
+#include "RunData.h"
+#include <QMenu>
+
+class Scratchpad : public BitInspectorPanel
+{
+	Q_OBJECT
+
+public:
+	Scratchpad(QWidget *parent);
+	~Scratchpad();
+	void addPoint(const SolutionPointData& point);
+	void clear();
+protected:
+	QMenu* contextMenu = new QMenu(this);
+	void contextMenuEvent(QContextMenuEvent* event) override;
+private:
+	//Points to display
+	std::vector<SolutionPointData> points;
+};

+ 51 - 0
metavis/SearchSpacePlott.cpp

@@ -0,0 +1,51 @@
+#include "pch.h"
+#include "SearchSpacePlott.h"
+
+SearchSpacePlott::SearchSpacePlott(QWidget *parent)
+	: GraphPlott(parent, false, true, false)
+{
+	QSlider* circleSizeSlider = new QSlider(Qt::Horizontal);
+	circleSizeSlider->setMinimum(1);
+	circleSizeSlider->setMaximum(15);
+	circleSizeSlider->setValue(circleSize);
+	circleSizeSlider->setMaximumWidth(80);
+	circleSizeSlider->setMaximumHeight(16);
+	this->buttonPanel->insertSpacing(1, 5);
+	this->buttonPanel->insertWidget(1, circleSizeSlider);
+	this->buttonPanel->insertSpacing(1, 5);
+	this->buttonPanel->insertWidget(1, new QLabel("Size:"));
+	connect(circleSizeSlider, &QSlider::valueChanged, this, [this, circleSizeSlider]() {this->circleSize = circleSizeSlider->value(); this->update(); });
+	QSlider* transparentSlider = new QSlider(Qt::Horizontal);
+	transparentSlider->setMinimum(5);
+	transparentSlider->setMaximum(50);
+	transparentSlider->setValue(50);
+	transparentSlider->setMaximumWidth(80);
+	transparentSlider->setMaximumHeight(16);
+	this->buttonPanel->insertSpacing(1, 5);
+	this->buttonPanel->insertWidget(1, transparentSlider);
+	this->buttonPanel->insertSpacing(1, 5);
+	this->buttonPanel->insertWidget(1, new QLabel("Transparency:"));
+	connect(transparentSlider, &QSlider::valueChanged, this, [this, transparentSlider]() {this->transparentAlphaValue = ((double)transparentSlider->value()) / 50.0; this->update(); });
+	this->setMinimumSize(200, 50);
+}
+
+SearchSpacePlott::~SearchSpacePlott()
+{
+}
+
+void SearchSpacePlott::mouseMoveEvent(QMouseEvent* event)
+{
+	GraphPlott::mouseMoveEvent(event);
+}
+
+void SearchSpacePlott::setMinimumIterationToDispaly(int min)
+{
+	minIter = min;
+	update();
+}
+
+void SearchSpacePlott::setMaximumIterationToDispaly(int max)
+{
+	maxIter = max;
+	update();
+}

+ 25 - 0
metavis/SearchSpacePlott.h

@@ -0,0 +1,25 @@
+#pragma once
+
+#include <QWidget>
+#include <QMouseEvent>
+#include "GraphPlott.h"
+
+
+class SearchSpacePlott : public GraphPlott
+{
+	Q_OBJECT
+
+public:
+	SearchSpacePlott(QWidget *parent);
+	~SearchSpacePlott();
+protected:
+	int minIter = 0;
+	int maxIter = 100;
+
+	int circleSize = 2;
+	double transparentAlphaValue = 1;
+	virtual void mouseMoveEvent(QMouseEvent* event) override;
+public slots:
+	void setMinimumIterationToDispaly(int min);
+	void setMaximumIterationToDispaly(int max);
+};

+ 144 - 0
metavis/TsneControlPanel.cpp

@@ -0,0 +1,144 @@
+#include "pch.h"
+#include "TsneControlPanel.h"
+#include <QPushButton>
+#include <QProgressBar>
+#include <QGridLayout>
+#include <QSpacerItem>
+#include <QLineEdit>
+#include <QSlider>
+
+TsneControlPanel::TsneControlPanel(QWidget *parent)
+	: QWidget(parent)
+{
+	plott->setVisibleWindow(-20, 20, -20, 20);
+
+
+	QVBoxLayout* layout = new QVBoxLayout(this);
+	layout->setContentsMargins(0, 0, 0, 0);
+	QHBoxLayout* buttonLayout = new QHBoxLayout();
+	buttonLayout->setContentsMargins(0, 0, 0, 0);
+	layout->addWidget(plott);
+	layout->addLayout(buttonLayout);
+
+	//ButtonPanel
+	showOptionsButton = new QPushButton("Hide Options");
+	connect(showOptionsButton, &QPushButton::pressed, this, &TsneControlPanel::toggleOptions);
+	QPushButton* startButton = new QPushButton("Start");
+	connect(startButton, &QPushButton::pressed, this, &TsneControlPanel::start);
+	QPushButton* pauseButton = new QPushButton("Pause");
+	connect(pauseButton, &QPushButton::pressed, this, &TsneControlPanel::pause);
+	iterationLabel->setText("Iteration: 0");
+	progressBar->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Preferred); 
+	progressBar->setAlignment(Qt::AlignCenter);
+	progressBar->setValue(0);
+	progressBar->setMaximum(tsneSettings->maxIter - 1);
+	buttonLayout->addWidget(startButton);
+	buttonLayout->addWidget(pauseButton);
+	buttonLayout->addWidget(iterationLabel);
+	buttonLayout->addWidget(progressBar);
+	buttonLayout->addWidget(showOptionsButton);
+	
+	
+	layout->addWidget(tsneSettings);
+	
+	layout->addWidget(slider);
+
+	//Slider
+	slider->setTitle("Iteration:");
+	connect(slider, &RangeSlider::maxChanged, plott, &TsnePlott::setMaximumIterationToDispaly);
+	connect(slider, &RangeSlider::minChanged, plott, &TsnePlott::setMinimumIterationToDispaly);
+	
+	
+	//Gradient
+	layout->addWidget(gradient);
+	connect(gradient, &ColorGradient::gradientChanged, this, [this]() {this->plott->updateColors(*gradient); });
+
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("Tsne");
+	if (settings.value("hideOptions", true).toBool()) {
+		toggleOptions();
+	}
+	settings.endGroup();
+}
+
+TsneControlPanel::~TsneControlPanel()
+{
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("Tsne");
+	settings.setValue("hideOptions", this->isOptionHidden);
+	settings.endGroup();
+}
+
+void TsneControlPanel::assignData(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end, QString runName)
+{
+	this->begin = begin;
+	this->end = end;
+	runName = runName;
+	plott->setDisplayLabel(runName);
+	resetPanel();
+	plott->clear();
+}
+
+void TsneControlPanel::clear()
+{
+	begin = std::vector<SolutionPointData>::iterator();
+	end = std::vector<SolutionPointData>::iterator();
+	runName = "";
+	resetPanel();
+	plott->clear();
+}
+
+
+void TsneControlPanel::toggleOptions()
+{
+	this->isOptionHidden = !this->isOptionHidden;
+	showOptionsButton->setText(this->isOptionHidden ? "More Options" : "Hide Options");
+	this->slider->setHidden(this->isOptionHidden);
+	this->gradient->setHidden(this->isOptionHidden);
+	this->tsneSettings->setHidden(this->isOptionHidden);
+}
+
+void TsneControlPanel::resetPanel()
+{
+	if (algo != nullptr) {
+		delete algo;
+		algo = nullptr;
+	}
+	iterationChanged(0);
+}
+
+
+void TsneControlPanel::pause()
+{
+	if (algo != nullptr) {
+		algo->pause();
+	}
+}
+
+void TsneControlPanel::iterationChanged(int iter)
+{
+	iterationLabel->setText("Iteration: " + QString::number(iter));
+	plott->update();
+	progressBar->setValue(iter);
+}
+
+void TsneControlPanel::start()
+{
+	qDebug() << "start";
+	if (begin == end) {
+		qDebug() << "NoData";
+		return;
+	}
+	double* matrixY = nullptr;
+	double** matrixYPtr = &matrixY;
+	resetPanel();
+	algo = new tSneAlgo(begin, end, matrixYPtr, tsneSettings->perplexity, tsneSettings->learnrate, tsneSettings->maxIter);
+	connect(algo, &tSneAlgo::changedIter, this, &TsneControlPanel::iterationChanged);
+	connect(algo, &tSneAlgo::algoDone, this, &TsneControlPanel::finished);
+	emit started();
+	algo->start();
+	qDebug() << "Y:" << matrixY;
+	plott->assignMatrix(begin, end, matrixY, std::distance(begin, end), *gradient);
+}

+ 48 - 0
metavis/TsneControlPanel.h

@@ -0,0 +1,48 @@
+#pragma once
+
+#include <QWidget>
+#include "TsnePlott.h"
+#include "RangeSlider.h"
+#include "ColorGradient.h"
+#include <QProgressBar>
+#include "TsneSettings.h"
+#include "tSneAlgo.h"
+#include <string>
+#include <vector>
+#include "RunData.h"
+
+class TsneControlPanel : public QWidget
+{
+	Q_OBJECT
+
+public:
+	TsneControlPanel(QWidget *parent);
+	~TsneControlPanel();
+	TsnePlott* plott = new TsnePlott(this);
+	void assignData(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end, QString runName);
+	void clear();
+
+
+protected:
+	RangeSlider* slider = new RangeSlider(this);
+	ColorGradient* gradient = new ColorGradient(this);
+	QProgressBar* progressBar = new QProgressBar();
+	TsneSettings* tsneSettings = new TsneSettings(this);
+	QLabel* iterationLabel = new QLabel();
+	bool isOptionHidden = false;
+	void toggleOptions();
+	void resetPanel();
+
+private:
+	QString runName;
+	std::vector<SolutionPointData>::iterator begin, end;
+	tSneAlgo* algo = nullptr;
+	QPushButton* showOptionsButton;
+public slots:
+	void start();
+	void pause();
+	void iterationChanged(int iter);
+signals:
+	void started();
+	void finished();
+};

+ 172 - 0
metavis/TsnePlott.cpp

@@ -0,0 +1,172 @@
+#include "pch.h"
+#include "TsnePlott.h"
+#include <limits>
+TsnePlott::TsnePlott(QWidget *parent)
+	: SearchSpacePlott(parent)
+{
+	setAxisLegend("X Axis", "Y Axis");
+}
+
+TsnePlott::~TsnePlott()
+{
+}
+
+void TsnePlott::assignMatrix(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end, double* yMatrixFromTsneAlgo, int n, ColorGradient& gradient)
+{
+	this->begin = begin;
+	this->end = end;
+	this->yMatrixFromTsneAlgo = yMatrixFromTsneAlgo;
+	this->N = n;
+	updateColors(gradient);
+	
+}
+
+void TsnePlott::clear()
+{
+	begin = end = std::vector<SolutionPointData>::iterator();
+	yMatrixFromTsneAlgo = nullptr;
+	N = 0;
+	colorPointDataVec.clear();
+	update();
+}
+
+void TsnePlott::updateColors(ColorGradient& gradient)
+{
+	colorPointDataVec.clear();
+	for (auto iterator = begin; iterator != end; iterator++) {
+		colorPointDataVec.push_back(gradient.getColorFromValue(iterator->objectiveFunction));
+	}
+	update();
+}
+
+void TsnePlott::frameGraphInView()
+{
+	if (begin == end || !yMatrixFromTsneAlgo) {
+		return;
+	}
+	VisibleWindow nextWindow(0,0,0,0);
+	QPointF first(yMatrixFromTsneAlgo[0], yMatrixFromTsneAlgo[1]);
+	nextWindow.xMin = nextWindow.xMax = first.x();
+	nextWindow.yMin = nextWindow.yMax = first.y();
+
+
+	for (int i = 1; i < this->N; i++) {
+		QPointF point(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]);
+		if (point.x() < nextWindow.xMin) {
+			nextWindow.xMin = point.x();
+		}
+		else if (point.x() > nextWindow.xMax) {
+			nextWindow.xMax = point.x();
+		}
+		if (point.y() < nextWindow.yMin) {
+			nextWindow.yMin = point.y();
+		}
+		else if (point.y() > nextWindow.yMax) {
+			nextWindow.yMax = point.y();
+		}
+	}
+	nextWindow.ZoomOut(0.05);
+	if (std::abs(nextWindow.xMax - nextWindow.xMin) > std::numeric_limits<double>::min()) {
+		window.xMin = nextWindow.xMin;
+		window.xMax = nextWindow.xMax;
+	}
+	if (std::abs(nextWindow.yMax - nextWindow.yMin) > std::numeric_limits<double>::min()) {
+		window.yMin = nextWindow.yMin;
+		window.yMax = nextWindow.yMax;
+	}
+	update();
+}
+
+void TsnePlott::searchForPointUnderCursor()
+{
+	//check if mouse stayed still
+	QPoint globalPosition = QCursor::pos();
+	QPointF pos = this->mapFromGlobal(globalPosition);
+
+	if (pos != lastPosition) {
+		return;
+	}
+	if (begin == end || !yMatrixFromTsneAlgo) {
+		return;
+	}
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+	
+	QPointF minPoint = transformGraphToView(QPointF(yMatrixFromTsneAlgo[0], yMatrixFromTsneAlgo[1]));
+	std::vector<SolutionPointData>::iterator minData = begin;
+	double minSqaredDistance = sqaredDistance(transformGraphToView(minPoint, stregth_factorX, stregth_factorY, translation), pos);
+	auto iter = begin;
+	for (int i = 1; i < this->N; i++, iter++) {
+		if (iter->iteration < minIter) {
+			continue;
+		}
+		if (iter->iteration > maxIter) {
+			break;
+		}
+		QPointF point(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]);
+		double distance = sqaredDistance(transformGraphToView(point, stregth_factorX, stregth_factorY, translation), pos);
+		if (distance < minSqaredDistance) {
+			minSqaredDistance = distance;
+			minPoint = point;
+			minData = iter;
+		}
+	}
+
+	//if curser is radius + 3pixel away
+	if (minSqaredDistance <= circleSize * circleSize + 9) {
+		QPointF pointInWidget = transformGraphToView(minPoint, stregth_factorX, stregth_factorY, translation);
+		QToolTip::showText(this->mapToGlobal(QPoint(pointInWidget.x(), pointInWidget.y())) - QPoint(0, 35), QString::fromStdString(minData->bitstringToStdString()));
+	}
+}
+
+void TsnePlott::addPointsInWindowToScratchPad(VisibleWindow& window)
+{
+	if (!pad) {
+		qDebug() << "NoPad";
+		return;
+	}
+	if (begin == end || !yMatrixFromTsneAlgo) {
+		return;
+	}
+	auto iter = begin;
+	for (int i = 1; i < this->N; i++, iter++) {
+		if (iter->iteration < minIter) {
+			continue;
+		}
+		if (iter->iteration > maxIter) {
+			break;
+		}
+		QPointF point(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]);
+		if (window.inBound(point)) {
+			pad->addPoint(*iter);
+		}
+	}
+}
+
+void TsnePlott::drawData(QPainter& painter)
+{
+	if (begin == end || !yMatrixFromTsneAlgo) {
+		return;
+	}
+	QRect graphDisplayRect = getDisplayRect();
+	QPointF translation(graphDisplayRect.left(), graphDisplayRect.top());
+	double stregth_factorX = graphDisplayRect.width() / std::abs(window.xMax - window.xMin);
+	double stregth_factorY = graphDisplayRect.height() / std::abs(window.yMax - window.yMin);
+	auto iter = begin;
+	painter.setPen(Qt::transparent);
+	for (int i = 0; i < this->N; i++, iter++) {
+		if (iter->iteration < minIter) {
+			continue;
+		}
+		if (iter->iteration > maxIter) {
+			break;
+		}
+		QColor color = colorPointDataVec[i];
+		color.setAlphaF(this->transparentAlphaValue);
+		painter.setBrush(color);
+		painter.drawEllipse(transformGraphToView(QPointF(yMatrixFromTsneAlgo[2 * i], yMatrixFromTsneAlgo[2 * i + 1]), stregth_factorX, stregth_factorY, translation), circleSize, circleSize);
+	}
+	painter.setBrush(Qt::BrushStyle::NoBrush);
+}

+ 33 - 0
metavis/TsnePlott.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include <QWidget>
+#include <SearchSpacePlott.h>
+#include <vector>
+#include "RunData.h"
+#include "ColorGradient.h"
+
+
+class TsnePlott : public SearchSpacePlott
+{
+	Q_OBJECT
+
+
+
+public:
+	TsnePlott(QWidget *parent);
+	~TsnePlott();
+	void assignMatrix(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end,  double* yMatrixFromTsneAlgo, int n, ColorGradient& gradient);
+	void clear();
+	void updateColors(ColorGradient& gradient);
+	void virtual frameGraphInView();
+protected:
+	virtual void drawData(QPainter& painter) override;
+	virtual void searchForPointUnderCursor() override;
+	virtual void addPointsInWindowToScratchPad(VisibleWindow& window) override;
+private:
+	std::vector<SolutionPointData>::iterator begin, end;
+	std::vector<QColor> colorPointDataVec;
+	double* yMatrixFromTsneAlgo = nullptr;
+	int N;
+
+};

+ 125 - 0
metavis/TsneSettings.cpp

@@ -0,0 +1,125 @@
+#include "pch.h"
+#include "TsneSettings.h"
+#include <QLineEdit>
+#include <QSlider>
+#include <QRegExp>
+
+
+TsneSettings::TsneSettings(QWidget *parent)
+	: QWidget(parent)
+{
+	readSettigns();
+	//Layout 
+	tsneSettings->setContentsMargins(0, 0, 0, 0);
+	tsneSettings->addWidget(new QLabel("T-SNE Settings:"), 0, 0);
+	tsneSettings->addWidget(new QLabel("   Perplexity"), 1, 0);
+	tsneSettings->addWidget(new QLabel("   Lernrate"), 2, 0);
+	
+	perplexityEdit->setMinimumWidth(80);
+	perplexityEdit->setMaximumWidth(80);
+	perplexityEdit->setText(QString::number(perplexity));
+	tsneSettings->addWidget(perplexityEdit, 1, 1);
+	
+	perplexitySlider->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Preferred);
+	perplexitySlider->setValue(perplexity);
+	perplexitySlider->setMinimum(perplexityMin);
+	perplexitySlider->setMaximum(perplexityMax);
+	perplexitySlider->setTickInterval((perplexityMax - perplexityMin + 1) / 10);
+	perplexitySlider->setTickPosition(QSlider::TickPosition::TicksBelow);
+	tsneSettings->addWidget(perplexitySlider, 1, 2);
+	
+	learnrateEdit->setMinimumWidth(80);
+	learnrateEdit->setMaximumWidth(80);
+	learnrateEdit->setText(QString::number(learnrate));
+	tsneSettings->addWidget(learnrateEdit, 2, 1);
+	
+	learnrateSlider->setValue(learnrate);
+	learnrateSlider->setMinimum(learnrateMin);
+	learnrateSlider->setMaximum(learnrateMax);
+	learnrateSlider->setTickInterval((learnrateMax - learnrateMin + 1) / 10);
+	learnrateSlider->setTickPosition(QSlider::TickPosition::TicksBelow);
+	learnrateSlider->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Preferred);
+	tsneSettings->addWidget(learnrateSlider, 2, 2);
+	
+
+	QRegExp rxMinMax("[0-9]+");
+	QRegExpValidator* validatorMinMax = new QRegExpValidator(rxMinMax, 0);
+	learnrateEdit->setValidator(validatorMinMax);
+	perplexityEdit->setValidator(validatorMinMax);
+
+	connect(perplexitySlider, &QSlider::valueChanged, this, &TsneSettings::setPerplexity);
+	connect(learnrateSlider, &QSlider::valueChanged, this, &TsneSettings::setLearnrate);
+	connect(learnrateEdit, &QLineEdit::editingFinished, this, &TsneSettings::learnrateEditChangeEvent);
+	connect(perplexityEdit, &QLineEdit::editingFinished, this, &TsneSettings::perplexityEditChangeEvent);
+}
+
+TsneSettings::~TsneSettings()
+{
+	writeSettings();
+}
+
+void TsneSettings::setPerplexity(int value)
+{
+	if (perplexity == value) return;
+	perplexity = std::clamp(value, perplexityMin, perplexityMax);
+	perplexitySlider->setValue(perplexity);
+	perplexityEdit->setText(QString::number(perplexity));
+	emit perplexityChanged(perplexity);
+}
+
+void TsneSettings::setLearnrate(int value)
+{
+	if (learnrate == value) return;
+	learnrate = std::clamp(value, learnrateMin, learnrateMax);
+	learnrateSlider->setValue(learnrate);
+	learnrateEdit->setText(QString::number(learnrate));
+	emit learnrateChanged(learnrate);
+}
+
+void TsneSettings::readSettigns()
+{
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("Tsne");
+	maxIter = settings.value("maxIter", 750).toInt();
+	perplexity = settings.value("perplexity", 10).toInt();
+	perplexityMin = settings.value("perplexity_MIN", 1).toInt();
+	perplexityMax = settings.value("perplexity_MAX", 50).toInt();
+	learnrate = settings.value("learnrate", 200).toInt();
+	learnrateMin = settings.value("learnrate_MIN", 1).toInt();
+	learnrateMax = settings.value("learnrate_MAX", 1000).toInt();
+	settings.endGroup();
+}
+
+void TsneSettings::writeSettings()
+{
+	//Settings
+	QSettings settings("settings.ini", QSettings::IniFormat, this);
+	settings.beginGroup("Tsne");
+	settings.setValue("maxIter", maxIter);
+	settings.setValue("perplexity", perplexity);
+	settings.setValue("perplexity_MIN", perplexityMin);
+	settings.setValue("perplexity_MAX", perplexityMax);
+	settings.setValue("learnrate", learnrate);
+	settings.setValue("learnrate_MIN", learnrateMin);
+	settings.setValue("learnrate_MAX", learnrateMax);
+	settings.endGroup();
+}
+
+void TsneSettings::learnrateEditChangeEvent()
+{
+	bool success = false;
+	int value = learnrateEdit->text().toInt(&success);
+	if (success) {
+		setLearnrate(value);
+	}
+}
+
+void TsneSettings::perplexityEditChangeEvent()
+{
+	bool success = false;
+	int value = perplexityEdit->text().toInt(&success);
+	if (success) {
+		setPerplexity(value);
+	}
+}

+ 34 - 0
metavis/TsneSettings.h

@@ -0,0 +1,34 @@
+#pragma once
+
+#include <QWidget>
+#include <QLineEdit>
+#include <QSlider>
+#include <QGridLayout>
+
+class TsneSettings : public QWidget
+{
+	Q_OBJECT
+
+public:
+	TsneSettings(QWidget *parent);
+	~TsneSettings();
+	int maxIter;
+	int perplexity, perplexityMax, perplexityMin;
+	int learnrate, learnrateMax, learnrateMin;
+	void setPerplexity(int value);
+	void setLearnrate(int value);
+protected:
+	QGridLayout* tsneSettings = new QGridLayout(this);
+	QSlider* perplexitySlider = new QSlider(Qt::Orientation::Horizontal);
+	QSlider* learnrateSlider = new QSlider(Qt::Orientation::Horizontal);
+	QLineEdit* perplexityEdit = new QLineEdit();
+	QLineEdit* learnrateEdit = new QLineEdit();
+private:
+	void readSettigns();
+	void writeSettings();
+	void learnrateEditChangeEvent();
+	void perplexityEditChangeEvent();
+signals:
+	void perplexityChanged(int perplexity);
+	void learnrateChanged(int learnrate);
+};

+ 5 - 2
metavis/main.cpp

@@ -2,10 +2,13 @@
 #include "metavis.h"
 #include <QtWidgets/QApplication>
 #include <QtGui>
-
+#include <QDebug>
+#include <Vector>
+#include <boost/multiprecision/cpp_int.hpp>
+#include "RunData.h"
 /* entrance of the program */
 int main(int argc, char *argv[])
-{
+{ 
 	QApplication a(argc, argv);
 	metavis w;
 	w.show();

+ 260 - 89
metavis/metavis.cpp

@@ -7,8 +7,6 @@
 #include <QLayout>
 #include <QDebug>
 #include <QStyleFactory>
-#include <QtWebChannel/QtWebChannel>
-#include <QtWebEngineWidgets/QWebEngineView>
 #include <QFileDialog>
 #include <QDir>
 #include <map>
@@ -16,29 +14,46 @@
 #include <QDesktopWidget>
 #include <QSlider>
 #include <QSizePolicy>
+#include <QScrollArea>
+#include <QMainWindow>
 #include "DockableGraphView.h"
-#include "ProjectManager.h"
+#include <QShortcut>
 #include "RangeSlider.h"
 #include "tsneIteractive.h"
 #include "util.h"
 
 
-
 metavis::metavis(QWidget* parent)
-	: QMainWindow(parent), actualBestAverageGraph(createCustomWidget("Best vs Avg")), actualParticleGraph(createCustomWidget("Particle", true)), actualMinMaxGraph(createCustomWidget("MinMaxGraph", true)), actualMeanHmmingDistanceGraph(createCustomWidget("MeanHammingDistance", true)),
-	multiBestGraph(createCustomWidget("All Runs: Best")), multiAvgGraph(createCustomWidget("All Runs: Avg", true)), multiMinGraph(createCustomWidget("All Runs: Min", true)), multiMaxGraph(createCustomWidget("All Runs: Max", true)), multiMeanHammingDistanceGraph(createCustomWidget("All Runs: Mean Hamming Distance", true))
+	: QMainWindow(parent)
 {
 	ui.setupUi(this);
 	/* create settings object*/
-	settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TK", "metavis", this);
+	//settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TK", "metavis", this);
+	settings = new QSettings("settings.ini", QSettings::IniFormat, this);
+	//settings = new QSettings(QCoreApplication::applicationDirPath()+ "hatschi.ini", QSettings::IniFormat);
 	setStyleSheet(styleSheet() + "QMainWindow::separator {background: rgb(200, 200, 200);width: 1px;height: 1px;}");
 	setStyleSheet(styleSheet() + "QTabBar::tab:selected {color: rgb(0, 122, 204);}");
 	setStyleSheet(styleSheet() + "QTabWidget::pane {border-top: 0px solid #C2C7CB;margin: -9px -9px -13px -9px;}");
+	this->setDockNestingEnabled(true);
+	option = dockOption::right;
+	createBitInSpector();
+	QDockWidget* saveForTabPad = lastDocked;
+	option = dockOption::splitTop;
+	createProjectManager();
+	option = dockOption::splitLeft;
+	createBitFieldV2();
+	QDockWidget* saveForTabTsne = lastDocked;
+	initPlotter();
+	createScratchpad(saveForTabPad);
+	createTSNE(saveForTabTsne);
+
 
 	readMainWindowSettings();
-	createBitField();
-	createProjectManager();
-	createTSNE();
+	ui.actionOpen->setShortcut(QKeySequence(Qt::CTRL + Qt::Key::Key_O));
+	QMenu* viewMenu = createPopupMenu();
+	viewMenu->setTitle("View");
+	ui.menuBar->insertMenu(manager->projectMenu->menuAction(), viewMenu);
+	this->setCentralWidget(nullptr);
 } 
 
 
@@ -55,59 +70,221 @@ metavis::~metavis()
 	writeActualMainWindowSettings();
 }
 
+void metavis::selectRunData(RunData* data)
+{
+	selectedBestGraph->removeAll();
+	selectedBestGraph->setDisplayLabel(QString::fromStdString(data->name));
+	for (SingleRun& run : data->singleRunList) {
+		selectedBestGraph->addSeries(&run.bestMaxSolutionFoundPerIteration, data->name, QString::fromStdString(run.name), QColor(12, 116, 137, 200), GraphPlottSeries::SeriesType::Line);
+	}
+	selectedBestGraph->addSeries(&data->bestAverageMaxSolutionFoundPerIteration, data->name, "average best from " + QString::fromStdString(data->name), QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line);
+	selectedBestGraph->getSeriesVector().back().lineWidth = 3;
+	selectedBestGraph->frameGraphInView();
+}
 
-GraphView* metavis::createCustomWidget(QString titleString, bool tabToLast)
+void metavis::selectSingleRun(SingleRun* run)
 {
-	DockableGraphView* dock = new DockableGraphView(this, titleString);
-	qDebug() << titleString;
-	if (tabToLast && lastDocked) {
+	selectedBestAverageGraph->removeAll();
+	selectedBestAverageGraph->setDisplayLabel(QString::fromStdString(run->name));
+	selectedBestAverageGraph->addSeries(&run->bestMaxSolutionFoundPerIteration, run->runDataName, "best", QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line);
+	selectedBestAverageGraph->addSeries(&run->averageSolutionPerItertion, run->runDataName, "average", QColor(0, 0, 255), GraphPlottSeries::SeriesType::Line);
+	selectedBestAverageGraph->frameGraphInView();
+
+	selectedMinMaxGraph->removeAll();
+	selectedMinMaxGraph->setDisplayLabel(QString::fromStdString(run->name));
+	selectedMinMaxGraph->addSeries(&run->dotsForDistribution, run->runDataName,"distribution", QColor(255, 165, 0, 100), GraphPlottSeries::SeriesType::Dot);
+	selectedMinMaxGraph->addSeries(&run->minSolutionPerItertion, run->runDataName,"min", QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line);
+	selectedMinMaxGraph->addSeries(&run->maxSolutionPerItertion, run->runDataName,"max" , QColor(0, 0, 255), GraphPlottSeries::SeriesType::Line);
+	selectedMinMaxGraph->frameGraphInView();
+
+	selectedMeanHammingDistanceGraph->removeAll();
+	selectedMeanHammingDistanceGraph->setDisplayLabel(QString::fromStdString(run->name));
+	selectedMeanHammingDistanceGraph->addSeries(&run->meanHammingDistancePerIteration, run->runDataName, "mean Hamming Distance", QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line);
+	selectedMeanHammingDistanceGraph->frameGraphInView();
+
+	bitfieldPanel->field->setDisplayLabel(QString::fromStdString(run->name));
+	bitfieldPanel->displaySingleRun(run);
+	bitfieldPanel->update();
+
+	inspectorPanel->inspector->updateData(run->begin, run->end);
+	inspectorPanel->setRunName(run->name);
+
+	tsnePanel->assignData(run->begin, run->end, QString::fromStdString(run->name));
+}
+
+
+
+
+void metavis::removeRunDataFromAllViews(RunData* data)
+{
+	selectedBestAverageGraph->removeRunData(data);
+	selectedBestAverageGraph->update();
+
+	selectedMinMaxGraph->removeRunData(data);
+	selectedMinMaxGraph->update();
+
+	selectedMeanHammingDistanceGraph->removeRunData(data);
+	selectedMeanHammingDistanceGraph->update();
+
+	selectedBestGraph->removeRunData(data);
+	selectedBestGraph->update();
+
+	bitfieldPanel->clearRun();
+	bitfieldPanel->update();
+
+	inspectorPanel->removeRun();
+	tsnePanel->clear();
+}
+
+
+
+void metavis::dockWidget(QDockWidget* dock)
+{
+	switch (option) {
+	case left:
+		addDockWidget(Qt::LeftDockWidgetArea, dock);
+		break;
+	case right:
+		addDockWidget(Qt::RightDockWidgetArea, dock);
+		break;
+	case top:
+		addDockWidget(Qt::TopDockWidgetArea, dock);
+		break;
+	case bottom:
+		addDockWidget(Qt::BottomDockWidgetArea, dock);
+		break;
+	case splitLeft:
+		this->splitDockWidget(lastDocked, dock, Qt::Orientation::Horizontal);
+		this->splitDockWidget(dock, lastDocked, Qt::Orientation::Horizontal);
+		break;
+	case splitRight:
+		this->splitDockWidget(lastDocked, dock, Qt::Orientation::Horizontal);
+		break;
+	case splitBottom:
+		this->splitDockWidget(lastDocked, dock, Qt::Orientation::Vertical);
+		break;
+	case splitTop:
+		this->splitDockWidget(lastDocked, dock, Qt::Orientation::Vertical);
+		this->splitDockWidget(dock, lastDocked, Qt::Orientation::Vertical);
+		break;
+	case tab:
 		tabifyDockWidget(lastDocked, dock);
-	}
-	else {
+		break;
+	default:
 		addDockWidget(Qt::LeftDockWidgetArea, dock);
-		lastDocked = dock;
+		break;
 	}
+	lastDocked = dock;
+}
+
+GraphView* metavis::createCustomWidget(QString titleString, bool tabToLast)
+{
+	DockableGraphView* dock = new DockableGraphView(this, titleString);
+	qDebug() << titleString;
+	dockWidget(dock);
 	return dock->view;
 }
 
-void metavis::createBitField()
-{
-	bitField = new GraphView(this, Bound(-0.1, 1.1, 0.0, 1601.0));
-	bitField->setUseFixedBound(true);
-	bitField->setMinimumSize(200, 200);
-	bitField->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
-	bitField->maxIter = -2;
-	bitField->useInterval = true;
-	//this->setCentralWidget(bitField);
-	QVBoxLayout* layout = new QVBoxLayout;
-	layout->addWidget(bitField);
-	RangeSlider* rangeSlider = new RangeSlider(this);
-	rangeSlider->setMinimumSize(100, 50);
-	rangeSlider->setMinRange(-2);
-	rangeSlider->setMaxRange(100);
-	connect(rangeSlider, &RangeSlider::maxChanged,
-		bitField, &GraphView::setMaxIter);
-	connect(rangeSlider, &RangeSlider::minChanged,
-		bitField, &GraphView::setMinIter);
-	rangeSlider->setMinSliderValue(-2);
-	rangeSlider->setMaxSliderValue(100);
-	layout->addWidget(rangeSlider);
-	ui.BitFieldWidget->setLayout(layout);
+
+void metavis::createBitFieldV2()
+{
+	QDockWidget* dock = new QDockWidget(this);
+	bitfieldPanel = new BitfieldControlPanel(this);
+	bitfieldPanel->field->setScratchpad(pad);
+	bitfieldPanel->field->setInformation("<h3><u>Bitfield</u></h3>This search space visualization displays all found solution of a single run.<br>Hover over a dot to see its bitstring.<br>The color represents the objective function.<br><b><font color=\"gray\">Gray</font> patterned area:</b> Represents the area where no solution can be generated.<br><b>Y Axis:</b> Represents the amount of set bits of a solution.<br><b>X Axis:</b> The x axis represents the position of the solution which is concluded by collapsing<br>all solutions of a Y Value and spreading these between 0 and 1. The solutions are sorted descendingly based on their value.<br>Example with a four long bitstring and two set bits. For two set bits, there are six different solutions:<br>1100 1010 1001 0110 0101 0011<br>The solution 0101 is the 5th possible solution and gets the position value \'0.8\'.<br><br><b>Tipp:</b> Select an interesting area and add the points to the scratchpad for fast comparison.<h3><u>Options</u></h3>The Transparency slider handles the transparency of the dots.<br>The Size slider handles the radius of the dots.<br><b>Tipp:</b> Make the dots big and the transparency low the see clustering.<br>Under \'More Options\' the color for the objective function and the displayed itertion can be controlled.");
+	dock->setWindowTitle("Bitfield");
+	dock->setObjectName("Bitfield");
+	dock->setWidget(bitfieldPanel);
+	dockWidget(dock);
 }
 
 void metavis::createProjectManager()
 {
-	QDockWidget* dockWidget = new QDockWidget(this);
-	ProjectManager* manager = new ProjectManager(this, this);
-	dockWidget->setWindowTitle("Project Manager");
-	dockWidget->setWidget(manager);
-	addDockWidget(Qt::RightDockWidgetArea, dockWidget);
+	QDockWidget* dock= new QDockWidget(this);
+	manager = new ProjectManager(this);
+	dock->setWindowTitle("Project Manager");
+	dock->setObjectName("Project Manager");
+	dock->setWidget(manager);
+	connect(ui.actionOpen, &QAction::triggered, manager, &ProjectManager::openFileDialog);
+	dockWidget(dock);
+	manager->projectMenu->setTitle("Project");
+	ui.menuBar->addMenu(manager->projectMenu);
+}
+
+void metavis::createTSNE(QDockWidget* dockto)
+{
+
+
+	QDockWidget* dock = new QDockWidget(this);
+	tsnePanel = new TsneControlPanel(this);
+	connect(tsnePanel, &TsneControlPanel::started, this, [this]() {this->showStatusBarMessage("T-SNE calculating...");});
+	connect(tsnePanel, &TsneControlPanel::finished, this, &metavis::clearStatusBar);
+	tsnePanel->plott->setScratchpad(pad);
+	tsnePanel->plott->setInformation("<h3><u>T-SNE</u></h3>This search space evaluation uses a gradient descent method and has to be calculated first via the \"Start\" button.<br>This search space visualization display all found solutions of a single run.<br>Hover over a dot to see its bitstring.<br>The color represents the objective function.<br> The axes have no special meaning besides indicating the distance between solutions.<br><b>Start Button:</b> Starts the tsne methods. This may take a while.<br><b>Pause Button:</b> Pauses the tsne methods.<br><br><br><b>Tipp</b> select a interesting area and add the points to the scratchpad for fast comparison.<h3><u>Options</u></h3>Transparency slider handles the transparency of the dots.<br>Size slider handles the radius of the dots.<br><b>Tipp</b> make the dots big and the transparency low the see clustering.<br>Under \'More Options\' the color for the objective function and the displayed itertion can be controlled.<br> Also to important parameter for T-SNE can be controlled via slider or textfield.<br><b>Perplexity</b> is a parameter that should indicate how many neighbors a solution have.<br><b>Learnrate:</b> is a parameter that determine how fast the gradient descent methods make updates.");
+	dock->setWindowTitle("T-SNE");
+	dock->setObjectName("T-SNE");
+	dock->setWidget(tsnePanel);
+	this->tabifyDockWidget(dockto, dock);
+	dockto->raise();
+}
+
+GraphPlott* metavis::initGraphPlott(QString title, QString YAxisLegend, QString XAxisLegend)
+{
+	QDockWidget* dock = new QDockWidget(this);
+	GraphPlott* graphplott = new GraphPlott(this);
+	graphplott->setDefaultVisibleWindow(0, 100, 30, 110);
+	dock->setWidget(graphplott);
+	dock->setWindowTitle(title);
+	dock->setObjectName(title);
+	graphplott->setAxisLegend(XAxisLegend, YAxisLegend);
+	dockWidget(dock);
+	return graphplott;
+}
+
+void metavis::initPlotter()
+{
+	option = splitLeft;
+	selectedBestGraph = initGraphPlott("Best Overview");
+	selectedBestGraph->setScratchpad(pad);
+	selectedBestGraph->setInformation("<h3><u>Best Overview</u></h3>Shows all best graphs in <font color=\"gray\">gray</font> for comparison.<br>The <font color=\"red\">red</font> line shows the average best over all repetition.<br>By hovering over a line the repetition name is shown.<br><br><b>Objective Function:</b> Describes how good the solution is, it depends on the problem if a low or high value is desired.");
+	option = splitTop;
+	selectedBestAverageGraph = initGraphPlott("Best Average");
+	selectedBestAverageGraph->setScratchpad(pad);
+	selectedBestAverageGraph->setInformation("<h3><u>Best Average</u></h3>The <font color=\"red\">red</font> line shows the best graph that presents the best objective function value found for each iteration of a single repetition.<br>The <font color=\"blue\">blue</font> line shows the average graph that presents the average objective function value in the popullation for each iteration of a single repetition.<br><br><b>Objective Function:</b> Describes how good the solution is. It depends on the problem if a low or high value is desired.");
+	//GraphPlott* selectedParticleGraph = initGraphPlott("Best Vs Average");
+	option = tab;
+	selectedMinMaxGraph = initGraphPlott("Min Max Distribution");
+	selectedMinMaxGraph->setInformation("<h3><u>Min Max Distribution</u></h3>The <font color=\"blue\">blue</font> line shows the max graph that presents the maximum objective function value in the popullation for each iteration of a single round.<br>The <font color=\"red\">red</font> line shows the minimum objective function value in the popullation for each iteration of a single round.<br>The <font color=\"orange\">orange</font> dots show all objective function values in the population for each iteration of a single repetition.<br><br><b>Objective Function:</b> Describes how good the solution is. It depends on the problem if a low or high value is desired.");
+	selectedMinMaxGraph->setScratchpad(pad);
+	option = tab;
+	selectedMeanHammingDistanceGraph = initGraphPlott("Mean Hamming Distance", "Mean Hamming Distance");
+	selectedMeanHammingDistanceGraph->setInformation("<h3><u>Mean Hamming Distance</u></h3>The <font color=\"red\">red</font> line shows the mean hamming distance for each solution to each solution from the population for each iteration of a single repetition.<br><br><b>Hamming Distance:</b> Describes the distance between to bitstrings by calculating the amount of different bits, e.g. 00110 and 11100 have a hamming distance of 3.");
+	multiBestGraph;
+	multiAvgGraph;
+	multiMinGraph;
+	multiMaxGraph;
+	multiMeanHammingDistanceGraph;
+}
+
+
+void metavis::createBitInSpector()
+{
+	QDockWidget* dock = new QDockWidget(this);
+	inspectorPanel = new BitInspectorPanel(this);
+	dock->setWidget(inspectorPanel);
+	dock->setWindowTitle("Inspector");
+	dock->setObjectName("Inspector");
+	dockWidget(dock);
 }
 
-void metavis::createTSNE()
+void metavis::createScratchpad(QDockWidget* dockto)
 {
-	tsneWidget = new tsneIteractive(this);
-	ui.tabWidget->addTab(tsneWidget, "tSNE");
+	QDockWidget* dock = new QDockWidget(this);
+	dock->setWidget(pad);
+	dock->setWindowTitle("Scratchpad");
+	dock->setObjectName("Scratchpad");
+	this->tabifyDockWidget(dockto, dock);
+	dockto->raise();
 }
 
 void metavis::writeActualMainWindowSettings()
@@ -120,6 +297,8 @@ void metavis::writeActualMainWindowSettings()
 		settings->setValue("size", size());
 		settings->setValue("screenCount", QApplication::desktop()->screenCount());
 	}
+	settings->setValue("geometry", saveGeometry());
+	settings->setValue("windowState", saveState());
 	settings->endGroup();
 }
 
@@ -128,43 +307,18 @@ void metavis::readMainWindowSettings()
 	settings->beginGroup("MainWindow");
 	if (QApplication::desktop()->screenCount() == settings->value("screenCount", 1)) {
 		//Only when same screeenCount move the window;
-		move(settings->value("pos", QPoint(200, 200)).toPoint());
+		move(settings->value("pos", QPoint(360, 200)).toPoint());
 	}
-	resize(settings->value("size", QSize(600, 400)).toSize());
+	resize(settings->value("size", QSize(1200, 675)).toSize());
 	if (settings->value("maximized", false).toBool()) {
 		showMaximized();
 	}
+	this->restoreGeometry(settings->value("geometry").toByteArray());
+	this->restoreState(settings->value("windowState").toByteArray());
 	settings->endGroup();
 }
 
 
-QColor metavis::interpolate(QColor& first, QColor& second, double alpha)
-{
-	double firstH, firstS, firstL;
-	double secondH, secondS, secondL;
-
-	first.getHslF(&firstH, &firstS, &firstL);
-	second.getHslF(&secondH, &secondS, &secondL);
-
-	const double h = util::linearInterpolate(firstH, secondH, alpha);
-	const double s = util::linearInterpolate(firstS, secondS, alpha);
-	const double l = util::linearInterpolate(firstL, secondL, alpha);
-
-	return QColor::fromHslF(h,s,l);
-}
-
-
-void metavis::updateBitFieldColors()
-{
-	QColor best(64, 186, 37);
-	QColor worst(255, 19, 71);
-	double bestValue = 32;
-	double worstValue = 46;
-	for (GraphDataPoint& data : runList.back().dotsForBitField) {
-		data.color = interpolate(best, worst, std::clamp(util::inverseLinearInterpolation(bestValue, worstValue, data.orginalPoint->objectiveFunction), 0.0, 1.0));
-	}
-}
-
 
 
 
@@ -172,26 +326,21 @@ void metavis::updateBitFieldColors()
 
 void metavis::openFile()
 {
-	qDebug() << "openFile";
-	QStringList pathList = QFileDialog::getOpenFileNames(this, "Open LogFile", QStandardPaths::displayName(QStandardPaths::DesktopLocation), "Metavis Logfile (*.metalog)");
-	if (pathList.isEmpty()) {
-		qDebug() << "No file selected";
-		return;
-	}
+	
 	//int oldIndex = runVec.size();
-	int size = runList.size();
+	/*int size = runList.size();
 	for (int i = 0; i < pathList.size(); i++) {
 		qDebug() << "file:" << pathList[i];
 		runList.push_back(RunData(pathList[i].toStdString()));
-	}
-	for (std::list<RunData>::iterator iter = std::next(runList.begin(), size); iter != runList.end(); iter++) {
+	}*/
+	/*for (std::list<RunData>::iterator iter = std::next(runList.begin(), size); iter != runList.end(); iter++) {
 		QColor runColor = multiBestGraph->generateNextColorForGraph();
-		multiBestGraph->addLine(&iter->bestSolutionPerIteration, &*iter, runColor);
+		multiBestGraph->addLine(&iter->bestMinSolutionFoundPerIteration, &*iter, runColor);
 		multiAvgGraph->addLine(&iter->averageSolutionPerItertion, &*iter, runColor);
 		multiMaxGraph->addLine(&iter->maxSolutionPerItertion, &*iter, runColor);
 		multiMinGraph->addLine(&iter->minSolutionPerItertion, &*iter, runColor);
 		multiMeanHammingDistanceGraph->addLine(&iter->meanHammingDistancePerIteration, &*iter, runColor);
-	}
+	}*/
 
 
 	/*
@@ -225,11 +374,33 @@ void metavis::openFile()
 	//	actualParticleGraph->addLine(iter->second);
 	//}
 	////Test
-	bitField->addDots(&runList.back().dotsForBitField, &runList.back(), QColor(255, 165, 0, 100));
+	/*RunData* rundata = &runList.back();
+
+	bitField->addDots(&rundata->dotsForBitField, rundata, QColor(255, 165, 0, 100));
 	updateBitFieldColors();
 	bitField->graphSeriesVec.back().useDataPointColor = true;
 	tsneWidget->assignRunData(&runList.back());
+	inspector->addData(&runList.back().solutionVec);
+	plottTest->addSeries(&rundata->bestMaxSolutionFoundPerIteration, rundata, QColor(255, 165, 0, 100), GraphPlottSeries::SeriesType::Line);*/
 	//actualMeanHmmingDistanceGraph->addLine(runVec[0].meanHammingDistancePerIteration, QColor(255, 0, 0));
 
 
 }
+
+void metavis::showStatusBarLoading()
+{
+	ui.statusBar->showMessage("Loading...");
+	ui.statusBar->setStyleSheet("background-color: rgb(247, 197, 72);");
+}
+
+void metavis::showStatusBarMessage(QString message)
+{
+	ui.statusBar->showMessage(message);
+	ui.statusBar->setStyleSheet("background-color: rgb(247, 197, 72);");
+}
+
+void metavis::clearStatusBar()
+{
+	ui.statusBar->clearMessage();
+	ui.statusBar->setStyleSheet("background-color: rgb(240, 240, 240);");
+}

+ 51 - 17
metavis/metavis.h

@@ -5,7 +5,16 @@
 #include "ui_metavis.h"
 #include "RunData.h"
 #include "GraphView.h"
+
+#include "BitfieldControlPanel.h"
+#include "TsneControlPanel.h"
+
+#include "GraphPlott.h"
+#include "BitInspectorPanel.h"
+#include "Scratchpad.h"
 #include "tsneIteractive.h"
+#include "ProjectManager.h"
+class ProjectManager;
 
 
 /**
@@ -18,41 +27,63 @@ class metavis : public QMainWindow
 public:
 	metavis(QWidget *parent = Q_NULLPTR);
 	~metavis();
-	GraphView* actualBestAverageGraph;
-	GraphView* actualParticleGraph;
-	GraphView* actualMinMaxGraph;
-	GraphView* actualMeanHmmingDistanceGraph;
-
-	GraphView* multiBestGraph;
-	GraphView* multiAvgGraph;
-	GraphView* multiMinGraph;
-	GraphView* multiMaxGraph;
-	GraphView* multiMeanHammingDistanceGraph;
-	
+	GraphPlott* selectedBestAverageGraph;
+	GraphPlott* selectedParticleGraph;
+	GraphPlott* selectedMinMaxGraph;
+	GraphPlott* selectedMeanHammingDistanceGraph;
+	GraphPlott* selectedBestGraph;
+
 
+
+	GraphPlott* multiBestGraph;
+	GraphPlott* multiAvgGraph;
+	GraphPlott* multiMinGraph;
+	GraphPlott* multiMaxGraph;
+	GraphPlott* multiMeanHammingDistanceGraph;
+	
+	GraphPlott* plottTest;
+	
+	BitfieldControlPanel* bitfieldPanel;
+	BitInspectorPanel* inspectorPanel;
+	Scratchpad* pad = new Scratchpad(this);
 	tsneIteractive* tsneWidget;
+	TsneControlPanel* tsnePanel;
 	GraphView* bitField;
+
+	enum dockOption{left, right, bottom, top, splitLeft, splitRight, splitBottom, splitTop, tab};
+
+	void selectRunData(RunData* data);
+	void selectSingleRun(SingleRun* run);
+	void removeRunDataFromAllViews(RunData* data);
+
+
+
+
+
 private:
 	Ui::metavisClass ui;
 	QSettings* settings;
-	std::list<RunData> runList;
+	ProjectManager* manager;
 
 	//To Tab all 
 	QDockWidget* lastDocked;
+	dockOption option;
+	void dockWidget(QDockWidget* dock);
 
 private:
 	/* Widget functions */
 	GraphView* createCustomWidget(QString titleString, bool tabToLast = false);
-	void createBitField();
+	void createBitFieldV2();
 	void createProjectManager();
-	void createTSNE();
+	void createTSNE(QDockWidget* dockto);
+	GraphPlott* initGraphPlott(QString title, QString YAxisLegend = "ObjectiveFunction", QString XAxisLegend = "Iteration");
+	void initPlotter();
+	void createBitInSpector();
+	void createScratchpad(QDockWidget* dockto);
 	/* Setting functions*/
 	void writeActualMainWindowSettings();
 	void readMainWindowSettings();
 
-	//Bitfield color interpolation
-	static QColor interpolate(QColor& first, QColor& second, double alpha);
-	void updateBitFieldColors();
 
 
 
@@ -65,4 +96,7 @@ public slots:
 	 * Open a logFile.	
 	 */
 	void openFile();
+	void showStatusBarLoading();
+	void showStatusBarMessage(QString message);
+	void clearStatusBar();
 };

BIN
metavis/metavis.ico


+ 19 - 7
metavis/metavis.qrc

@@ -1,9 +1,21 @@
 <RCC>
-  <qresource prefix="metavis">
-    <file>Resources/close_big_red.svg</file>
-    <file>Resources/settingIcon_hovered.svg</file>
-    <file>Resources/close.svg</file>
-    <file>Resources/settingIcon.svg</file>
-    <file>Resources/assignButton.svg</file>
-  </qresource>
+    <qresource prefix="/metavis">
+        <file>Resources/close_big_red.svg</file>
+        <file>Resources/settingIcon_hovered.svg</file>
+        <file>Resources/close.svg</file>
+        <file>Resources/settingIcon.svg</file>
+        <file>Resources/assignButton.svg</file>
+        <file>Resources/information_icon.svg</file>
+        <file>Resources/information_icon_hovered.svg</file>
+        <file>Resources/gridIcon.svg</file>
+        <file>Resources/gridIcon_hovered.svg</file>
+        <file>Resources/up-triangle.svg</file>
+        <file>Resources/frame.svg</file>
+        <file>Resources/frame_hovered.svg</file>
+        <file>Resources/binaryIcon.svg</file>
+        <file>Resources/rubbish.svg</file>
+        <file>Resources/rubbish_hovered.svg</file>
+        <file>Resources/arrow_right.svg</file>
+        <file>Resources/file.svg</file>
+    </qresource>
 </RCC>

+ 11 - 76
metavis/metavis.ui

@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>744</width>
-    <height>560</height>
+    <width>1200</width>
+    <height>675</height>
    </rect>
   </property>
   <property name="windowTitle">
@@ -30,21 +30,6 @@
     <property name="bottomMargin">
      <number>0</number>
     </property>
-    <item>
-     <widget class="QTabWidget" name="tabWidget">
-      <property name="styleSheet">
-       <string notr="true"/>
-      </property>
-      <property name="currentIndex">
-       <number>0</number>
-      </property>
-      <widget class="QWidget" name="BitFieldWidget">
-       <attribute name="title">
-        <string>BitField</string>
-       </attribute>
-      </widget>
-     </widget>
-    </item>
    </layout>
   </widget>
   <widget class="QMenuBar" name="menuBar">
@@ -52,7 +37,7 @@
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>744</width>
+     <width>1200</width>
      <height>21</height>
     </rect>
    </property>
@@ -64,32 +49,10 @@
      <string>File</string>
     </property>
     <addaction name="actionOpen"/>
-    <addaction name="separator"/>
-    <addaction name="actionSettings"/>
-   </widget>
-   <widget class="QMenu" name="menuView">
-    <property name="title">
-     <string>View</string>
-    </property>
-   </widget>
-   <widget class="QMenu" name="menuProject">
-    <property name="title">
-     <string>Project</string>
-    </property>
-    <addaction name="ActionAddMetalogFile"/>
    </widget>
    <addaction name="menuFile"/>
-   <addaction name="menuView"/>
-   <addaction name="menuProject"/>
-  </widget>
-  <widget class="QToolBar" name="mainToolBar">
-   <attribute name="toolBarArea">
-    <enum>TopToolBarArea</enum>
-   </attribute>
-   <attribute name="toolBarBreak">
-    <bool>false</bool>
-   </attribute>
   </widget>
+  <widget class="QStatusBar" name="statusBar"/>
   <action name="actionOpen">
    <property name="text">
     <string>Open..</string>
@@ -108,7 +71,12 @@
   </action>
   <action name="ActionAddMetalogFile">
    <property name="text">
-    <string>Add .metalog-File..</string>
+    <string>Add .csv-File..</string>
+   </property>
+  </action>
+  <action name="ActionRemoveFiles">
+   <property name="text">
+    <string>Remove all files.</string>
    </property>
   </action>
  </widget>
@@ -116,40 +84,7 @@
  <resources>
   <include location="metavis.qrc"/>
  </resources>
- <connections>
-  <connection>
-   <sender>actionSettings</sender>
-   <signal>triggered()</signal>
-   <receiver>metavisClass</receiver>
-   <slot>openSetting()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>-1</x>
-     <y>-1</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>299</x>
-     <y>158</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>actionOpen</sender>
-   <signal>triggered()</signal>
-   <receiver>metavisClass</receiver>
-   <slot>openFile()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>-1</x>
-     <y>-1</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>371</x>
-     <y>279</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
+ <connections/>
  <slots>
   <slot>openSetting()</slot>
   <slot>openFile()</slot>

+ 112 - 4
metavis/metavis.vcxproj

@@ -1,10 +1,18 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" ToolsVersion="16.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Debug|Win32">
+      <Configuration>Debug</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
     <ProjectConfiguration Include="Debug|x64">
       <Configuration>Debug</Configuration>
       <Platform>x64</Platform>
     </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
     <ProjectConfiguration Include="Release|x64">
       <Configuration>Release</Configuration>
       <Platform>x64</Platform>
@@ -20,10 +28,18 @@
     <ConfigurationType>Application</ConfigurationType>
     <PlatformToolset>v142</PlatformToolset>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <PlatformToolset>v142</PlatformToolset>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>Application</ConfigurationType>
+    <PlatformToolset>v142</PlatformToolset>
+  </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <PropertyGroup Condition="'$(QtMsBuild)'=='' or !Exists('$(QtMsBuild)\qt.targets')">
     <QtMsBuild>$(MSBuildProjectDirectory)\QtMsBuild</QtMsBuild>
@@ -32,10 +48,18 @@
     <OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir>
     <IntDir>$(SolutionDir)Intermediate\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(SolutionDir)Intermediate\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
+  </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir>
     <IntDir>$(SolutionDir)Intermediate\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
   </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <OutDir>$(SolutionDir)Build\$(Platform)\$(Configuration)\</OutDir>
+    <IntDir>$(SolutionDir)Intermediate\$(ProjectName)\$(Platform)\$(Configuration)\</IntDir>
+  </PropertyGroup>
   <Target Name="QtMsBuildNotFound" BeforeTargets="CustomBuild;ClCompile" Condition="!Exists('$(QtMsBuild)\qt.targets') or !Exists('$(QtMsBuild)\qt.props')">
     <Message Importance="High" Text="QtMsBuild: could not locate qt.targets, qt.props; project may not build correctly." />
   </Target>
@@ -44,20 +68,34 @@
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
   <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
   </ImportGroup>
+  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
   <PropertyGroup Label="UserMacros" />
   <ImportGroup Condition="Exists('$(QtMsBuild)\qt_defaults.props')">
     <Import Project="$(QtMsBuild)\qt_defaults.props" />
   </ImportGroup>
   <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
     <QtInstall>msvc2017_64</QtInstall>
-    <QtModules>charts;core;datavisualization;gui;widgets;webchannel;webenginewidgets</QtModules>
+    <QtModules>charts;core;gui;widgets;;concurrent</QtModules>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="QtSettings">
+    <QtInstall>msvc2017_64</QtInstall>
+    <QtModules>charts;core;gui;widgets;;concurrent</QtModules>
   </PropertyGroup>
   <PropertyGroup Label="QtSettings" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <QtInstall>msvc2017_64</QtInstall>
-    <QtModules>charts;core;datavisualization;gui;widgets;webchannel;webenginewidgets</QtModules>
+    <QtModules>charts;core;gui;widgets;;concurrent</QtModules>
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="QtSettings">
+    <QtInstall>msvc2017_64</QtInstall>
+    <QtModules>charts;core;gui;widgets;;concurrent</QtModules>
   </PropertyGroup>
   <ImportGroup Condition="Exists('$(QtMsBuild)\qt.props')">
     <Import Project="$(QtMsBuild)\qt.props" />
@@ -82,6 +120,26 @@
       <AdditionalDependencies>$(Qt_LIBS_);%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
   </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <Optimization>Disabled</Optimization>
+      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <AdditionalIncludeDirectories>$(SolutionDir)\metaviscon\;C:\Program Files (x86)\boost\boost_1_72_0;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>$(Qt_LIBS_);%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
     <ClCompile>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -101,29 +159,65 @@
       <AdditionalDependencies>$(Qt_LIBS_);%(AdditionalDependencies)</AdditionalDependencies>
     </Link>
   </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <MultiProcessorCompilation>true</MultiProcessorCompilation>
+      <DebugInformationFormat>
+      </DebugInformationFormat>
+      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <AdditionalIncludeDirectories>$(SolutionDir)\metaviscon\;C:\Program Files (x86)\boost\boost_1_72_0;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <LanguageStandard>stdcpp17</LanguageStandard>
+    </ClCompile>
+    <Link>
+      <SubSystem>Windows</SubSystem>
+      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
+      <GenerateDebugInformation>false</GenerateDebugInformation>
+      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+      <AdditionalDependencies>$(Qt_LIBS_);%(AdditionalDependencies)</AdditionalDependencies>
+    </Link>
+  </ItemDefinitionGroup>
   <ItemGroup>
     <ClCompile Include="..\metaviscon\src\t_sne\sptree.cpp" />
     <ClCompile Include="..\metaviscon\src\t_sne\tsne.cpp" />
+    <ClCompile Include="Bitfield.cpp" />
+    <ClCompile Include="BitfieldControlPanel.cpp" />
+    <ClCompile Include="BitInspector.cpp" />
+    <ClCompile Include="BitInspectorPanel.cpp" />
     <ClCompile Include="ColorButton.cpp" />
     <ClCompile Include="ColorGradient.cpp" />
+    <ClCompile Include="Concurrent.cpp" />
     <ClCompile Include="DockableGraphView.cpp" />
+    <ClCompile Include="GraphPlott.cpp" />
     <ClCompile Include="GraphView.cpp" />
     <ClCompile Include="GraphViewSettingDialog.cpp" />
     <ClCompile Include="GraphViewSettingItem.cpp" />
+    <ClCompile Include="HoverButton.cpp" />
+    <ClCompile Include="InformationPopUp.cpp" />
     <ClCompile Include="main.cpp" />
     <ClCompile Include="MetalogManagerItem.cpp" />
     <ClCompile Include="metavis.cpp" />
     <ClCompile Include="pch.cpp">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
     </ClCompile>
+    <ClCompile Include="Plott.cpp" />
     <ClCompile Include="Project.cpp" />
     <ClCompile Include="ProjectManager.cpp" />
     <ClCompile Include="RangeSlider.cpp" />
     <ClCompile Include="RunData.cpp" />
+    <ClCompile Include="Scratchpad.cpp" />
+    <ClCompile Include="SearchSpacePlott.cpp" />
     <ClCompile Include="SettingDialog.cpp" />
+    <ClCompile Include="tSneAlgo.cpp" />
+    <ClCompile Include="TsneControlPanel.cpp" />
     <ClCompile Include="tsneIteractive.cpp" />
-    <ClCompile Include="Worker.cpp" />
+    <ClCompile Include="TsnePlott.cpp" />
+    <ClCompile Include="TsneSettings.cpp" />
   </ItemGroup>
   <ItemGroup>
     <QtMoc Include="metavis.h" />
@@ -151,10 +245,24 @@
     <ClInclude Include="..\metaviscon\src\t_sne\vptree.h" />
     <QtMoc Include="ColorGradient.h" />
     <QtMoc Include="ColorButton.h" />
+    <QtMoc Include="BitInspector.h" />
+    <QtMoc Include="Bitfield.h" />
+    <QtMoc Include="BitfieldControlPanel.h" />
+    <QtMoc Include="BitInspectorPanel.h" />
+    <ClInclude Include="Concurrent.h" />
+    <QtMoc Include="Plott.h" />
+    <QtMoc Include="GraphPlott.h" />
+    <QtMoc Include="HoverButton.h" />
+    <QtMoc Include="InformationPopUp.h" />
     <ClInclude Include="Project.h" />
-    <ClInclude Include="Worker.h" />
+    <QtMoc Include="tSneAlgo.h" />
     <QtMoc Include="RangeSlider.h" />
     <QtMoc Include="tsneIteractive.h" />
+    <QtMoc Include="Scratchpad.h" />
+    <QtMoc Include="SearchSpacePlott.h" />
+    <QtMoc Include="TsneControlPanel.h" />
+    <QtMoc Include="TsnePlott.h" />
+    <QtMoc Include="TsneSettings.h" />
     <ClInclude Include="util.h" />
     <QtMoc Include="DockableGraphView.h" />
     <QtMoc Include="GraphViewSettingDialog.h" />

+ 92 - 5
metavis/metavis.vcxproj.filters

@@ -71,6 +71,9 @@
     <Filter Include="Header Files\Data\algorithm\tSNE">
       <UniqueIdentifier>{492da30c-1983-45f2-a819-091e43e6d706}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\MultiThreading">
+      <UniqueIdentifier>{c80d6242-cd8a-4453-92f3-102a7a2a8474}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="GraphView.cpp">
@@ -121,15 +124,57 @@
     <ClCompile Include="..\metaviscon\src\t_sne\sptree.cpp">
       <Filter>Source Files\Algorithm\tSNE</Filter>
     </ClCompile>
-    <ClCompile Include="Worker.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
     <ClCompile Include="ColorGradient.cpp">
       <Filter>Source Files\UserInterface\Widget</Filter>
     </ClCompile>
     <ClCompile Include="ColorButton.cpp">
       <Filter>Source Files\UserInterface\Widget</Filter>
     </ClCompile>
+    <ClCompile Include="tSneAlgo.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Concurrent.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Plott.cpp">
+      <Filter>Source Files\UserInterface\GraphView</Filter>
+    </ClCompile>
+    <ClCompile Include="BitInspector.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="HoverButton.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="GraphPlott.cpp">
+      <Filter>Source Files\UserInterface\GraphView</Filter>
+    </ClCompile>
+    <ClCompile Include="Bitfield.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="BitfieldControlPanel.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="BitInspectorPanel.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Scratchpad.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="SearchSpacePlott.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="TsneControlPanel.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="TsnePlott.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="TsneSettings.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="InformationPopUp.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <QtMoc Include="DockableGraphView.h">
@@ -168,6 +213,48 @@
     <QtMoc Include="ColorButton.h">
       <Filter>Header Files\UserInterface\Widget</Filter>
     </QtMoc>
+    <QtMoc Include="tSneAlgo.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="Plott.h">
+      <Filter>Header Files\UserInterface\GraphView</Filter>
+    </QtMoc>
+    <QtMoc Include="BitInspector.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="Bitfield.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="BitfieldControlPanel.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="GraphPlott.h">
+      <Filter>Header Files\UserInterface\GraphView</Filter>
+    </QtMoc>
+    <QtMoc Include="HoverButton.h">
+      <Filter>Header Files\UserInterface\Widget</Filter>
+    </QtMoc>
+    <QtMoc Include="BitInspectorPanel.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="Scratchpad.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="SearchSpacePlott.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="TsneControlPanel.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="TsnePlott.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="TsneSettings.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
+    <QtMoc Include="InformationPopUp.h">
+      <Filter>Header Files</Filter>
+    </QtMoc>
   </ItemGroup>
   <ItemGroup>
     <QtUic Include="metavis.ui">
@@ -219,8 +306,8 @@
     <ClInclude Include="..\metaviscon\src\t_sne\tsne.h">
       <Filter>Header Files\Data\algorithm\tSNE</Filter>
     </ClInclude>
-    <ClInclude Include="Worker.h">
-      <Filter>Header Files</Filter>
+    <ClInclude Include="Concurrent.h">
+      <Filter>Header Files\MultiThreading</Filter>
     </ClInclude>
   </ItemGroup>
 </Project>

+ 23 - 0
metavis/settings.ini

@@ -0,0 +1,23 @@
+[BitField]
+hideOptions=true
+
+[MainWindow]
+maximized=false
+pos=@Point(361 231)
+size=@Size(1200 675)
+screenCount=1
+geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x1i\0\0\0\xe7\0\0\x6\x18\0\0\x3\x89\0\0\x1i\0\0\0\xe7\0\0\x6\x18\0\0\x3\x89\0\0\0\0\0\0\0\0\a\x80\0\0\x1i\0\0\0\xe7\0\0\x6\x18\0\0\x3\x89)
+windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x1\0\0\x4\xb0\0\0\x2z\xfc\x2\0\0\0\x2\xfc\0\0\0\x15\0\0\x1\x85\0\0\0z\0\xff\xff\xff\xfc\x1\0\0\0\x3\xfc\0\0\0\0\0\0\x1\x9b\0\0\0y\0\xff\xff\xff\xfc\x2\0\0\0\x2\xfc\0\0\0\x15\0\0\0\xe8\0\0\0?\x1\0\0\x14\xfa\0\0\0\x1\x2\0\0\0\x3\xfb\0\0\0\x18\0\x42\0\x65\0s\0t\0 \0\x41\0v\0\x65\0r\0\x61\0g\0\x65\x1\0\0\0\0\xff\xff\xff\xff\0\0\0*\0\xff\xff\xff\xfb\0\0\0(\0M\0i\0n\0 \0M\0\x61\0x\0 \0\x44\0i\0s\0t\0r\0i\0\x62\0u\0t\0i\0o\0n\x1\0\0\0\0\xff\xff\xff\xff\0\0\0*\0\xff\xff\xff\xfb\0\0\0*\0M\0\x65\0\x61\0n\0 \0H\0\x61\0m\0m\0i\0n\0g\0 \0\x44\0i\0s\0t\0\x61\0n\0\x63\0\x65\x1\0\0\0\0\xff\xff\xff\xff\0\0\0*\0\xff\xff\xff\xfb\0\0\0\x1a\0\x42\0\x65\0s\0t\0 \0O\0v\0\x65\0r\0v\0i\0\x65\0w\x1\0\0\0\xfe\0\0\0\x9c\0\0\0*\0\xff\xff\xff\xfc\0\0\x1\x9c\0\0\x1\xe5\0\0\x1\x9c\0\xff\xff\xff\xfa\0\0\0\0\x1\0\0\0\x2\xfb\0\0\0\x10\0\x42\0i\0t\0\x66\0i\0\x65\0l\0\x64\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\xc8\0\xff\xff\xff\xfb\0\0\0\n\0T\0-\0S\0N\0\x45\x1\0\0\0\0\xff\xff\xff\xff\0\0\x1\x9c\0\xff\xff\xff\xfb\0\0\0\x1e\0P\0r\0o\0j\0\x65\0\x63\0t\0 \0M\0\x61\0n\0\x61\0g\0\x65\0r\x1\0\0\x3\x82\0\0\x1.\0\0\0P\0\xff\xff\xff\xfc\0\0\x1\x9b\0\0\0\xf4\0\0\0\x86\x1\0\0\x14\xfa\0\0\0\0\x2\0\0\0\x2\xfb\0\0\0\x12\0I\0n\0s\0p\0\x65\0\x63\0t\0o\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0q\0\xff\xff\xff\xfb\0\0\0\x14\0S\0\x63\0r\0\x61\0t\0\x63\0h\0p\0\x61\0\x64\x1\0\0\0\0\xff\xff\xff\xff\0\0\0q\0\xff\xff\xff\0\0\0\0\0\0\x2z\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\0)
+
+[ProjectManager]
+path=
+
+[Tsne]
+hideOptions=true
+maxIter=750
+perplexity=10
+perplexity_MIN=1
+perplexity_MAX=50
+learnrate=200
+learnrate_MIN=1
+learnrate_MAX=1000

+ 691 - 0
metavis/tSneAlgo.cpp

@@ -0,0 +1,691 @@
+#include "pch.h"
+#include "tSneAlgo.h"
+#include <cfloat>
+#include <cmath>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <ctime>
+
+
+//This product includes software developed by the Delft University of Technology.
+
+
+#include "src/t_sne/tsne.h"
+#include "src/t_sne/vptree.h"
+#include "src/t_sne/sptree.h"
+
+#pragma warning(disable:4996)
+
+
+static double sign(double inputArrayX) { return (inputArrayX == .0 ? .0 : (inputArrayX < .0 ? -1.0 : 1.0)); }
+
+static void zeroMean(double* inputArrayX, int N, int D);
+static void computeGaussianPerplexity(double* inputArrayX, int N, int D, double* P, double perplexity);
+static void computeGaussianPerplexity(double* inputArrayX, int N, int D, unsigned int** _row_P, unsigned int** _col_P, double** _val_P, double perplexity, int K);
+static double randn();
+static void computeExactGradient(double* P, double* Y, int N, int D, double* dC);
+static void computeGradient(unsigned int* inp_row_P, unsigned int* inp_col_P, double* inp_val_P, double* Y, int N, int D, double* dC, double theta);
+static double evaluateError(double* P, double* Y, int N, int D);
+static double evaluateError(unsigned int* row_P, unsigned int* col_P, double* val_P, double* Y, int N, int D, double theta);
+static void computeSquaredEuclideanDistance(double* inputArrayX, int N, int D, double* DD);
+static void symmetrizeMatrix(unsigned int** row_P, unsigned int** col_P, double** val_P, int N);
+
+tSneAlgo::tSneAlgo(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end, double** YnotInitialized, double perplexity, double learningRate, int maxIter)
+	:perplexity(perplexity), learningRate(learningRate), N(std::distance(begin, end)), D(begin->bitVec.size()), maxIter(maxIter)
+{
+	//N -> amount of dataPoints 
+	//D -> Dimension of DataPoints
+	qDebug() << "N:" << N << " D:" << D;
+    
+    //Create Input Matrix
+	inputArrayX = new double[N * D];
+	for (int n = 0; n < N; n++) {
+		const SolutionPointData& sol = *std::next(begin, n);
+		for (int d = 0; d < D; d++) {
+			inputArrayX[n * D + d] = sol.bitVec[d] ? 1.0 : 0.0;
+		}
+	}
+
+    //Create Output Matrix
+    *YnotInitialized = outputArrayY = (double*)calloc(N * outputDimesion, sizeof(double));
+}
+
+tSneAlgo::~tSneAlgo()
+{
+    reset();
+	delete inputArrayX;
+	delete outputArrayY;
+}
+
+void tSneAlgo::run()
+{
+    //TSNE::run
+    //Init
+     // Set random seed
+ 
+    if (useRandomSeed != true) {
+        if (randomSeet >= 0) {
+            printf("Using random seed: %d\n", randomSeet);
+            srand((unsigned int)randomSeet);
+        }
+        else {
+            printf("Using current time as random seed...\n");
+            srand(time(NULL));
+        }
+    }
+
+    // Determine whether we are using an exact algorithm
+    if (N - 1 < 3 * perplexity) { printf("Perplexity too large for the number of data points!\n"); exit(1); }
+    printf("Using no_dims = %d, perplexity = %f, and theta = %f\n", outputDimesion, perplexity, theta);
+    bool exact = (theta == .0) ? true : false;
+
+    // Set learning parameters
+    float total_time = .0;
+    clock_t start, end;
+    double momentum = .5, final_momentum = .8;
+
+    // Allocate some memory
+    double* dY = (double*)malloc(N * outputDimesion * sizeof(double));
+    double* uY = (double*)malloc(N * outputDimesion * sizeof(double));
+    double* gains = (double*)malloc(N * outputDimesion * sizeof(double));
+    if (dY == NULL || uY == NULL || gains == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    for (int i = 0; i < N * outputDimesion; i++)    uY[i] = .0;
+    for (int i = 0; i < N * outputDimesion; i++) gains[i] = 1.0;
+
+    // Normalize input data (to prevent numerical problems)
+    printf("Computing input similarities...\n");
+    start = clock();
+    zeroMean(inputArrayX, N, D);
+    double max_X = 0.0;
+    for (int i = 0; i < N * D; i++) {
+        if (fabs(inputArrayX[i]) > max_X) max_X = fabs(inputArrayX[i]);
+    }
+    for (int i = 0; i < N * D; i++) inputArrayX[i] /= max_X;
+    // Compute input similarities for exact t-SNE
+    double* P = nullptr; unsigned int* row_P = nullptr; unsigned int* col_P = nullptr; double* val_P = nullptr;
+    if (exact) {
+
+        // Compute similarities
+        printf("Exact?");
+        P = (double*)malloc(N * N * sizeof(double));
+        if (P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+        computeGaussianPerplexity(inputArrayX, N, D, P, perplexity);
+
+        // Symmetrize input similarities
+        printf("Symmetrizing...\n");
+        int nN = 0;
+        for (int n = 0; n < N; n++) {
+            int mN = (n + 1) * N;
+            for (int m = n + 1; m < N; m++) {
+                P[nN + m] += P[mN + n];
+                P[mN + n] = P[nN + m];
+                mN += N;
+            }
+            nN += N;
+        }
+        double sum_P = .0;
+        for (int i = 0; i < N * N; i++) sum_P += P[i];
+        for (int i = 0; i < N * N; i++) P[i] /= sum_P;
+    }
+
+    // Compute input similarities for approximate t-SNE
+    else {
+        // Compute asymmetric pairwise input similarities
+        computeGaussianPerplexity(inputArrayX, N, D, &row_P, &col_P, &val_P, perplexity, (int)(3 * perplexity));
+
+        // Symmetrize input similarities
+        symmetrizeMatrix(&row_P, &col_P, &val_P, N);
+        double sum_P = .0;
+        for (int i = 0; i < row_P[N]; i++) sum_P += val_P[i];
+        for (int i = 0; i < row_P[N]; i++) val_P[i] /= sum_P;
+    }
+    end = clock();
+    // Lie about the P-values
+    if (exact) { for (int i = 0; i < N * N; i++)        P[i] *= 12.0; }
+    else { for (int i = 0; i < row_P[N]; i++) val_P[i] *= 12.0; }
+
+    // Initialize solution (randomly)
+    if (skipRandomInit != true) {
+        for (int i = 0; i < N * outputDimesion; i++) outputArrayY[i] = randn() * .0001;
+    }
+
+    // Perform main training loop
+    if (exact) printf("Input similarities computed in %4.2f seconds!\nLearning embedding...\n", (float)(end - start) / CLOCKS_PER_SEC);
+    else printf("Input similarities computed in %4.2f seconds (sparsity = %f)!\nLearning embedding...\n", (float)(end - start) / CLOCKS_PER_SEC, (double)row_P[N] / ((double)N * (double)N));
+    start = clock();
+    double last_C = -1;
+    for (actualIteration = 0; actualIteration < maxIter; actualIteration++) {
+        checkPaused();
+        if (checkCancel()) break;
+        emit changedIter(actualIteration);
+        // Compute (approximate) gradient
+        if (exact) computeExactGradient(P, outputArrayY, N, outputDimesion, dY);
+        else computeGradient(row_P, col_P, val_P, outputArrayY, N, outputDimesion, dY, theta);
+
+        // Update gains
+        for (int i = 0; i < N * outputDimesion; i++) gains[i] = (sign(dY[i]) != sign(uY[i])) ? (gains[i] + .2) : (gains[i] * .8);
+        for (int i = 0; i < N * outputDimesion; i++) if (gains[i] < .01) gains[i] = .01;
+
+        // Perform gradient update (with momentum and gains)
+        for (int i = 0; i < N * outputDimesion; i++) uY[i] = momentum * uY[i] - learningRate * gains[i] * dY[i];
+        for (int i = 0; i < N * outputDimesion; i++)  outputArrayY[i] +=  uY[i];
+
+        // Make solution zero-mean
+        zeroMean(outputArrayY, N, outputDimesion);
+
+        // Stop lying about the P-values after a while, and switch momentum
+        if (actualIteration == stopLyingIter) {
+            if (exact) { for (int i = 0; i < N * N; i++)        P[i] /= 12.0; }
+            else { for (int i = 0; i < row_P[N]; i++) val_P[i] /= 12.0; }
+        }
+        if (actualIteration == momentumSwitchIter) momentum = final_momentum;
+
+        // Print out progress
+        if (actualIteration > 0 && (actualIteration % 50 == 0 || actualIteration == maxIter - 1)) {
+            end = clock();
+            double C = .0;
+            if (exact) C = evaluateError(P, outputArrayY, N, outputDimesion);
+            else      C = evaluateError(row_P, col_P, val_P, outputArrayY, N, outputDimesion, theta);  // doing approximate computation here!
+
+            if (actualIteration == 0)
+                printf("Iteration %d: error is %f\n", actualIteration + 1, C);
+            else {
+                total_time += (float)(end - start) / CLOCKS_PER_SEC;
+                printf("Iteration %d: error is %f (50 iterations in %4.2f seconds)\n", actualIteration, C, (float)(end - start) / CLOCKS_PER_SEC);
+            }
+            start = clock();
+            last_C = C;
+        }
+    }
+    end = clock(); total_time += (float)(end - start) / CLOCKS_PER_SEC;
+
+    // Clean up memory
+    free(dY);
+    free(uY);
+    free(gains);
+    if (exact) free(P);
+    else {
+        free(row_P); row_P = NULL;
+        free(col_P); col_P = NULL;
+        free(val_P); val_P = NULL;
+    }
+    printf("Fitting performed in %4.2f seconds.\n", total_time);
+    emit algoDone();
+}
+
+
+void tSneAlgo::setLearningRate(double epsillon)
+{
+    learningRate = epsillon;
+
+}
+
+void tSneAlgo::setPerplexity(double perplexity)
+{
+    this->perplexity = perplexity;
+}
+
+
+
+// Compute gradient of the t-SNE cost function (using Barnes-Hut algorithm)
+static void computeGradient(unsigned int* inp_row_P, unsigned int* inp_col_P, double* inp_val_P, double* Y, int N, int D, double* dC, double theta)
+{
+
+    // Construct space-partitioning tree on current map
+    SPTree* tree = new SPTree(D, Y, N);
+
+    // Compute all terms required for t-SNE gradient
+    double sum_Q = .0;
+    double* pos_f = (double*)calloc(N * D, sizeof(double));
+    double* neg_f = (double*)calloc(N * D, sizeof(double));
+    if (pos_f == NULL || neg_f == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    tree->computeEdgeForces(inp_row_P, inp_col_P, inp_val_P, N, pos_f);
+    for (int n = 0; n < N; n++) tree->computeNonEdgeForces(n, theta, neg_f + n * D, &sum_Q);
+
+    // Compute final t-SNE gradient
+    for (int i = 0; i < N * D; i++) {
+        dC[i] = pos_f[i] - (neg_f[i] / sum_Q);
+    }
+    free(pos_f);
+    free(neg_f);
+    delete tree;
+}
+
+// Compute gradient of the t-SNE cost function (exact)
+static void computeExactGradient(double* P, double* Y, int N, int D, double* dC) {
+
+    // Make sure the current gradient contains zeros
+    for (int i = 0; i < N * D; i++) dC[i] = 0.0;
+
+    // Compute the squared Euclidean distance matrix
+    double* DD = (double*)malloc(N * N * sizeof(double));
+    if (DD == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    computeSquaredEuclideanDistance(Y, N, D, DD);
+
+    // Compute Q-matrix and normalization sum
+    double* Q = (double*)malloc(N * N * sizeof(double));
+    if (Q == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    double sum_Q = .0;
+    int nN = 0;
+    for (int n = 0; n < N; n++) {
+        for (int m = 0; m < N; m++) {
+            if (n != m) {
+                Q[nN + m] = 1 / (1 + DD[nN + m]);
+                sum_Q += Q[nN + m];
+            }
+        }
+        nN += N;
+    }
+
+    // Perform the computation of the gradient
+    nN = 0;
+    int nD = 0;
+    for (int n = 0; n < N; n++) {
+        int mD = 0;
+        for (int m = 0; m < N; m++) {
+            if (n != m) {
+                double mult = (P[nN + m] - (Q[nN + m] / sum_Q)) * Q[nN + m];
+                for (int d = 0; d < D; d++) {
+                    dC[nD + d] += (Y[nD + d] - Y[mD + d]) * mult;
+                }
+            }
+            mD += D;
+        }
+        nN += N;
+        nD += D;
+    }
+
+    // Free memory
+    free(DD); DD = NULL;
+    free(Q);  Q = NULL;
+}
+
+
+// Evaluate t-SNE cost function (exactly)
+static double evaluateError(double* P, double* Y, int N, int D) {
+
+    // Compute the squared Euclidean distance matrix
+    double* DD = (double*)malloc(N * N * sizeof(double));
+    double* Q = (double*)malloc(N * N * sizeof(double));
+    if (DD == NULL || Q == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    computeSquaredEuclideanDistance(Y, N, D, DD);
+
+    // Compute Q-matrix and normalization sum
+    int nN = 0;
+    double sum_Q = DBL_MIN;
+    for (int n = 0; n < N; n++) {
+        for (int m = 0; m < N; m++) {
+            if (n != m) {
+                Q[nN + m] = 1 / (1 + DD[nN + m]);
+                sum_Q += Q[nN + m];
+            }
+            else Q[nN + m] = DBL_MIN;
+        }
+        nN += N;
+    }
+    for (int i = 0; i < N * N; i++) Q[i] /= sum_Q;
+
+    // Sum t-SNE error
+    double C = .0;
+    for (int n = 0; n < N * N; n++) {
+        C += P[n] * log((P[n] + FLT_MIN) / (Q[n] + FLT_MIN));
+    }
+
+    // Clean up memory
+    free(DD);
+    free(Q);
+    return C;
+}
+
+// Evaluate t-SNE cost function (approximately)
+static double evaluateError(unsigned int* row_P, unsigned int* col_P, double* val_P, double* Y, int N, int D, double theta)
+{
+
+    // Get estimate of normalization term
+    SPTree* tree = new SPTree(D, Y, N);
+    double* buff = (double*)calloc(D, sizeof(double));
+    double sum_Q = .0;
+    for (int n = 0; n < N; n++) tree->computeNonEdgeForces(n, theta, buff, &sum_Q);
+
+    // Loop over all edges to compute t-SNE error
+    int ind1, ind2;
+    double C = .0, Q;
+    for (int n = 0; n < N; n++) {
+        ind1 = n * D;
+        for (int i = row_P[n]; i < row_P[n + 1]; i++) {
+            Q = .0;
+            ind2 = col_P[i] * D;
+            for (int d = 0; d < D; d++) buff[d] = Y[ind1 + d];
+            for (int d = 0; d < D; d++) buff[d] -= Y[ind2 + d];
+            for (int d = 0; d < D; d++) Q += buff[d] * buff[d];
+            Q = (1.0 / (1.0 + Q)) / sum_Q;
+            C += val_P[i] * log((val_P[i] + FLT_MIN) / (Q + FLT_MIN));
+        }
+    }
+
+    // Clean up memory
+    free(buff);
+    delete tree;
+    return C;
+}
+
+
+// Compute input similarities with a fixed perplexity
+static void computeGaussianPerplexity(double* inputArrayX, int N, int D, double* P, double perplexity) {
+
+    // Compute the squared Euclidean distance matrix
+    double* DD = (double*)malloc(N * N * sizeof(double));
+    if (DD == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    computeSquaredEuclideanDistance(inputArrayX, N, D, DD);
+
+    // Compute the Gaussian kernel row by row
+    int nN = 0;
+    for (int n = 0; n < N; n++) {
+
+        // Initialize some variables
+        bool found = false;
+        double beta = 1.0;
+        double min_beta = -DBL_MAX;
+        double max_beta = DBL_MAX;
+        double tol = 1e-5;
+        double sum_P;
+
+        // Iterate until we found a good perplexity
+        int iter = 0;
+        while (!found && iter < 200) {
+
+            // Compute Gaussian kernel row
+            for (int m = 0; m < N; m++) P[nN + m] = exp(-beta * DD[nN + m]);
+            P[nN + n] = DBL_MIN;
+
+            // Compute entropy of current row
+            sum_P = DBL_MIN;
+            for (int m = 0; m < N; m++) sum_P += P[nN + m];
+            double H = 0.0;
+            for (int m = 0; m < N; m++) H += beta * (DD[nN + m] * P[nN + m]);
+            H = (H / sum_P) + log(sum_P);
+
+            // Evaluate whether the entropy is within the tolerance level
+            double Hdiff = H - log(perplexity);
+            if (Hdiff < tol && -Hdiff < tol) {
+                found = true;
+            }
+            else {
+                if (Hdiff > 0) {
+                    min_beta = beta;
+                    if (max_beta == DBL_MAX || max_beta == -DBL_MAX)
+                        beta *= 2.0;
+                    else
+                        beta = (beta + max_beta) / 2.0;
+                }
+                else {
+                    max_beta = beta;
+                    if (min_beta == -DBL_MAX || min_beta == DBL_MAX)
+                        beta /= 2.0;
+                    else
+                        beta = (beta + min_beta) / 2.0;
+                }
+            }
+
+            // Update iteration counter
+            iter++;
+        }
+
+        // Row normalize P
+        for (int m = 0; m < N; m++) P[nN + m] /= sum_P;
+        nN += N;
+    }
+
+    // Clean up memory
+    free(DD); DD = NULL;
+}
+
+
+// Compute input similarities with a fixed perplexity using ball trees (this function allocates memory another function should free)
+static void computeGaussianPerplexity(double* inputArrayX, int N, int D, unsigned int** _row_P, unsigned int** _col_P, double** _val_P, double perplexity, int K) {
+
+    if (perplexity > K) printf("Perplexity should be lower than K!\n");
+
+    // Allocate the memory we need
+    *_row_P = (unsigned int*)malloc((N + 1) * sizeof(unsigned int));
+    *_col_P = (unsigned int*)calloc(N * K, sizeof(unsigned int));
+    *_val_P = (double*)calloc(N * K, sizeof(double));
+    if (*_row_P == NULL || *_col_P == NULL || *_val_P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    unsigned int* row_P = *_row_P;
+    unsigned int* col_P = *_col_P;
+    double* val_P = *_val_P;
+    double* cur_P = (double*)malloc((N - 1) * sizeof(double));
+    if (cur_P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    row_P[0] = 0;
+    for (int n = 0; n < N; n++) row_P[n + 1] = row_P[n] + (unsigned int)K;
+
+    // Build ball tree on data set
+    VpTree<DataPoint, euclidean_distance>* tree = new VpTree<DataPoint, euclidean_distance>();
+    vector<DataPoint> obj_X(N, DataPoint(D, -1, inputArrayX));
+    for (int n = 0; n < N; n++) obj_X[n] = DataPoint(D, n, inputArrayX + n * D);
+    tree->create(obj_X);
+
+    // Loop over all points to find nearest neighbors
+    printf("Building tree...\n");
+    vector<DataPoint> indices;
+    vector<double> distances;
+    for (int n = 0; n < N; n++) {
+
+        if (n % 10000 == 0) printf(" - point %d of %d\n", n, N);
+
+        // Find nearest neighbors
+        indices.clear();
+        distances.clear();
+        tree->search(obj_X[n], K + 1, &indices, &distances);
+
+        // Initialize some variables for binary search
+        bool found = false;
+        double beta = 1.0;
+        double min_beta = -DBL_MAX;
+        double max_beta = DBL_MAX;
+        double tol = 1e-5;
+
+        // Iterate until we found a good perplexity
+        int iter = 0; double sum_P;
+        while (!found && iter < 200) {
+
+            // Compute Gaussian kernel row
+            for (int m = 0; m < K; m++) cur_P[m] = exp(-beta * distances[m + 1] * distances[m + 1]);
+
+            // Compute entropy of current row
+            sum_P = DBL_MIN;
+            for (int m = 0; m < K; m++) sum_P += cur_P[m];
+            double H = .0;
+            for (int m = 0; m < K; m++) H += beta * (distances[m + 1] * distances[m + 1] * cur_P[m]);
+            H = (H / sum_P) + log(sum_P);
+
+            // Evaluate whether the entropy is within the tolerance level
+            double Hdiff = H - log(perplexity);
+            if (Hdiff < tol && -Hdiff < tol) {
+                found = true;
+            }
+            else {
+                if (Hdiff > 0) {
+                    min_beta = beta;
+                    if (max_beta == DBL_MAX || max_beta == -DBL_MAX)
+                        beta *= 2.0;
+                    else
+                        beta = (beta + max_beta) / 2.0;
+                }
+                else {
+                    max_beta = beta;
+                    if (min_beta == -DBL_MAX || min_beta == DBL_MAX)
+                        beta /= 2.0;
+                    else
+                        beta = (beta + min_beta) / 2.0;
+                }
+            }
+
+            // Update iteration counter
+            iter++;
+        }
+
+        // Row-normalize current row of P and store in matrix
+        for (unsigned int m = 0; m < K; m++) cur_P[m] /= sum_P;
+        for (unsigned int m = 0; m < K; m++) {
+            col_P[row_P[n] + m] = (unsigned int)indices[m + 1].index();
+            val_P[row_P[n] + m] = cur_P[m];
+        }
+    }
+
+    // Clean up memory
+    obj_X.clear();
+    free(cur_P);
+    delete tree;
+}
+
+
+// Symmetrizes a sparse matrix
+static void symmetrizeMatrix(unsigned int** _row_P, unsigned int** _col_P, double** _val_P, int N) {
+
+    // Get sparse matrix
+    unsigned int* row_P = *_row_P;
+    unsigned int* col_P = *_col_P;
+    double* val_P = *_val_P;
+
+    // Count number of elements and row counts of symmetric matrix
+    int* row_counts = (int*)calloc(N, sizeof(int));
+    if (row_counts == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    for (int n = 0; n < N; n++) {
+        for (int i = row_P[n]; i < row_P[n + 1]; i++) {
+
+            // Check whether element (col_P[i], n) is present
+            bool present = false;
+            for (int m = row_P[col_P[i]]; m < row_P[col_P[i] + 1]; m++) {
+                if (col_P[m] == n) present = true;
+            }
+            if (present) row_counts[n]++;
+            else {
+                row_counts[n]++;
+                row_counts[col_P[i]]++;
+            }
+        }
+    }
+    int no_elem = 0;
+    for (int n = 0; n < N; n++) no_elem += row_counts[n];
+
+    // Allocate memory for symmetrized matrix
+    unsigned int* sym_row_P = (unsigned int*)malloc((N + 1) * sizeof(unsigned int));
+    unsigned int* sym_col_P = (unsigned int*)malloc(no_elem * sizeof(unsigned int));
+    double* sym_val_P = (double*)malloc(no_elem * sizeof(double));
+    if (sym_row_P == NULL || sym_col_P == NULL || sym_val_P == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+
+    // Construct new row indices for symmetric matrix
+    sym_row_P[0] = 0;
+    for (int n = 0; n < N; n++) sym_row_P[n + 1] = sym_row_P[n] + (unsigned int)row_counts[n];
+
+    // Fill the result matrix
+    int* offset = (int*)calloc(N, sizeof(int));
+    if (offset == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    for (int n = 0; n < N; n++) {
+        for (unsigned int i = row_P[n]; i < row_P[n + 1]; i++) {                                  // considering element(n, col_P[i])
+
+            // Check whether element (col_P[i], n) is present
+            bool present = false;
+            for (unsigned int m = row_P[col_P[i]]; m < row_P[col_P[i] + 1]; m++) {
+                if (col_P[m] == n) {
+                    present = true;
+                    if (n <= col_P[i]) {                                                 // make sure we do not add elements twice
+                        sym_col_P[sym_row_P[n] + offset[n]] = col_P[i];
+                        sym_col_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = n;
+                        sym_val_P[sym_row_P[n] + offset[n]] = val_P[i] + val_P[m];
+                        sym_val_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = val_P[i] + val_P[m];
+                    }
+                }
+            }
+
+            // If (col_P[i], n) is not present, there is no addition involved
+            if (!present) {
+                sym_col_P[sym_row_P[n] + offset[n]] = col_P[i];
+                sym_col_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = n;
+                sym_val_P[sym_row_P[n] + offset[n]] = val_P[i];
+                sym_val_P[sym_row_P[col_P[i]] + offset[col_P[i]]] = val_P[i];
+            }
+
+            // Update offsets
+            if (!present || (present && n <= col_P[i])) {
+                offset[n]++;
+                if (col_P[i] != n) offset[col_P[i]]++;
+            }
+        }
+    }
+
+    // Divide the result by two
+    for (int i = 0; i < no_elem; i++) sym_val_P[i] /= 2.0;
+
+    // Return symmetrized matrices
+    free(*_row_P); *_row_P = sym_row_P;
+    free(*_col_P); *_col_P = sym_col_P;
+    free(*_val_P); *_val_P = sym_val_P;
+
+    // Free up some memery
+    free(offset); offset = NULL;
+    free(row_counts); row_counts = NULL;
+}
+
+// Compute squared Euclidean distance matrix
+static void computeSquaredEuclideanDistance(double* inputArrayX, int N, int D, double* DD) {
+    const double* XnD = inputArrayX;
+    for (int n = 0; n < N; ++n, XnD += D) {
+        const double* XmD = XnD + D;
+        double* curr_elem = &DD[n * N + n];
+        *curr_elem = 0.0;
+        double* curr_elem_sym = curr_elem + N;
+        for (int m = n + 1; m < N; ++m, XmD += D, curr_elem_sym += N) {
+            *(++curr_elem) = 0.0;
+            for (int d = 0; d < D; ++d) {
+                *curr_elem += (XnD[d] - XmD[d]) * (XnD[d] - XmD[d]);
+            }
+            *curr_elem_sym = *curr_elem;
+        }
+    }
+}
+
+
+// Makes data zero-mean
+static void zeroMean(double* inputArrayX, int N, int D) {
+
+    // Compute data mean
+    double* mean = (double*)calloc(D, sizeof(double));
+    if (mean == NULL) { printf("Memory allocation failed!\n"); exit(1); }
+    int nD = 0;
+    for (int n = 0; n < N; n++) {
+        for (int d = 0; d < D; d++) {
+            mean[d] += inputArrayX[nD + d];
+        }
+        nD += D;
+    }
+    for (int d = 0; d < D; d++) {
+        mean[d] /= (double)N;
+    }
+    // Subtract data mean
+    nD = 0;
+    for (int n = 0; n < N; n++) {
+        for (int d = 0; d < D; d++) {
+            inputArrayX[nD + d] -= mean[d];
+        }
+        nD += D;
+    }
+    free(mean); mean = NULL;
+}
+
+
+// Generates a Gaussian random number
+static double randn() {
+    double inputArrayX, y, radius;
+    do {
+        inputArrayX = 2 * (rand() / ((double)RAND_MAX + 1)) - 1;
+        y = 2 * (rand() / ((double)RAND_MAX + 1)) - 1;
+        radius = (inputArrayX * inputArrayX) + (y * y);
+    } while ((radius >= 1.0) || (radius == 0.0));
+    radius = sqrt(-2 * log(radius) / radius);
+    inputArrayX *= radius;
+    y *= radius;
+    return inputArrayX;
+}

+ 37 - 0
metavis/tSneAlgo.h

@@ -0,0 +1,37 @@
+#pragma once
+#include <QObject>
+#include "RunData.h"
+#include "Concurrent.h"
+#include <vector>
+
+
+class tSneAlgo : public QObject, public Concurrent
+{
+	Q_OBJECT
+public:
+	tSneAlgo(std::vector<SolutionPointData>::iterator begin, std::vector<SolutionPointData>::iterator end, double** YnotInitialized, double perplexity, double learningRate, int maxIter);
+	~tSneAlgo();
+	int actualIteration = 0;
+	double perplexity, learningRate;
+	// in between 0.0 and 1.0
+	double theta = 0;
+	int maxIter = 750, stopLyingIter = 120, momentumSwitchIter = 20;
+private:
+	int N, D, outputDimesion = 2;
+	bool useRandomSeed = true;
+	bool skipRandomInit = false;
+	int randomSeet = 182437123;
+
+	//intermediate
+	double* inputArrayX;
+	double* outputArrayY;
+	void run() override;
+
+public:
+	void setLearningRate(double epsillon);
+	void setPerplexity(double perplexity);
+signals:
+	void changedIter(int iter);
+	void algoDone();
+};
+

+ 61 - 37
metavis/tsneIteractive.cpp

@@ -6,9 +6,10 @@
 #include <chrono>
 
 #include "src/t_sne/tsne.h"
+#include "tSneAlgo.h"
 
 tsneIteractive::tsneIteractive(QWidget *parent)
-	: QWidget(parent), view(new GraphView(this, Bound(-50,50,-50,50))), gradient(new ColorGradient(this)), timer(new QTimer)
+	: QWidget(parent), view(new GraphView(this, Bound(-50,50,-50,50))), gradient(new ColorGradient(this))
 {
 	ui.setupUi(this);
 	ui.verticalLayout->insertWidget(0, view);
@@ -20,13 +21,42 @@ tsneIteractive::tsneIteractive(QWidget *parent)
 	connect(timer, &QTimer::timeout, this, static_cast<void (tsneIteractive::*)()>(&tsneIteractive::updateCanvasIfAlgoRuns));
 	connect(ui.startButton, &QPushButton::pressed,
 		this, &tsneIteractive::startRun);
+	connect(ui.pauseButton, &QPushButton::pressed,
+		this, &tsneIteractive::pauseRun);
 	connect(gradient, &ColorGradient::gradientChanged, this, &tsneIteractive::updateViewGradient);
+	ui.perplexitySlider->setMinimum(1);
+	ui.perplexitySlider->setMaximum(50);
+	ui.perplexitySlider->setValue(20);
+	ui.perplexityLineEdit->setText(QString::number(20));
+	ui.learnrateSlider->setMinimum(1);
+	ui.learnrateSlider->setMaximum(1000);
+	ui.learnrateSlider->setValue(200);
+	ui.learnrateLineEdit->setText(QString::number(200));
+	connect(ui.learnrateSlider, &QSlider::valueChanged, this, [this](int value){
+		ui.learnrateSlider->setToolTip(QString::number(value));
+		ui.learnrateLineEdit->setText(QString::number(value));
+		if (tsneConcurrent != nullptr) {
+			this->tsneConcurrent->setLearningRate(value);
+		}
+		});
+	connect(ui.perplexitySlider, &QSlider::valueChanged, this, [this](int value) {
+		ui.perplexitySlider->setToolTip(QString::number(value));
+		ui.perplexityLineEdit->setText(QString::number(value));
+		if (tsneConcurrent != nullptr) {
+			this->tsneConcurrent->setPerplexity(value);
+		}
+		});
+	ui.progressBar->setMinimum(0);
+	ui.progressBar->setMaximum(750);
+	ui.progressBar->setValue(0);
 	
 }
 
 tsneIteractive::~tsneIteractive()
 {
-	//hTsne.get();
+	if (tsneConcurrent != nullptr) {
+		delete tsneConcurrent;
+	}
 }
 
 void tsneIteractive::assignRunData(RunData* data)
@@ -34,63 +64,57 @@ void tsneIteractive::assignRunData(RunData* data)
 	this->data = data;
 }
 
+tSneAlgo* tsneIteractive::getTsneConcurrent()
+{
+	return tsneConcurrent;
+}
+
 void tsneIteractive::updateCanvasIfAlgoRuns()
 {
-	if (hTsne.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
-		hTsne.get();
+	if (tsneConcurrent->actualIteration >= 750) {
 		timer->stop();
 	}
+	ui.progressBar->setValue(tsneConcurrent->actualIteration);
 	//view->autoZoomOut();
 	view->update();
+	ui.iterLabel->setText(QString("Iteration: ") + QString::number(tsneConcurrent->actualIteration));
 }
 
 void tsneIteractive::updateViewGradient()
 {
-	qDebug() << "tsneIteractive::updateViewGradient()";
 	view->updateGraphColors(*gradient);
 	update();
 }
 
+void tsneIteractive::pauseRun()
+{
+	qDebug() << "Pause";
+	tsneConcurrent->pause();
+	if (timer->isActive()) {
+		timer->stop();
+	}
+	else {
+		timer->start();
+	}
+}
+
 void tsneIteractive::startRun()
 {
 	if (data == nullptr) {
 		qDebug() << "NoData!";
 		return;
 	}
-	qDebug() << "Start run!";
-	//Erstelle Y:
-	//N -> amount of dataPoints 
-	//D -> Dimension of DataPoints
-	size_t N = data->solutionVec.size(), D = data->solutionVec[0].bitVec.size();
-	qDebug() << "N:" << N << " D:" << D;
-	double* X = new double[N * D];
-
-	int nD = 0;
-	for (int n = 0; n < N; n++) {
-		const SolutionPointData& sol = data->solutionVec[n];
-		for (int d = 0; d < D; d++) {
-			X[nD + d] = sol.bitVec[d] ? 1.0 : 0.0;
-		}
-		nD += D;
+	double* Y = nullptr;
+	double** X = &Y;
+	if (tsneConcurrent != nullptr) {
+		delete tsneConcurrent;
 	}
-	//no_dims -> dimension of target 
-	size_t no_dims = 2;
-	//double* Y = new double[N * no_dims];
-	double* Y = (double*)calloc(N * no_dims,  sizeof(double));
-	view->addYMatrix(Y, N, data->solutionVec);
+	tsneConcurrent = new tSneAlgo(data->solutionVec.begin(), data->solutionVec.end(), X, 20, 200, 750);
+	tsneConcurrent->start();
+	qDebug() << "Y:" << Y;
+	view->addYMatrix(Y, data->solutionVec);
 	view->updateGraphColors(*gradient);
 	view->update();
-	//Perplexity and theta
-	double perplexity = 20;
-	double theta = 0;
-	//learnig rate epsillon;
-	double eta = 200;
-	//Random 
-	int rand_seed = 17235761;
-	bool skip_random_init = false;
-	//Iter changes
-	int max_iter = 700, stop_lying_iter = 120, mom_switch_iter = 20;
-	hTsne = std::async(std::launch::async, TSNE::run, X, N, D, Y, no_dims, perplexity, theta, eta, rand_seed, skip_random_init, max_iter, stop_lying_iter, mom_switch_iter);
 	timer->start(34);
-	std::cout << "Finished:" << std::endl;
+
 }

+ 6 - 3
metavis/tsneIteractive.h

@@ -1,11 +1,12 @@
 #pragma once
 
 #include <QWidget>
-#include <future>
 #include "ui_tsneIteractive.h"
 #include "GraphView.h"
 #include "RunData.h"
 #include "ColorGradient.h"
+#include "tSneAlgo.h"
+
 class tsneIteractive : public QWidget
 {
 	Q_OBJECT
@@ -17,16 +18,18 @@ public:
 	ColorGradient* gradient;
 	RunData* data = nullptr;
 	void assignRunData(RunData* data);
+	tSneAlgo* tsneConcurrent = nullptr;
+	tSneAlgo* getTsneConcurrent();
 private:
 	Ui::tsneIteractive ui;
 	
 	//Concurrent
-	std::future<void> hTsne = std::async(std::launch::async, [](){});
-	QTimer* timer;
+	QTimer* timer = new QTimer(this);
 	void updateCanvasIfAlgoRuns();
 	void updateViewGradient();
 
 
 public slots:
 	void startRun();
+	void pauseRun();
 };

+ 82 - 41
metavis/tsneIteractive.ui

@@ -19,29 +19,6 @@
      <property name="sizeConstraint">
       <enum>QLayout::SetFixedSize</enum>
      </property>
-     <item row="2" column="2" colspan="3">
-      <widget class="QSlider" name="learnrateSlider">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="tickPosition">
-        <enum>QSlider::TicksBelow</enum>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1">
-      <widget class="QLabel" name="learnRateLabel">
-       <property name="minimumSize">
-        <size>
-         <width>0</width>
-         <height>20</height>
-        </size>
-       </property>
-       <property name="text">
-        <string>Learnrate</string>
-       </property>
-      </widget>
-     </item>
      <item row="1" column="1">
       <widget class="QLabel" name="perplexityLabel">
        <property name="sizePolicy">
@@ -61,13 +38,16 @@
        </property>
       </widget>
      </item>
-     <item row="1" column="2" colspan="3">
-      <widget class="QSlider" name="perplexitySlider">
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
+     <item row="0" column="1">
+      <widget class="QPushButton" name="pauseButton">
+       <property name="minimumSize">
+        <size>
+         <width>35</width>
+         <height>30</height>
+        </size>
        </property>
-       <property name="tickPosition">
-        <enum>QSlider::TicksBelow</enum>
+       <property name="text">
+        <string>Pause</string>
        </property>
       </widget>
      </item>
@@ -84,16 +64,61 @@
        </property>
       </widget>
      </item>
-     <item row="0" column="1">
-      <widget class="QPushButton" name="pauseButton">
+     <item row="2" column="1">
+      <widget class="QLabel" name="learnrateLabel">
        <property name="minimumSize">
         <size>
-         <width>35</width>
-         <height>30</height>
+         <width>0</width>
+         <height>20</height>
         </size>
        </property>
        <property name="text">
-        <string>Pause</string>
+        <string>Learnrate</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="2">
+      <widget class="QLineEdit" name="perplexityLineEdit">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>70</width>
+         <height>16777215</height>
+        </size>
+       </property>
+      </widget>
+     </item>
+     <item row="0" column="2">
+      <widget class="QLabel" name="iterLabel">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize">
+        <size>
+         <width>0</width>
+         <height>20</height>
+        </size>
+       </property>
+       <property name="text">
+        <string>Iteration: 0</string>
+       </property>
+      </widget>
+     </item>
+     <item row="1" column="3">
+      <widget class="QSlider" name="perplexitySlider">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
        </property>
       </widget>
      </item>
@@ -110,16 +135,32 @@
        </property>
       </widget>
      </item>
-     <item row="0" column="2">
-      <widget class="QLabel" name="iterLabel">
-       <property name="minimumSize">
+     <item row="2" column="2">
+      <widget class="QLineEdit" name="learnrateLineEdit">
+       <property name="enabled">
+        <bool>true</bool>
+       </property>
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize">
         <size>
-         <width>0</width>
-         <height>20</height>
+         <width>70</width>
+         <height>16777215</height>
         </size>
        </property>
-       <property name="text">
-        <string>Iteration: 0</string>
+      </widget>
+     </item>
+     <item row="2" column="3" colspan="2">
+      <widget class="QSlider" name="learnrateSlider">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="tickPosition">
+        <enum>QSlider::TicksBelow</enum>
        </property>
       </widget>
      </item>