Browse Source

ColorGradient

Tom Troppmann 4 years ago
parent
commit
76e1328698

+ 60 - 0
metavis/ColorButton.cpp

@@ -0,0 +1,60 @@
+#include "pch.h"
+#include "ColorButton.h"
+#include <QColorDialog>
+#include <QPixmap>
+
+ColorButton::ColorButton(QWidget *parent, QColor color)
+	: QPushButton(parent), color(color)
+{
+	//setText("Set Color");
+	
+	//setContentsMargins(0, 0, 0, 0);
+	//this->setStyleSheet(this->styleSheet() + "border: 1px solid white; background-color: red");
+	updateVisual();
+	setToolTip("Set Color");
+	connect(this, &QPushButton::pressed, this, &ColorButton::openColorMenu);
+}
+
+ColorButton::~ColorButton()
+{
+}
+
+QColor ColorButton::getColor()
+{
+	return color;
+}
+
+void ColorButton::updateVisual()
+{
+	QPixmap pixmap(100, 14);
+	pixmap.fill(color);
+	QIcon redIcon(pixmap);
+	setIcon(QIcon(redIcon));
+	setIconSize(QSize(100, 14));
+}
+
+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;
+	updateVisual();
+	emit colorChanged(this->color);
+}
+
+void ColorButton::setColor(QColor color)
+{
+	this->color = color;
+	updateVisual();
+}
+
+
+
+

+ 23 - 0
metavis/ColorButton.h

@@ -0,0 +1,23 @@
+#pragma once
+
+#include <QPushButton>
+#include <QColor>
+class ColorButton : public QPushButton
+{
+	Q_OBJECT
+
+
+public:
+	ColorButton(QWidget *parent, QColor color);
+	~ColorButton();
+	QColor getColor();
+private:
+	QColor color;
+	void updateVisual();
+	void resizeEvent(QResizeEvent* event) override;
+	void openColorMenu();
+public slots:
+	void setColor(QColor color);
+signals:
+	void colorChanged(QColor color);
+};

+ 238 - 0
metavis/ColorGradient.cpp

