static void meshdeform_matrix_add_cell(MeshDeformBind *mdb, LinearSolver *context, int x, int y, int z)
{
	MDefBoundIsect *isect;
	float weight, totweight;
	int i, a, acenter;

	acenter = meshdeform_index(mdb, x, y, z, 0);
	if (mdb->tag[acenter] == MESHDEFORM_TAG_EXTERIOR)
		return;

	EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[acenter], 1.0f);
	
	totweight = meshdeform_boundary_total_weight(mdb, x, y, z);
	for (i = 1; i <= 6; i++) {
		a = meshdeform_index(mdb, x, y, z, i);
		if (a == -1 || mdb->tag[a] == MESHDEFORM_TAG_EXTERIOR)
			continue;

		isect = mdb->boundisect[acenter][i - 1];
		if (!isect) {
			weight = (1.0f / mdb->width[0]) / totweight;
			EIG_linear_solver_matrix_add(context, mdb->varidx[acenter], mdb->varidx[a], -weight);
		}
	}
}
static void laplacian_triangle_weights(LaplacianSystem *sys, int f, int i1, int i2, int i3)
{
	float t1, t2, t3;
	float *varea = sys->varea, *v1, *v2, *v3;

	v1 = sys->verts[i1];
	v2 = sys->verts[i2];
	v3 = sys->verts[i3];

	/* instead of *0.5 we divided by the number of faces of the edge, it still
	 * needs to be verified that this is indeed the correct thing to do! */
	t1 = cotangent_tri_weight_v3(v1, v2, v3) / laplacian_edge_count(sys->edgehash, i2, i3);
	t2 = cotangent_tri_weight_v3(v2, v3, v1) / laplacian_edge_count(sys->edgehash, i3, i1);
	t3 = cotangent_tri_weight_v3(v3, v1, v2) / laplacian_edge_count(sys->edgehash, i1, i2);

	EIG_linear_solver_matrix_add(sys->context, i1, i1, (t2 + t3) * varea[i1]);
	EIG_linear_solver_matrix_add(sys->context, i2, i2, (t1 + t3) * varea[i2]);
	EIG_linear_solver_matrix_add(sys->context, i3, i3, (t1 + t2) * varea[i3]);

	EIG_linear_solver_matrix_add(sys->context, i1, i2, -t3 * varea[i1]);
	EIG_linear_solver_matrix_add(sys->context, i2, i1, -t3 * varea[i2]);

	EIG_linear_solver_matrix_add(sys->context, i2, i3, -t1 * varea[i2]);
	EIG_linear_solver_matrix_add(sys->context, i3, i2, -t1 * varea[i3]);

	EIG_linear_solver_matrix_add(sys->context, i3, i1, -t2 * varea[i3]);
	EIG_linear_solver_matrix_add(sys->context, i1, i3, -t2 * varea[i1]);

	if (sys->storeweights) {
		sys->fweights[f][0] = t1 * varea[i1];
		sys->fweights[f][1] = t2 * varea[i2];
		sys->fweights[f][2] = t3 * varea[i3];
	}
}
/**
 * This method computes the Laplacian Matrix and Differential Coordinates for all vertex in the mesh.
 * The Linear system is LV = d
 * Where L is Laplacian Matrix, V as the vertexes in Mesh, d is the differential coordinates
 * The Laplacian Matrix is computes as a
 * Lij = sum(Wij) (if i == j)
 * Lij = Wij (if i != j)
 * Wij is weight between vertex Vi and vertex Vj, we use cotangent weight
 *
 * The Differential Coordinate is computes as a
 * di = Vi * sum(Wij) - sum(Wij * Vj)
 * Where :
 * di is the Differential Coordinate i
 * sum (Wij) is the sum of all weights between vertex Vi and its vertexes neighbors (Vj)
 * sum (Wij * Vj) is the sum of the product between vertex neighbor Vj and weight Wij for all neighborhood.
 *
 * This Laplacian Matrix is described in the paper:
 * Desbrun M. et.al, Implicit fairing of irregular meshes using diffusion and curvature flow, SIGGRAPH '99, pag 317-324,
 * New York, USA
 *
 * The computation of Laplace Beltrami operator on Hybrid Triangle/Quad Meshes is described in the paper:
 * Pinzon A., Romero E., Shape Inflation With an Adapted Laplacian Operator For Hybrid Quad/Triangle Meshes,
 * Conference on Graphics Patterns and Images, SIBGRAPI, 2013
 *
 * The computation of Differential Coordinates is described in the paper:
 * Sorkine, O. Laplacian Surface Editing. Proceedings of the EUROGRAPHICS/ACM SIGGRAPH Symposium on Geometry Processing,
 * 2004. p. 179-188.
 */
