Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • adfc2e5
  • /
  • topo-blend
  • /
  • landmarks_dialog.cpp
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge Iframe embedding
swh:1:cnt:3a1611c9f665679d51f08e7fd91515162be973c2
directory badge Iframe embedding
swh:1:dir:4cd23d1e54634cfb4ba85fc907bddef6128f3245

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
Generate software citation in BibTex format (requires biblatex-software package)
Generating citation ...
landmarks_dialog.cpp
#include "landmarks_dialog.h"
#include "ui_landmarks_dialog.h"
#include "GraphCorresponder.h"

#include <QFileDialog>
#include <QItemSelectionModel>
#include "correspondence-manager.h"

LandmarksDialog::LandmarksDialog(topoblend *topo_blender, QWidget *parent) :  QDialog(parent), ui(new Ui::LandmarksDialog)
{
	tb = topo_blender;

	if(!tb->gcoor)
		gcorr = tb->c_manager->makeCorresponder();
	else
		gcorr = tb->gcoor;

    ui->setupUi(this);
	
	// Set up the table widgets
	QStringList headers;
	headers.push_back("Source");
	headers.push_back("Target");
	ui->landmarksTable->setHorizontalHeaderLabels(headers);
	ui->landmarksTable->setColumnWidth(0,150);
	ui->landmarksTable->setColumnWidth(1, 150);

	headers.push_back("Score");
	ui->corrTable->setHorizontalHeaderLabels(headers);
	ui->corrTable->setColumnWidth(0,100);
	ui->corrTable->setColumnWidth(1,100);
	ui->corrTable->setColumnWidth(2,100);

	/// Point Landmarks
	this->connect(ui->addPointLandmarkButton, SIGNAL(clicked()), SLOT(addPointLandmark()));
	this->connect(ui->removePointLandmarkButton, SIGNAL(clicked()), SLOT(removePointLandmark()));
	this->connect(ui->pointLandmarksList, SIGNAL(itemSelectionChanged()), SLOT(visualizeCurrentPointLandmark()));
	this->connect(ui->visAllButton, SIGNAL(clicked()), SLOT(visualizeAllPointLandmarks()));


	/// Part Landmarks
	// Selections
	this->connect(ui->sClearButton, SIGNAL(clicked()), SLOT(sClearSelections()));
	this->connect(ui->tClearButton, SIGNAL(clicked()), SLOT(tClearSelections()));
	this->connect(ui->sList, SIGNAL(itemSelectionChanged()), SLOT(visualizeSelections()));
	this->connect(ui->tList, SIGNAL(itemSelectionChanged()), SLOT(visualizeSelections()));
	this->connect(ui->landmarksTable, SIGNAL(itemSelectionChanged()), SLOT(visualizeLandmark()));

	// Editing
	this->connect(ui->addButton, SIGNAL(clicked()), SLOT(addLandmark()));
	this->connect(ui->removeButton, SIGNAL(clicked()), SLOT(removeLandmark()));

	// I/O
	this->connect(ui->loadButton, SIGNAL(clicked()), SLOT(loadLandmarks()));
	this->connect(ui->saveButton, SIGNAL(clicked()), SLOT(saveLandmarks()));
	this->connect(ui->loadCorrButton, SIGNAL(clicked()), SLOT(loadCorrespondenceFile()));

	/// Alignment
	this->connect(ui->showAABB, SIGNAL(stateChanged(int)), SLOT(showAABB(int)));
	this->connect(ui->normalizeButton, SIGNAL(clicked()), SLOT(normalize()));
	this->connect(ui->rotateButton, SIGNAL(clicked()), SLOT(rotateGraph()));
	this->connect(ui->scaleTarget, SIGNAL(valueChanged(int)), SLOT(scaleGraph(int)));

	this->connect(ui->alignList1, SIGNAL(itemSelectionChanged()), SLOT(visualizeSelections()));
	this->connect(ui->alignList2, SIGNAL(itemSelectionChanged()), SLOT(visualizeSelections()));
	this->connect(ui->basicAlignButton, SIGNAL(clicked()), SLOT(basicAlign()));

	/// Correspondences
	this->connect(ui->prepareButton, SIGNAL(clicked()), SLOT(prepareMatrices()));

	this->connect(ui->spatialWeight, SIGNAL(valueChanged(double)), SLOT(setSpatialWeight(double)));
	this->connect(ui->structuralWeight, SIGNAL(valueChanged(double)), SLOT(setStructuralWeight(double)));
	this->connect(ui->sizeWeight, SIGNAL(valueChanged(double)), SLOT(setSizeWeight(double)));
	this->connect(ui->orientationWeight, SIGNAL(valueChanged(double)), SLOT(setOrientationWeight(double)));
	this->connect(ui->computeDisMButton, SIGNAL(clicked()), SLOT(computeDisM()));

	this->connect(ui->scoreThreshold, SIGNAL(valueChanged(double)), SLOT(setScoreThreshold(double)));
	this->connect(ui->computeCorrButton, SIGNAL(clicked()), SLOT(computePartToPartCorrespondences()));

	this->connect(ui->alignNodesButton, SIGNAL(clicked()), SLOT(alignAllNodes()));

	this->connect(ui->runButton, SIGNAL(clicked()), SLOT(computeCorrespondences()));
	this->connect(ui->corrTable, SIGNAL(cellClicked(int, int)), SLOT(visualizeCorr(int, int)));

	this->connect(ui->sourceID, SIGNAL(valueChanged(int)), SLOT(visualizePart2PartDistance(int)));
	tb->connect(ui->p2pButton, SIGNAL(clicked()), SLOT(testPoint2PointCorrespondences()));

	// Reload
	this->connect(ui->reloadButton, SIGNAL(clicked()), SLOT(reload()));
	this->connect(gcorr, SIGNAL(cleared()), SLOT(updateAll()));

	// Update the contents
	updateAll();
}

