//============================================================================
//
// This file is part of the Shapes Generative Model Library (SGML) project.
//
// Copyright (c) 2010-2014 - Evangelos Kalogerakis, Siddhartha Chaudhuri (authors of the code) / Stanford University, UMass-Amherst
//
// SGML is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// SGML is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with SGML.  If not, see <http://www.gnu.org/licenses/>.
//
//============================================================================

#include "S12_MeshCreator.hpp"


namespace SNL {
	namespace S12 {

		MeshPart* MeshCreator::getRefPart(MeshPart *p, vector<MeshPart*>& parts)
		{
			for (size_t pm = 0; pm < p->mesh->parts.size(); pm++)
			{
				MeshPart *part = parts[ p->mesh->parts[pm]->mesh_part_id ];
				if ( part->label == p->label && part->sublabel_id == 1 )
				{
					return part;
				}
			}				

			return NULL;
		}

		MeshCreator::MeshCreator( ShapeBNetSample& sample,  vector<Label*>& labels, vector<MeshPart*>& parts, vector<TriMesh*>& meshes, vector< vector< MeshPart* > >& all_samples_best_parts, const char* part_path, size_t id )
		{
			if ( sample.prob < 0.1 )
			{
				std::cout << "Probability of not having the labels given from this sample is too low." << std::endl;
				this->valid_sampled_mesh = false;
				return;
			}
			this->labels = labels;
			this->id = id;
			this->valid_sampled_mesh = true;
			best_parts.resize( labels.size(), NULL );

			for (size_t l = 0; l < labels.size(); l++)
			{
				// do not include parts from this label
				if (sample.layout_nodes_value[l] == 0 )
					continue;

				std::cout << "Putting together parts from label " << labels[l]->name << std::endl;		
				MeshPart *best_part = NULL;
				double min_feature_distance = FLT_MAX;	
				for (size_t m = 0; m < meshes.size(); m++)
				{
					double feature_distance = 0.0;

					for (size_t a = 0; a < sample.bnet->adjacencynumparts_nodes.size(); a++)
					{
						if ( sample.bnet->adjacencynumparts_nodes[a]->label == labels[l] )
						{
							size_t adj_pos = sample.bnet->adjacencynumparts_nodes[a]->adj_label_pos;
							if ( sample.adjacencynumparts_nodes_value[a] != sample.bnet->adjacentparts_training_data[m][l][ adj_pos ] )
								feature_distance += 1.0;	
						}
					}
					//for (size_t a = 0; a < sample.bnet->adjacencynumslots_nodes.size(); a++)
					//{
					//	if ( sample.bnet->adjacencynumslots_nodes[a]->label == labels[l] )
					//	{
					//		size_t adj_pos = sample.bnet->adjacencynumslots_nodes[a]->adj_label_pos;
					//		if ( sample.adjacencynumslots_nodes_value[a] != sample.bnet->adjacentslots_training_data[m][l][ adj_pos ] )
					//			feature_distance += 0.5;	
					//	}
					//}
					feature_distance /= float( sample.bnet->adjacencynumparts_nodes.size() );
					if ( feature_distance > 0.05 )
					{ 
						continue;
					}

					feature_distance += dist( sample.bnet->features_training_data[m][l], sample.parts_features[l] ) / float( sample.parts_features[l].size() );
					if (feature_distance > 1.0)
					{
						feature_distance = FLT_MAX;
						continue;
					}

					if ( feature_distance < min_feature_distance && sample.bnet->style_id[ meshes[m]->id ] == sample.root_node_value )
					{
						MeshPart *ref_part = NULL;
						bool invalid = false;
						for (size_t pm = 0; pm < meshes[m]->parts.size(); pm++)
						{
							MeshPart *part = parts[ meshes[m]->parts[pm]->mesh_part_id ];
							if ( part->label == labels[l] && part->sublabel_id == 1 )
							{
								ref_part = part;
							}
							if ( part->label == labels[l] && part->sublabel_id != 1 && len( part->transformation_with_respect_to_reference_part.first ) < .001 )
							{
								invalid = true;
							}
						}				
						if (ref_part != NULL && !invalid) 
						{
							best_parts[l] = ref_part;
							min_feature_distance = feature_distance;
						}
					}
				}

				if ( min_feature_distance == FLT_MAX ) 
				{
					std::cout << "Could not find compatible part for this label " << labels[l]->name << std::endl;
					this->valid_sampled_mesh = false;
					return;
				}
			} // end of loop over labels

			// check is sample is a mesh already existing in the database
			bool sampled_mesh_exists = false;
			for (size_t m = 0; m < meshes.size(); m++)
			{
				bool all_parts_exist_in_this_mesh = true;
				for (size_t pm = 0; pm < meshes[m]->parts.size(); pm++)
				{
					bool part_exists = false;
					MeshPart *part = parts[ meshes[m]->parts[pm]->mesh_part_id ];
					if ( part->sublabel_id != 1)
						continue;

					for (size_t l = 0; l < best_parts.size(); l++)
					{
						if ( part == best_parts[l] )
							part_exists = true;
					}
					if ( !part_exists )
					{
						all_parts_exist_in_this_mesh = false;
						break;
					}
				}
				if ( all_parts_exist_in_this_mesh )
				{
					sampled_mesh_exists = true;
					break;
				}
			}
			// check if sample is the same with one of the already sampled meshes
			for (size_t m = 0; m < all_samples_best_parts.size(); m++)
			{
				bool all_parts_exist_in_this_mesh = true;
				for (size_t l = 0; l < best_parts.size(); l++)
				{
					if ( all_samples_best_parts[m][l] != best_parts[l] )
						all_parts_exist_in_this_mesh = false;
				}
				if ( all_parts_exist_in_this_mesh )
				{
					sampled_mesh_exists = true;
					break;
				}
			}
			if ( sampled_mesh_exists )
			{
				std::cout << "Sampled a mesh already existing in the database or samples." << std::endl;
				this->valid_sampled_mesh = false;
				return;
			}

			// for each best_part, get all parts from the mesh it belongs to having the same label
			// Get sublabels of their adjacent parts. Do not use sublabels of the parts themselves,
			// since if there is no adjacent part to a part with a given sublabel, then there is no way
			// to know its transformation (for now, use them, but the sample will be rejected later)
			// Example: you sampled a seat. In order to put the seat somewhere, you have to have
			// parts with sublabels that can be adjacent to this seat. 
			vector< vector< pair<size_t, size_t> > > votes_sublabels(labels.size());
			for (size_t l = 0; l < labels.size(); l++)
			{
				if ( best_parts[l] == NULL )
					continue;
				for (size_t pm = 0; pm < best_parts[l]->mesh->parts.size(); pm++)
				{
					MeshPart *part = parts[ best_parts[l]->mesh->parts[pm]->mesh_part_id ];
					if ( part->label == labels[l] )
					{
						for (size_t a = 0; a < part->adjacent_parts.size(); a++)
						{
							add_vote( votes_sublabels[ part->adjacent_parts[a]->label->id ], part->adjacent_parts[a]->sublabel_id );
						}
						add_vote( votes_sublabels[ part->label->id ], part->sublabel_id );
					}
				}
			}

			// if there are disagreement between sublabels and cardinality, valid sample is false, return
			for (size_t l = 0; l < labels.size(); l++)
			{
				if ( best_parts[l] == NULL )
					continue;
				if ( votes_sublabels[l].size() < sample.cardinality_nodes_value[l]  )
				{
					//std::cout << labels[l]->name << " " << votes_sublabels[l] << std::endl;
					//std::cout << sample.cardinality_nodes_value[l] << std::endl;
					std::cout << "Number of parts incompatible with adjacency metadata information for label " << labels[l]->name << std::endl;
					std::cout << sample.cardinality_nodes_value[l] << " vs " << votes_sublabels[l].size() << std::endl;
					this->valid_sampled_mesh = false;
					return;
				}
				vector<size_t> most_popular_sublabels = order_elements_according_to_votes( votes_sublabels[l] );
				// for each sublabel found (unique part from adjacent parts)
				// create an sampled_part s(proper id, scale, ref_part)
				for (size_t i = 0; i < max( sample.cardinality_nodes_value[l], votes_sublabels[l].size() ); i++)
				{
					sampled_parts.push_back( SampledPart( MAX_NUM_SUBLABELS*l + most_popular_sublabels[i], best_parts[l], sample.scales[l] ) );
				}
			}


			// look at the training meshes and see which parts can be adjacent
			for (size_t l = 0; l < labels.size(); l++)
			{
				if ( best_parts[l] == NULL )
					continue;
				// e.g. for label leg
				for (size_t pm = 0; pm < best_parts[l]->mesh->parts.size(); pm++)
				{
					// e.g. for each instance 1,2,3,4 of label leg from the original mesh
					MeshPart *part = parts[ best_parts[l]->mesh->parts[pm]->mesh_part_id ];
					if ( part->label == labels[l] )
					{
						// e.g. let's say leg 2 case: for each adjacent part to instance leg 2, let's say seat 1
						for (size_t a = 0; a < part->adjacent_parts.size(); a++)
						{
							int refa = part->should_be_attached_to_boundary_id_of_ref_part[a];
							if (refa == -1)
								continue;

							// find seat 1 ( part->adjacent_parts[a] )
							int pos = getSampledPart( MAX_NUM_SUBLABELS*part->adjacent_parts[a]->label->id + part->adjacent_parts[a]->sublabel_id );
							if (pos == -1)
								continue;
							// find leg 2 ( part )
							int pos2 = getSampledPart( MAX_NUM_SUBLABELS*part->label->id + part->sublabel_id );
							if (pos2 == -1)
								continue;

							// seat 1 should have the transformation stored in the adjancent part (seat 1) of leg 2
							// for now overwrite sampled_parts[pos].transformation_with_respect_to_reference_part if exists!!!
							sampled_parts[pos].transformation_with_respect_to_reference_part = part->adjacent_parts[a]->transformation_with_respect_to_reference_part;
							// attach seat 1 is adjacent to leg 2
							sampled_parts[pos2].adj_parts.push_back( &sampled_parts[pos] );
							// leg 2 has a corresponding slot in leg 1 (reference part). Use this slot, since we'll always work with ref. parts.
							sampled_parts[pos2].should_be_attached_to_boundary_id_of_ref_part.push_back( refa );					
						}
					}
				}
			}

			// final check: do replicates of reference part have (0,0,0) transformation?
			// do replicates have different adjacencies compared to the reference part? if yes, reject sample
			for (size_t p = 0; p < sampled_parts.size(); p++)
			{
				if ( sampled_parts[p].adj_parts.empty() )
				{
					std::cout << "A part has not adjacencies - it has label " << sampled_parts[p].ref_part->label->name << std::endl;
					this->valid_sampled_mesh = false;
					return;
				}
				if ( sampled_parts[p].id % MAX_NUM_SUBLABELS != 1 )
				{
					if ( len( sampled_parts[p].transformation_with_respect_to_reference_part.first ) < .001 )
					{
						std::cout << "A part with sublabel != 1 has null transformation - it has label " << sampled_parts[p].ref_part->label->name << std::endl;
						this->valid_sampled_mesh = false;
						return;
					}
					for (size_t p2 = 0; p2 < sampled_parts.size(); p2++)
					{
						if ( sampled_parts[p2].id % MAX_NUM_SUBLABELS == 1 && sampled_parts[p].ref_part->label == sampled_parts[p2].ref_part->label )
						{
							for (size_t a = 0; a < sampled_parts[p].adj_parts.size(); a++)
							{
								bool adjacency_exists_also_in_ref_part = false;
								for (size_t a2 = 0; a2 < sampled_parts[p2].adj_parts.size(); a2++)
								{
									if ( sampled_parts[p].adj_parts[a]->ref_part->label == sampled_parts[p2].adj_parts[a2]->ref_part->label )
										adjacency_exists_also_in_ref_part = true;
								}
								if (!adjacency_exists_also_in_ref_part)
								{
									std::cout << "A part with sublabel != 1 has different adjacecies with respect to reference part - it has label " << sampled_parts[p].ref_part->label->name << std::endl;
									this->valid_sampled_mesh = false;
									return;
								}
							}
							break;
						}
					}
				}

			}


			for (size_t p = 0; p < sampled_parts.size(); p++)
			{
				char part_filename[ 4096 ];
				sprintf(part_filename, "%s%d.obj", part_path, sampled_parts[p].ref_part->id);
				sampled_parts[p].ref_mesh = TriMesh::read(part_filename);
			}
		}

