<commit_before>#include "MeshCuboidStructure.h"

#include <deque>
#include <fstream>
#include <iostream>


MeshCuboidStructure::MeshCuboidStructure(const MyMesh* _mesh)
	: mesh_(_mesh)
	, query_label_index_(0)
	, translation_(0.0)
	, scale_(1.0)
{
	assert(_mesh);
}

MeshCuboidStructure::~MeshCuboidStructure()
{
}

MeshCuboidStructure::MeshCuboidStructure(const MeshCuboidStructure& _other)
{
	deep_copy(_other);
}

MeshCuboidStructure& MeshCuboidStructure::operator=(const MeshCuboidStructure& _other)
{
	deep_copy(_other);
	return (*this);
}

void MeshCuboidStructure::deep_copy(const MeshCuboidStructure& _other)
{
	this->mesh_ = _other.mesh_;

	this->labels_ = _other.labels_;
	this->label_names_ = _other.label_names_;
	this->label_symmetries_ = _other.label_symmetries_;

	this->translation_ = _other.translation_;
	this->scale_ = _other.scale_;

	this->query_label_index_ = _other.query_label_index_;

	// Deep copy sample points.
	assert(_other.sample_points_.size() == _other.num_sample_points());
	this->sample_points_.clear();
	this->sample_points_.reserve(_other.num_sample_points());

	for (std::vector<MeshSamplePoint *>::const_iterator it = _other.sample_points_.begin();
		it != _other.sample_points_.end(); ++it)
	{
		MeshSamplePoint *sample_point = new MeshSamplePoint(**it);
		this->sample_points_.push_back(sample_point);
	}

	// Deep copy label cuboids.
	assert(_other.label_cuboids_.size() == _other.num_labels());
	unsigned int num_labels = _other.num_labels();
	this->label_cuboids_.clear();
	this->label_cuboids_.resize(num_labels);

	for (LabelIndex label_index = 0; label_index < num_labels; ++label_index)
	{
		this->label_cuboids_[label_index].reserve(_other.label_cuboids_[label_index].size());
		for (std::vector<MeshCuboid *>::const_iterator it = _other.label_cuboids_[label_index].begin();
			it != _other.label_cuboids_[label_index].end(); ++it)
		{
			MeshCuboid *cuboid = new MeshCuboid(**it);
			this->label_cuboids_[label_index].push_back(cuboid);
		}
	}
}

void MeshCuboidStructure::clear()
{
	clear_sample_points();
	clear_cuboids();
	clear_labels();
}

void MeshCuboidStructure::clear_sample_points()
{
	for (std::vector<MeshSamplePoint *>::iterator it = sample_points_.begin();
		it != sample_points_.end(); ++it)
		delete (*it);
	sample_points_.clear();

	translation_ = MyMesh::Normal(0.0);
	scale_ = 1.0;
}

void MeshCuboidStructure::clear_cuboids()
{
	for (std::vector< std::vector<MeshCuboid *> >::iterator it = label_cuboids_.begin();
		it != label_cuboids_.end(); ++it)
	{
		for (std::vector<MeshCuboid *>::iterator jt = (*it).begin(); jt != (*it).end(); ++jt)
			delete (*jt);
	}

	label_cuboids_.clear();
}

void MeshCuboidStructure::clear_labels()
{
	labels_.clear();
	label_names_.clear();
	label_symmetries_.clear();

	query_label_index_ = 0;
}