LandmarksDialog::~LandmarksDialog()
{
    delete ui;
}

Structure::Graph * LandmarksDialog::sg()
{
	return gcorr->sg;
}

Structure::Graph * LandmarksDialog::tg()
{
	return gcorr->tg;
}

bool LandmarksDialog::sIsLandmark( int i )
{
	return gcorr->sIsLandmark[i];
}

bool LandmarksDialog::tIsLandmark( int i )
{
	return gcorr->tIsLandmark[i];
}

Structure::Node* LandmarksDialog::sNode( int i )
{
	return sg()->nodes[i];
}

Structure::Node* LandmarksDialog::tNode( int i )
{
	return tg()->nodes[i];
}

void LandmarksDialog::updateSList()
{
	// Clear
	ui->sList->clear();

	// Add items
	for (int i = 0; i < sg()->nodes.size(); i++){
		if (!sIsLandmark(i))
			ui->sList->addItem(new QListWidgetItem(sNode(i)->id));
	}
}

void LandmarksDialog::updateTList()
{
	// Clear
	ui->tList->clear();

	// Add items
	for (int i = 0; i < tg()->nodes.size(); i++){
		if (!tIsLandmark(i))
			ui->tList->addItem(new QListWidgetItem(tNode(i)->id));
	}
}

void LandmarksDialog::updateLandmarksTableWidget()
{
	// Clear
	ui->landmarksTable->clearContents();

	// Resize the table
	int nLandmarks = gcorr->landmarks.size();
	int nRows = ui->landmarksTable->rowCount();
	if (nLandmarks > nRows)	{
		for (int i = nRows; i < nLandmarks; i++)
			ui->landmarksTable->insertRow(i);
	}
	if (nLandmarks < nRows)	{
		for (int i = nRows - 1; i > nLandmarks - 1; i--)
			ui->landmarksTable->removeRow(i);
	}

	// Add items
	for (int i = 0; i < nLandmarks; i++)
	{
		QString sItem, tItem;
		PART_LANDMARK set2set = gcorr->landmarks[i];
		
		foreach (QString s, set2set.first)	sItem += s + ", ";
		sItem.remove(sItem.size()-2, 2);
		ui->landmarksTable->setItem(i, 0, new QTableWidgetItem(sItem));

		foreach (QString t, set2set.second)	tItem += t + ", ";
		tItem.remove(tItem.size()-2, 2);
		ui->landmarksTable->setItem(i, 1, new QTableWidgetItem(tItem));
	}

	ui->landmarksTable->resizeColumnsToContents();
}