		MeshCreator::~MeshCreator()
		{}

		//


		//
		////////////// OLD CODE
		////
		////	 
		////
		////void MeshCreator::validateSampledParts( vector<MeshPart*>& parts, vector<TriMesh*>& meshes)
		////{
		////	for (size_t l = 0; l < new_parts.size(); l++)
		////	{
		////		for (size_t p = 0; p < new_parts[l].size(); p++)
		////		{
		////			for (size_t a = 0; a < new_parts[l][p]->boundary_center_of_mass.size(); a++)
		////			{
		////				MeshPart *adj_part = new_parts[l][p]->adjacent_parts[a];
		////				for (size_t s = 0; s < new_parts[l][p]->boundary_center_of_mass[a].size(); s++)
		////				{
		////					if ( new_parts[l][p]->boundary_slot_ids[a][s] <= 0 )
		////						continue;
		////					
		////					float min_dist = FLT_MAX;
		////					pair<int, int> couple = make_pair<int, int>(-1, -1);
		////					for (size_t a2 = 0; a2 < adj_part->boundary_center_of_mass.size(); a2++)
		////					{						
		////						for (size_t s2 = 0; s2 < adj_part->boundary_center_of_mass[a2].size(); s2++)
		////						{
		////							float dist = len( adj_part->boundary_center_of_mass[a2][s2] - new_parts[l][p]->boundary_center_of_mass[a][s] );
		////							if (dist < min_dist )
		////							{
		////								min_dist = dist;
		////								couple = make_pair<int, int>( new_parts[l][p]->boundary_slot_ids[a][s], adj_part->boundary_slot_ids[a2][s2] );
		////							}
		////						}
		////					}
		////
		////					if ( couple.first <= 0 || couple.second <= 0 )
		////						continue;
		////
		////					bool valid = false;
		////
		////					for (size_t l2 = 0; l2 < new_parts.size(); l2++)
		////					{
		////						for (size_t p2 = 0; p2 < new_parts[l2].size(); p2++)
		////						{
		////							if ( adj_part->label != new_parts[l2][p2]->label )
		////								continue;
		////							for (size_t a2 = 0; a2 < new_parts[l2][p2]->boundary_center_of_mass.size(); a2++)
		////							{
		////								for (size_t s2 = 0; s2 < new_parts[l2][p2]->boundary_center_of_mass[a2].size(); s2++)
		////								{
		////									if (couple.second == new_parts[l2][p2]->boundary_slot_ids[a2][s2])
		////									{
		////										valid = true;
		////										break;
		////									}
		////								}
		////							}
		////						}
		////					}
		////
		////					if (!valid)
		////					{
		////						std::cout << "Slots do not match." << std::endl;
		////						this->valid_sampled_mesh = false;
		////						return;
		////					}
		////				}
		////			}
		////		}
		////	}
		////
		////	bool sampled_mesh_exists = false;
		////	for (size_t m = 0; m < meshes.size(); m++)
		////	{
		////		if ( meshes[m]->parts.size() != num_parts )
		////			continue;
		////		bool all_parts_exist_in_this_mesh = true;
		////		for (size_t pm = 0; pm < meshes[m]->parts.size(); pm++)
		////		{
		////			bool part_exists = false;
		////			MeshPart *part = parts[ meshes[m]->parts[pm]->mesh_part_id ];
		////			
		////			for (size_t l = 0; l < new_parts.size(); l++)
		////			{
		////				for (size_t p = 0; p < new_parts[l].size(); p++)
		////				{
		////					if ( part == new_parts[l][p] )
		////						part_exists = true;
		////				}
		////			}
		////			if ( !part_exists )
		////			{
		////				all_parts_exist_in_this_mesh = false;
		////				continue;
		////			}
		////		}
		////		if ( all_parts_exist_in_this_mesh )
		////		{
		////			sampled_mesh_exists = true;
		////			break;
		////		}
		////	}
		////
		////	if ( sampled_mesh_exists )
		////	{
		////		std::cout << "Sampled a mesh already existing in the database." << std::endl;
		////		this->valid_sampled_mesh = false;
		////	}
		////
		////
		////		for (size_t pm = 0; pm < mesh->parts.size(); pm++)
		////		{
		////			MeshPart *part = parts[ mesh->parts[pm]->mesh_part_id ];
		////			if (part->label == labels[l])
		////			{
		////				new_parts[l].push_back( part );
		////				num_parts++;
		////				char part_filename[ FILE_STRING_SIZE ];
		////				sprintf(part_filename, "%s%d.obj", part_path, part->id);
		////				TriMesh* mesh = TriMesh::read(part_filename);
		////				new_parts_meshes[l].push_back( mesh );
		////			}
		////		}
		////
		////	vector<size_t> count_available_slots_per_label( new_parts.size() );
		////
		////	for (size_t l = 0; l < new_parts.size(); l++)
		////	{
		////		for (size_t p = 0; p < new_parts[l].size(); p++)
		////		{
		////			for (size_t a = 0; a < new_parts[l][p]->adjacent_parts.size(); a++)
		////			{
		////				size_t adj_label = new_parts[l][p]->adjacent_parts[a]->label->id;
		////				count_available_slots_per_label[ adj_label ]++;
		////			}
		////		}
		////	}
		////
		////	for (size_t l = 0; l < new_parts.size(); l++)
		////	{
		////		// there is a boundary on the mesh with a label that has no parts, hard to geometrically optimize mesh
		////		if ( count_available_slots_per_label[l] > 0 && new_parts[l].empty() )
		////		{
		////			this->valid_sampled_mesh = false;
		////			std::cout << "Slots do not match" << std::endl;
		////			return;
		////		}
		////		// the number of boundaries per label is less than the number of parts, hard to geometrically optimize mesh
		////		if ( count_available_slots_per_label[l] < new_parts[l].size() )
		////		{
		////			this->valid_sampled_mesh = false;
		////			std::cout << "Slots do not match" << std::endl;
		////			return;
		////		}
		////	}	
		////}
		//
		////////////////// sanity check with location parameters
		////////// HERE
		////////TriMesh *imesh = parts[200]->mesh;
		////////for (size_t l = 0; l < labels.size(); l++)
		////////{
		////////	sample.configurations[l] = NULL;
		////////	sample.parts_features.clear();
		////////}
		////////sample.parts_features.resize( labels.size() );
		////////for (size_t p = 0; p < imesh->parts.size(); p++)
		////////{
		////////	sample.configurations[ parts[ imesh->parts[p]->mesh_part_id ]->label->id ] = parts[ imesh->parts[p]->mesh_part_id ]->conf;
		////////}
		////////for (size_t l = 0; l < labels.size(); l++)
		////////{
		////////	if ( sample.configurations[l] == NULL) continue;
		////////	for (size_t np = 1; np <= sample.configurations[l]->num_part_clusters; np++)
		////////	{
		////////		for (size_t p = 0; p < imesh->parts.size(); p++)
		////////		{
		////////			if ( parts[ imesh->parts[p]->mesh_part_id ]->conf == sample.configurations[l] && parts[ imesh->parts[p]->mesh_part_id ]->sublabel_id == np )
		////////			{
		////////				for (size_t f = 0; f < parts[ imesh->parts[p]->mesh_part_id ]->location_parameters.size(); f++)
		////////					sample.parts_features[l].push_back( parts[ imesh->parts[p]->mesh_part_id ]->location_parameters[f] );
		////////				for (size_t f = 0; f < parts[ imesh->parts[p]->mesh_part_id ]->feature_parameters.size(); f++)
		////////					sample.parts_features[l].push_back( parts[ imesh->parts[p]->mesh_part_id ]->feature_parameters[f] );
		////////				for (size_t f = 0; f < parts[ imesh->parts[p]->mesh_part_id ]->orientation_parameters.size(); f++)
		////////					sample.parts_features[l].push_back( parts[ imesh->parts[p]->mesh_part_id ]->orientation_parameters[f] );
		////////				for (size_t f = 0; f < parts[ imesh->parts[p]->mesh_part_id ]->scale_parameters.size(); f++)
		////////					sample.parts_features[l].push_back( parts[ imesh->parts[p]->mesh_part_id ]->scale_parameters[f] );
		////////			}
		////////		}
		////////	}
		////////}
		////
		////
		////////		TriMesh* mesh = imesh; //sample.configurations[l]->parts[best_p]->mesh;
		////
		////////		// HERE
		////////		// get parameters for each part			
		////////		std::cout << labels[l]->name << std::endl;
		////////		std::cout << (int)sample.configurations[l]->used_coord_system_type << std::endl;
		////////		std::cout << sample.configurations[l]->used_coord_system_id << std::endl;
		////////		std::cout << sample.configurations[l]->adjacent_label_id << std::endl;
		////////		parts_pivots.clear();
		////////		for (size_t np = 0; np < sample.configurations[l]->num_part_clusters; np++)
		////////		{
		////////			vector< point >	  part_pivots;
		////////			vector< float >		location_parameters_v;
		////////							
		////////			for (size_t f = 0; f < sample.configurations[l]->parts[0]->location_parameters.size(); f++)
		////////				location_parameters_v.push_back( new_parts[l][np]->location_parameters[f] );
		////
		////////			for (size_t f = 0; f < location_parameters_v.size(); f += 3)
		////////				part_pivots.push_back( point( location_parameters_v[f], location_parameters_v[f+1], location_parameters_v[f+2] ) );
		////
		////////			for (size_t pv = 0; pv < part_pivots.size(); pv++)
		////////			{
		////////				if ( sample.configurations[l]->used_coord_system_type == SPHERICAL )
		////////					part_pivots[pv] = spherical_to_cartesian( part_pivots[pv] );
		////////				if ( sample.configurations[l]->used_coord_system_type == CYLINDRICAL )
		////////					part_pivots[pv] = cylindrical_to_cartesian( part_pivots[pv] );
		////
		////////				XForm<float> local_coord_system_label;
		////////				if (sample.configurations[l]->used_coord_system_id != -1)
		////////					local_coord_system_label = getLocalCoordinateSystem( new_parts[ sample.configurations[l]->used_coord_system_id ]);
		////////				part_pivots[pv] = inv( local_coord_system_label ) * part_pivots[pv];
		////////			}
		////
		////////			parts_pivots.push_back( part_pivots );
		////////		}
		////
		////
		////
		////
		//////myXForm MeshCreator::getLocalCoordinateSystem(vector<MeshPart*>& ref_parts)
		//////{	
		//////	if ( ref_parts.empty() )
		//////		return myXForm(FLT_MAX);
		//////	myXForm local_coordinate_system = ref_parts[0]->local_coord_system;
		//////	for (size_t s = 1; s < ref_parts.size(); s++)
		//////		local_coordinate_system = local_coordinate_system + ref_parts[s]->local_coord_system;
		//////	return local_coordinate_system;
		//////}
		////
		////
		////		// get parameters for each part
		////
		////
		////	////	vector< vector< point > >		sampled_pivots;
		////	////	vector< vector< float > >   feature_parameters;
		////	////	vector< vector< float > >   orientation_parameters;
		////	////	vector< vector< float > >   scale_parameters;
		////	////	size_t ff = 0;
		////	////	for (size_t np = 0; np < sample.layouts[l]->num_part_clusters; np++)
		////	////	{
		////	////		vector< point >	  sampled_part_pivot;
		////	////		vector< float >		location_parameters_v;
		////	////		vector< float >   feature_parameters_v;
		////	////		vector< float >   orientation_parameters_v;
		////	////		vector< float >   scale_parameters_v;
		////
		////	////		for (size_t f = 0; f < sample.layouts[l]->parts[0]->location_parameters.size(); f++, ff++)
		////	////			location_parameters_v.push_back( sample.parts_features[l][ff] );
		////	////		for (size_t f = 0; f < sample.layouts[l]->parts[0]->feature_parameters.size(); f++, ff++)
		////	////			feature_parameters_v.push_back( sample.parts_features[l][ff] );
		////	////		for (size_t f = 0; f < sample.layouts[l]->parts[0]->orientation_parameters.size(); f++, ff++)
		////	////			orientation_parameters_v.push_back( sample.parts_features[l][ff] );
		////	////		for (size_t f = 0; f < sample.layouts[l]->parts[0]->scale_parameters.size(); f++, ff++)
		////	////			scale_parameters_v.push_back( sample.parts_features[l][ff] );
		////
		////	////		for (size_t f = 0; f < location_parameters_v.size(); f += 3)
		////	////			sampled_part_pivot.push_back( point( location_parameters_v[f], location_parameters_v[f+1], location_parameters_v[f+2] ) );
		////
		////	////		for (size_t pv = 0; pv < sampled_part_pivot.size(); pv++)
		////	////		{
		////	////			if ( sample.layouts[l]->used_coord_system_type == SPHERICAL )
		////	////				sampled_part_pivot[pv] = spherical_to_cartesian( sampled_part_pivot[pv] );
		////	////			if ( sample.layouts[l]->used_coord_system_type == CYLINDRICAL )
		////	////				sampled_part_pivot[pv] = cylindrical_to_cartesian( sampled_part_pivot[pv] );
		////
		////	////			myXForm local_coord_system_label;
		////	////			if (sample.layouts[l]->used_coord_system_id != -1)
		////	////				local_coord_system_label = getLocalCoordinateSystem( new_parts[ sample.layouts[l]->used_coord_system_id ]);
		////	////			sampled_part_pivot[pv] = local_coord_system_label * sampled_part_pivot[pv];
		////	////		}
		////
		////	////		sampled_pivots.push_back( sampled_part_pivot );
		////	////		feature_parameters.push_back( feature_parameters_v );
		////	////		orientation_parameters.push_back( orientation_parameters_v );
		////	////		scale_parameters.push_back( scale_parameters_v );				
		////	////	}
		////
		////	////	size_t best_p = 0;
		////	////	float min_feature_distance = FLT_MAX;
		////	////	for (size_t p = 0; p < sample.layouts[l]->parts.size(); p++)
		////	////	{
		////	////		if ( sample.layouts[l]->parts[p]->sublabel_id != 1 )
		////	////			continue;
		////	////		float d = dist2( sample.layouts[l]->parts[p]->feature_parameters, feature_parameters[0] );
		////	////		// get part with closest feature vector and compatible style based on the value of the bnet root node
		////	////		//std::cout << sample.layouts[l]->parts[p]->id << " " << sample.layouts[l]->parts[p]->mesh->id << " " << sample.bnet->style_id[sample.layouts[l]->parts[p]->mesh->id] << " " << sample.root_node_value << " " << d << " " << min_feature_distance << std::endl;				
		////	////		if (d < min_feature_distance && sample.bnet->style_id[sample.layouts[l]->parts[p]->mesh->id] == sample.root_node_value )
		////	////		{
		////	////			min_feature_distance = d;
		////	////			best_p = p;
		////	////		}
		////	////	}
		////	////	if ( min_feature_distance == FLT_MAX ) 
		////	////	{
		////	////		std::cout << "Could not find compatible parts from the same object style" << std::endl;
		////	////		this->valid_sampled_mesh = false;
		////	////		return;
		////	////	}
		////
		////
		////
		////
		////	////	// decide location
		////	////	for (size_t np = 0; np < new_parts[l].size(); np++)
		////	////	{				
		////	////		vector<point>		pivots;
		////	////		if ( sample.layouts[l]->adjacent_label_id.empty() )
		////	////		{
		////	////			pivots.push_back( point( new_parts[l][np]->local_coord_system.translation) );
		////	////		}
		////	////		else
		////	////		{
		////	////			size_t num_slots_in_this_part[2] = {0, 0};
		////	////			for (size_t a = 0; a < new_parts[l][np]->boundary_center_of_mass.size(); a++)
		////	////			{
		////	////				int adj_label_id = sample.layouts[l]->consistent_adjacent_label_with_configuration( new_parts[l][np]->adjacent_parts[a]->label );
		////	////				if ( adj_label_id == -1) 
		////	////					continue;
		////	////				for (size_t j = 0; j < new_parts[l][np]->boundary_center_of_mass[a].size(); j++)
		////	////				{
		////	////					num_slots_in_this_part[ (size_t)adj_label_id ]++;
		////	////					if ( num_slots_in_this_part[ (size_t)adj_label_id ] > sample.layouts[l]->adjacent_label_num_slots[ (size_t)adj_label_id ] )
		////	////						continue;
		////	////					pivots.push_back( new_parts[l][np]->boundary_center_of_mass[a][j] );
		////	////				}
		////	////			}
		////	////		}
		////	////		if ( pivots.size() != sampled_pivots[np].size() || pivots.empty() )
		////	////		{
		////	////			std::cout << "Internal Error: MeshCreator.cpp, pivots.size() != sampled_pivots[np].size() or pivots.empty(). Cancelling sample" << std::endl;
		////	////			this->valid_sampled_mesh = false;
		////	////			return;
		////	////		}
		////
		////
		////	////		// rescale parts
		////	////		for (size_t v = 0; v < new_parts_meshes[l][np]->vertices.size(); v++)
		////	////			new_parts_meshes[l][np]->vertices[v] = new_parts_meshes[l][np]->vertices[v] - new_parts[l][np]->local_coord_system.translation;
		////
		////	////		vec sampled_scale = vec( scale_parameters[0][0], scale_parameters[0][1], scale_parameters[0][2] );
		////	////		vec part_scale = sampled_scale / vec( new_parts[l][0]->scales[0], new_parts[l][0]->scales[1], new_parts[l][0]->scales[2] );
		////	////		//part_scale[0] = max( min( part_scale[0], 1.25f ), 0.75f ); // in case of a buggy estimate of scale
		////	////		//part_scale[1] = max( min( part_scale[1], 1.25f ), 0.75f );
		////	////		//part_scale[2] = max( min( part_scale[2], 1.25f ), 0.75f );
		////	////		for (size_t v = 0; v < new_parts_meshes[l][np]->vertices.size(); v++)
		////	////			new_parts_meshes[l][np]->vertices[v] = new_parts_meshes[l][np]->vertices[v] * part_scale;
		////
		////	////		for (size_t v = 0; v < new_parts_meshes[l][np]->vertices.size(); v++)
		////	////			new_parts_meshes[l][np]->vertices[v] = new_parts_meshes[l][np]->vertices[v] + new_parts[l][np]->local_coord_system.translation;
		////
		////	////		// translate parts
		////	////		vec		part_translation(0, 0, 0);		
		////	////		for (size_t s = 0; s < pivots.size(); s++)
		////	////			part_translation = part_translation + (sampled_pivots[np][s] - pivots[s] );
		////	////		part_translation /= float( pivots.size() );
		////
		////	////		for (size_t v = 0; v < new_parts_meshes[l][np]->vertices.size(); v++)
		////	////			new_parts_meshes[l][np]->vertices[v] = new_parts_meshes[l][np]->vertices[v] + part_translation;
		////
		////	////		translations[l].push_back( part_translation );
		////	////		scales[l].push_back( part_scale ) ;
		////	////		rotations[l].push_back( vec(0, 0, 0) );
		////
		////	////		//std::cout << labels[l]->name << std::endl;
		////	////		//std::cout << (int)sample.layouts[l]->used_coord_system_type << std::endl;
		////	////		//std::cout << sample.layouts[l]->used_coord_system_id << std::endl;
		////	////		//std::cout << sample.layouts[l]->adjacent_label_id << std::endl;
		////	////		//std::cout << sample.layouts[l]->adjacent_label_num_slots << std::endl;
		////	////		//std::cout << part_translation << std::endl;
		////	////		//std::cout << sampled_scale << " " << vec( new_parts[l][np]->scales[0], new_parts[l][np]->scales[1], new_parts[l][np]->scales[2] ) << " " << part_scale << std::endl;
		////	////		//system("pause");
		////	////	} // end of loop over each part of the label
		////
		////	////} //end of loop over each label
		////
		////
		//
		//
		//	//////queue< SampledPart > queue_sampled_parts;
		//	//////queue_sampled_parts.push( unprocessed_sampled_parts[0] );
		//	//////// start BFS-like construction of mesh
		//	//////while( !queue_sampled_parts.empty() )
		//	//////{
		//	//////	SampledPart s = queue_sampled_parts.front();
		//	//////	sampled_parts.push_back(s);
		//	//////	queue_sampled_parts.pop();
		//	//////	s.done = true;
		//	//////	// at this point, s must have trans filled, [scale_data filled, id, ref_part]
		//	//////	// now we should complete adjacent_parts_done and adj_part_id_slot_id
		//	//////	for (size_t a = 0; a < s.part->adjacent_parts.size(); a++)
		//	//////	{
		//	//////		if ( s.adjacent_parts_done[a] )
		//	//////			continue;
		//	//////		s.adjacent_parts_done[a] = true;
		//	//////		// label id of the adjacent part in the ORIGINAL MESH
		//	//////		size_t l = s.part->adjacent_parts[a]->label->id;
		//
		//	//////		// access transformation stores in s.part->adjacent_trans[a]
		//	//////		// find unprocessed_sampled_parts s' with label i and done false, if no part found continue
		//	//////		// s.trans = accessed transformation
		//	//////		// put it inside queue
		//	//////		
		//	//////		// access neighboring slotids in  s.part->adjacent_trans[a] per slot sid of s.part
		//	//////		// for each of them, push_back triple <sid, <s', neighboring slot>>
		//
		//	//////		// for each adjacent_part of s'.part
		//	//////		// access neighboring slots
		//
		//	//////		find a2 in adjacent_parts of s' whose slotids are neighboring slots
		//	//////		// s'.adjacent_parts_done[a2's].done = true
		//
		//	//////		// 
		//
		//	//////	}
		//
		//
		//
		//	////// start BFS
		//	//////{
		//	//////	{
		//	//////		// sublabel id of the adjacent part of s in the ORIGINAL MESH
		//	//////		size_t   adj_por_sublabel_id = s.part->adjacent_parts[a]->sublabel_id;
		//	//////		// transformation of the adjacent part in the ORIGINAL MESH
		//	//////		myXForm  adj_por_trans = s.part->adjacent_parts[a]->local_coord_system;
		//
		//	//////		// get REFERENCE SAMPLED PART for label l
		//	//////		MeshPart *ref_part = unprocessed_sampled_parts[l].part;
		//	//////		// get SAMPLED PART for label l
		//	//////		MeshPart *part;
		//	//////		for (size_t pm = 0; pm < ref_part->mesh->parts.size(); pm++)
		//	//////		{
		//	//////			MeshPart *cpart = parts[ ref_part->mesh->parts[pm]->mesh_part_id ];
		//	//////				if ( cpart->label == labels[l] && cpart->sublabel_id == adj_por_sublabel_id)
		//	//////				{
		//	//////					part = cpart;
		//	//////					break;
		//	//////				}
		//	//////		}
		//
		//	//////		// new part to be added
		//	//////		SampledPart news(100*l+(part->sublabel_id-1), ref_part, part, sample.scales[l] ); 
		//	//////		// fill transformation for new part
		//	//////		myXForm  sampled_p_trans = ref_part->local_coord_system;
		//	//////		sampled_p_trans.inv();			
		//	//////		news.xform = adj_por_trans * sampled_p_trans;
		//
		//	//////		// set done the adjacent parts that have label and sublabel id equal to s
		//	//////		size_t antia;
		//	//////		for (size_t a2 = 0; a2 < part->adjacent_parts.size(); a2++)
		//	//////		{
		//	//////			for (size_t ss = 0; ss < sampled_parts.size(); ss++)
		//	//////			{
		//	//////				if (part->adjacent_parts[a2]->label == sampled_parts[ss].part->label && part->adjacent_parts[a2]->sublabel_id == sampled_parts[ss].part->sublabel_id)
		//	//////					news.adjacent_parts_done[a2] = true;
		//	//////			}
		//	//////			if (part->adjacent_parts[a2]->label == s.part->label && part->adjacent_parts[a2]->sublabel_id == s.part->sublabel_id)
		//	//////				antia = a2;
		//	//////		}
		//
		//	//////		// SLOTS registration
		//	//////		vector< int > s_slots = s.part->boundary_slot_ids[a];
		//	//////		vector< int > news_slots = news.part->boundary_slot_ids[antia];
		//
		//	//////
		//	//////		queue_sampled_parts.push( news );
		//
		//
		//	//////	}
		//	//////}
		//