bool MeshCuboidStructure::load_cuboids(const std::string _filename, bool _verbose)
{
	if (labels_.empty())
	{
		std::cerr << "Error: Load label information first." << std::endl;
		return false;
	}

	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	clear_cuboids();
	label_cuboids_.resize(num_labels());

	std::string buffer;

	while (!file.eof())
	{
		std::getline(file, buffer);
		if (buffer == "") break;

		std::stringstream strstr(buffer);
		std::string token;
		if (strstr.eof())
		{
			std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
			return false;
		}
		else std::getline(strstr, token, ' ');

		if (token.compare("@ATTRIBUTE") == 0)
		{
			// Skip.
		}
		else if (token[0] == '@')
		{
			// Skip.
		}
		else
		{
			std::stringstream strstr(buffer);
			std::string token;
			bool is_failed = false;

			LabelIndex label_index;
			std::array<MyMesh::Normal, 3> bbox_axes;
			MyMesh::Point bbox_center;
			MyMesh::Normal bbox_size;

			if (std::getline(strstr, token, ',').fail()) is_failed = true;
			label_index = std::stoi(token);

			for (unsigned int axis_index = 0; axis_index < 3; ++axis_index)
			{
				for (unsigned int i = 0; i < 3; i++)
				{
					if (std::getline(strstr, token, ',').fail()) is_failed = true;
					bbox_axes[axis_index][i] = std::stof(token);
				}
			}

			for (unsigned int i = 0; i < 3; i++)
			{
				if (std::getline(strstr, token, ',').fail()) is_failed = true;
				bbox_center[i] = std::stof(token);
			}

			for (unsigned int i = 0; i < 3; i++)
			{
				if (std::getline(strstr, token, ',').fail()) is_failed = true;
				bbox_size[i] = std::stof(token);
			}

			if (is_failed)
			{
				std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
				return false;
			}
			else if (label_index >= num_labels())
			{
				std::cerr << "Error: The label index exceeds the number of labels"
					<< " (" << label_index << " >= " << num_labels() << ": \"" << _filename << "\"" << std::endl;
				return false;
			}

			MeshCuboid *cuboid = new MeshCuboid(label_index);
			cuboid->set_bbox_axes(bbox_axes);
			cuboid->set_bbox_center(bbox_center);
			cuboid->set_bbox_size(bbox_size);
			cuboid->update_corner_points();

			label_cuboids_[label_index].push_back(cuboid);
		}
	}
	file.close();


	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::save_cuboids(const std::string _filename, bool _verbose)
{
	std::ofstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't save file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Saving " << _filename << "..." << std::endl;


	file << "@RELATION cuboid_structure" << std::endl;

	file << "@ATTRIBUTE label_index\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_axis_0_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_0_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_0_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_axis_1_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_1_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_1_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_axis_2_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_2_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_2_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_center_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_center_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_center_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_size_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_size_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_size_z\tNUMERIC" << std::endl;

	file << "@DATA" << std::endl;
	

	const std::vector<MeshCuboid *> cuboids = get_all_cuboids();

	for (std::vector<MeshCuboid *>::const_iterator it = cuboids.begin();
		it != cuboids.end(); ++it)
	{
		const MeshCuboid *cuboid = (*it);
		assert(cuboid);
		bool first_item = true;

		if (first_item) first_item = false; else file << ",";
		file << cuboid->get_label_index();

		for (unsigned int axis_index = 0; axis_index < 3; ++axis_index)
		{
			for (unsigned int i = 0; i < 3; i++)
			{
				if (first_item) first_item = false; else file << ",";
				file << cuboid->get_bbox_axis(axis_index)[i];
			}
		}

		for (unsigned int i = 0; i < 3; i++)
		{
			if (first_item) first_item = false; else file << ",";
			file << cuboid->get_bbox_center()[i];
		}

		for (unsigned int i = 0; i < 3; i++)
		{
			if (first_item) first_item = false; else file << ",";
			file << cuboid->get_bbox_size()[i];
		}

		file << std::endl;
	}

	file.close();
	return true;
}

void MeshCuboidStructure::apply_mesh_transformation()
{
	assert(mesh_);
	reset_transformation();
	scale(mesh_->get_scale());
	translate(mesh_->get_translation());
}

void MeshCuboidStructure::translate(const MyMesh::Normal _translate)
{
	for (std::vector<MeshSamplePoint *>::iterator it = sample_points_.begin();
		it != sample_points_.end(); ++it)
	{
		MyMesh::Point &p = (*it)->point_;
		p = p + _translate;
	}

	translation_ += _translate;
}

void MeshCuboidStructure::scale(const Real _scale)
{
	assert(_scale > 0);
	for (std::vector<MeshSamplePoint *>::iterator it = sample_points_.begin();
		it != sample_points_.end(); ++it)
	{
		MyMesh::Point &p = (*it)->point_;
		p = p * _scale;
	}

	scale_ *= _scale;
	translation_ *= _scale;
}

void MeshCuboidStructure::reset_transformation()
{
	if (translation_ != MyMesh::Point(0.0) || scale_ != 1.0)
	{
		scale(1.0 / scale_);
		translate(-translation_);
	}

	assert(translation_ == MyMesh::Point(0.0));
	assert(scale_ == 1.0);
}

bool MeshCuboidStructure::load_labels(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	// NOTE:
	// All cuboids are deleted.
	clear_cuboids();
	clear_labels();


	std::string buffer;
	Label new_label = 0;

	while (!file.eof())
	{
		std::getline(file, buffer);
		if (buffer == "") break;

		std::stringstream strstr(buffer);
		
		const unsigned int num_tokens = 3;
		std::string tokens[num_tokens];

		for (unsigned int i = 0; i < num_tokens; ++i)
		{
			if (strstr.eof())
			{
				std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
				return false;
			}

			std::getline(strstr, tokens[i], ' ');
		}

		if (tokens[1] != "pnts" || tokens[2] != "1")
		{
			std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
			return false;
		}
		
		// NOTE:
		// In this file format, labels are defined by the recorded order.
		labels_.push_back(new_label);
		label_names_.push_back(tokens[0]);
		label_symmetries_.push_back(std::list<LabelIndex>());
		++new_label;
	}

	file.close();


	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::load_label_symmetries(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	label_symmetries_.clear();
	label_symmetries_.resize(num_labels());


	std::string buffer;
	Label new_label = 0;

	while (!file.eof())
	{
		std::getline(file, buffer);
		if (buffer == "") break;

		std::stringstream strstr(buffer);
		std::list<LabelIndex> label_symmetry;

		while (!strstr.eof())
		{
			std::string token;
			std::getline(strstr, token, ' ');

			LabelIndex label_index = get_label_index(token);
			assert(label_index < num_labels());
			label_symmetry.push_back(label_index);
		}

		for (std::list<LabelIndex>::iterator it = label_symmetry.begin(); it != label_symmetry.end(); ++it)
		{
			LabelIndex label_index = (*it);

			for (std::list<LabelIndex>::iterator jt = label_symmetry.begin(); jt != label_symmetry.end(); ++jt)
			{
				LabelIndex n_label_index = (*jt);
				if (n_label_index != label_index)
				{
					label_symmetries_[label_index].push_back(n_label_index);
				}
			}
		}
	}

	file.close();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::load_sample_points(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	clear_sample_points();


	std::string buffer;

	for (SamplePointIndex sample_point_index = 0; !file.eof(); ++sample_point_index)
	{
		std::getline(file, buffer);

		std::stringstream strstr(buffer);
		std::string token;
		std::getline(strstr, token, ' ');
		FaceIndex corr_fid = atoi(token.c_str());
		assert(corr_fid >= 0);

		if (strstr.eof())
			continue;

		Real bx, by, bz;
		std::getline(strstr, token, ' ');
		bx = std::stof(token);
		std::getline(strstr, token, ' ');
		by = std::stof(token);
		std::getline(strstr, token, ' ');
		bz = std::stof(token);
		MyMesh::Point bary_coord = MyMesh::Point(bx, by, bz);

		Real px, py, pz;
		std::getline(strstr, token, ' ');
		px = std::stof(token);
		std::getline(strstr, token, ' ');
		py = std::stof(token);
		std::getline(strstr, token, ' ');
		pz = std::stof(token);
		MyMesh::Point pos = MyMesh::Point(px, py, pz);

		MeshSamplePoint *sample_point = new MeshSamplePoint(sample_point_index, corr_fid, bary_coord, pos);
		sample_points_.push_back(sample_point);
		assert(sample_points_[sample_point_index] == sample_point);
	}

	file.close();

	apply_mesh_transformation();

	std::cout << "Done." << std::endl;

	return true;
}

bool MeshCuboidStructure::load_sample_point_labels(const char *_filename, bool _verbose)
{
	if (labels_.empty())
	{
		std::cerr << "Error: Load label information first." << std::endl;
		return false;
	}
	else if (sample_points_.empty())
	{
		std::cerr << "Error: Load sample points first." << std::endl;
		return false;
	}

	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	std::string buffer;
	SamplePointIndex sample_point_index = 0;

	while (!file.eof() && sample_point_index < num_sample_points())
	{
		std::getline(file, buffer);

		std::stringstream strstr(buffer);
		std::string token;
		if (strstr.eof())
		{
			std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
			return false;
		}
		else std::getline(strstr, token, ' ');

		if (token.compare("@ATTRIBUTE") == 0)
		{
			// Skip.
		}
		else if (token[0] == '@')
		{
			// Skip.
		}
		else
		{
			std::stringstream strstr(buffer);
			std::string token;

			MeshSamplePoint* sample_point = sample_points_[sample_point_index];
			assert(sample_point);
			sample_point->label_index_confidence_.resize(num_labels());
			std::fill(sample_point->label_index_confidence_.begin(), sample_point->label_index_confidence_.end(), 0);


			for (LabelIndex label_index = 0; label_index < num_labels(); ++label_index)
			{
				if (strstr.eof())
				{
					std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
					return false;
				}
				else std::getline(strstr, token, ',');
				sample_point->label_index_confidence_[label_index] = std::stof(token);
			}

			++sample_point_index;
		}
	}
	file.close();

	assert(sample_point_index == num_sample_points());


	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::test_load_cuboids(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;

	clear();

	std::string buffer;

	for (unsigned int label_index = 0; !file.eof(); label_index++)
	{
		std::getline(file, buffer);
		std::stringstream strstr(buffer);
		std::string token;

		if (buffer == "" || strstr.eof())
			continue;

		MeshCuboid *new_cuboid = new MeshCuboid(label_index);
		MyMesh::Point bbox_center(0.0);
		std::array<MyMesh::Point, MeshCuboid::k_num_corners> bbox_corners;

		for (unsigned int corner_index = 0; corner_index < MeshCuboid::k_num_corners; ++corner_index)
		{
			Real px, py, pz;
			assert(!strstr.eof());
			std::getline(strstr, token, ',');
			px = std::stof(token);
			assert(!strstr.eof());
			std::getline(strstr, token, ',');
			py = std::stof(token);
			assert(!strstr.eof());
			std::getline(strstr, token, ',');
			pz = std::stof(token);
			MyMesh::Point pos = MyMesh::Point(px, py, pz);

			bbox_center = bbox_center + pos;
			bbox_corners[corner_index] = pos;
		}

		bbox_center = bbox_center / MeshCuboid::k_num_corners;
		new_cuboid->set_bbox_center(bbox_center);
		new_cuboid->set_bbox_corners(bbox_corners);
		new_cuboid->cuboidize();

		// A label is the same with its label index.
		labels_.push_back(label_index);

		std::vector<MeshCuboid *> new_label_cuboid;
		new_label_cuboid.push_back(new_cuboid);
		label_cuboids_.push_back(new_label_cuboid);
	}

	SamplePointIndex sample_point_index = 0;
	////
	//for (unsigned int label_index = 0; label_index < num_labels(); ++label_index)
	if (num_labels() > 0)
	{
		unsigned int label_index = 0;
	
		MeshCuboid *new_cuboid = label_cuboids_[label_index][0];

		MyMesh::Point corner_0 = new_cuboid->get_bbox_corner(0);
		MyMesh::Point corner_1 = new_cuboid->get_bbox_corner(1);
		MyMesh::Point corner_2 = new_cuboid->get_bbox_corner(2);

		Real pz = corner_0[2];

		Real min_x = corner_0[0];
		Real max_x = corner_1[0];

		Real min_y = corner_0[1];
		Real max_y = corner_2[1];

		unsigned int num_axis_points = 30;
		for (unsigned int i = 0; i < num_axis_points; ++i)
		{
			Real px = (max_x - min_x) / static_cast<Real>(num_axis_points - 1) * i + min_x;
			for (unsigned int j = 0; j < num_axis_points; ++j)
			{
				Real py = (max_y - min_y) / static_cast<Real>(num_axis_points - 1) * j + min_y;

				MyMesh::Point pos = MyMesh::Point(px, py, pz);
				MeshSamplePoint *sample_point = new MeshSamplePoint(sample_point_index, 0, MyMesh::Point(0.0), pos);
				sample_point->label_index_confidence_.resize(num_labels());
				++sample_point_index;

				for (unsigned int label_index = 0; label_index < num_labels(); label_index++)
					sample_point->label_index_confidence_[label_index] = 0;

				sample_point->label_index_confidence_[0] = 1.0;

				sample_points_.push_back(sample_point);
				new_cuboid->add_sample_point(sample_point);
			}
		}

		//MyMesh::Point corner_0 = new_cuboid->get_bbox_corner(0);
		//MyMesh::Point corner_2 = new_cuboid->get_bbox_corner(2);
		//MyMesh::Point corner_4 = new_cuboid->get_bbox_corner(4);

		//Real px = corner_0[0];

		//Real min_y = corner_0[1];
		//Real max_y = corner_2[1];

		//Real min_z = corner_0[2];
		//Real max_z = corner_4[2];

		//unsigned int num_axis_points = 11;
		//for (unsigned int i = 0; i < num_axis_points; ++i)
		//{
		//	Real py = (max_y - min_y) / static_cast<Real>(num_axis_points - 1) * i + min_y;
		//	for (unsigned int j = 0; j < num_axis_points; ++j)
		//	{
		//		Real pz = (max_z - min_z) / static_cast<Real>(num_axis_points - 1) * j + min_z;

		//		MyMesh::Point pos = MyMesh::Point(px, py, pz);
		//		MeshSamplePoint *sample_point = new MeshSamplePoint(0, MyMesh::Point(0.0), pos);
		//		sample_point->label_index_confidence_.resize(num_labels());

		//		for (unsigned int label_index = 0; label_index < num_labels(); label_index++)
		//			sample_point->label_index_confidence_[label_index] = 0;

		//		sample_point->label_index_confidence_[0] = 1.0;

		//		sample_points_.push_back(sample_point);
		//		new_cuboid->add_point(sample_point);
		//	}
		//}
	}
	////

	file.close();

	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();

	std::cout << "Done." << std::endl;

	return true;
}

std::vector<MeshCuboid *> MeshCuboidStructure::get_all_cuboids() const
{
	std::vector<MeshCuboid *> all_cuboids;

	for (std::vector< std::vector<MeshCuboid *> >::const_iterator it = label_cuboids_.begin();
		it != label_cuboids_.end(); ++it)
		all_cuboids.insert(all_cuboids.end(), (*it).begin(), (*it).end());

	return all_cuboids;
}

void MeshCuboidStructure::make_mesh_vertices_as_sample_points()
{
	assert(mesh_);
	clear();

	// NOTE:
	// Since now the sample points are generated from mesh, 
	// the transformation of mesh is applied first.
	apply_mesh_transformation();

	sample_points_.reserve(3 * mesh_->n_faces());
	SamplePointIndex sample_point_index = 0;

	for (MyMesh::FaceIter f_it = mesh_->faces_begin(); f_it != mesh_->faces_end(); ++f_it)
	{
		MyMesh::FaceHandle fh = f_it.handle();
		FaceIndex corr_fid = fh.idx();

		unsigned int i = 0;
		for (MyMesh::ConstFaceVertexIter fv_it = mesh_->cfv_iter(fh); fv_it; ++fv_it, ++i)
		{
			assert(i < 3);
			MyMesh::VertexHandle vh = fv_it.handle();

			MyMesh::Point bary_coord(0.0);
			bary_coord[i] = 1.0;

			MyMesh::Point pos = mesh_->point(vh);

			sample_points_.push_back(new MeshSamplePoint(sample_point_index, corr_fid, bary_coord, pos));
			++sample_point_index;
		}
	}
}

void MeshCuboidStructure::apply_mesh_face_labels_to_sample_points()
{
	assert(mesh_);
	
	for (SamplePointIndex sample_point_index = 0; sample_point_index < num_sample_points(); ++sample_point_index)
	{
		MeshSamplePoint* sample_point = sample_points_[sample_point_index];

		FaceIndex fid = sample_point->corr_fid_;
		assert(fid < mesh_->n_faces());

		MyMesh::FaceHandle fh = mesh_->face_handle(fid);
		Label label = mesh_->property(mesh_->face_label_, fh);

		LabelIndex label_index;
		bool ret = exist_label(label, &label_index);
		assert(ret);
		assert(label_index < num_labels());

		sample_point->label_index_confidence_.clear();
		sample_point->label_index_confidence_.resize(num_labels(), 0.0);

		// Note:
		// The confidence of the given label becomes '1.0'.
		sample_point->label_index_confidence_[label_index] = 1.0;
	}
}

void MeshCuboidStructure::apply_mesh_face_labels_to_cuboids()
{
	// Apple mesh face labels to sample points.
	apply_mesh_face_labels_to_sample_points();

	std::list<MeshCuboid *> part_list;

	for (std::vector< std::vector<MeshCuboid *> >::iterator it = label_cuboids_.begin();
		it != label_cuboids_.end(); ++it)
	{
		for (std::vector<MeshCuboid *>::iterator jt = (*it).begin(); jt != (*it).end(); ++jt)
		{
			MeshCuboid *label_cuboid = (*jt);
			// Update the label based on the label confidence values of sample points.
			label_cuboid->update_label_using_sample_points();
			part_list.push_back(label_cuboid);
		}
	}

	label_cuboids_.clear();
	label_cuboids_.resize(num_labels());<commit_msg>Ignore mesh labels which do not exist in the label list.<commit_after>#include "MeshCuboidStructure.h"

#include <deque>
#include <fstream>
#include <iostream>


MeshCuboidStructure::MeshCuboidStructure(const MyMesh* _mesh)
	: mesh_(_mesh)
	, query_label_index_(0)
	, translation_(0.0)
	, scale_(1.0)
{
	assert(_mesh);
}

MeshCuboidStructure::~MeshCuboidStructure()
{
}

MeshCuboidStructure::MeshCuboidStructure(const MeshCuboidStructure& _other)
{
	deep_copy(_other);
}

MeshCuboidStructure& MeshCuboidStructure::operator=(const MeshCuboidStructure& _other)
{
	deep_copy(_other);
	return (*this);
}

void MeshCuboidStructure::deep_copy(const MeshCuboidStructure& _other)
{
	this->mesh_ = _other.mesh_;

	this->labels_ = _other.labels_;
	this->label_names_ = _other.label_names_;
	this->label_symmetries_ = _other.label_symmetries_;

	this->translation_ = _other.translation_;
	this->scale_ = _other.scale_;

	this->query_label_index_ = _other.query_label_index_;

	// Deep copy sample points.
	assert(_other.sample_points_.size() == _other.num_sample_points());
	this->sample_points_.clear();
	this->sample_points_.reserve(_other.num_sample_points());

	for (std::vector<MeshSamplePoint *>::const_iterator it = _other.sample_points_.begin();
		it != _other.sample_points_.end(); ++it)
	{
		MeshSamplePoint *sample_point = new MeshSamplePoint(**it);
		this->sample_points_.push_back(sample_point);
	}

	// Deep copy label cuboids.
	assert(_other.label_cuboids_.size() == _other.num_labels());
	unsigned int num_labels = _other.num_labels();
	this->label_cuboids_.clear();
	this->label_cuboids_.resize(num_labels);

	for (LabelIndex label_index = 0; label_index < num_labels; ++label_index)
	{
		this->label_cuboids_[label_index].reserve(_other.label_cuboids_[label_index].size());
		for (std::vector<MeshCuboid *>::const_iterator it = _other.label_cuboids_[label_index].begin();
			it != _other.label_cuboids_[label_index].end(); ++it)
		{
			MeshCuboid *cuboid = new MeshCuboid(**it);
			this->label_cuboids_[label_index].push_back(cuboid);
		}
	}
}

void MeshCuboidStructure::clear()
{
	clear_sample_points();
	clear_cuboids();
	clear_labels();
}

void MeshCuboidStructure::clear_sample_points()
{
	for (std::vector<MeshSamplePoint *>::iterator it = sample_points_.begin();
		it != sample_points_.end(); ++it)
		delete (*it);
	sample_points_.clear();

	translation_ = MyMesh::Normal(0.0);
	scale_ = 1.0;
}

void MeshCuboidStructure::clear_cuboids()
{
	for (std::vector< std::vector<MeshCuboid *> >::iterator it = label_cuboids_.begin();
		it != label_cuboids_.end(); ++it)
	{
		for (std::vector<MeshCuboid *>::iterator jt = (*it).begin(); jt != (*it).end(); ++jt)
			delete (*jt);
	}

	label_cuboids_.clear();
}

void MeshCuboidStructure::clear_labels()
{
	labels_.clear();
	label_names_.clear();
	label_symmetries_.clear();

	query_label_index_ = 0;
}

bool MeshCuboidStructure::load_cuboids(const std::string _filename, bool _verbose)
{
	if (labels_.empty())
	{
		std::cerr << "Error: Load label information first." << std::endl;
		return false;
	}

	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	clear_cuboids();
	label_cuboids_.resize(num_labels());

	std::string buffer;

	while (!file.eof())
	{
		std::getline(file, buffer);
		if (buffer == "") break;

		std::stringstream strstr(buffer);
		std::string token;
		if (strstr.eof())
		{
			std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
			return false;
		}
		else std::getline(strstr, token, ' ');

		if (token.compare("@ATTRIBUTE") == 0)
		{
			// Skip.
		}
		else if (token[0] == '@')
		{
			// Skip.
		}
		else
		{
			std::stringstream strstr(buffer);
			std::string token;
			bool is_failed = false;

			LabelIndex label_index;
			std::array<MyMesh::Normal, 3> bbox_axes;
			MyMesh::Point bbox_center;
			MyMesh::Normal bbox_size;

			if (std::getline(strstr, token, ',').fail()) is_failed = true;
			label_index = std::stoi(token);

			for (unsigned int axis_index = 0; axis_index < 3; ++axis_index)
			{
				for (unsigned int i = 0; i < 3; i++)
				{
					if (std::getline(strstr, token, ',').fail()) is_failed = true;
					bbox_axes[axis_index][i] = std::stof(token);
				}
			}

			for (unsigned int i = 0; i < 3; i++)
			{
				if (std::getline(strstr, token, ',').fail()) is_failed = true;
				bbox_center[i] = std::stof(token);
			}

			for (unsigned int i = 0; i < 3; i++)
			{
				if (std::getline(strstr, token, ',').fail()) is_failed = true;
				bbox_size[i] = std::stof(token);
			}

			if (is_failed)
			{
				std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
				return false;
			}
			else if (label_index >= num_labels())
			{
				std::cerr << "Error: The label index exceeds the number of labels"
					<< " (" << label_index << " >= " << num_labels() << ": \"" << _filename << "\"" << std::endl;
				return false;
			}

			MeshCuboid *cuboid = new MeshCuboid(label_index);
			cuboid->set_bbox_axes(bbox_axes);
			cuboid->set_bbox_center(bbox_center);
			cuboid->set_bbox_size(bbox_size);
			cuboid->update_corner_points();

			label_cuboids_[label_index].push_back(cuboid);
		}
	}
	file.close();


	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::save_cuboids(const std::string _filename, bool _verbose)
{
	std::ofstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't save file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Saving " << _filename << "..." << std::endl;


	file << "@RELATION cuboid_structure" << std::endl;

	file << "@ATTRIBUTE label_index\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_axis_0_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_0_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_0_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_axis_1_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_1_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_1_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_axis_2_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_2_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_axis_2_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_center_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_center_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_center_z\tNUMERIC" << std::endl;

	file << "@ATTRIBUTE bbox_size_x\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_size_y\tNUMERIC" << std::endl;
	file << "@ATTRIBUTE bbox_size_z\tNUMERIC" << std::endl;

	file << "@DATA" << std::endl;
	

	const std::vector<MeshCuboid *> cuboids = get_all_cuboids();

	for (std::vector<MeshCuboid *>::const_iterator it = cuboids.begin();
		it != cuboids.end(); ++it)
	{
		const MeshCuboid *cuboid = (*it);
		assert(cuboid);
		bool first_item = true;

		if (first_item) first_item = false; else file << ",";
		file << cuboid->get_label_index();

		for (unsigned int axis_index = 0; axis_index < 3; ++axis_index)
		{
			for (unsigned int i = 0; i < 3; i++)
			{
				if (first_item) first_item = false; else file << ",";
				file << cuboid->get_bbox_axis(axis_index)[i];
			}
		}

		for (unsigned int i = 0; i < 3; i++)
		{
			if (first_item) first_item = false; else file << ",";
			file << cuboid->get_bbox_center()[i];
		}

		for (unsigned int i = 0; i < 3; i++)
		{
			if (first_item) first_item = false; else file << ",";
			file << cuboid->get_bbox_size()[i];
		}

		file << std::endl;
	}

	file.close();
	return true;
}

void MeshCuboidStructure::apply_mesh_transformation()
{
	assert(mesh_);
	reset_transformation();
	scale(mesh_->get_scale());
	translate(mesh_->get_translation());
}

void MeshCuboidStructure::translate(const MyMesh::Normal _translate)
{
	for (std::vector<MeshSamplePoint *>::iterator it = sample_points_.begin();
		it != sample_points_.end(); ++it)
	{
		MyMesh::Point &p = (*it)->point_;
		p = p + _translate;
	}

	translation_ += _translate;
}

void MeshCuboidStructure::scale(const Real _scale)
{
	assert(_scale > 0);
	for (std::vector<MeshSamplePoint *>::iterator it = sample_points_.begin();
		it != sample_points_.end(); ++it)
	{
		MyMesh::Point &p = (*it)->point_;
		p = p * _scale;
	}

	scale_ *= _scale;
	translation_ *= _scale;
}

void MeshCuboidStructure::reset_transformation()
{
	if (translation_ != MyMesh::Point(0.0) || scale_ != 1.0)
	{
		scale(1.0 / scale_);
		translate(-translation_);
	}

	assert(translation_ == MyMesh::Point(0.0));
	assert(scale_ == 1.0);
}

bool MeshCuboidStructure::load_labels(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	// NOTE:
	// All cuboids are deleted.
	clear_cuboids();
	clear_labels();


	std::string buffer;
	Label new_label = 0;

	while (!file.eof())
	{
		std::getline(file, buffer);
		if (buffer == "") break;

		std::stringstream strstr(buffer);
		
		const unsigned int num_tokens = 3;
		std::string tokens[num_tokens];

		for (unsigned int i = 0; i < num_tokens; ++i)
		{
			if (strstr.eof())
			{
				std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
				return false;
			}

			std::getline(strstr, tokens[i], ' ');
		}

		if (tokens[1] != "pnts" || tokens[2] != "1")
		{
			std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
			return false;
		}
		
		// NOTE:
		// In this file format, labels are defined by the recorded order.
		labels_.push_back(new_label);
		label_names_.push_back(tokens[0]);
		label_symmetries_.push_back(std::list<LabelIndex>());
		++new_label;
	}

	file.close();


	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::load_label_symmetries(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	label_symmetries_.clear();
	label_symmetries_.resize(num_labels());


	std::string buffer;
	Label new_label = 0;

	while (!file.eof())
	{
		std::getline(file, buffer);
		if (buffer == "") break;

		std::stringstream strstr(buffer);
		std::list<LabelIndex> label_symmetry;

		while (!strstr.eof())
		{
			std::string token;
			std::getline(strstr, token, ' ');

			LabelIndex label_index = get_label_index(token);
			assert(label_index < num_labels());
			label_symmetry.push_back(label_index);
		}

		for (std::list<LabelIndex>::iterator it = label_symmetry.begin(); it != label_symmetry.end(); ++it)
		{
			LabelIndex label_index = (*it);

			for (std::list<LabelIndex>::iterator jt = label_symmetry.begin(); jt != label_symmetry.end(); ++jt)
			{
				LabelIndex n_label_index = (*jt);
				if (n_label_index != label_index)
				{
					label_symmetries_[label_index].push_back(n_label_index);
				}
			}
		}
	}

	file.close();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::load_sample_points(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	clear_sample_points();


	std::string buffer;

	for (SamplePointIndex sample_point_index = 0; !file.eof(); ++sample_point_index)
	{
		std::getline(file, buffer);

		std::stringstream strstr(buffer);
		std::string token;
		std::getline(strstr, token, ' ');
		FaceIndex corr_fid = atoi(token.c_str());
		assert(corr_fid >= 0);

		if (strstr.eof())
			continue;

		Real bx, by, bz;
		std::getline(strstr, token, ' ');
		bx = std::stof(token);
		std::getline(strstr, token, ' ');
		by = std::stof(token);
		std::getline(strstr, token, ' ');
		bz = std::stof(token);
		MyMesh::Point bary_coord = MyMesh::Point(bx, by, bz);

		Real px, py, pz;
		std::getline(strstr, token, ' ');
		px = std::stof(token);
		std::getline(strstr, token, ' ');
		py = std::stof(token);
		std::getline(strstr, token, ' ');
		pz = std::stof(token);
		MyMesh::Point pos = MyMesh::Point(px, py, pz);

		MeshSamplePoint *sample_point = new MeshSamplePoint(sample_point_index, corr_fid, bary_coord, pos);
		sample_points_.push_back(sample_point);
		assert(sample_points_[sample_point_index] == sample_point);
	}

	file.close();

	apply_mesh_transformation();

	std::cout << "Done." << std::endl;

	return true;
}

bool MeshCuboidStructure::load_sample_point_labels(const char *_filename, bool _verbose)
{
	if (labels_.empty())
	{
		std::cerr << "Error: Load label information first." << std::endl;
		return false;
	}
	else if (sample_points_.empty())
	{
		std::cerr << "Error: Load sample points first." << std::endl;
		return false;
	}

	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;


	std::string buffer;
	SamplePointIndex sample_point_index = 0;

	while (!file.eof() && sample_point_index < num_sample_points())
	{
		std::getline(file, buffer);

		std::stringstream strstr(buffer);
		std::string token;
		if (strstr.eof())
		{
			std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
			return false;
		}
		else std::getline(strstr, token, ' ');

		if (token.compare("@ATTRIBUTE") == 0)
		{
			// Skip.
		}
		else if (token[0] == '@')
		{
			// Skip.
		}
		else
		{
			std::stringstream strstr(buffer);
			std::string token;

			MeshSamplePoint* sample_point = sample_points_[sample_point_index];
			assert(sample_point);
			sample_point->label_index_confidence_.resize(num_labels());
			std::fill(sample_point->label_index_confidence_.begin(), sample_point->label_index_confidence_.end(), 0);


			for (LabelIndex label_index = 0; label_index < num_labels(); ++label_index)
			{
				if (strstr.eof())
				{
					std::cerr << "Error: Wrong file format: \"" << _filename << "\"" << std::endl;
					return false;
				}
				else std::getline(strstr, token, ',');
				sample_point->label_index_confidence_[label_index] = std::stof(token);
			}

			++sample_point_index;
		}
	}
	file.close();

	assert(sample_point_index == num_sample_points());


	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();


	std::cout << "Done." << std::endl;
	return true;
}

bool MeshCuboidStructure::test_load_cuboids(const char *_filename, bool _verbose)
{
	std::ifstream file(_filename);
	if (!file)
	{
		std::cerr << "Can't open file: \"" << _filename << "\"" << std::endl;
		return false;
	}

	if (_verbose)
		std::cout << "Loading " << _filename << "..." << std::endl;

	clear();

	std::string buffer;

	for (unsigned int label_index = 0; !file.eof(); label_index++)
	{
		std::getline(file, buffer);
		std::stringstream strstr(buffer);
		std::string token;

		if (buffer == "" || strstr.eof())
			continue;

		MeshCuboid *new_cuboid = new MeshCuboid(label_index);
		MyMesh::Point bbox_center(0.0);
		std::array<MyMesh::Point, MeshCuboid::k_num_corners> bbox_corners;

		for (unsigned int corner_index = 0; corner_index < MeshCuboid::k_num_corners; ++corner_index)
		{
			Real px, py, pz;
			assert(!strstr.eof());
			std::getline(strstr, token, ',');
			px = std::stof(token);
			assert(!strstr.eof());
			std::getline(strstr, token, ',');
			py = std::stof(token);
			assert(!strstr.eof());
			std::getline(strstr, token, ',');
			pz = std::stof(token);
			MyMesh::Point pos = MyMesh::Point(px, py, pz);

			bbox_center = bbox_center + pos;
			bbox_corners[corner_index] = pos;
		}

		bbox_center = bbox_center / MeshCuboid::k_num_corners;
		new_cuboid->set_bbox_center(bbox_center);
		new_cuboid->set_bbox_corners(bbox_corners);
		new_cuboid->cuboidize();

		// A label is the same with its label index.
		labels_.push_back(label_index);

		std::vector<MeshCuboid *> new_label_cuboid;
		new_label_cuboid.push_back(new_cuboid);
		label_cuboids_.push_back(new_label_cuboid);
	}

	SamplePointIndex sample_point_index = 0;
	////
	//for (unsigned int label_index = 0; label_index < num_labels(); ++label_index)
	if (num_labels() > 0)
	{
		unsigned int label_index = 0;
	
		MeshCuboid *new_cuboid = label_cuboids_[label_index][0];

		MyMesh::Point corner_0 = new_cuboid->get_bbox_corner(0);
		MyMesh::Point corner_1 = new_cuboid->get_bbox_corner(1);
		MyMesh::Point corner_2 = new_cuboid->get_bbox_corner(2);

		Real pz = corner_0[2];

		Real min_x = corner_0[0];
		Real max_x = corner_1[0];

		Real min_y = corner_0[1];
		Real max_y = corner_2[1];

		unsigned int num_axis_points = 30;
		for (unsigned int i = 0; i < num_axis_points; ++i)
		{
			Real px = (max_x - min_x) / static_cast<Real>(num_axis_points - 1) * i + min_x;
			for (unsigned int j = 0; j < num_axis_points; ++j)
			{
				Real py = (max_y - min_y) / static_cast<Real>(num_axis_points - 1) * j + min_y;

				MyMesh::Point pos = MyMesh::Point(px, py, pz);
				MeshSamplePoint *sample_point = new MeshSamplePoint(sample_point_index, 0, MyMesh::Point(0.0), pos);
				sample_point->label_index_confidence_.resize(num_labels());
				++sample_point_index;

				for (unsigned int label_index = 0; label_index < num_labels(); label_index++)
					sample_point->label_index_confidence_[label_index] = 0;

				sample_point->label_index_confidence_[0] = 1.0;

				sample_points_.push_back(sample_point);
				new_cuboid->add_sample_point(sample_point);
			}
		}

		//MyMesh::Point corner_0 = new_cuboid->get_bbox_corner(0);
		//MyMesh::Point corner_2 = new_cuboid->get_bbox_corner(2);
		//MyMesh::Point corner_4 = new_cuboid->get_bbox_corner(4);

		//Real px = corner_0[0];

		//Real min_y = corner_0[1];
		//Real max_y = corner_2[1];

		//Real min_z = corner_0[2];
		//Real max_z = corner_4[2];

		//unsigned int num_axis_points = 11;
		//for (unsigned int i = 0; i < num_axis_points; ++i)
		//{
		//	Real py = (max_y - min_y) / static_cast<Real>(num_axis_points - 1) * i + min_y;
		//	for (unsigned int j = 0; j < num_axis_points; ++j)
		//	{
		//		Real pz = (max_z - min_z) / static_cast<Real>(num_axis_points - 1) * j + min_z;

		//		MyMesh::Point pos = MyMesh::Point(px, py, pz);
		//		MeshSamplePoint *sample_point = new MeshSamplePoint(0, MyMesh::Point(0.0), pos);
		//		sample_point->label_index_confidence_.resize(num_labels());

		//		for (unsigned int label_index = 0; label_index < num_labels(); label_index++)
		//			sample_point->label_index_confidence_[label_index] = 0;

		//		sample_point->label_index_confidence_[0] = 1.0;

		//		sample_points_.push_back(sample_point);
		//		new_cuboid->add_point(sample_point);
		//	}
		//}
	}
	////

	file.close();

	// NOTE:
	// Draws all points.
	query_label_index_ = num_labels();

	std::cout << "Done." << std::endl;

	return true;
}

std::vector<MeshCuboid *> MeshCuboidStructure::get_all_cuboids() const
{
	std::vector<MeshCuboid *> all_cuboids;

	for (std::vector< std::vector<MeshCuboid *> >::const_iterator it = label_cuboids_.begin();
		it != label_cuboids_.end(); ++it)
		all_cuboids.insert(all_cuboids.end(), (*it).begin(), (*it).end());

	return all_cuboids;
}

void MeshCuboidStructure::make_mesh_vertices_as_sample_points()
{
	assert(mesh_);
	clear();

	// NOTE:
	// Since now the sample points are generated from mesh, 
	// the transformation of mesh is applied first.
	apply_mesh_transformation();

	sample_points_.reserve(3 * mesh_->n_faces());
	SamplePointIndex sample_point_index = 0;

	for (MyMesh::FaceIter f_it = mesh_->faces_begin(); f_it != mesh_->faces_end(); ++f_it)
	{
		MyMesh::FaceHandle fh = f_it.handle();
		FaceIndex corr_fid = fh.idx();

		unsigned int i = 0;
		for (MyMesh::ConstFaceVertexIter fv_it = mesh_->cfv_iter(fh); fv_it; ++fv_it, ++i)
		{
			assert(i < 3);
			MyMesh::VertexHandle vh = fv_it.handle();

			MyMesh::Point bary_coord(0.0);
			bary_coord[i] = 1.0;

			MyMesh::Point pos = mesh_->point(vh);

			sample_points_.push_back(new MeshSamplePoint(sample_point_index, corr_fid, bary_coord, pos));
			++sample_point_index;
		}
	}
}

void MeshCuboidStructure::apply_mesh_face_labels_to_sample_points()
{
	assert(mesh_);
	
	for (SamplePointIndex sample_point_index = 0; sample_point_index < num_sample_points(); ++sample_point_index)
	{
		MeshSamplePoint* sample_point = sample_points_[sample_point_index];

		FaceIndex fid = sample_point->corr_fid_;
		assert(fid < mesh_->n_faces());

		MyMesh::FaceHandle fh = mesh_->face_handle(fid);
		Label label = mesh_->property(mesh_->face_label_, fh);

		sample_point->label_index_confidence_.clear();
		sample_point->label_index_confidence_.resize(num_labels(), 0.0);

		LabelIndex label_index;
		bool ret = exist_label(label, &label_index);

		// NOTE:
		// If the mesh face label does not exist, ignore this sample point.
		if (ret)
		{
			assert(label_index < num_labels());

			// Note:
			// The confidence of the given label becomes '1.0'.
			sample_point->label_index_confidence_[label_index] = 1.0;
		}
	}
}

void MeshCuboidStructure::apply_mesh_face_labels_to_cuboids()
{
	// Apple mesh face labels to sample points.
	apply_mesh_face_labels_to_sample_points();

	std::list<MeshCuboid *> part_list;

	for (std::vector< std::vector<MeshCuboid *> >::iterator it = label_cuboids_.begin();
		it != label_cuboids_.end(); ++it)
	{
		for (std::vector<MeshCuboid *>::iterator jt = (*it).begin(); jt != (*it).end(); ++jt)
		{
			MeshCuboid *label_cuboid = (*jt);
			// Update the label based on the label confidence values of sample points.
			label_cuboid->update_label_using_sample_points();
			part_list.push_back(label_cuboid);
		}
	}

	label_cuboids_.clear();
	label_cuboids_.resize(num_labels());
{'fraction_non_alphanumeric': 0.17188320434673424, 'fraction_numerical': 0.006803186996324453, 'mean_word_length': 4.358942989968192, 'pattern_counts': {'":': 2, '<': 725, '<?xml version=': 0, '>': 199, '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': '7219980', 'n_tokens_mistral': 18150, 'n_tokens_neox': 16430, 'n_words': 3117}