void LandmarksDialog::updateLandmarksTab()
{
	updatePointLandmarksList();

	updateSList();
	updateTList();
	updateLandmarksTableWidget();
}


void LandmarksDialog::addLandmark()
{
	QList<QListWidgetItem *> sItems = ui->sList->selectedItems();
	QList<QListWidgetItem *> tItems = ui->tList->selectedItems();

	if (sItems.empty() || tItems.empty()) return;


	QVector<QString> sParts, tParts;

	foreach (QListWidgetItem* item, sItems)
		sParts.push_back(item->text());

	foreach (QListWidgetItem* item, tItems)
		tParts.push_back(item->text());

	gcorr->addLandmarks(sParts, tParts);

	updateLandmarksTab();
}

void LandmarksDialog::removeLandmark()
{
	int selectedID = ui->landmarksTable->currentRow();
	
	gcorr->removeLandmark(selectedID);

	updateLandmarksTab();
}

void LandmarksDialog::sClearSelections()
{
	ui->sList->clearSelection();
}

void LandmarksDialog::tClearSelections()
{
	ui->tList->clearSelection();
}

void LandmarksDialog::visualizeSelections()
{
	/// Source
	// Set black for all
	for (int i = 0; i < sg()->nodes.size(); i++)
	{
		Structure::Node * node = sNode(i);
		node->vis_property["color"] = Qt::lightGray;
		node->vis_property["showControl"] = false;
	}

	// Set yellow for selection
	foreach (QListWidgetItem* item, ui->sList->selectedItems())
		sg()->getNode(item->text())->vis_property["color"] = Qt::yellow;

	foreach (QListWidgetItem* item, ui->alignList1->selectedItems())
		sg()->getNode(item->text())->vis_property["color"] = Qt::yellow;

	/// Target
	// Set black for all
	for (int i = 0; i < tg()->nodes.size(); i++)
	{
		Structure::Node * node = tNode(i);
		node->vis_property["color"] = Qt::lightGray;
		node->vis_property["showControl"] = false;
	}

	// Set yellow for selection
	foreach (QListWidgetItem* item, ui->tList->selectedItems())
		tg()->getNode(item->text())->vis_property["color"] = Qt::yellow;

	foreach (QListWidgetItem* item, ui->alignList2->selectedItems())
		tg()->getNode(item->text())->vis_property["color"] = Qt::yellow;

	tb->updateDrawArea();
}


void LandmarksDialog::visualizeLandmark()
{
	QList<QTableWidgetItem *> items = ui->landmarksTable->selectedItems();

	if (! items.empty())
	{
		// Set black for all
		for (int i = 0; i < sg()->nodes.size(); i++)
		{
			Structure::Node * node = sNode(i);
			node->vis_property["color"] = Qt::lightGray;
			node->vis_property["showControl"] = false;
		}

		for (int i = 0; i < tg()->nodes.size(); i++)
		{
			Structure::Node * node = tNode(i);
			node->vis_property["color"] = Qt::lightGray;
			node->vis_property["showControl"] = false;
		}

		// Get the landmark
		int id = ui->landmarksTable->row(items.front());
		PART_LANDMARK set2set = gcorr->landmarks[id];

		// Set red for landmark
		foreach (QString sID, set2set.first)
			sg()->getNode(sID)->vis_property["color"] = Qt::red;

		foreach (QString tID, set2set.second)
			tg()->getNode(tID)->vis_property["color"] = Qt::red;

		tb->updateDrawArea();
	}

}