		//////std::cout << labels->at(l)->name << " " << cardinality_nodes[l]->sample_value << " " << cardinality_nodes[l]->values[ cardinality_nodes[l]->sample_value ] << std::endl;



		//////			std::cout << sample.bnet->cardinality_nodes[l]->sample_value << std::endl;
		//////			std::cout << sample.bnet->layout_nodes[l]->sample_value << std::endl;

		//////			vector<size_t> parent_values( sample.bnet->adjacencynumparts_nodes[a]->parents.size() );
		//////			for (size_t p = 0; p < sample.bnet->adjacencynumparts_nodes[a]->parents.size(); p++)
		//////				parent_values[p] = sample.bnet->adjacencynumparts_nodes[a]->parents[p]->sample_value;
		//////			std::cout << parent_values << std::endl;


		//////			std::cout << sample.bnet->adjacencynumparts_nodes[a]->parents[1]->cpt << std::endl;
		//////			std::cout << sample.bnet->cardinality_nodes[l]->cpt << std::endl;



		//////for (size_t i = 0; i < cpt.size(); i++)
		//////{
		//////	vector<size_t> v;
		//////	size_t d = getValues(i, v);
		//////	std::cout << std:endl << d << " " << v[0] << " " << v[1] << " " << cpt[i] << std::endl;
		//////	system("pause");
		//////}



