/*
 * The main process of levenberg-marquart optimization
 */
bool intraCamLMEpiProc(const double K[9],
		const double invK[9],
		const double R0[9],
		const double t0[3],
		int n3D2D,
		const double Ms[],
		const double ms[],
		int n2D2D,
		const double Rpre[],
		const double tpre[],
		const double umspre[],
		const double ums[],
		double R_opt[9],
		double t_opt[3],
		IntraCamPoseOption* opt) {
	assert(opt);
	double param[6];

	//compute the reprojection error
	opt->npts = n3D2D;
	opt->lambda = opt->lambda0;
	opt->err0 = reprojError2(K, R0, t0, n3D2D, Ms, ms) + _epiError2(invK, n2D2D, Rpre, tpre, umspre, R0, t0, ums);
	opt->err = opt->err0;
	if (opt->verboseLM > 0)
		printf("[%d]err:%lf, lambda:%lf\n", -1, opt->err, opt->lambda);

	double R[9], t[3];
	doubleArrCopy(R, 0, R0, 9);
	doubleArrCopy(t, 0, t0, 3);

	opt->retTypeLM = 1;
	int i = 0;
	for (; i < opt->maxIterLM; i++) {
		intraCamEpiLMStep(K, invK, R, t, n3D2D, Ms, ms, n2D2D, Rpre, tpre, umspre, ums, param, opt->lambda);
		intraCamUpdatePose(R, t, param, R_opt, t_opt);
		double err = reprojError2(K, R_opt, t_opt, n3D2D, Ms, ms) + _epiError2(invK, n2D2D, Rpre, tpre, umspre, R_opt,
				t_opt, ums);
		if (opt->verboseLM > 0)
			printf("[%d]err:%lf, lambda:%lf\n", i, err, opt->lambda);
		if (fabs(err - opt->err) < opt->epsErrorChangeLM) {
			opt->retTypeLM = 0;
			break;
		}
		if (err < opt->err) {
			doubleArrCopy(R, 0, R_opt, 9);
			doubleArrCopy(t, 0, t_opt, 3);
			opt->err = err;
			opt->lambda /= 10;
		} else {
			opt->lambda *= 10;
			if (opt->lambda > 1e+4) {
				//cannot find the optimum 
				opt->retTypeLM = -1;
				break;
			}
		}
	}
	opt->nIterLM = i;
	return opt->retTypeLM >= 0;
}
double reprojError(const double* R, double *t, int npts, const double * Ms,
		const double* ms0) {
	return sqrt(reprojError2(R, t, npts, Ms, ms0) / npts);
}