<commit_before>#pragma once

#include <QWidget>

#include <QAction>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenuBar>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>

#include "NQVTKWidget.h"

#include "Rendering/DistanceFieldParamSet.h"
#include "Rendering/ImageDataTexture3D.h"
#include "Rendering/PCAParamSet.h"
#include "Rendering/PolyData.h"
#include "Rendering/SimpleRenderer.h"
#include "Rendering/TransferFunctionParamSet.h"

#include "Math/Vector3.h"

#include <vtkSmartPointer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLImageDataReader.h>

#include <string>

class PCASlider : public QWidget
{
	Q_OBJECT;

public:
	PCASlider(QWidget *parent = 0) : QWidget(parent)
	{
		// Create subwidgets
		QHBoxLayout *line = new QHBoxLayout(this);
		line->setMargin(0);
		line->setSpacing(2);
		// - Slider
		slider = new QSlider(this);
		slider->setRange(-300, 300);
		slider->setValue(0);
		slider->setOrientation(Qt::Horizontal);
		slider->setMaximumHeight(7);
		slider->setTickPosition(QSlider::TicksBothSides);
		slider->setTickInterval(50);
		connect(slider, SIGNAL(valueChanged(int)), 
			this, SLOT(slider_valueChanged(int)));
		line->addWidget(slider);
		// - Value readout
		label = new QLabel("0.0", this);
		label->setMaximumWidth(50);
		label->setMinimumWidth(50);
		line->addWidget(label);
		// - Reset button
		resetButton = new QPushButton("0", this);
		resetButton->setMaximumWidth(20);
		resetButton->setMinimumWidth(20);
		resetButton->setMaximumHeight(16);
		connect(resetButton, SIGNAL(clicked()), 
			this, SLOT(reset()));
		line->addWidget(resetButton);
	}

signals:
	void valueChanged(float);

public slots:
	void reset()
	{
		slider->setValue(0);
	}

	void setValue(float val)
	{
		slider->setValue(100 * val);
	}

private slots:
	void slider_valueChanged(int val)
	{
		float v = static_cast<float>(val) / 100.0;
		label->setText(QString("%1").arg(v, 0, 'f', 3));
		emit valueChanged(v);
	}

private:
	QSlider *slider;
	QLabel *label;
	QPushButton *resetButton;
};



class RenderableControlWidget : public QWidget
{
	Q_OBJECT;

public:
	RenderableControlWidget(NQVTKWidget *mainView, QWidget *parent = 0) : QWidget(parent)
	{
		assert(mainView);
		this->mainView = mainView;

		renderable = 0;
		color = NQVTK::Vector3(1.0, 1.0, 1.0);
		opacity = 1.0;

		// Create the layout
		QVBoxLayout *layout = new QVBoxLayout(this);
		layout->setMargin(0);
		layout->setSpacing(0);
		this->setLayout(layout);

		// Set up the renderer
		CreateRenderer();

		// Create the menu bar
		CreateMenus();

		// Add a renderable slot in the main view
		slot = mainView->GetRenderer()->AddRenderable(0);
	}

	void LoadMesh(const std::string &filename)
	{
		if (renderable)
		{
			// Delete old renderables
			NQVTK::Renderable *simpleObj = 
				simpleView->GetRenderer()->SetRenderable(0, 0);
			if (simpleObj != 0 && simpleObj != renderable) delete simpleObj;
			delete renderable;
		}

		qDebug("Loading mesh %s", filename.c_str());
		vtkSmartPointer<vtkXMLPolyDataReader> reader = 
			vtkSmartPointer<vtkXMLPolyDataReader>::New();
		reader->SetFileName(filename.c_str());
		reader->Update();

		// Create renderable in the main view
		mainView->makeCurrent();
		NQVTK::PolyData *pd = new NQVTK::PolyData(reader->GetOutput());
		renderable = pd;
		renderable->color = color;
		renderable->opacity = opacity;
		mainView->GetRenderer()->SetRenderable(slot, renderable);

		// Add renderable to the simple view
		if (simpleView->isSharing())
		{
			// GL resources are shared, just add the original renderable
			simpleView->GetRenderer()->SetRenderable(0, renderable);
		}
		else
		{
			qDebug("WARNING! NQVTKWidgets can't share GL resources!");
			// TODO: we need to manually sync transformations between these objects
			simpleView->makeCurrent();
			NQVTK::Renderable *obj2 = new NQVTK::PolyData(reader->GetOutput()); 
			obj2->color = color;
			simpleView->GetRenderer()->SetRenderable(0, obj2);
		}
		mainView->makeCurrent();

		// Add other param sets
		// - PCA
		// TODO: also deform objects in simpleViews?
		int numEigenModes = NQVTK::PCAParamSet::GetNumEigenModes(pd);
		if (numEigenModes > 0)
		{
			NQVTK::PCAParamSet *pcaps = new NQVTK::PCAParamSet(numEigenModes);
			pd->SetParamSet("pca", pcaps);
		}

		// TODO: update interactor
		//simpleView->SetInteractor(new NQVTK::MainViewInteractor(simpleRen));
	}