void LandmarksDialog::saveLandmarks()
{
	QString filename = QFileDialog::getSaveFileName(NULL,"Save Lanmarks","./", "Text file (*.txt)");

	gcorr->saveLandmarks(filename);
}

void LandmarksDialog::loadLandmarks()
{
	QString filename = QFileDialog::getOpenFileName(NULL,"Load Lanmarks","./", "Text file (*.txt)");
	gcorr->loadLandmarks(filename);

	updateLandmarksTab();
}

void LandmarksDialog::updateCorrTableWidget()
{
	// Clear
	ui->corrTable->clearContents();
	ui->corrTable->setRowCount(gcorr->correspondences.size());

	// Add items
	int nCoor = gcorr->correspondences.size();
	for (int i = 0; i < nCoor; i++)
	{
		// Correspondences and scores
		PART_LANDMARK vec2vec = gcorr->correspondences[i];
		std::vector<float> scores = gcorr->corrScores[vec2vec];

		// One to many
		if (vec2vec.first.size() == 1)
		{
			QString sID = vec2vec.first.front();
			QString tIDs, scoreStr;
			for (int j = 0; j < (int)vec2vec.second.size(); j++)
			{
				tIDs += vec2vec.second[j] +  " ";
				scoreStr += QString::number(scores[j], 'f', 4) + " ";
			}

			ui->corrTable->setItem(i, 0, new QTableWidgetItem(sID));
			ui->corrTable->setItem(i, 1, new QTableWidgetItem(tIDs));
			ui->corrTable->setItem(i, 2, new QTableWidgetItem(scoreStr));
		}
		// Many to one
		else
		{
			QString tID = vec2vec.second.front();
			QString sIDs, scoreStr;
			for (int j = 0; j < (int)vec2vec.first.size(); j++)
			{
				sIDs += vec2vec.first[j] + " ";
				scoreStr += QString::number(scores[j], 'f', 4) + " ";
			}

			ui->corrTable->setItem(i, 0, new QTableWidgetItem(sIDs));
			ui->corrTable->setItem(i, 1, new QTableWidgetItem(tID));
			ui->corrTable->setItem(i, 2, new QTableWidgetItem(scoreStr));
		}
	}
}

void LandmarksDialog::updateCorrTab()
{
	updateCorrTableWidget();

	this->ui->spatialWeight->setValue(gcorr->spactialW);
	this->ui->structuralWeight->setValue(gcorr->structuralW);
	this->ui->sizeWeight->setValue(gcorr->sizeW);
	this->ui->orientationWeight->setValue(gcorr->orientationW);

	this->ui->scoreThreshold->setValue(gcorr->scoreThreshold);

	this->ui->sourceID->setMaximum(gcorr->sg->nodes.size()-1);
}

void LandmarksDialog::updateAlignmentTab()
{
	// Clear
	ui->alignList1->clear();
	ui->alignList2->clear();

	// Add items
	for (int i = 0; i < sg()->nodes.size(); i++)
		ui->alignList1->addItem(new QListWidgetItem(sNode(i)->id));
	for (int i = 0; i < tg()->nodes.size(); i++)
		ui->alignList2->addItem(new QListWidgetItem(tNode(i)->id));
}

void LandmarksDialog::updateAll()
{
	//normalize();

	ui->sName->setText("Source: " + gcorr->sgName());
	ui->tName->setText("Target: " + gcorr->tgName());

	updateLandmarksTab();
	updateCorrTab();

	// Alignment tab
	this->ui->graphID->setMaximum(tb->graphs.size()-1);
	updateAlignmentTab();
}

void LandmarksDialog::reload()
{
	gcorr = tb->c_manager->makeCorresponder();
	if (!gcorr)
	{
		this->done(0);
		return;
	}

	// Update all
	updateAll();
}