@@ -0,0 +1,238 @@
+#include "pch.h"
+#include <QLayout>
+#include "ColorGradient.h"
+#include "util.h"
+
+#define LeftRightGap 10
+#define ColorExampleStart 30
+#define ColorExmapleHeight 80
+#define SliderBeginHeight 83
+#define SliderBody 14
+#define SliderPeak 6
+#define SelectedPreview 20
+#define SelectedHeight 115
+ColorGradient::ColorGradient(QWidget *parent)
+	: QWidget(parent)
+{
+	interpolationCombobox = new QComboBox(this);
+	interpolationCombobox->addItem("RGB");
+	interpolationCombobox->addItem("HLS");
+	connect(interpolationCombobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
+		this, [this](int index) {this->setInterpolationMode((ColorGradient::ColorInterpolationMode)index); });
+	modeCombobox = new QComboBox(this);
+	modeCombobox->addItem("Interpolate");
+	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;
+		});
+
+	QGridLayout* layout = new QGridLayout(this);
+	layout->setContentsMargins(0, 0, 0, 0);
+	layout->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);
+	
+	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);
+	//this->setMinimumHeight(150);
+	this->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+}
+
+ColorGradient::~ColorGradient()
+{
+
+}
+
+QColor ColorGradient::getColor(double alpha)
+{
+	alpha = std::clamp(alpha, 0.0, 1.0);
+	switch(mode) {
+	case ColorMode::Discrete: {
+		QColor result(255,255,255);
+		for (ColorPoint& point : pointList) {
+			if (point.alpha >= alpha) {
+				result = point.color;
+				break;
+			}
+		}
+		return result;
+	}
+	case ColorMode::Interpolate: {
+		ColorPoint before(0.0, QColor(255, 255, 255));
+		ColorPoint last(1.0, QColor(255, 255, 255));
+		ColorPoint* first = &before;
+		ColorPoint* second = &last;
+		for (ColorPoint& point : pointList) {
+			if (point.alpha >= alpha) {
+				second = &point;
+				break;
+			}
+			first = &point;
+		}
+		double alphaBetween = util::inverseLinearInterpolation(first->alpha, second->alpha, alpha);
+		switch (interpolationMode) {
+		case ColorInterpolationMode::HSL:
+			return util::interpolateHSL(first->color, second->color, alphaBetween);
+		case ColorInterpolationMode::RGB:
+		default:
+			return util::interpolateRGB(first->color, second->color, alphaBetween);
+		}
+		
+	}
+	default: {
+		return QColor(0, 0, 0);
+	}
+	}
+	
+}
+
+void ColorGradient::addColorPoint(double alpha)
+{
+	auto iter = pointList.begin();
+	for (; iter != pointList.end(); iter++) {
+		if (iter->alpha >= alpha) {
+			break;
+		}
+	}
+	selected = &*pointList.insert(iter, ColorPoint(alpha, getColor(alpha)));
+	colorbutton->setVisible(true);
+	colorbutton->setColor(selected->color);
+	emit gradientChanged();
+}
+
+void ColorGradient::removeColorPoint(ColorPoint& pointToRemove)
+{
+	pointList.erase(std::remove_if(pointList.begin(), pointList.end(),
+			[&pointToRemove](ColorPoint& point) {return &point == &pointToRemove; }));
+	selected = nullptr;
+	emit gradientChanged();
+}
+
+void ColorGradient::setMode(ColorMode mode)
+{
+	this->mode = mode;
+	update();
+	emit gradientChanged();
+	interpolationCombobox->setEnabled(mode != ColorGradient::ColorMode::Discrete);
+}
+
+void ColorGradient::setInterpolationMode(ColorInterpolationMode mode)
+{
+	this->interpolationMode = mode;
+	update();
+	emit gradientChanged();
+}
+
+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
+	QPen sliderPen;
+	sliderPen.setWidth(2);
+	painter.setPen(Qt::NoPen);
+	
+	
+	for (ColorPoint& point : pointList) {
+		QPainterPath slider;
+		if (&point == selected) {
+			sliderPen.setColor(QColor(0, 0, 0));
+			painter.setPen(sliderPen);
+		}
+		painter.setBrush(point.color);
+		int middlePosition = util::linearInterpolate(colorExampleRect.left(), colorExampleRect.right(), point.alpha);
+		slider.moveTo(middlePosition, SliderBeginHeight);
+		slider.lineTo(middlePosition - SliderPeak, SliderBeginHeight + SliderPeak);
+		slider.lineTo(middlePosition - SliderPeak, SliderBeginHeight + SliderPeak + SliderBody);
+		slider.lineTo(middlePosition + SliderPeak, SliderBeginHeight + SliderPeak + SliderBody);
+		slider.lineTo(middlePosition + SliderPeak, SliderBeginHeight + SliderPeak);
+		slider.closeSubpath();
+		painter.drawPath(slider);
+		if (&point == selected) {
+			painter.setPen(Qt::NoPen);
+		}
+	}
+	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);
+		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);
+	}
+
+
+
+
+}
+
+void ColorGradient::mousePressEvent(QMouseEvent* event)
+{
+	QPoint mousePos = event->pos();
+	QRect area(QPoint(rect().left() + LeftRightGap, ColorExmapleHeight), QPoint(rect().right() - LeftRightGap, ColorExmapleHeight+SliderBody+SliderPeak));
+	if (area.contains(mousePos)) {
+
+		// Check for existing color point
+		// Select with left mouse Button
+		// Remove Point with right mouse Button
+		for (ColorPoint& point : pointList) {
+			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);
+				}
+				else if(event->buttons() & Qt::RightButton){
+					removeColorPoint(point);
+					colorbutton->setVisible(false);
+				}
+				update();
+				return;
+			}
+		}
+		
+
+
+		// Insert new Color Point
+		double alpha = util::inverseLinearInterpolation(area.left(), area.right() + 1, mousePos.x());
+		addColorPoint(alpha);
+		update();
+	}
+}
+
+void ColorGradient::mouseMoveEvent(QMouseEvent* event)
+{
+	if (selected == 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;
+	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);
+
+	pointList.sort([](ColorPoint& a, ColorPoint& b) {
+		return a.alpha < b.alpha;
+		});
+	emit gradientChanged();
+	update();
+}