	void LoadDistanceField(const std::string &filename)
	{
		if (!renderable) return;
		// Is there an old distance field?
		NQVTK::DistanceFieldParamSet *dfps = 
			dynamic_cast<NQVTK::DistanceFieldParamSet*>(
				renderable->GetParamSet("distancefield"));
		if (dfps) delete dfps;

		// Load the distance field
		vtkSmartPointer<vtkXMLImageDataReader> reader = 
			vtkSmartPointer<vtkXMLImageDataReader>::New();
		reader->SetFileName(filename.c_str());
		reader->Update();
		NQVTK::ImageDataTexture3D *tex = 
			NQVTK::ImageDataTexture3D::New(reader->GetOutput());
		assert(tex);
		// Assign to renderable
		dfps = new NQVTK::DistanceFieldParamSet(tex);
		renderable->SetParamSet("distancefield", dfps);

		// For now, also add a transfer function
		// TODO: this should probably be handled some other way
		NQVTK::TransferFunctionParamSet *tfps = <commit_msg>Added support for MetaImage volumes.<commit_after>#pragma once

#include <QWidget>

#include <QAction>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenuBar>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>

#include "NQVTKWidget.h"

#include "Rendering/DistanceFieldParamSet.h"
#include "Rendering/ImageDataTexture3D.h"
#include "Rendering/PCAParamSet.h"
#include "Rendering/PolyData.h"
#include "Rendering/SimpleRenderer.h"
#include "Rendering/TransferFunctionParamSet.h"

#include "Math/Vector3.h"

#include <vtkMetaImageReader.h>
#include <vtkSmartPointer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLImageDataReader.h>

#include <string>

class PCASlider : public QWidget
{
	Q_OBJECT;

public:
	PCASlider(QWidget *parent = 0) : QWidget(parent)
	{
		// Create subwidgets
		QHBoxLayout *line = new QHBoxLayout(this);
		line->setMargin(0);
		line->setSpacing(2);
		// - Slider
		slider = new QSlider(this);
		slider->setRange(-300, 300);
		slider->setValue(0);
		slider->setOrientation(Qt::Horizontal);
		slider->setMaximumHeight(7);
		slider->setTickPosition(QSlider::TicksBothSides);
		slider->setTickInterval(50);
		connect(slider, SIGNAL(valueChanged(int)), 
			this, SLOT(slider_valueChanged(int)));
		line->addWidget(slider);
		// - Value readout
		label = new QLabel("0.0", this);
		label->setMaximumWidth(50);
		label->setMinimumWidth(50);
		line->addWidget(label);
		// - Reset button
		resetButton = new QPushButton("0", this);
		resetButton->setMaximumWidth(20);
		resetButton->setMinimumWidth(20);
		resetButton->setMaximumHeight(16);
		connect(resetButton, SIGNAL(clicked()), 
			this, SLOT(reset()));
		line->addWidget(resetButton);
	}

signals:
	void valueChanged(float);

public slots:
	void reset()
	{
		slider->setValue(0);
	}

	void setValue(float val)
	{
		slider->setValue(100 * val);
	}

private slots:
	void slider_valueChanged(int val)
	{
		float v = static_cast<float>(val) / 100.0;
		label->setText(QString("%1").arg(v, 0, 'f', 3));
		emit valueChanged(v);
	}

private:
	QSlider *slider;
	QLabel *label;
	QPushButton *resetButton;
};



class RenderableControlWidget : public QWidget
{
	Q_OBJECT;

public:
	RenderableControlWidget(NQVTKWidget *mainView, QWidget *parent = 0) : QWidget(parent)
	{
		assert(mainView);
		this->mainView = mainView;

		renderable = 0;
		color = NQVTK::Vector3(1.0, 1.0, 1.0);
		opacity = 1.0;

		// Create the layout
		QVBoxLayout *layout = new QVBoxLayout(this);
		layout->setMargin(0);
		layout->setSpacing(0);
		this->setLayout(layout);

		// Set up the renderer
		CreateRenderer();

		// Create the menu bar
		CreateMenus();

		// Add a renderable slot in the main view
		slot = mainView->GetRenderer()->AddRenderable(0);
	}

	void LoadMesh(const std::string &filename)
	{
		if (renderable)
		{
			// Delete old renderables
			NQVTK::Renderable *simpleObj = 
				simpleView->GetRenderer()->SetRenderable(0, 0);
			if (simpleObj != 0 && simpleObj != renderable) delete simpleObj;
			delete renderable;
		}

		qDebug("Loading mesh %s", filename.c_str());
		vtkSmartPointer<vtkXMLPolyDataReader> reader = 
			vtkSmartPointer<vtkXMLPolyDataReader>::New();
		reader->SetFileName(filename.c_str());
		reader->Update();

		// Create renderable in the main view
		mainView->makeCurrent();
		NQVTK::PolyData *pd = new NQVTK::PolyData(reader->GetOutput());
		renderable = pd;
		renderable->color = color;
		renderable->opacity = opacity;
		mainView->GetRenderer()->SetRenderable(slot, renderable);

		// Add renderable to the simple view
		if (simpleView->isSharing())
		{
			// GL resources are shared, just add the original renderable
			simpleView->GetRenderer()->SetRenderable(0, renderable);
		}
		else
		{
			qDebug("WARNING! NQVTKWidgets can't share GL resources!");
			// TODO: we need to manually sync transformations between these objects
			simpleView->makeCurrent();
			NQVTK::Renderable *obj2 = new NQVTK::PolyData(reader->GetOutput()); 
			obj2->color = color;
			simpleView->GetRenderer()->SetRenderable(0, obj2);
		}
		mainView->makeCurrent();

		// Add other param sets
		// - PCA
		// TODO: also deform objects in simpleViews?
		int numEigenModes = NQVTK::PCAParamSet::GetNumEigenModes(pd);
		if (numEigenModes > 0)
		{
			NQVTK::PCAParamSet *pcaps = new NQVTK::PCAParamSet(numEigenModes);
			pd->SetParamSet("pca", pcaps);
		}

		// TODO: update interactor
		//simpleView->SetInteractor(new NQVTK::MainViewInteractor(simpleRen));
	}

	void LoadDistanceField(const std::string &filename)
	{
		if (!renderable) return;
		// Is there an old distance field?
		NQVTK::DistanceFieldParamSet *dfps = 
			dynamic_cast<NQVTK::DistanceFieldParamSet*>(
				renderable->GetParamSet("distancefield"));
		if (dfps) delete dfps;

		// Load the distance field
		NQVTK::ImageDataTexture3D *tex = 0;
		std::string extension = filename.substr(filename.rfind(".") + 1);
		if (extension == std::string("vti"))
		{
			vtkSmartPointer<vtkXMLImageDataReader> reader = 
				vtkSmartPointer<vtkXMLImageDataReader>::New();
			reader->SetFileName(filename.c_str());
			reader->Update();
			tex = NQVTK::ImageDataTexture3D::New(reader->GetOutput());
		}
		else if (extension == std::string("mhd") || extension == std::string("mha"))
		{
			vtkSmartPointer<vtkMetaImageReader> reader = 
				vtkSmartPointer<vtkMetaImageReader>::New();
			reader->SetFileName(filename.c_str());
			reader->Update();
			tex = NQVTK::ImageDataTexture3D::New(reader->GetOutput());
		}
		else
		{
			qDebug("Error loading volume! File extension '%s' not supported!", 
				extension.c_str());
		}
		assert(tex);
		// Assign to renderable
		dfps = new NQVTK::DistanceFieldParamSet(tex);
		renderable->SetParamSet("distancefield", dfps);

		// For now, also add a transfer function
		// TODO: this should probably be handled some other way
		NQVTK::TransferFunctionParamSet *tfps = 
{'fraction_non_alphanumeric': 0.14199477430399135, 'fraction_numerical': 0.011802865122984053, 'mean_word_length': 4.721649484536083, 'pattern_counts': {'":': 0, '<': 44, '<?xml version=': 0, '>': 151, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3496836', 'n_tokens_mistral': 4235, 'n_tokens_neox': 3818, 'n_words': 784}