static void initLaplacianMatrix(LaplacianSystem *sys)
{
	float no[3];
	float w2, w3;
	int i = 3, j, ti;
	int idv[3];

	for (ti = 0; ti < sys->total_tris; ti++) {
		const unsigned int *vidt = sys->tris[ti];
		const float *co[3];

		co[0] = sys->co[vidt[0]];
		co[1] = sys->co[vidt[1]];
		co[2] = sys->co[vidt[2]];

		normal_tri_v3(no, UNPACK3(co));
		add_v3_v3(sys->no[vidt[0]], no);
		add_v3_v3(sys->no[vidt[1]], no);
		add_v3_v3(sys->no[vidt[2]], no);

		for (j = 0; j < 3; j++) {
			const float *v1, *v2, *v3;

			idv[0] = vidt[j];
			idv[1] = vidt[(j + 1) % i];
			idv[2] = vidt[(j + 2) % i];

			v1 = sys->co[idv[0]];
			v2 = sys->co[idv[1]];
			v3 = sys->co[idv[2]];

			w2 = cotangent_tri_weight_v3(v3, v1, v2);
			w3 = cotangent_tri_weight_v3(v2, v3, v1);

			sys->delta[idv[0]][0] += v1[0] * (w2 + w3);
			sys->delta[idv[0]][1] += v1[1] * (w2 + w3);
			sys->delta[idv[0]][2] += v1[2] * (w2 + w3);

			sys->delta[idv[0]][0] -= v2[0] * w2;
			sys->delta[idv[0]][1] -= v2[1] * w2;
			sys->delta[idv[0]][2] -= v2[2] * w2;

			sys->delta[idv[0]][0] -= v3[0] * w3;
			sys->delta[idv[0]][1] -= v3[1] * w3;
			sys->delta[idv[0]][2] -= v3[2] * w3;

			EIG_linear_solver_matrix_add(sys->context, idv[0], idv[1], -w2);
			EIG_linear_solver_matrix_add(sys->context, idv[0], idv[2], -w3);
			EIG_linear_solver_matrix_add(sys->context, idv[0], idv[0], w2 + w3);
		}
	}
}
Esempio n. 4
0
static void fill_laplacian_matrix(LaplacianSystem *sys)
{
	int i;
	unsigned int idv1, idv2;

	for (i = 0; i < sys->numPolys; i++) {
		const MPoly *mp = &sys->mpoly[i];
		const MLoop *l_next = &sys->mloop[mp->loopstart];
		const MLoop *l_term = l_next + mp->totloop;
		const MLoop *l_prev = l_term - 2;
		const MLoop *l_curr = l_term - 1;

		for (;
		     l_next != l_term;
		     l_prev = l_curr, l_curr = l_next, l_next++)
		{
			const unsigned int l_curr_index = l_curr - sys->mloop;

			/* Is ring if number of faces == number of edges around vertice*/
			if (sys->numNeEd[l_curr->v] == sys->numNeFa[l_curr->v] && sys->zerola[l_curr->v] == 0) {
				EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_next->v, sys->fweights[l_curr_index][2] * sys->vweights[l_curr->v]);
				EIG_linear_solver_matrix_add(sys->context, l_curr->v, l_prev->v, sys->fweights[l_curr_index][1] * sys->vweights[l_curr->v]);
			}
			if (sys->numNeEd[l_next->v] == sys->numNeFa[l_next->v] && sys->zerola[l_next->v] == 0) {
				EIG_linear_solver_matrix_add(sys->context, l_next->v, l_curr->v, sys->fweights[l_curr_index][2] * sys->vweights[l_next->v]);
				EIG_linear_solver_matrix_add(sys->context, l_next->v, l_prev->v, sys->fweights[l_curr_index][0] * sys->vweights[l_next->v]);
			}
			if (sys->numNeEd[l_prev->v] == sys->numNeFa[l_prev->v] && sys->zerola[l_prev->v] == 0) {
				EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_curr->v, sys->fweights[l_curr_index][1] * sys->vweights[l_prev->v]);
				EIG_linear_solver_matrix_add(sys->context, l_prev->v, l_next->v, sys->fweights[l_curr_index][0] * sys->vweights[l_prev->v]);
			}
		}
	}

	for (i = 0; i < sys->numEdges; i++) {
		idv1 = sys->medges[i].v1;
		idv2 = sys->medges[i].v2;
		/* Is boundary */
		if (sys->numNeEd[idv1] != sys->numNeFa[idv1] &&
		    sys->numNeEd[idv2] != sys->numNeFa[idv2] &&
		    sys->zerola[idv1] == 0 &&
		    sys->zerola[idv2] == 0)
		{
			EIG_linear_solver_matrix_add(sys->context, idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
			EIG_linear_solver_matrix_add(sys->context, idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
		}
	}
}
static void laplacian_system_construct_end(LaplacianSystem *sys)
{
	int (*face)[3];
	int a, totvert = sys->totvert, totface = sys->totface;

	laplacian_begin_solve(sys, 0);

	sys->varea = MEM_callocN(sizeof(float) * totvert, "LaplacianSystemVarea");

	sys->edgehash = BLI_edgehash_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(sys->totface));
	for (a = 0, face = sys->faces; a < sys->totface; a++, face++) {
		laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
		laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
		laplacian_increase_edge_count(sys->edgehash, (*face)[2], (*face)[0]);
	}

	if (sys->areaweights)
		for (a = 0, face = sys->faces; a < sys->totface; a++, face++)
			laplacian_triangle_area(sys, (*face)[0], (*face)[1], (*face)[2]);
	
	for (a = 0; a < totvert; a++) {
		if (sys->areaweights) {
			if (sys->varea[a] != 0.0f)
				sys->varea[a] = 0.5f / sys->varea[a];
		}
		else
			sys->varea[a] = 1.0f;

		/* for heat weighting */
		if (sys->heat.H)
			EIG_linear_solver_matrix_add(sys->context, a, a, sys->heat.H[a]);
	}

	if (sys->storeweights)
		sys->fweights = MEM_callocN(sizeof(float) * 3 * totface, "LaplacianFWeight");
	
	for (a = 0, face = sys->faces; a < totface; a++, face++)
		laplacian_triangle_weights(sys, a, (*face)[0], (*face)[1], (*face)[2]);

	MEM_freeN(sys->faces);
	sys->faces = NULL;

	if (sys->varea) {
		MEM_freeN(sys->varea);
		sys->varea = NULL;
	}

	BLI_edgehash_free(sys->edgehash, NULL);
	sys->edgehash = NULL;
}
static void laplacianDeformPreview(LaplacianSystem *sys, float (*vertexCos)[3])
{
	int vid, i, j, n, na;
	n = sys->total_verts;
	na = sys->total_anchors;

	if (!sys->is_matrix_computed) {
		sys->context = EIG_linear_least_squares_solver_new(n + na, n, 3);

		for (i = 0; i < n; i++) {
			EIG_linear_solver_variable_set(sys->context, 0, i, sys->co[i][0]);
			EIG_linear_solver_variable_set(sys->context, 1, i, sys->co[i][1]);
			EIG_linear_solver_variable_set(sys->context, 2, i, sys->co[i][2]);
		}
		for (i = 0; i < na; i++) {
			vid = sys->index_anchors[i];
			EIG_linear_solver_variable_set(sys->context, 0, vid, vertexCos[vid][0]);
			EIG_linear_solver_variable_set(sys->context, 1, vid, vertexCos[vid][1]);
			EIG_linear_solver_variable_set(sys->context, 2, vid, vertexCos[vid][2]);
		}

		initLaplacianMatrix(sys);
		computeImplictRotations(sys);

		for (i = 0; i < n; i++) {
			EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
		}
		for (i = 0; i < na; i++) {
			vid = sys->index_anchors[i];
			EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
			EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
		}
		if (EIG_linear_solver_solve(sys->context)) {
			sys->has_solution = true;

			for (j = 1; j <= sys->repeat; j++) {
				rotateDifferentialCoordinates(sys);

				for (i = 0; i < na; i++) {
					vid = sys->index_anchors[i];
					EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
					EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
					EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
				}

				if (!EIG_linear_solver_solve(sys->context)) {
					sys->has_solution = false;
					break;
				}
			}
			if (sys->has_solution) {
				for (vid = 0; vid < sys->total_verts; vid++) {
					vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
					vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
					vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
				}
			}
			else {
				sys->has_solution = false;
			}

		}
		else {
			sys->has_solution = false;
		}
		sys->is_matrix_computed = true;

	}
	else if (sys->has_solution) {
		for (i = 0; i < n; i++) {
			EIG_linear_solver_right_hand_side_add(sys->context, 0, i, sys->delta[i][0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, i, sys->delta[i][1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, i, sys->delta[i][2]);
		}
		for (i = 0; i < na; i++) {
			vid = sys->index_anchors[i];
			EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
			EIG_linear_solver_matrix_add(sys->context, n + i, vid, 1.0f);
		}

		if (EIG_linear_solver_solve(sys->context)) {
			sys->has_solution = true;
			for (j = 1; j <= sys->repeat; j++) {
				rotateDifferentialCoordinates(sys);

				for (i = 0; i < na; i++) {
					vid = sys->index_anchors[i];
					EIG_linear_solver_right_hand_side_add(sys->context, 0, n + i, vertexCos[vid][0]);
					EIG_linear_solver_right_hand_side_add(sys->context, 1, n + i, vertexCos[vid][1]);
					EIG_linear_solver_right_hand_side_add(sys->context, 2, n + i, vertexCos[vid][2]);
				}
				if (!EIG_linear_solver_solve(sys->context)) {
					sys->has_solution = false;
					break;
				}
			}
			if (sys->has_solution) {
				for (vid = 0; vid < sys->total_verts; vid++) {
					vertexCos[vid][0] = EIG_linear_solver_variable_get(sys->context, 0, vid);
					vertexCos[vid][1] = EIG_linear_solver_variable_get(sys->context, 1, vid);
					vertexCos[vid][2] = EIG_linear_solver_variable_get(sys->context, 2, vid);
				}
			}
			else {
				sys->has_solution = false;
			}
		}
		else {
			sys->has_solution = false;
		}
	}
}
Esempio n. 7
0
static void laplaciansmoothModifier_do(
        LaplacianSmoothModifierData *smd, Object *ob, DerivedMesh *dm,
        float (*vertexCos)[3], int numVerts)
{
	LaplacianSystem *sys;
	MDeformVert *dvert = NULL;
	MDeformVert *dv = NULL;
	float w, wpaint;
	int i, iter;
	int defgrp_index;

	sys = init_laplacian_system(dm->getNumEdges(dm), dm->getNumPolys(dm), dm->getNumLoops(dm), numVerts);
	if (!sys) {
		return;
	}

	sys->mpoly = dm->getPolyArray(dm);
	sys->mloop = dm->getLoopArray(dm);
	sys->medges = dm->getEdgeArray(dm);
	sys->vertexCos = vertexCos;
	sys->min_area = 0.00001f;
	modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);

	sys->vert_centroid[0] = 0.0f;
	sys->vert_centroid[1] = 0.0f;
	sys->vert_centroid[2] = 0.0f;
	memset_laplacian_system(sys, 0);

	sys->context = EIG_linear_least_squares_solver_new(numVerts, numVerts, 3);

	init_laplacian_matrix(sys);

	for (iter = 0; iter < smd->repeat; iter++) {
		for (i = 0; i < numVerts; i++) {
			EIG_linear_solver_variable_set(sys->context, 0, i, vertexCos[i][0]);
			EIG_linear_solver_variable_set(sys->context, 1, i, vertexCos[i][1]);
			EIG_linear_solver_variable_set(sys->context, 2, i, vertexCos[i][2]);
			if (iter == 0) {
				add_v3_v3(sys->vert_centroid, vertexCos[i]);
			}
		}
		if (iter == 0 && numVerts > 0) {
			mul_v3_fl(sys->vert_centroid, 1.0f / (float)numVerts);
		}

		dv = dvert;
		for (i = 0; i < numVerts; i++) {
			EIG_linear_solver_right_hand_side_add(sys->context, 0, i, vertexCos[i][0]);
			EIG_linear_solver_right_hand_side_add(sys->context, 1, i, vertexCos[i][1]);
			EIG_linear_solver_right_hand_side_add(sys->context, 2, i, vertexCos[i][2]);
			if (iter == 0) {
				if (dv) {
					wpaint = defvert_find_weight(dv, defgrp_index);
					dv++;
				}
				else {
					wpaint = 1.0f;
				}

				if (sys->zerola[i] == 0) {
					if (smd->flag & MOD_LAPLACIANSMOOTH_NORMALIZED) {
						w = sys->vweights[i];
						sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / w;
						w = sys->vlengths[i];
						sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;
						if (sys->numNeEd[i] == sys->numNeFa[i]) {
							EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda) * wpaint);
						}
						else {
							EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
						}
					}
					else {
						w = sys->vweights[i] * sys->ring_areas[i];
						sys->vweights[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda) * wpaint / (4.0f * w);
						w = sys->vlengths[i];
						sys->vlengths[i] = (w == 0.0f) ? 0.0f : -fabsf(smd->lambda_border) * wpaint * 2.0f / w;

						if (sys->numNeEd[i] == sys->numNeFa[i]) {
							EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda) * wpaint / (4.0f * sys->ring_areas[i]));
						}
						else {
							EIG_linear_solver_matrix_add(sys->context, i, i,  1.0f + fabsf(smd->lambda_border) * wpaint * 2.0f);
						}
					}
				}
				else {
					EIG_linear_solver_matrix_add(sys->context, i, i, 1.0f);
				}
			}
		}

		if (iter == 0) {
			fill_laplacian_matrix(sys);
		}

		if (EIG_linear_solver_solve(sys->context)) {
			validate_solution(sys, smd->flag, smd->lambda, smd->lambda_border);
		}
	}
	EIG_linear_solver_delete(sys->context);
	sys->context = NULL;

	delete_laplacian_system(sys);
}