		//////	for (size_t a = 0; a < sample.bnet->adjacencynumparts_nodes.size(); a++)
		//////	{
		//////		if ( sample.bnet->adjacencynumparts_nodes[a]->label == labels[l] )
		//////		{
		//////			size_t adj_pos = sample.bnet->adjacencynumparts_nodes[a]->adj_label_pos;


		//////			vector<size_t> parent_values( sample.bnet->adjacencynumparts_nodes[a]->parents.size() );
		//////			for (size_t p = 0; p < sample.bnet->adjacencynumparts_nodes[a]->parents.size(); p++)
		//////				parent_values[p] = sample.bnet->adjacencynumparts_nodes[a]->parents[p]->sample_value;
		//////			for (size_t d = 0; d < sample.bnet->adjacencynumparts_nodes[a]->domain_size; d++)
		//////				std::cout << d << "(" << sample.bnet->adjacencynumparts_nodes[a]->values[d] << "): " << sample.bnet->adjacencynumparts_nodes[a]->cpt[ sample.bnet->adjacencynumparts_nodes[a]->acn(d, parent_values) ] << " | ";

		//////			std::cout << meshes[m]->filename << std::endl;
		//////			std::cout << labels[l]->name << "-" << labels[l]->adj_labels[ adj_pos ]->name << ", s:" << sample.adjacencynumparts_nodes_value[a] << ", m:" << sample.bnet->adjacentparts_training_data[m][l][ adj_pos ] << std::endl;
		//////			system("pause");
		//////			//if ( sample.adjacencynumparts_nodes_value[a] != sample.bnet->adjacentparts_training_data[m][l][ adj_pos ] )
		//////			//	feature_distance = FLT_MAX;	
		//////		}
		//////	}

	}
}