+ 47 - 0
metavis/ColorGradient.h

@@ -0,0 +1,47 @@
+#pragma once
+
+#include <QWidget>
+#include <QColor>
+#include <QComboBox>
+#include <list>
+#include "ColorButton.h"
+
+struct ColorPoint {
+	double alpha;
+	QColor color;
+	ColorPoint(double alpha, QColor color) : alpha(std::clamp(alpha, 0.0, 1.0)), color(color) {}
+};
+
+
+class ColorGradient : public QWidget
+{
+	Q_OBJECT
+
+public:
+	enum ColorInterpolationMode{ RGB, HSL};
+	enum ColorMode{ Interpolate, Discrete};
+	ColorGradient(QWidget *parent);
+	~ColorGradient();
+	QColor getColor(double alpha);
+	void addColorPoint(double alpha);
+	void removeColorPoint(ColorPoint& point);
+	void setMode(ColorMode mode);
+	void setInterpolationMode(ColorInterpolationMode mode);
+private:
+	ColorMode mode = ColorMode::Interpolate;
+	ColorInterpolationMode interpolationMode = ColorInterpolationMode::RGB;
+	std::list<ColorPoint> pointList;
+	//UI
+	ColorPoint* selected = nullptr;
+	QComboBox* interpolationCombobox = nullptr;
+	QComboBox* modeCombobox = nullptr;
+	QSpacerItem* spacerH = nullptr;
+	QLabel* label = nullptr;
+	ColorButton* colorbutton = nullptr;
+	void paintEvent(QPaintEvent* event) override;
+	void mousePressEvent(QMouseEvent* event) override;
+	void mouseMoveEvent(QMouseEvent* event) override;
+
+signals:
+	void gradientChanged();
+};

+ 127 - 7
metavis/GraphView.cpp

@@ -7,6 +7,7 @@
 #include <random>
 #include <algorithm>
 #include <chrono>
+#include "util.h"
 
 #define X_AXIS_GAP_AMOUNT 5
 #define Y_AXIS_GAP_AMOUNT 10
@@ -46,7 +47,7 @@ void GraphView::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);
-	if (graphSeriesVec.empty()) {
+	if (graphSeriesVec.empty() && yDoubleDoubleValuesAmount == 0) {
 		painter.setPen(axisPen);
 		painter.setFont(QFont("Arial", 12, QFont::Bold));
 		painter.drawText(rect(), Qt::AlignCenter, "No Data connected");
@@ -130,6 +131,19 @@ void GraphView::paintEvent(QPaintEvent* event)
 		}
 	}
 
+	if (yDoubleDoubleValuesAmount > 0) {
+		linePen.setWidth(2);
+		linePen.setColor(QColor(0,100,200, 0));
+		painter.setPen(linePen);
+		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);
+		}
+		painter.setBrush(Qt::BrushStyle::NoBrush);
+	}
+
+
+
 
 	if (drawTotalBound) {
 		painter.setPen(axisPen);
@@ -376,9 +390,7 @@ void GraphView::keyPressEvent(QKeyEvent* event)
 		}
 		break;
 	case Qt::Key_R:
-		fixedBound = totalBound;
-		calculateRangeXY();
-		generateAxisNumberStrings();
+		resetBound();
 		update();
 	default:
 		QWidget::keyPressEvent(event);
@@ -387,6 +399,14 @@ void GraphView::keyPressEvent(QKeyEvent* event)
 	QWidget::keyPressEvent(event);
 }
 
+void GraphView::resetBound()
+{
+	calculateTotalMatrixBound();
+	fixedBound = totalBound;
+	calculateRangeXY();
+	generateAxisNumberStrings();
+}
+
 void GraphView::wheelEvent(QWheelEvent* event)
 {
 	QPoint numPixels = event->pixelDelta();
@@ -501,6 +521,38 @@ void GraphView::reset()
 }
 
 