void LandmarksDialog::visualizePart2PartDistance( int id)
{
	gcorr->visualizePart2PartDistance(id);

	tb->updateDrawArea();
}

void LandmarksDialog::computeCorrespondences()
{
	gcorr->isReady = false;
	gcorr->computeCorrespondences();
	updateCorrTab();
}

void LandmarksDialog::rotateGraph()
{
	double angle = ui->angleAroundZ->value();

	Structure::Graph *graph = tb->getGraph(ui->graphID->value());
	if( graph )
	{
		// Rotate the target graph
		graph->rotate(angle, Vector3(0, 0, 1));

		// Update the scene
		tb->updateDrawArea();
	}
}

void LandmarksDialog::showAABB(int state)
{
	foreach (Structure::Graph *g, tb->graphs)
		g->property["showAABB"] = (state == 2);

	tb->updateDrawArea();
}

void LandmarksDialog::scaleGraph(int slider)
{
	double scaleFactor = slider / 50.0;

	Structure::Graph *g = tb->graphs[ui->graphID->value()];
	g->scale(scaleFactor);

	tb->updateDrawArea();
}

void LandmarksDialog::normalize()
{
	foreach(Structure::Graph *g, tb->graphs)
	{
		g->moveBottomCenterToOrigin();
		g->normalize();
	}

	tb->setSceneBounds();
	tb->updateDrawArea();
}

void LandmarksDialog::addPointLandmark()
{
	gcorr->addPointLandmark();

	updatePointLandmarksList();

	tb->updateDrawArea();
}

void LandmarksDialog::updatePointLandmarksList()
{
	// Clear
	ui->pointLandmarksList->clear();

	// Add items
	foreach (POINT_LANDMARK landmark, gcorr->pointLandmarks)
	{
		 QVector<POINT_ID> sPoints = landmark.first;
		 QVector<POINT_ID> tPoints = landmark.second;

		 QString sIDString, tIDString;
		 foreach( POINT_ID sID, sPoints ) sIDString += "<" + QString::number(sID.first) + ", " + QString::number(sID.second) + ">";
		 foreach( POINT_ID tID, tPoints ) tIDString += "<" + QString::number(tID.first) + ", " + QString::number(tID.second) + ">";
		 ui->pointLandmarksList->addItem(new QListWidgetItem(sIDString + "\t" + tIDString));
	}
}

void LandmarksDialog::visualizeCurrentPointLandmark()
{
	int currRow = ui->pointLandmarksList->currentRow();
	if (currRow < 0 || currRow > gcorr->pointLandmarks.size() - 1)
	{
		qDebug() << "Current row is out of range.";
		return;
	}

	// Clear all selection
	gcorr->sg->clearSelections();
	gcorr->tg->clearSelections();

	// Add current point landmarks
	QColor color = Qt::yellow;
	POINT_LANDMARK landmark = gcorr->pointLandmarks[currRow];

	foreach (POINT_ID sID, landmark.first)
	{
		int nID = sID.first;
		int pID = sID.second;
		gcorr->sg->nodes[nID]->addSelectionWithColor(pID, color);
	}

	foreach (POINT_ID tID, landmark.second)
	{
		int nID = tID.first;
		int pID = tID.second;
		gcorr->tg->nodes[nID]->addSelectionWithColor(pID, color);
	}

	tb->updateDrawArea();
}

void LandmarksDialog::visualizeAllPointLandmarks()
{
	// Clear all selection
	gcorr->sg->clearSelections();
	gcorr->tg->clearSelections();

	// Add all point landmarks
	int num = gcorr->pointLandmarks.size();
	for (int id = 0; id < num; id++)
	{
		double t = (id+1) / (double) num;
		QColor color = qtJetColorMap(t);

		POINT_LANDMARK landmark = gcorr->pointLandmarks[id];

		foreach (POINT_ID sID, landmark.first)
		{
			int nID = sID.first;
			int pID = sID.second;
			gcorr->sg->nodes[nID]->addSelectionWithColor(pID, color);
		}

		foreach (POINT_ID tID, landmark.second)
		{
			int nID = tID.first;
			int pID = tID.second;
			gcorr->tg->nodes[nID]->addSelectionWithColor(pID, color);
		}
	}

	tb->updateDrawArea();
}


