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;

			nlMatrixAdd(idv[0], idv[1], -w2);
			nlMatrixAdd(idv[0], idv[2], -w3);
			nlMatrixAdd(idv[0], idv[0], w2 + w3);
		}
	}
}
static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
{
	float t1, t2, t3, len1, len2, len3, area;
	float *varea = sys->varea, *v1, *v2, *v3;
	int obtuse = 0;

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

	t1 = cotangent_tri_weight_v3(v1, v2, v3);
	t2 = cotangent_tri_weight_v3(v2, v3, v1);
	t3 = cotangent_tri_weight_v3(v3, v1, v2);

	if      (angle_v3v3v3(v2, v1, v3) > DEG2RADF(90.0f)) obtuse = 1;
	else if (angle_v3v3v3(v1, v2, v3) > DEG2RADF(90.0f)) obtuse = 2;
	else if (angle_v3v3v3(v1, v3, v2) > DEG2RADF(90.0f)) obtuse = 3;

	if (obtuse > 0) {
		area = area_tri_v3(v1, v2, v3);

		varea[i1] += (obtuse == 1) ? area : area * 0.5f;
		varea[i2] += (obtuse == 2) ? area : area * 0.5f;
		varea[i3] += (obtuse == 3) ? area : area * 0.5f;
	}
	else {
		len1 = len_v3v3(v2, v3);
		len2 = len_v3v3(v1, v3);
		len3 = len_v3v3(v1, v2);

		t1 *= len1 * len1;
		t2 *= len2 * len2;
		t3 *= len3 * len3;

		varea[i1] += (t2 + t3) * 0.25f;
		varea[i2] += (t1 + t3) * 0.25f;
		varea[i3] += (t1 + t2) * 0.25f;
	}
}
static void fill_laplacian_matrix(LaplacianSystem *sys)
{
	float *v1, *v2, *v3, *v4;
	float w2, w3, w4;
	int i, j;
	bool has_4_vert;
	unsigned int idv1, idv2, idv3, idv4, idv[4];

	for (i = 0; i < sys->numFaces; i++) {
		idv1 = sys->mfaces[i].v1;
		idv2 = sys->mfaces[i].v2;
		idv3 = sys->mfaces[i].v3;
		has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0;

		if (has_4_vert) {
			idv[0] = sys->mfaces[i].v1;
			idv[1] = sys->mfaces[i].v2;
			idv[2] = sys->mfaces[i].v3;
			idv[3] = sys->mfaces[i].v4;
			for (j = 0; j < 4; j++) {
				idv1 = idv[j];
				idv2 = idv[(j + 1) % 4];
				idv3 = idv[(j + 2) % 4];
				idv4 = idv[(j + 3) % 4];

				v1 = sys->vertexCos[idv1];
				v2 = sys->vertexCos[idv2];
				v3 = sys->vertexCos[idv3];
				v4 = sys->vertexCos[idv4];

				w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2);
				w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3);
				w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1);

				w2 = w2 / 4.0f;
				w3 = w3 / 4.0f;
				w4 = w4 / 4.0f;

				if (sys->numNeEd[idv1] == sys->numNeFa[idv1] && sys->zerola[idv1] == 0) {
					nlMatrixAdd(idv1, idv2, w2 * sys->vweights[idv1]);
					nlMatrixAdd(idv1, idv3, w3 * sys->vweights[idv1]);
					nlMatrixAdd(idv1, idv4, w4 * sys->vweights[idv1]);
				}
			}
		}
		else {
			/* Is ring if number of faces == number of edges around vertice*/
			if (sys->numNeEd[idv1] == sys->numNeFa[idv1] && sys->zerola[idv1] == 0) {
				nlMatrixAdd(idv1, idv2, sys->fweights[i][2] * sys->vweights[idv1]);
				nlMatrixAdd(idv1, idv3, sys->fweights[i][1] * sys->vweights[idv1]);
			}
			if (sys->numNeEd[idv2] == sys->numNeFa[idv2] && sys->zerola[idv2] == 0) {
				nlMatrixAdd(idv2, idv1, sys->fweights[i][2] * sys->vweights[idv2]);
				nlMatrixAdd(idv2, idv3, sys->fweights[i][0] * sys->vweights[idv2]);
			}
			if (sys->numNeEd[idv3] == sys->numNeFa[idv3] && sys->zerola[idv3] == 0) {
				nlMatrixAdd(idv3, idv1, sys->fweights[i][1] * sys->vweights[idv3]);
				nlMatrixAdd(idv3, idv2, sys->fweights[i][0] * sys->vweights[idv3]);
			}
		}
	}

	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)
		{
			nlMatrixAdd(idv1, idv2, sys->eweights[i] * sys->vlengths[idv1]);
			nlMatrixAdd(idv2, idv1, sys->eweights[i] * sys->vlengths[idv2]);
		}
	}
}
static void init_laplacian_matrix(LaplacianSystem *sys)
{
	float *v1, *v2, *v3, *v4;
	float w1, w2, w3, w4;
	float areaf;
	int i, j;
	unsigned int idv1, idv2, idv3, idv4, idv[4];
	bool has_4_vert;
	for (i = 0; i < sys->numEdges; i++) {
		idv1 = sys->medges[i].v1;
		idv2 = sys->medges[i].v2;

		v1 = sys->vertexCos[idv1];
		v2 = sys->vertexCos[idv2];

		sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1;
		sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1;
		w1 = len_v3v3(v1, v2);
		if (w1 < sys->min_area) {
			sys->zerola[idv1] = 1;
			sys->zerola[idv2] = 1;
		}
		else {
			w1 = 1.0f / w1;
		}

		sys->eweights[i] = w1;
	}
	for (i = 0; i < sys->numFaces; i++) {
		has_4_vert = ((&sys->mfaces[i])->v4) ? 1 : 0;

		idv1 = sys->mfaces[i].v1;
		idv2 = sys->mfaces[i].v2;
		idv3 = sys->mfaces[i].v3;
		idv4 = has_4_vert ? sys->mfaces[i].v4 : 0;

		sys->numNeFa[idv1] += 1;
		sys->numNeFa[idv2] += 1;
		sys->numNeFa[idv3] += 1;
		if (has_4_vert) sys->numNeFa[idv4] += 1;

		v1 = sys->vertexCos[idv1];
		v2 = sys->vertexCos[idv2];
		v3 = sys->vertexCos[idv3];
		v4 = has_4_vert ? sys->vertexCos[idv4] : NULL;

		if (has_4_vert) {
			areaf = area_quad_v3(v1, v2, v3, sys->vertexCos[sys->mfaces[i].v4]);
		}
		else {
			areaf = area_tri_v3(v1, v2, v3);
		}
		if (fabsf(areaf) < sys->min_area) {
			sys->zerola[idv1] = 1;
			sys->zerola[idv2] = 1;
			sys->zerola[idv3] = 1;
			if (has_4_vert) sys->zerola[idv4] = 1;
		}

		if (has_4_vert) {
			sys->ring_areas[idv1] += average_area_quad_v3(v1, v2, v3, v4);
			sys->ring_areas[idv2] += average_area_quad_v3(v2, v3, v4, v1);
			sys->ring_areas[idv3] += average_area_quad_v3(v3, v4, v1, v2);
			sys->ring_areas[idv4] += average_area_quad_v3(v4, v1, v2, v3);
		}
		else {
			sys->ring_areas[idv1] += areaf;
			sys->ring_areas[idv2] += areaf;
			sys->ring_areas[idv3] += areaf;
		}

		if (has_4_vert) {

			idv[0] = idv1;
			idv[1] = idv2;
			idv[2] = idv3;
			idv[3] = idv4;

			for (j = 0; j < 4; j++) {
				idv1 = idv[j];
				idv2 = idv[(j + 1) % 4];
				idv3 = idv[(j + 2) % 4];
				idv4 = idv[(j + 3) % 4];

				v1 = sys->vertexCos[idv1];
				v2 = sys->vertexCos[idv2];
				v3 = sys->vertexCos[idv3];
				v4 = sys->vertexCos[idv4];

				w2 = cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2);
				w3 = cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3);
				w4 = cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1);

				sys->vweights[idv1] += (w2 + w3 + w4) / 4.0f;
			}
		}
		else {
			w1 = cotangent_tri_weight_v3(v1, v2, v3) / 2.0f;
			w2 = cotangent_tri_weight_v3(v2, v3, v1) / 2.0f;
			w3 = cotangent_tri_weight_v3(v3, v1, v2) / 2.0f;

			sys->fweights[i][0] = sys->fweights[i][0] + w1;
			sys->fweights[i][1] = sys->fweights[i][1] + w2;
			sys->fweights[i][2] = sys->fweights[i][2] + w3;

			sys->vweights[idv1] = sys->vweights[idv1] + w2 + w3;
			sys->vweights[idv2] = sys->vweights[idv2] + w1 + w3;
			sys->vweights[idv3] = sys->vweights[idv3] + w1 + w2;
		}
	}
	for (i = 0; i < sys->numEdges; i++) {
		idv1 = sys->medges[i].v1;
		idv2 = sys->medges[i].v2;
		/* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */
		if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) {
			sys->vlengths[idv1] += sys->eweights[i];
			sys->vlengths[idv2] += sys->eweights[i];
		}
	}

}
/**
 * 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 v1[3], v2[3], v3[3], v4[3], no[3];
	float w2, w3, w4;
	int i, j, fi;
	bool has_4_vert;
	unsigned int idv1, idv2, idv3, idv4;

	for (fi = 0; fi < sys->total_faces; fi++) {
		const unsigned int *vidf = sys->faces[fi];

		idv1 = vidf[0];
		idv2 = vidf[1];
		idv3 = vidf[2];
		idv4 = vidf[3];

		has_4_vert = vidf[3] ? 1 : 0;
		if (has_4_vert) {
			normal_quad_v3(no, sys->co[idv1], sys->co[idv2], sys->co[idv3], sys->co[idv4]);
			add_v3_v3(sys->no[idv4], no);
			i = 4;
		}
		else {
			normal_tri_v3(no, sys->co[idv1], sys->co[idv2], sys->co[idv3]);
			i = 3;
		}
		add_v3_v3(sys->no[idv1], no);
		add_v3_v3(sys->no[idv2], no);
		add_v3_v3(sys->no[idv3], no);

		for (j = 0; j < i; j++) {
			idv1 = vidf[j];
			idv2 = vidf[(j + 1) % i];
			idv3 = vidf[(j + 2) % i];
			idv4 = has_4_vert ? vidf[(j + 3) % i] : 0;

			copy_v3_v3(v1, sys->co[idv1]);
			copy_v3_v3(v2, sys->co[idv2]);
			copy_v3_v3(v3, sys->co[idv3]);
			if (has_4_vert) {
				copy_v3_v3(v4, sys->co[idv4]);
			}

			if (has_4_vert) {

				w2 = (cotangent_tri_weight_v3(v4, v1, v2) + cotangent_tri_weight_v3(v3, v1, v2)) / 2.0f;
				w3 = (cotangent_tri_weight_v3(v2, v3, v1) + cotangent_tri_weight_v3(v4, v1, v3)) / 2.0f;
				w4 = (cotangent_tri_weight_v3(v2, v4, v1) + cotangent_tri_weight_v3(v3, v4, v1)) / 2.0f;

				sys->delta[idv1][0] -= v4[0] * w4;
				sys->delta[idv1][1] -= v4[1] * w4;
				sys->delta[idv1][2] -= v4[2] * w4;

				nlRightHandSideAdd(0, idv1, -v4[0] * w4);
				nlRightHandSideAdd(1, idv1, -v4[1] * w4);
				nlRightHandSideAdd(2, idv1, -v4[2] * w4);

				nlMatrixAdd(idv1, idv4, -w4);
			}
			else {
				w2 = cotangent_tri_weight_v3(v3, v1, v2);
				w3 = cotangent_tri_weight_v3(v2, v3, v1);
				w4 = 0.0f;
			}

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

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

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

			nlMatrixAdd(idv1, idv2, -w2);
			nlMatrixAdd(idv1, idv3, -w3);
			nlMatrixAdd(idv1, idv1, w2 + w3 + w4);

		}
	}
}
Example #7
0
static void init_laplacian_matrix(LaplacianSystem *sys)
{
	float *v1, *v2;
	float w1, w2, w3;
	float areaf;
	int i;
	unsigned int idv1, idv2;

	for (i = 0; i < sys->numEdges; i++) {
		idv1 = sys->medges[i].v1;
		idv2 = sys->medges[i].v2;

		v1 = sys->vertexCos[idv1];
		v2 = sys->vertexCos[idv2];

		sys->numNeEd[idv1] = sys->numNeEd[idv1] + 1;
		sys->numNeEd[idv2] = sys->numNeEd[idv2] + 1;
		w1 = len_v3v3(v1, v2);
		if (w1 < sys->min_area) {
			sys->zerola[idv1] = 1;
			sys->zerola[idv2] = 1;
		}
		else {
			w1 = 1.0f / w1;
		}

		sys->eweights[i] = w1;
	}

	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 float *v_prev = sys->vertexCos[l_prev->v];
			const float *v_curr = sys->vertexCos[l_curr->v];
			const float *v_next = sys->vertexCos[l_next->v];
			const unsigned int l_curr_index = l_curr - sys->mloop;

			sys->numNeFa[l_curr->v] += 1;

			areaf = area_tri_v3(v_prev, v_curr, v_next);

			if (areaf < sys->min_area) {
				sys->zerola[l_curr->v] = 1;
			}

			sys->ring_areas[l_prev->v] += areaf;
			sys->ring_areas[l_curr->v] += areaf;
			sys->ring_areas[l_next->v] += areaf;

			w1 = cotangent_tri_weight_v3(v_curr, v_next, v_prev) / 2.0f;
			w2 = cotangent_tri_weight_v3(v_next, v_prev, v_curr) / 2.0f;
			w3 = cotangent_tri_weight_v3(v_prev, v_curr, v_next) / 2.0f;

			sys->fweights[l_curr_index][0] += w1;
			sys->fweights[l_curr_index][1] += w2;
			sys->fweights[l_curr_index][2] += w3;

			sys->vweights[l_curr->v] += w2 + w3;
			sys->vweights[l_next->v] += w1 + w3;
			sys->vweights[l_prev->v] += w1 + w2;
		}
	}
	for (i = 0; i < sys->numEdges; i++) {
		idv1 = sys->medges[i].v1;
		idv2 = sys->medges[i].v2;
		/* if is boundary, apply scale-dependent umbrella operator only with neighboors in boundary */
		if (sys->numNeEd[idv1] != sys->numNeFa[idv1] && sys->numNeEd[idv2] != sys->numNeFa[idv2]) {
			sys->vlengths[idv1] += sys->eweights[i];
			sys->vlengths[idv2] += sys->eweights[i];
		}
	}

}