+void GraphView::calculateTotalMatrixBound()
+{
+	if (yDoubleDoubleValuesAmount > 0) {
+		/*double maxX, maxY;
+		double minX = maxX = yArray[0], minY = maxY = yArray[1];
+		for (int i = 1; i < yDoubleDoubleValuesAmount; i++) {
+			
+			if (yArray[2 * i] < minX) {
+				minX = yArray[2 * i];
+			}else if (yArray[2 * i] > maxX) {
+				maxX = yArray[2 * i];
+			}
+			if (yArray[2 * i + 1] < minY) {
+				minY = yArray[2 * i + 1];
+			}
+			else if (yArray[2 * i + 1] > maxY) {
+				maxY = yArray[2 * i + 1];
+			}
+		}
+		totalBound.minX = minX;
+		totalBound.minY = minY;
+		totalBound.maxX = maxX;
+		totalBound.maxY = maxY;*/
+
+		// Calculate AveragePoint of Matrix
+		
+		
+		
+		
+	}
+}
+
 void GraphView::calculateTotalGraphBound()
 {
 	totalBound.minX = std::min_element(std::begin(graphSeriesVec), std::end(graphSeriesVec), [](const GraphSeries& a, const GraphSeries& b) -> bool {return a.minX < b.minX; })->minX;
@@ -510,17 +562,19 @@ void GraphView::calculateTotalGraphBound()
 	
 }
 