void LandmarksDialog::removePointLandmark()
{
	int currRow = ui->pointLandmarksList->currentRow();
	if (currRow >= 0 && currRow < gcorr->pointLandmarks.size())
		gcorr->pointLandmarks.remove(currRow);

	updatePointLandmarksList();

	tb->updateDrawArea();
}

void LandmarksDialog::setSpatialWeight( double w )
{
	gcorr->spactialW = w;
}

void LandmarksDialog::setStructuralWeight( double w )
{
	gcorr->structuralW = w;
}

void LandmarksDialog::setSizeWeight( double w )
{
	gcorr->sizeW = w;
}

void LandmarksDialog::setOrientationWeight( double w )
{
	gcorr->orientationW = w;
}

void LandmarksDialog::computeDisM()
{
	gcorr->computeFinalDistanceMatrix();
}

void LandmarksDialog::setScoreThreshold( double tau )
{
	gcorr->scoreThreshold = tau;
}

void LandmarksDialog::computePartToPartCorrespondences()
{
	gcorr->computePartToPartCorrespondences();
	updateCorrTab();
}

void LandmarksDialog::alignAllNodes()
{
	gcorr->correspondAllNodes();
}

void LandmarksDialog::prepareMatrices()
{
	gcorr->prepareAllMatrices();
}

void LandmarksDialog::basicAlign()
{
	if(ui->alignList1->selectedItems().empty()) return;
	if(ui->alignList2->selectedItems().empty()) return;

	Structure::Node * snode = sg()->getNode(ui->alignList1->selectedItems().front()->text());
	Structure::Node * tnode = tg()->getNode(ui->alignList2->selectedItems().front()->text());

	if(snode->type() != tnode->type()) return;

	if(snode->type() == Structure::CURVE)
	{
		gcorr->correspondTwoCurves((Structure::Curve*)snode,(Structure::Curve*)tnode,gcorr->tg);
	}
	if(snode->type() == Structure::SHEET)
	{
		gcorr->correspondTwoSheets((Structure::Sheet*)snode,(Structure::Sheet*)tnode,gcorr->tg);
	}

	tb->updateDrawArea();
}

void LandmarksDialog::visualizeCorr( int row, int column )
{
	Q_UNUSED(column)

	if (row >= 0 && row < (int)gcorr->correspondences.size())
	{
		// Set black for all
		for (int i = 0; i < sg()->nodes.size(); i++)
		{
			Structure::Node * node = sNode(i);
			node->vis_property["color"] = Qt::lightGray;
			node->vis_property["showControl"] = false;
		}

		for (int i = 0; i < tg()->nodes.size(); i++)
		{
			Structure::Node * node = tNode(i);
			node->vis_property["color"] = Qt::lightGray;
			node->vis_property["showControl"] = false;
		}

		// Get the correspondence
		PART_LANDMARK set2set = gcorr->correspondences[row];

		// Set red for landmark
		foreach (QString sID, set2set.first)
			sg()->getNode(sID)->vis_property["color"] = Qt::red;

		foreach (QString tID, set2set.second)
			tg()->getNode(tID)->vis_property["color"] = Qt::red;

		tb->updateDrawArea();
	}
}

void LandmarksDialog::loadCorrespondenceFile()
{
	gcorr->loadCorrespondences(QFileDialog::getOpenFileName(NULL,"Load Correspondence","./", "Text file (*.txt)"));
	gcorr->isReady = true;

	updateAll();
	updateLandmarksTableWidget();
	updateLandmarksTab();
}

back to top

Software Heritage — Copyright (C) 2015–2025, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API