//Author: Yusuf Sahillioglu

//[1] isometric part matching (paper: Scale Normalization for Isometric Shape Matching) or [2] more general partial matching (paper: Partial 3D Correspondence from Shape Extremities)
int theAlgo;
#define PART_MATCH			1
#define GEN_PARTIAL_MATCH	2

#include "Model.h" //a screen object

#include <windows.h> //for get_time just-below
inline double get_time()
{
	LARGE_INTEGER t, frequency;
	QueryPerformanceCounter(&t);
	QueryPerformanceFrequency(&frequency);
	return (double)t.QuadPart/(double)frequency.QuadPart;
}

int main(int argc, char ** argv)
{
	int a, b, fileFormat, theAlgo, sMaxGeoDivider, tMaxGeoDivider;
	float weight7 = 0.0f/*0.25f*/, arbitraryScale = 1.0f, xZeta;
	bool dense40 = true;
	cout << "\n[1]: Scale Normalization for Isometric Shape Matching\n[2]: Partial 3D Correspondence from Shape Extremities\n\n";
	cout << "9 parameters expected: PartialShapeCorresponder_x64.exe <sourceID> <targetID> <meshFormat> <[1]or[2]> <arbitraryScaling> <# dense samples == 40> <sMaxGeoDivider> <tMaxGeoDivider> <xZeta>\n\n";
	cout << "first four used by both [1-2], next one used only by [1], last four only by [2]\n\n";
	if (argc != 10)
	{
		cout << "<*ID>: nonnegative integer\n";
		cout << "<meshFormat>: input mesh file in 1: obj, 2: off, 3: ply format\n";
		cout << "<[1]or[2]>: which algo to launch? 1: for [1], 2: for [2]\n";
		cout << "<arbitraryScaling>: scale target mesh with this to manually achieve scale difference; 2.5 used for [1]\n";
		cout << "<# dense samples == 40>: 1: sets # of dense samples to be used in confidence computations to 40, otherwise: to 120; 120 used for [2]\n";
		cout << "<sMaxGeoDivider>: divide max geodesic dist by this in source mesh to decide closeness threshold during pruning, e.g. 8 for SCAPE, in general in [8,20]\n";
		cout << "<tMaxGeoDivider>: divide max geodesic dist by this in target mesh to decide closeness threshold during pruning, e.g. 14 for Centaur, in general in [8,20]\n";
		cout << "<xZeta>: multiplier of zeta in outlier removal of combining step, 3 used for [2]\n";
		exit(0);
	}
	a = atoi(argv[1]);
	b = atoi(argv[2]);
	fileFormat = atoi(argv[3]);
	theAlgo = atoi(argv[4]);
	if (theAlgo != PART_MATCH && theAlgo != GEN_PARTIAL_MATCH)
		exit(0);
	arbitraryScale = (float) atof(argv[5]);
	dense40 = (atoi(argv[6]) == 1);
	if (weight7 < 0.0f || weight7 > 1.0f || a < 0 || b < 0)
		exit(0); //input in wrong range
	sMaxGeoDivider = atoi(argv[7]);
	tMaxGeoDivider = atoi(argv[8]);
	xZeta = (float) atof(argv[9]);

	Model* jModel = new Model("Model # 1", a, true);
	jModel->init(fileFormat);
	Model* jModel2 = new Model("Model # 2", b, false);
	jModel2->init(fileFormat);

	double start_time = get_time();
	if (theAlgo == PART_MATCH)
	{
		jModel->getMesh()->shortcutEdges = jModel2->getMesh()->shortcutEdges = false;
		jModel->getMesh()->scaleInvDemo = jModel2->getMesh()->scaleInvDemo = true;
		jModel->getMesh()->partialMatching(jModel2->getMesh(), arbitraryScale);
	}
	else
	{
		jModel->getMesh()->shortcutEdges = jModel2->getMesh()->shortcutEdges = false;
		//jModel->getMesh()->partialMatching2( jModel2->getMesh() ); //initial 2 matches --> initial 58x58 --> 57x57, 56x56, .., good 8x8 --> good 58x58 --> excluded 50x50
		jModel->getMesh()->weight7 = weight7; //overwrite default values w/ these cmd line arguments
		jModel->getMesh()->dense40 = dense40;
		jModel->getMesh()->pruningDistDenom = sMaxGeoDivider;
		jModel2->getMesh()->pruningDistDenom = tMaxGeoDivider;
		jModel->getMesh()->batchRun = false;
		jModel->getMesh()->xZeta = xZeta;
		jModel->getMesh()->partialMatching3( jModel2->getMesh(), true ); //match bases of local maxima and minima of mu
	}

	cout << "\n>>>>>> " << get_time()-start_time << " secs for all computations (excluding load time of 2 input meshes)\n";	

	return 0;
}