+
+
 void GraphView::calculateRangeXY()
 {
-	actualBound = useFixedBound ? fixedBound : totalBound;
+	actualBound = fixedBound;
 	rangeGraphX = std::abs(actualBound.maxX - actualBound.minX);
 	rangeGraphY = std::abs(actualBound.maxY - actualBound.minY);
-	if (std::abs(rangeGraphX) < 0.01) {
+	if (std::abs(rangeGraphX) < 0.0001) {
 		actualBound.minX -= 1.0;
 		actualBound.maxX += 1.0;
 		rangeGraphX = 2;
 	}
-	if (std::abs(rangeGraphY) < 0.01) {
+	if (std::abs(rangeGraphY) < 0.0001) {
 		actualBound.minY -= 1.0;
 		actualBound.maxY += 1.0;
 		rangeGraphY = 2;
@@ -565,6 +619,60 @@ QColor GraphView::generateNextColorForGraph()
 	return QColor::fromHsvF(hueoffset, 0.83, 1.0);
 }
 
+
+QColor 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 GraphView::addYMatrix(double* yArray, int length, std::vector<SolutionPointData>& solVec)
+{
+	this->yArray = yArray; yDoubleDoubleValuesAmount = length;
+	this->solVec = &solVec;
+	if (pointColors != nullptr) delete pointColors;
+	pointColors = new QColor[length];
+}
+void GraphView::autoZoomOut()
+{
+	if (yDoubleDoubleValuesAmount == 0) return;
+	QPointF sumDistance(0, 0);
+	for (int i = 0; i < yDoubleDoubleValuesAmount; i++) {
+		sumDistance += QPointF(std::abs(yArray[2 * i]), std::abs(yArray[2 * i + 1]));
+	}
+	QPointF avgDistance(sumDistance.x() / yDoubleDoubleValuesAmount,
+		sumDistance.y() / yDoubleDoubleValuesAmount);
+	double scalar = 3;
+	double addScalar = 1;
+	if (fixedBound.maxX < avgDistance.x() * scalar) {
+		fixedBound.minX = -avgDistance.x() * scalar * addScalar;
+		fixedBound.maxX = avgDistance.x() * scalar * addScalar;
+		fixedBound.minY = -avgDistance.y() * scalar * addScalar;
+		fixedBound.maxY = avgDistance.y() * scalar * addScalar;
+	}
+}
+
+void GraphView::updateGraphColors(ColorGradient& gradient)
+{
+	if (yDoubleDoubleValuesAmount == 0) return;
+	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));
+	}
+}
+
 void GraphView::generateAxisNumberStrings()
 {
 	for (int i = 0; i < 11; i++) {
@@ -625,6 +733,7 @@ void GraphView::addDots(std::vector<GraphDataPoint>* dots, RunData* run, QColor
 
 void GraphView::removeAllSeriesWithRundata(RunData* run)
 {
+	//TODO not implemented jet
 	//std::for_each(graphSeriesVec);
 }
 
@@ -706,3 +815,14 @@ void Bound::move(GraphView* widget, QPointF& delta, double realPixelWidthX, doub
 	maxY += delta.y() * realPixelWidthY;
 	widget->update();
 }
+
+void Bound::move(GraphView* widget, QPointF& targetPoint)
+{
+	//Calculate MiddlePoint
+	QPointF actualMiddlePoint((maxX - minX) / 2.0, (maxY - minY) / 2.0);
+	QPointF dif = targetPoint - actualMiddlePoint;
+	minX += dif.x();
+	maxX += dif.x();
+	minY += dif.y();
+	maxY += dif.y();
+}

+ 21 - 1
metavis/GraphView.h

@@ -6,7 +6,7 @@
 #include <QPainter>
 #include <vector>
 #include "RunData.h"
-
+#include "ColorGradient.h"
 
 class GraphView;
 class RunData;
@@ -41,6 +41,7 @@ struct Bound {
 	Bound(double minX, double maxX, double minY, double maxY):minX(minX), maxX(maxX), minY(minY), maxY(maxY){}
 	void move(GraphView* widget,const Change& type, const double changePercentage = 0.1);
 	void move(GraphView* widget, QPointF& delta, double realPixelWidthX, double realPixelWidthY);
+	void move(GraphView* widget, QPointF& targetPoint);
 };
 
 class GraphView :public QWidget
@@ -65,6 +66,15 @@ private:
 	Bound actualBound = totalBound;
 	bool drawTotalBound = false;
 	double rangeGraphX = 0, rangeGraphY = 0;
+
+	double* yArray = nullptr;
+	QColor* pointColors = nullptr;
+	std::vector<SolutionPointData>* solVec = nullptr;
+	int yDoubleDoubleValuesAmount = 0;
+	
+
+
+
 	//Visualization
 	QString xAxisNumbers[11];
 	QString yAxisNumbers[11];
@@ -93,7 +103,17 @@ public:
 	void update();
 	void setDrawBound(bool value);
 	QColor generateNextColorForGraph();
+	void resetBound();
+	void addYMatrix(double* yArray, int length, std::vector<SolutionPointData>& solVec);
+	void autoZoomOut();
+	void updateGraphColors(ColorGradient& gradient);
+
+
+
+
+
 private:
+	void calculateTotalMatrixBound();
 	void calculateTotalGraphBound();
 	void GraphView::calculateMinMaxXY(GraphSeries& lgs);
 	void addSeries(std::vector<GraphDataPoint>* line, RunData* run, QColor color, GraphSeries::SeriesType type);

+ 1 - 1
metavis/GraphViewSettingItem.cpp

@@ -30,7 +30,7 @@ GraphViewSettingItem::GraphViewSettingItem(GraphView* view, GraphSeries* series,
 	connect(ui.CircleSlider, &QSlider::valueChanged, [=](const int& newValue) { series->circleRadius = newValue; view->update(); });
 	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.SetColorButton, &QPushButton::pressed, this, &GraphViewSettingItem::setColor);
 	connect(ui.NameEdit, &QLineEdit::textChanged, [=](const QString& text) { series->name = text; updateGroupBoxTitle(); });
 }
 

+ 0 - 7
metavis/GraphViewSettingItem.ui

@@ -161,13 +161,6 @@
           </property>
          </widget>
         </item>
-        <item row="1" column="1">
-         <widget class="QPushButton" name="SetColorButton">
-          <property name="text">
-           <string>SetColor</string>
-          </property>
-         </widget>
-        </item>
         <item row="2" column="1">
          <widget class="QCheckBox" name="HideCheckbox">
           <property name="text">

+ 21 - 0
metavis/Project.cpp

@@ -6,3 +6,24 @@ void Project::addMetalogFile(std::string metaLogFile)
 	//If file exist and can be open
 	runVec.push_back(Wrapper(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 from list -> delete itself;
+	//TODO
+
+}
+
+void Project::addGraphView(GraphView* view)
+{
+	viewVec.push_back(view);
+}
+
+void Project::assignRunDataPointVecToView(RunData* data, std::vector<GraphDataPoint>* vec, GraphView* view)
+{
+
+}

+ 11 - 0
metavis/Worker.cpp

@@ -0,0 +1,11 @@
+#include "pch.h"
+#include "Worker.h"
+
+Worker::Worker(std::thread t) : t(std::move(t))
+{
+}
+
+Worker::~Worker()
+{
+	t.join();
+}

+ 10 - 0
metavis/Worker.h

@@ -0,0 +1,10 @@
+#pragma once
+#include <thread>
+class Worker
+{
+	std::thread t;
+public:
+	Worker(std::thread t);
+	~Worker();
+};
+

+ 4 - 3
metavis/metavis.cpp

@@ -106,8 +106,8 @@ void metavis::createProjectManager()
 
 void metavis::createTSNE()
 {
-	tsneIteractive* window = new tsneIteractive(ui.tabWidget);
-	ui.tabWidget->addTab(window, "tSNE");
+	tsneWidget = new tsneIteractive(this);
+	ui.tabWidget->addTab(tsneWidget, "tSNE");
 }
 
 void metavis::writeActualMainWindowSettings()
@@ -225,9 +225,10 @@ void metavis::openFile()
 	//	actualParticleGraph->addLine(iter->second);
 	//}
 	////Test
-	bitField->addDots(&runList.back().dotsForBitField, &runList.front(), QColor(255, 165, 0, 100));
+	bitField->addDots(&runList.back().dotsForBitField, &runList.back(), QColor(255, 165, 0, 100));
 	updateBitFieldColors();
 	bitField->graphSeriesVec.back().useDataPointColor = true;
+	tsneWidget->assignRunData(&runList.back());
 	//actualMeanHmmingDistanceGraph->addLine(runVec[0].meanHammingDistancePerIteration, QColor(255, 0, 0));
 
 

+ 3 - 1
metavis/metavis.h

@@ -5,6 +5,8 @@
 #include "ui_metavis.h"
 #include "RunData.h"
 #include "GraphView.h"
+#include "tsneIteractive.h"
+
 
 /**
  * Main class of the GUI.
@@ -28,7 +30,7 @@ public:
 	GraphView* multiMeanHammingDistanceGraph;
 	
 
-
+	tsneIteractive* tsneWidget;
 	GraphView* bitField;
 private:
 	Ui::metavisClass ui;

+ 13 - 2
metavis/metavis.vcxproj

@@ -71,7 +71,7 @@
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
-      <AdditionalIncludeDirectories>C:\Program Files (x86)\boost\boost_1_72_0;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)\metaviscon\;C:\Program Files (x86)\boost\boost_1_72_0;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <LanguageStandard>stdcpp17</LanguageStandard>
     </ClCompile>
     <Link>
@@ -90,7 +90,7 @@
       <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
-      <AdditionalIncludeDirectories>C:\Program Files (x86)\boost\boost_1_72_0;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>$(SolutionDir)\metaviscon\;C:\Program Files (x86)\boost\boost_1_72_0;.\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <LanguageStandard>stdcpp17</LanguageStandard>
     </ClCompile>
     <Link>
@@ -102,6 +102,10 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\metaviscon\src\t_sne\sptree.cpp" />
+    <ClCompile Include="..\metaviscon\src\t_sne\tsne.cpp" />
+    <ClCompile Include="ColorButton.cpp" />
+    <ClCompile Include="ColorGradient.cpp" />
     <ClCompile Include="DockableGraphView.cpp" />
     <ClCompile Include="GraphView.cpp" />
     <ClCompile Include="GraphViewSettingDialog.cpp" />
@@ -119,6 +123,7 @@
     <ClCompile Include="RunData.cpp" />
     <ClCompile Include="SettingDialog.cpp" />
     <ClCompile Include="tsneIteractive.cpp" />
+    <ClCompile Include="Worker.cpp" />
   </ItemGroup>
   <ItemGroup>
     <QtMoc Include="metavis.h" />
@@ -141,7 +146,13 @@
     <QtMoc Include="SettingDialog.h" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\metaviscon\src\t_sne\sptree.h" />
+    <ClInclude Include="..\metaviscon\src\t_sne\tsne.h" />
+    <ClInclude Include="..\metaviscon\src\t_sne\vptree.h" />
+    <QtMoc Include="ColorGradient.h" />
+    <QtMoc Include="ColorButton.h" />
     <ClInclude Include="Project.h" />
+    <ClInclude Include="Worker.h" />
     <QtMoc Include="RangeSlider.h" />
     <QtMoc Include="tsneIteractive.h" />
     <ClInclude Include="util.h" />

+ 46 - 1
metavis/metavis.vcxproj.filters

@@ -59,6 +59,18 @@
     <Filter Include="Source Files\UserInterface\Widget">
       <UniqueIdentifier>{52a467e5-efc6-44c1-a9f6-ff9005d2b7dc}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Source Files\Algorithm">
+      <UniqueIdentifier>{08564a5b-8aa0-4f33-bf76-2f50ff559168}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\Algorithm\tSNE">
+      <UniqueIdentifier>{94e95fb3-1251-48f0-9e2f-ef92e78f6777}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\Data\algorithm">
+      <UniqueIdentifier>{c236e5d9-90d7-4b48-beb3-ed38213acbbc}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Header Files\Data\algorithm\tSNE">
+      <UniqueIdentifier>{492da30c-1983-45f2-a819-091e43e6d706}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="GraphView.cpp">
@@ -103,6 +115,21 @@
     <ClCompile Include="tsneIteractive.cpp">
       <Filter>Source Files\UserInterface\MainMenu</Filter>
     </ClCompile>
+    <ClCompile Include="..\metaviscon\src\t_sne\tsne.cpp">
+      <Filter>Source Files\Algorithm\tSNE</Filter>
+    </ClCompile>
+    <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>
   </ItemGroup>
   <ItemGroup>
     <QtMoc Include="DockableGraphView.h">
@@ -132,8 +159,14 @@
     <QtMoc Include="RangeSlider.h">
       <Filter>Header Files\UserInterface\Widget</Filter>
     </QtMoc>
+    <QtMoc Include="ColorGradient.h">
+      <Filter>Header Files\UserInterface\Widget</Filter>
+    </QtMoc>
     <QtMoc Include="tsneIteractive.h">
-      <Filter>Header Files</Filter>
+      <Filter>Header Files\UserInterface\MainMenu</Filter>
+    </QtMoc>
+    <QtMoc Include="ColorButton.h">
+      <Filter>Header Files\UserInterface\Widget</Filter>
     </QtMoc>
   </ItemGroup>
   <ItemGroup>
@@ -177,5 +210,17 @@
     <ClInclude Include="Project.h">
       <Filter>Header Files\Data</Filter>
     </ClInclude>
+    <ClInclude Include="..\metaviscon\src\t_sne\vptree.h">
+      <Filter>Header Files\Data\algorithm\tSNE</Filter>
+    </ClInclude>
+    <ClInclude Include="..\metaviscon\src\t_sne\sptree.h">
+      <Filter>Header Files\Data\algorithm\tSNE</Filter>
+    </ClInclude>
+    <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>
   </ItemGroup>
 </Project>

+ 84 - 1
metavis/tsneIteractive.cpp

@@ -1,13 +1,96 @@
 #include "pch.h"
 #include "tsneIteractive.h"
+#include <QDebug>
+#include <thread>
+#include <future>
+#include <chrono>
+
+#include "src/t_sne/tsne.h"
 
 tsneIteractive::tsneIteractive(QWidget *parent)
-	: QWidget(parent), view(new GraphView(this))
+	: QWidget(parent), view(new GraphView(this, Bound(-50,50,-50,50))), gradient(new ColorGradient(this)), timer(new QTimer)
 {
 	ui.setupUi(this);
 	ui.verticalLayout->insertWidget(0, view);
+	view->setSizePolicy(QSizePolicy::Policy::Expanding, QSizePolicy::Policy::Expanding);
+	ui.verticalLayout->addWidget(gradient);
+	//ui.gridLayout->addWidget(gradient, 4, 0);
+	//ui.gridLayout->addWidget(gradient, 4, 0, 1, 4);
+	view->setUseFixedBound(true);
+	connect(timer, &QTimer::timeout, this, static_cast<void (tsneIteractive::*)()>(&tsneIteractive::updateCanvasIfAlgoRuns));
+	connect(ui.startButton, &QPushButton::pressed,
+		this, &tsneIteractive::startRun);
+	connect(gradient, &ColorGradient::gradientChanged, this, &tsneIteractive::updateViewGradient);
+	
 }
 
 tsneIteractive::~tsneIteractive()
 {
+	//hTsne.get();
+}
+
+void tsneIteractive::assignRunData(RunData* data)
+{
+	this->data = data;
+}
+
+void tsneIteractive::updateCanvasIfAlgoRuns()
+{
+	if (hTsne.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+		hTsne.get();
+		timer->stop();
+	}
+	//view->autoZoomOut();
+	view->update();
+}
+
+void tsneIteractive::updateViewGradient()
+{
+	qDebug() << "tsneIteractive::updateViewGradient()";
+	view->updateGraphColors(*gradient);
+	update();
+}
+
+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;
+	}
+	//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);
+	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;
 }

+ 17 - 3
metavis/tsneIteractive.h

@@ -1,18 +1,32 @@
 #pragma once
 
 #include <QWidget>
+#include <future>
 #include "ui_tsneIteractive.h"
 #include "GraphView.h"
-
+#include "RunData.h"
+#include "ColorGradient.h"
 class tsneIteractive : public QWidget
 {
 	Q_OBJECT
-
 public:
 	tsneIteractive(QWidget *parent = Q_NULLPTR);
 	~tsneIteractive();
-	GraphView* view;
 
+	GraphView* view;
+	ColorGradient* gradient;
+	RunData* data = nullptr;
+	void assignRunData(RunData* data);
 private:
 	Ui::tsneIteractive ui;
+	
+	//Concurrent
+	std::future<void> hTsne = std::async(std::launch::async, [](){});
+	QTimer* timer;
+	void updateCanvasIfAlgoRuns();
+	void updateViewGradient();
+
+
+public slots:
+	void startRun();
 };

+ 26 - 0
metavis/util.h

@@ -1,4 +1,5 @@
 #pragma once
+#include <QColor>
 namespace util {
 	inline double linearInterpolate(double first, double second, double alpha) {
 		return first * (1.0 - alpha) + second * alpha;
@@ -7,4 +8,29 @@ namespace util {
 		if (max - min == 0) return max;
 		else return (value - min) / (max - min);
 	}
+	inline QColor interpolateHSL(QColor& first, QColor& second, double alpha)
+	{
+		double firstH, firstS, firstL;
+		double secondH, secondS, secondL;
+
+		first.getHslF(&firstH, &firstS, &firstL);
+		second.getHslF(&secondH, &secondS, &secondL);
+		if (firstH == -1) {
+			firstH = (secondH != -1) ? secondH : 0;
+		}
+		if (secondH == -1) {
+			secondH = (firstH != -1) ? firstH : 0;
+		}
+		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);
+	}
+	inline QColor interpolateRGB(QColor& first, QColor& second, double alpha)
+	{
+		const double r = util::linearInterpolate(first.redF(), second.redF(), alpha);
+		const double g = util::linearInterpolate(first.greenF(), second.greenF(), alpha);
+		const double b = util::linearInterpolate(first.blueF(), second.blueF(), alpha);
+		return QColor::fromRgbF(r, g, b);
+	}
 }

+ 1 - 0
metaviscon/src/t_sne/sptree.cpp

@@ -1,3 +1,4 @@
+#include "pch.h"
 /*
  *
  * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)

+ 1 - 0
metaviscon/src/t_sne/tsne.cpp

@@ -1,3 +1,4 @@
+#include "pch.h"
 /*
  *
  * Copyright (c) 2014, Laurens van der Maaten (Delft University of Technology)