コード例 #1
0
static void hook_co_apply(struct HookData_cb *hd, const int j)
{
	float *co = hd->vertexCos[j];
	float fac;

	if (hd->use_falloff) {
		float len_sq;

		if (hd->use_uniform) {
			float co_uniform[3];
			mul_v3_m3v3(co_uniform, hd->mat_uniform, co);
			len_sq = len_squared_v3v3(hd->cent, co_uniform);
		}
		else {
			len_sq = len_squared_v3v3(hd->cent, co);
		}

		fac = hook_falloff(hd, len_sq);
	}
	else {
		fac = hd->fac_orig;
	}

	if (fac) {
		if (hd->dvert) {
			fac *= defvert_find_weight(&hd->dvert[j], hd->defgrp_index);
		}

		if (fac) {
			float co_tmp[3];
			mul_v3_m4v3(co_tmp, hd->mat, co);
			interp_v3_v3v3(co, co, co_tmp, fac);
		}
	}
}
コード例 #2
0
ファイル: BLI_kdopbvh.c プロジェクト: nttputus/blensor
//Determines the nearest point of the given node BV. Returns the squared distance to that point.
static float calc_nearest_point(const float proj[3], BVHNode *node, float *nearest)
{
	int i;
	const float *bv = node->bv;

	//nearest on AABB hull
	for (i=0; i != 3; i++, bv += 2) {
		if (bv[0] > proj[i])
			nearest[i] = bv[0];
		else if (bv[1] < proj[i])
			nearest[i] = bv[1];
		else
			nearest[i] = proj[i]; 
	}

#if 0
	//nearest on a general hull
	copy_v3_v3(nearest, data->co);
	for (i = data->tree->start_axis; i != data->tree->stop_axis; i++, bv+=2)
	{
		float proj = dot_v3v3( nearest, KDOP_AXES[i]);
		float dl = bv[0] - proj;
		float du = bv[1] - proj;

		if (dl > 0) {
			madd_v3_v3fl(nearest, KDOP_AXES[i], dl);
		}
		else if (du < 0) {
			madd_v3_v3fl(nearest, KDOP_AXES[i], du);
		}
	}
#endif

	return len_squared_v3v3(proj, nearest);
}
コード例 #3
0
ファイル: bvhutils.c プロジェクト: kujira70/Blender
/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_faces.
 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
	const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
	const MVert *vert = data->vert;
	const MFace *face = data->face + index;

	const float *t0, *t1, *t2, *t3;
	t0 = vert[face->v1].co;
	t1 = vert[face->v2].co;
	t2 = vert[face->v3].co;
	t3 = face->v4 ? vert[face->v4].co : NULL;

	
	do {
		float nearest_tmp[3], dist_sq;

		closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
		dist_sq = len_squared_v3v3(co, nearest_tmp);

		if (dist_sq < nearest->dist_sq) {
			nearest->index = index;
			nearest->dist_sq = dist_sq;
			copy_v3_v3(nearest->co, nearest_tmp);
			normal_tri_v3(nearest->no, t0, t1, t2);
		}

		t1 = t2;
		t2 = t3;
		t3 = NULL;

	} while (t2);
}
コード例 #4
0
ファイル: editmesh_bvh.c プロジェクト: DrangPo/blender
static bool bmbvh_overlap_cb(void *userdata, int index_a, int index_b, int UNUSED(thread))
{
	struct BMBVHTree_OverlapData *data = userdata;
	const BMBVHTree *bmtree_a = data->tree_pair[0];
	const BMBVHTree *bmtree_b = data->tree_pair[1];

	BMLoop **tri_a = bmtree_a->looptris[index_a];
	BMLoop **tri_b = bmtree_b->looptris[index_b];
	const float *tri_a_co[3] = {tri_a[0]->v->co, tri_a[1]->v->co, tri_a[2]->v->co};
	const float *tri_b_co[3] = {tri_b[0]->v->co, tri_b[1]->v->co, tri_b[2]->v->co};
	float ix_pair[2][3];
	int verts_shared = 0;

	if (bmtree_a->looptris == bmtree_b->looptris) {
		if (UNLIKELY(tri_a[0]->f == tri_b[0]->f)) {
			return false;
		}

		verts_shared = (
		        ELEM(tri_a_co[0], UNPACK3(tri_b_co)) +
		        ELEM(tri_a_co[1], UNPACK3(tri_b_co)) +
		        ELEM(tri_a_co[2], UNPACK3(tri_b_co)));

		/* if 2 points are shared, bail out */
		if (verts_shared >= 2) {
			return false;
		}
	}

	return (isect_tri_tri_epsilon_v3(UNPACK3(tri_a_co), UNPACK3(tri_b_co), ix_pair[0], ix_pair[1], data->epsilon) &&
	        /* if we share a vertex, check the intersection isn't a 'point' */
	        ((verts_shared == 0) || (len_squared_v3v3(ix_pair[0], ix_pair[1]) > data->epsilon)));
}
コード例 #5
0
ファイル: bvhutils.c プロジェクト: kujira70/Blender
/* copy of function above (warning, should de-duplicate with editmesh_bvh.c) */
static void editmesh_faces_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
	const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
	BMEditMesh *em = data->em_evil;
	const BMLoop **ltri = (const BMLoop **)em->looptris[index];

	const float *t0, *t1, *t2;
	t0 = ltri[0]->v->co;
	t1 = ltri[1]->v->co;
	t2 = ltri[2]->v->co;

	{
		float nearest_tmp[3], dist_sq;

		closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
		dist_sq = len_squared_v3v3(co, nearest_tmp);

		if (dist_sq < nearest->dist_sq) {
			nearest->index = index;
			nearest->dist_sq = dist_sq;
			copy_v3_v3(nearest->co, nearest_tmp);
			normal_tri_v3(nearest->no, t0, t1, t2);
		}
	}
}
コード例 #6
0
ファイル: BLI_kdtree.c プロジェクト: bdancer/blender-for-vray
/**
 * A version of #BLI_kdtree_range_search which runs a callback
 * instead of allocating an array.
 *
 * \param search_cb: Called for every node found in \a range, false return value performs an early exit.
 *
 * \note the order of calls isn't sorted based on distance.
 */
void BLI_kdtree_range_search_cb(
        const KDTree *tree, const float co[3], float range,
        bool (*search_cb)(void *user_data, int index, const float co[3], float dist_sq), void *user_data)
{
	const KDTreeNode *nodes = tree->nodes;

	uint *stack, defaultstack[KD_STACK_INIT];
	float range_sq = range * range, dist_sq;
	uint totstack, cur = 0;

#ifdef DEBUG
	BLI_assert(tree->is_balanced == true);
#endif

	if (UNLIKELY(tree->root == KD_NODE_UNSET))
		return;

	stack = defaultstack;
	totstack = KD_STACK_INIT;

	stack[cur++] = tree->root;

	while (cur--) {
		const KDTreeNode *node = &nodes[stack[cur]];

		if (co[node->d] + range < node->co[node->d]) {
			if (node->left != KD_NODE_UNSET)
				stack[cur++] = node->left;
		}
		else if (co[node->d] - range > node->co[node->d]) {
			if (node->right != KD_NODE_UNSET)
				stack[cur++] = node->right;
		}
		else {
			dist_sq = len_squared_v3v3(node->co, co);
			if (dist_sq <= range_sq) {
				if (search_cb(user_data, node->index, node->co, dist_sq) == false) {
					goto finally;
				}
			}

			if (node->left != KD_NODE_UNSET)
				stack[cur++] = node->left;
			if (node->right != KD_NODE_UNSET)
				stack[cur++] = node->right;
		}

		if (UNLIKELY(cur + 3 > totstack)) {
			stack = realloc_nodes(stack, &totstack, defaultstack != stack);
		}
	}

finally:
	if (stack != defaultstack)
		MEM_freeN(stack);
}
コード例 #7
0
void BLI_removeDoubleNodes(BGraph *graph, float limit)
{
	const float limit_sq = limit * limit;
	BNode *node_src, *node_replaced;
	
	for (node_src = graph->nodes.first; node_src; node_src = node_src->next) {
		for (node_replaced = graph->nodes.first; node_replaced; node_replaced = node_replaced->next) {
			if (node_replaced != node_src && len_squared_v3v3(node_replaced->p, node_src->p) <= limit_sq) {
				BLI_replaceNode(graph, node_src, node_replaced);
			}
		}
	}
	
}
コード例 #8
0
static float hook_falloff(float *co_1, float *co_2, const float falloff_squared, float fac)
{
	if(falloff_squared) {
		float len_squared = len_squared_v3v3(co_1, co_2);
		if(len_squared > falloff_squared) {
			return 0.0f;
		}
		else if(len_squared > 0.0) {
			return fac * (1.0 - (len_squared / falloff_squared));
		}
	}

	return fac;
}
コード例 #9
0
BNode *BLI_FindNodeByPosition(BGraph *graph, const float p[3], const float limit)
{
	const float limit_sq = limit * limit;
	BNode *closest_node = NULL, *node;
	float min_distance = 0.0f;
	
	for (node = graph->nodes.first; node; node = node->next) {
		float distance = len_squared_v3v3(p, node->p);
		if (distance <= limit_sq && (closest_node == NULL || distance < min_distance)) {
			closest_node = node;
			min_distance = distance;
		}
	}
	
	return closest_node;
}
コード例 #10
0
static void testAxialSymmetry(BGraph *graph, BNode *root_node, BNode *node1, BNode *node2, BArc *arc1, BArc *arc2, float axis[3], float limit, int group)
{
	const float limit_sq = limit * limit;
	float nor[3], vec[3], p[3];

	sub_v3_v3v3(p, node1->p, root_node->p);
	cross_v3_v3v3(nor, p, axis);

	sub_v3_v3v3(p, root_node->p, node2->p);
	cross_v3_v3v3(vec, p, axis);
	add_v3_v3(vec, nor);
	
	cross_v3_v3v3(nor, vec, axis);
	
	if (fabsf(nor[0]) > fabsf(nor[1]) && fabsf(nor[0]) > fabsf(nor[2]) && nor[0] < 0) {
		negate_v3(nor);
	}
	else if (fabsf(nor[1]) > fabsf(nor[0]) && fabsf(nor[1]) > fabsf(nor[2]) && nor[1] < 0) {
		negate_v3(nor);
	}
	else if (fabsf(nor[2]) > fabsf(nor[1]) && fabsf(nor[2]) > fabsf(nor[0]) && nor[2] < 0) {
		negate_v3(nor);
	}
	
	/* mirror node2 along axis */
	copy_v3_v3(p, node2->p);
	BLI_mirrorAlongAxis(p, root_node->p, nor);
	
	/* check if it's within limit before continuing */
	if (len_squared_v3v3(node1->p, p) <= limit_sq) {
		/* mark node as symmetric physically */
		copy_v3_v3(root_node->symmetry_axis, nor);
		root_node->symmetry_flag |= SYM_PHYSICAL;
		root_node->symmetry_flag |= SYM_AXIAL;

		/* flag side on arcs */
		flagAxialSymmetry(root_node, node1, arc1, group);
		flagAxialSymmetry(root_node, node2, arc2, group);
		
		if (graph->axial_symmetry) {
			graph->axial_symmetry(root_node, node1, node2, arc1, arc2);
		}
	}
	else {
		/* NOT SYMMETRIC */
	}
}
コード例 #11
0
ファイル: editmesh_bvh.c プロジェクト: DrangPo/blender
static void bmbvh_find_face_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
{
	struct FaceSearchUserData *bmcb_data = userdata;
	const BMLoop **ltri = bmcb_data->looptris[index];
	const float dist_max_sq = bmcb_data->dist_max_sq;

	const float *tri_cos[3];

	bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);

	float co_close[3];
	closest_on_tri_to_point_v3(co_close, co, UNPACK3(tri_cos));
	const float dist_sq = len_squared_v3v3(co, co_close);
	if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
		/* XXX, normal ignores cage */
		copy_v3_v3(hit->no, ltri[0]->f->no);
		hit->dist_sq = dist_sq;
		hit->index = index;
	}
}
コード例 #12
0
ファイル: bvhutils.c プロジェクト: kujira70/Blender
/* Callback to bvh tree raycast. The tree must have been built using bvhtree_from_mesh_edges.
 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_edges_spherecast(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
	const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
	const MVert *vert = data->vert;
	const MEdge *edge = &data->edge[index];

	const float radius_sq = SQUARE(data->sphere_radius);
	float dist;
	const float *v1, *v2, *r1;
	float r2[3], i1[3], i2[3];
	v1 = vert[edge->v1].co;
	v2 = vert[edge->v2].co;

	/* In case we get a zero-length edge, handle it as a point! */
	if (equals_v3v3(v1, v2)) {
		mesh_verts_spherecast_do(data, index, v1, ray, hit);
		return;
	}

	r1 = ray->origin;
	add_v3_v3v3(r2, r1, ray->direction);

	if (isect_line_line_v3(v1, v2, r1, r2, i1, i2)) {
		/* No hit if intersection point is 'behind' the origin of the ray, or too far away from it. */
		if ((dot_v3v3v3(r1, i2, r2) >= 0.0f) && ((dist = len_v3v3(r1, i2)) < hit->dist)) {
			const float e_fac = line_point_factor_v3(i1, v1, v2);
			if (e_fac < 0.0f) {
				copy_v3_v3(i1, v1);
			}
			else if (e_fac > 1.0f) {
				copy_v3_v3(i1, v2);
			}
			/* Ensure ray is really close enough from edge! */
			if (len_squared_v3v3(i1, i2) <= radius_sq) {
				hit->index = index;
				hit->dist = dist;
				copy_v3_v3(hit->co, i2);
			}
		}
	}
}
コード例 #13
0
ファイル: bvhutils.c プロジェクト: kujira70/Blender
/* Callback to bvh tree nearest point. The tree must have been built using bvhtree_from_mesh_edges.
 * userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree. */
static void mesh_edges_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
	const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
	const MVert *vert = data->vert;
	const MEdge *edge = data->edge + index;
	float nearest_tmp[3], dist_sq;

	const float *t0, *t1;
	t0 = vert[edge->v1].co;
	t1 = vert[edge->v2].co;

	closest_to_line_segment_v3(nearest_tmp, co, t0, t1);
	dist_sq = len_squared_v3v3(nearest_tmp, co);
	
	if (dist_sq < nearest->dist_sq) {
		nearest->index = index;
		nearest->dist_sq = dist_sq;
		copy_v3_v3(nearest->co, nearest_tmp);
		sub_v3_v3v3(nearest->no, t0, t1);
		normalize_v3(nearest->no);
	}
}
コード例 #14
0
ファイル: bvhutils.c プロジェクト: kujira70/Blender
/* copy of function above */
static void mesh_looptri_nearest_point(void *userdata, int index, const float co[3], BVHTreeNearest *nearest)
{
	const BVHTreeFromMesh *data = (BVHTreeFromMesh *) userdata;
	const MVert *vert = data->vert;
	const MLoopTri *lt = &data->looptri[index];
	const float *vtri_co[3] = {
	    vert[data->loop[lt->tri[0]].v].co,
	    vert[data->loop[lt->tri[1]].v].co,
	    vert[data->loop[lt->tri[2]].v].co,
	};
	float nearest_tmp[3], dist_sq;

	closest_on_tri_to_point_v3(nearest_tmp, co, UNPACK3(vtri_co));
	dist_sq = len_squared_v3v3(co, nearest_tmp);

	if (dist_sq < nearest->dist_sq) {
		nearest->index = index;
		nearest->dist_sq = dist_sq;
		copy_v3_v3(nearest->co, nearest_tmp);
		normal_tri_v3(nearest->no, UNPACK3(vtri_co));
	}
}
コード例 #15
0
ファイル: bmesh_intersect.c プロジェクト: LucaRood/Blender
static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base)
{
	/* not optimal but list will be typically < 5 */
	unsigned int i;
	struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
	LinkNode *node;

	BLI_assert(v_ls_base->list_len > 1);

	for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
		BMVert *v = node->link;
		BLI_assert(v->head.htype == BM_VERT);
		vert_sort[i].val = len_squared_v3v3(co, v->co);
		vert_sort[i].v   = v;
	}

	qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float);

	for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
		node->link = vert_sort[i].v;
	}
}
コード例 #16
0
/**
 * Callback used by BLI_task 'for loop' helper.
 */
static void vert2geom_task_cb(void *userdata, void *userdata_chunk, int iter)
{
	Vert2GeomData *data = userdata;
	Vert2GeomDataChunk *data_chunk = userdata_chunk;

	float tmp_co[3];
	int i;

	/* Convert the vertex to tree coordinates. */
	copy_v3_v3(tmp_co, data->v_cos[iter]);
	BLI_space_transform_apply(data->loc2trgt, tmp_co);

	for (i = 0; i < ARRAY_SIZE(data->dist); i++) {
		if (data->dist[i]) {
			BVHTreeNearest nearest = {0};

			/* Note that we use local proximity heuristics (to reduce the nearest search).
			 *
			 * If we already had an hit before in same chunk of tasks (i.e. previous vertex by index),
			 * we assume this vertex is going to have a close hit to that other vertex, so we can initiate
			 * the "nearest.dist" with the expected value to that last hit.
			 * This will lead in pruning of the search tree.
			 */
			nearest.dist_sq = data_chunk->is_init[i] ? len_squared_v3v3(tmp_co, data_chunk->last_hit_co[i]) : FLT_MAX;
			nearest.index = -1;

			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(data->treeData[i]->tree, tmp_co, &nearest,
			                         data->treeData[i]->nearest_callback, data->treeData[i]);
			data->dist[i][iter] = sqrtf(nearest.dist_sq);

			if (nearest.index != -1) {
				copy_v3_v3(data_chunk->last_hit_co[i], nearest.co);
				data_chunk->is_init[i] = true;
			}
		}
	}
}
コード例 #17
0
static void bmbvh_find_vert_closest_cb(void *userdata, int index, const float co[3], BVHTreeNearest *hit)
{
	struct VertSearchUserData *bmcb_data = userdata;
	const BMLoop **ltri = bmcb_data->looptris[index];
	const float dist_max_sq = bmcb_data->dist_max_sq;
	int i;

	const float *tri_cos[3];

	bmbvh_tri_from_face(tri_cos, ltri, bmcb_data->cos_cage);

	for (i = 0; i < 3; i++) {
		const float dist_sq = len_squared_v3v3(co, tri_cos[i]);
		if (dist_sq < hit->dist_sq && dist_sq < dist_max_sq) {
			copy_v3_v3(hit->co, tri_cos[i]);
			/* XXX, normal ignores cage */
			copy_v3_v3(hit->no, ltri[i]->v->no);
			hit->dist_sq = dist_sq;
			hit->index = index;
			bmcb_data->index_tri = i;
		}
	}
}
コード例 #18
0
ファイル: bvhutils.c プロジェクト: OldBrunet/BGERTPS
// Callback to bvh tree nearest point. The tree must bust have been built using bvhtree_from_mesh_edges.
// userdata must be a BVHMeshCallbackUserdata built from the same mesh as the tree.
static void mesh_edges_nearest_point(void *userdata, int index, const float *co, BVHTreeNearest *nearest)
{
	const BVHTreeFromMesh *data = (BVHTreeFromMesh*) userdata;
	MVert *vert	= data->vert;
	MEdge *edge = data->edge + index;
	float nearest_tmp[3], dist;

	float *t0, *t1;
	t0 = vert[ edge->v1 ].co;
	t1 = vert[ edge->v2 ].co;
	
	// NOTE: casts to "float*" here are due to co being "const float*"
	closest_to_line_segment_v3(nearest_tmp, (float*)co, t0, t1);
	dist = len_squared_v3v3(nearest_tmp, (float*)co);
	
	if(dist < nearest->dist)
	{
		nearest->index = index;
		nearest->dist = dist;
		VECCOPY(nearest->co, nearest_tmp);
		sub_v3_v3v3(nearest->no, t0, t1);
		normalize_v3(nearest->no);
	}
}
コード例 #19
0
ファイル: shrinkwrap.c プロジェクト: Walid-Shouman/Blender
static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for_render)
{
	int i;

	/* Options about projection direction */
	const float proj_limit_squared = calc->smd->projLimit * calc->smd->projLimit;
	float proj_axis[3]      = {0.0f, 0.0f, 0.0f};

	/* Raycast and tree stuff */

	/** \note 'hit.dist' is kept in the targets space, this is only used
	 * for finding the best hit, to get the real dist,
	 * measure the len_v3v3() from the input coord to hit.co */
	BVHTreeRayHit hit;
	BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;

	/* auxiliary target */
	DerivedMesh *auxMesh    = NULL;
	BVHTreeFromMesh auxData = NULL_BVHTreeFromMesh;
	SpaceTransform local2aux;

	/* If the user doesn't allows to project in any direction of projection axis
	 * then theres nothing todo. */
	if ((calc->smd->shrinkOpts & (MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR | MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR)) == 0)
		return;


	/* Prepare data to retrieve the direction in which we should project each vertex */
	if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
		if (calc->vert == NULL) return;
	}
	else {
		/* The code supports any axis that is a combination of X,Y,Z
		 * although currently UI only allows to set the 3 different axis */
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_X_AXIS) proj_axis[0] = 1.0f;
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Y_AXIS) proj_axis[1] = 1.0f;
		if (calc->smd->projAxis & MOD_SHRINKWRAP_PROJECT_OVER_Z_AXIS) proj_axis[2] = 1.0f;

		normalize_v3(proj_axis);

		/* Invalid projection direction */
		if (len_squared_v3(proj_axis) < FLT_EPSILON) {
			return;
		}
	}

	if (calc->smd->auxTarget) {
		auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render);
		if (!auxMesh)
			return;
		SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
	}

	/* After sucessufuly build the trees, start projection vertexs */
	if (bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 4, 6) &&
	    (auxMesh == NULL || bvhtree_from_mesh_faces(&auxData, auxMesh, 0.0, 4, 6)))
	{

#ifndef __APPLE__
#pragma omp parallel for private(i, hit) schedule(static)
#endif
		for (i = 0; i < calc->numVerts; ++i) {
			float *co = calc->vertexCos[i];
			float tmp_co[3], tmp_no[3];
			const float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);

			if (weight == 0.0f) {
				continue;
			}

			if (calc->vert) {
				/* calc->vert contains verts from derivedMesh  */
				/* this coordinated are deformed by vertexCos only for normal projection (to get correct normals) */
				/* for other cases calc->varts contains undeformed coordinates and vertexCos should be used */
				if (calc->smd->projAxis == MOD_SHRINKWRAP_PROJECT_OVER_NORMAL) {
					copy_v3_v3(tmp_co, calc->vert[i].co);
					normal_short_to_float_v3(tmp_no, calc->vert[i].no);
				}
				else {
					copy_v3_v3(tmp_co, co);
					copy_v3_v3(tmp_no, proj_axis);
				}
			}
			else {
				copy_v3_v3(tmp_co, co);
				copy_v3_v3(tmp_no, proj_axis);
			}


			hit.index = -1;
			hit.dist = 10000.0f; /* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */

			/* Project over positive direction of axis */
			if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR) {

				if (auxData.tree) {
					BKE_shrinkwrap_project_normal(0, tmp_co, tmp_no,
					                              &local2aux, auxData.tree, &hit,
					                              auxData.raycast_callback, &auxData);
				}

				BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, tmp_no,
				                              &calc->local2target, treeData.tree, &hit,
				                              treeData.raycast_callback, &treeData);
			}

			/* Project over negative direction of axis */
			if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_PROJECT_ALLOW_NEG_DIR) {
				float inv_no[3];
				negate_v3_v3(inv_no, tmp_no);

				if (auxData.tree) {
					BKE_shrinkwrap_project_normal(0, tmp_co, inv_no,
					                              &local2aux, auxData.tree, &hit,
					                              auxData.raycast_callback, &auxData);
				}

				BKE_shrinkwrap_project_normal(calc->smd->shrinkOpts, tmp_co, inv_no,
				                              &calc->local2target, treeData.tree, &hit,
				                              treeData.raycast_callback, &treeData);
			}

			/* don't set the initial dist (which is more efficient),
			 * because its calculated in the targets space, we want the dist in our own space */
			if (proj_limit_squared != 0.0f) {
				if (len_squared_v3v3(hit.co, co) > proj_limit_squared) {
					hit.index = -1;
				}
			}

			if (hit.index != -1) {
				madd_v3_v3v3fl(hit.co, hit.co, tmp_no, calc->keepDist);
				interp_v3_v3v3(co, co, hit.co, weight);
			}
		}
	}

	/* free data structures */
	free_bvhtree_from_mesh(&treeData);
	free_bvhtree_from_mesh(&auxData);
}
コード例 #20
0
ファイル: BPH_mass_spring.cpp プロジェクト: diekev/blender
/* computes where the cloth would be if it were subject to perfectly stiff edges
 * (edge distance constraints) in a lagrangian solver.  then add forces to help
 * guide the implicit solver to that state.  this function is called after
 * collisions*/
static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
{
	Cloth *cloth= clmd->clothObject;
	float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * cloth->mvert_num, "cos cloth_calc_helper_forces");
	float *masses = (float *)MEM_callocN(sizeof(float) * cloth->mvert_num, "cos cloth_calc_helper_forces");
	LinkNode *node;
	ClothSpring *spring;
	ClothVertex *cv;
	int i, steps;
	
	cv = cloth->verts;
	for (i = 0; i < cloth->mvert_num; i++, cv++) {
		copy_v3_v3(cos[i], cv->tx);
		
		if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
			masses[i] = 1e+10;
		}
		else {
			masses[i] = cv->mass;
		}
	}
	
	steps = 55;
	for (i=0; i<steps; i++) {
		for (node=cloth->springs; node; node=node->next) {
			/* ClothVertex *cv1, *cv2; */ /* UNUSED */
			int v1, v2;
			float len, c, l, vec[3];
			
			spring = (ClothSpring *)node->link;
			if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR) 
				continue;
			
			v1 = spring->ij; v2 = spring->kl;
			/* cv1 = cloth->verts + v1; */ /* UNUSED */
			/* cv2 = cloth->verts + v2; */ /* UNUSED */
			len = len_v3v3(cos[v1], cos[v2]);
			
			sub_v3_v3v3(vec, cos[v1], cos[v2]);
			normalize_v3(vec);
			
			c = (len - spring->restlen);
			if (c == 0.0f)
				continue;
			
			l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2]));
			
			mul_v3_fl(vec, -(1.0f / masses[v1]) * l);
			add_v3_v3(cos[v1], vec);
	
			sub_v3_v3v3(vec, cos[v2], cos[v1]);
			normalize_v3(vec);
			
			mul_v3_fl(vec, -(1.0f / masses[v2]) * l);
			add_v3_v3(cos[v2], vec);
		}
	}
	
	cv = cloth->verts;
	for (i = 0; i < cloth->mvert_num; i++, cv++) {
		float vec[3];
		
		/*compute forces*/
		sub_v3_v3v3(vec, cos[i], cv->tx);
		mul_v3_fl(vec, cv->mass*dt*20.0f);
		add_v3_v3(cv->tv, vec);
		//copy_v3_v3(cv->tx, cos[i]);
	}
	
	MEM_freeN(cos);
	MEM_freeN(masses);
	
	return 1;
}
コード例 #21
0
ファイル: armature_edit.c プロジェクト: Ichthyostega/blender
/* bone adding between selected joints */
static int armature_fill_bones_exec(bContext *C, wmOperator *op)
{
	Object *obedit = CTX_data_edit_object(C);
	bArmature *arm = (obedit) ? obedit->data : NULL;
	Scene *scene = CTX_data_scene(C);
	View3D *v3d = CTX_wm_view3d(C);
	ListBase points = {NULL, NULL};
	EditBone *newbone = NULL;
	int count;

	/* sanity checks */
	if (ELEM(NULL, obedit, arm))
		return OPERATOR_CANCELLED;

	/* loop over all bones, and only consider if visible */
	CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
	{
		if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
			fill_add_joint(ebone, 0, &points);
		if (ebone->flag & BONE_TIPSEL)
			fill_add_joint(ebone, 1, &points);
	}
	CTX_DATA_END;

	/* the number of joints determines how we fill:
	 *  1) between joint and cursor (joint=head, cursor=tail)
	 *  2) between the two joints (order is dependent on active-bone/hierarchy)
	 *  3+) error (a smarter method involving finding chains needs to be worked out
	 */
	count = BLI_listbase_count(&points);

	if (count == 0) {
		BKE_report(op->reports, RPT_ERROR, "No joints selected");
		return OPERATOR_CANCELLED;
	}
	else if (count == 1) {
		EditBonePoint *ebp;
		float curs[3];

		/* Get Points - selected joint */
		ebp = points.first;

		/* Get points - cursor (tail) */
		invert_m4_m4(obedit->imat, obedit->obmat);
		mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));

		/* Create a bone */
		newbone = add_points_bone(obedit, ebp->vec, curs);
	}
	else if (count == 2) {
		EditBonePoint *ebp_a, *ebp_b;
		float head[3], tail[3];
		short headtail = 0;

		/* check that the points don't belong to the same bone */
		ebp_a = (EditBonePoint *)points.first;
		ebp_b = ebp_a->next;

		if (((ebp_a->head_owner == ebp_b->tail_owner) && (ebp_a->head_owner != NULL)) ||
		    ((ebp_a->tail_owner == ebp_b->head_owner) && (ebp_a->tail_owner != NULL)))
		{
			BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
			BLI_freelistN(&points);
			return OPERATOR_CANCELLED;
		}

		/* find which one should be the 'head' */
		if ((ebp_a->head_owner && ebp_b->head_owner) || (ebp_a->tail_owner && ebp_b->tail_owner)) {
			/* use active, nice predictable */
			if (arm->act_edbone && ELEM(arm->act_edbone, ebp_a->head_owner, ebp_a->tail_owner)) {
				headtail = 1;
			}
			else if (arm->act_edbone && ELEM(arm->act_edbone, ebp_b->head_owner, ebp_b->tail_owner)) {
				headtail = 2;
			}
			else {
				/* rule: whichever one is closer to 3d-cursor */
				float curs[3];
				float dist_sq_a, dist_sq_b;

				/* get cursor location */
				invert_m4_m4(obedit->imat, obedit->obmat);
				mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));

				/* get distances */
				dist_sq_a = len_squared_v3v3(ebp_a->vec, curs);
				dist_sq_b = len_squared_v3v3(ebp_b->vec, curs);

				/* compare distances - closer one therefore acts as direction for bone to go */
				headtail = (dist_sq_a < dist_sq_b) ? 2 : 1;
			}
		}
		else if (ebp_a->head_owner) {
			headtail = 1;
		}
		else if (ebp_b->head_owner) {
			headtail = 2;
		}

		/* assign head/tail combinations */
		if (headtail == 2) {
			copy_v3_v3(head, ebp_a->vec);
			copy_v3_v3(tail, ebp_b->vec);
		}
		else if (headtail == 1) {
			copy_v3_v3(head, ebp_b->vec);
			copy_v3_v3(tail, ebp_a->vec);
		}

		/* add new bone and parent it to the appropriate end */
		if (headtail) {
			newbone = add_points_bone(obedit, head, tail);

			/* do parenting (will need to set connected flag too) */
			if (headtail == 2) {
				/* ebp tail or head - tail gets priority */
				if (ebp_a->tail_owner)
					newbone->parent = ebp_a->tail_owner;
				else
					newbone->parent = ebp_a->head_owner;
			}
			else {
				/* ebp_b tail or head - tail gets priority */
				if (ebp_b->tail_owner)
					newbone->parent = ebp_b->tail_owner;
				else
					newbone->parent = ebp_b->head_owner;
			}

			/* don't set for bone connecting two head points of bones */
			if (ebp_a->tail_owner || ebp_b->tail_owner) {
				newbone->flag |= BONE_CONNECTED;
			}
		}
	}
	else {
		/* FIXME.. figure out a method for multiple bones */
		BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
		BLI_freelistN(&points);
		return OPERATOR_CANCELLED;
	}

	if (newbone) {
		ED_armature_edit_deselect_all(obedit);
		arm->act_edbone = newbone;
		newbone->flag |= BONE_TIPSEL;
	}

	/* updates */
	WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);

	/* free points */
	BLI_freelistN(&points);

	return OPERATOR_FINISHED;
}
コード例 #22
0
ファイル: armature_utils.c プロジェクト: mgschwan/blensor
/* put EditMode back in Object */
void ED_armature_from_edit(bArmature *arm)
{
	EditBone *eBone, *neBone;
	Bone *newBone;
	Object *obt;
	
	/* armature bones */
	BKE_armature_bonelist_free(&arm->bonebase);
	arm->act_bone = NULL;
	
	/* remove zero sized bones, this gives unstable restposes */
	for (eBone = arm->edbo->first; eBone; eBone = neBone) {
		float len_sq = len_squared_v3v3(eBone->head, eBone->tail);
		neBone = eBone->next;
		if (len_sq <= SQUARE(0.000001f)) {  /* FLT_EPSILON is too large? */
			EditBone *fBone;
			
			/* Find any bones that refer to this bone */
			for (fBone = arm->edbo->first; fBone; fBone = fBone->next) {
				if (fBone->parent == eBone)
					fBone->parent = eBone->parent;
			}
			if (G.debug & G_DEBUG)
				printf("Warning: removed zero sized bone: %s\n", eBone->name);
			bone_free(arm, eBone);
		}
	}
	
	/*	Copy the bones from the editData into the armature */
	for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
		newBone = MEM_callocN(sizeof(Bone), "bone");
		eBone->temp.bone = newBone;   /* Associate the real Bones with the EditBones */
		
		BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
		copy_v3_v3(newBone->arm_head, eBone->head);
		copy_v3_v3(newBone->arm_tail, eBone->tail);
		newBone->arm_roll = eBone->roll;
		
		newBone->flag = eBone->flag;
		
		if (eBone == arm->act_edbone) {
			/* don't change active selection, this messes up separate which uses
			 * editmode toggle and can separate active bone which is de-selected originally */
			/* newBone->flag |= BONE_SELECTED; */ /* important, editbones can be active with only 1 point selected */
			arm->act_bone = newBone;
		}
		newBone->roll = 0.0f;
		
		newBone->weight = eBone->weight;
		newBone->dist = eBone->dist;
		
		newBone->xwidth = eBone->xwidth;
		newBone->zwidth = eBone->zwidth;
		newBone->rad_head = eBone->rad_head;
		newBone->rad_tail = eBone->rad_tail;
		newBone->segments = eBone->segments;
		newBone->layer = eBone->layer;

		/* Bendy-Bone parameters */
		newBone->roll1 = eBone->roll1;
		newBone->roll2 = eBone->roll2;
		newBone->curveInX = eBone->curveInX;
		newBone->curveInY = eBone->curveInY;
		newBone->curveOutX = eBone->curveOutX;
		newBone->curveOutY = eBone->curveOutY;
		newBone->ease1 = eBone->ease1;
		newBone->ease2 = eBone->ease2;
		newBone->scaleIn = eBone->scaleIn;
		newBone->scaleOut = eBone->scaleOut;


		if (eBone->prop)
			newBone->prop = IDP_CopyProperty(eBone->prop);
	}
	
	/* Fix parenting in a separate pass to ensure ebone->bone connections are valid at this point.
	 * Do not set bone->head/tail here anymore, using EditBone data for that is not OK since our later fiddling
	 * with parent's arm_mat (for roll conversion) may have some small but visible impact on locations (T46010). */
	for (eBone = arm->edbo->first; eBone; eBone = eBone->next) {
		newBone = eBone->temp.bone;
		if (eBone->parent) {
			newBone->parent = eBone->parent->temp.bone;
			BLI_addtail(&newBone->parent->childbase, newBone);
		}
		/*	...otherwise add this bone to the armature's bonebase */
		else {
			BLI_addtail(&arm->bonebase, newBone);
		}
	}
	
	/* Finalize definition of restpose data (roll, bone_mat, arm_mat, head/tail...). */
	armature_finalize_restpose(&arm->bonebase, arm->edbo);
	
	/* so all users of this armature should get rebuilt */
	for (obt = G.main->object.first; obt; obt = obt->id.next) {
		if (obt->data == arm) {
			BKE_pose_rebuild(obt, arm);
		}
	}
	
	DAG_id_tag_update(&arm->id, 0);
}
コード例 #23
0
ファイル: MOD_warp.c プロジェクト: dfelinto/blender
static void warpModifier_do(WarpModifierData *wmd,
                            const ModifierEvalContext *ctx,
                            Mesh *mesh,
                            float (*vertexCos)[3],
                            int numVerts)
{
  Object *ob = ctx->object;
  float obinv[4][4];
  float mat_from[4][4];
  float mat_from_inv[4][4];
  float mat_to[4][4];
  float mat_unit[4][4];
  float mat_final[4][4];

  float tmat[4][4];

  const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
  float strength = wmd->strength;
  float fac = 1.0f, weight;
  int i;
  int defgrp_index;
  MDeformVert *dvert, *dv = NULL;

  float(*tex_co)[3] = NULL;

  if (!(wmd->object_from && wmd->object_to)) {
    return;
  }

  MOD_get_vgroup(ob, mesh, wmd->defgrp_name, &dvert, &defgrp_index);
  if (dvert == NULL) {
    defgrp_index = -1;
  }

  if (wmd->curfalloff == NULL) { /* should never happen, but bad lib linking could cause it */
    wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
  }

  if (wmd->curfalloff) {
    curvemapping_initialize(wmd->curfalloff);
  }

  invert_m4_m4(obinv, ob->obmat);

  mul_m4_m4m4(mat_from, obinv, wmd->object_from->obmat);
  mul_m4_m4m4(mat_to, obinv, wmd->object_to->obmat);

  invert_m4_m4(tmat, mat_from);  // swap?
  mul_m4_m4m4(mat_final, tmat, mat_to);

  invert_m4_m4(mat_from_inv, mat_from);

  unit_m4(mat_unit);

  if (strength < 0.0f) {
    float loc[3];
    strength = -strength;

    /* inverted location is not useful, just use the negative */
    copy_v3_v3(loc, mat_final[3]);
    invert_m4(mat_final);
    negate_v3_v3(mat_final[3], loc);
  }
  weight = strength;

  Tex *tex_target = wmd->texture;
  if (mesh != NULL && tex_target != NULL) {
    tex_co = MEM_malloc_arrayN(numVerts, sizeof(*tex_co), "warpModifier_do tex_co");
    MOD_get_texture_coords((MappingInfoModifierData *)wmd, ctx, ob, mesh, vertexCos, tex_co);

    MOD_init_texture((MappingInfoModifierData *)wmd, ctx);
  }

  for (i = 0; i < numVerts; i++) {
    float *co = vertexCos[i];

    if (wmd->falloff_type == eWarp_Falloff_None ||
        ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
         (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius))) {
      /* skip if no vert group found */
      if (defgrp_index != -1) {
        dv = &dvert[i];
        weight = defvert_find_weight(dv, defgrp_index) * strength;
        if (weight <= 0.0f) {
          continue;
        }
      }

      /* closely match PROP_SMOOTH and similar */
      switch (wmd->falloff_type) {
        case eWarp_Falloff_None:
          fac = 1.0f;
          break;
        case eWarp_Falloff_Curve:
          fac = curvemapping_evaluateF(wmd->curfalloff, 0, fac);
          break;
        case eWarp_Falloff_Sharp:
          fac = fac * fac;
          break;
        case eWarp_Falloff_Smooth:
          fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
          break;
        case eWarp_Falloff_Root:
          fac = sqrtf(fac);
          break;
        case eWarp_Falloff_Linear:
          /* pass */
          break;
        case eWarp_Falloff_Const:
          fac = 1.0f;
          break;
        case eWarp_Falloff_Sphere:
          fac = sqrtf(2 * fac - fac * fac);
          break;
        case eWarp_Falloff_InvSquare:
          fac = fac * (2.0f - fac);
          break;
      }

      fac *= weight;

      if (tex_co) {
        struct Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
        TexResult texres;
        texres.nor = NULL;
        BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
        fac *= texres.tin;
      }

      if (fac != 0.0f) {
        /* into the 'from' objects space */
        mul_m4_v3(mat_from_inv, co);

        if (fac == 1.0f) {
          mul_m4_v3(mat_final, co);
        }
        else {
          if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
            /* interpolate the matrix for nicer locations */
            blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
            mul_m4_v3(tmat, co);
          }
          else {
            float tvec[3];
            mul_v3_m4v3(tvec, mat_final, co);
            interp_v3_v3v3(co, co, tvec, fac);
          }
        }

        /* out of the 'from' objects space */
        mul_m4_v3(mat_from, co);
      }
    }
  }

  if (tex_co) {
    MEM_freeN(tex_co);
  }
}
コード例 #24
0
ファイル: MOD_mirror.c プロジェクト: vanangamudi/blender-main
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
                                   Object *ob,
                                   DerivedMesh *dm,
                                   int axis)
{
    const float tolerance_sq = mmd->tolerance * mmd->tolerance;
    const int do_vtargetmap = !(mmd->flag & MOD_MIR_NO_MERGE);
    int is_vtargetmap = FALSE; /* true when it should be used */

    DerivedMesh *result;
    const int maxVerts = dm->getNumVerts(dm);
    const int maxEdges = dm->getNumEdges(dm);
    const int maxLoops = dm->getNumLoops(dm);
    const int maxPolys = dm->getNumPolys(dm);
    MVert *mv, *mv_prev;
    MEdge *me;
    MLoop *ml;
    MPoly *mp;
    float mtx[4][4];
    int i, j;
    int a, totshape;
    int *vtargetmap = NULL, *vtmap_a = NULL, *vtmap_b = NULL;

    /* mtx is the mirror transformation */
    unit_m4(mtx);
    mtx[axis][axis] = -1.0f;

    if (mmd->mirror_ob) {
        float tmp[4][4];
        float itmp[4][4];

        /* tmp is a transform from coords relative to the object's own origin,
         * to coords relative to the mirror object origin */
        invert_m4_m4(tmp, mmd->mirror_ob->obmat);
        mult_m4_m4m4(tmp, tmp, ob->obmat);

        /* itmp is the reverse transform back to origin-relative coordinates */
        invert_m4_m4(itmp, tmp);

        /* combine matrices to get a single matrix that translates coordinates into
         * mirror-object-relative space, does the mirror, and translates back to
         * origin-relative space */
        mult_m4_m4m4(mtx, mtx, tmp);
        mult_m4_m4m4(mtx, itmp, mtx);
    }

    result = CDDM_from_template(dm, maxVerts * 2, maxEdges * 2, 0, maxLoops * 2, maxPolys * 2);

    /*copy customdata to original geometry*/
    DM_copy_vert_data(dm, result, 0, 0, maxVerts);
    DM_copy_edge_data(dm, result, 0, 0, maxEdges);
    DM_copy_loop_data(dm, result, 0, 0, maxLoops);
    DM_copy_poly_data(dm, result, 0, 0, maxPolys);


    /* subsurf for eg wont have mesh data in the */
    /* now add mvert/medge/mface layers */

    if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
        dm->copyVertArray(dm, CDDM_get_verts(result));
    }
    if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
        dm->copyEdgeArray(dm, CDDM_get_edges(result));
    }
    if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
        dm->copyLoopArray(dm, CDDM_get_loops(result));
        dm->copyPolyArray(dm, CDDM_get_polys(result));
    }

    /* copy customdata to new geometry,
     * copy from its self because this data may have been created in the checks above */
    DM_copy_vert_data(result, result, 0, maxVerts, maxVerts);
    DM_copy_edge_data(result, result, 0, maxEdges, maxEdges);
    /* loops are copied later */
    DM_copy_poly_data(result, result, 0, maxPolys, maxPolys);

    if (do_vtargetmap) {
        /* second half is filled with -1 */
        vtargetmap = MEM_mallocN(sizeof(int) * maxVerts * 2, "MOD_mirror tarmap");

        vtmap_a = vtargetmap;
        vtmap_b = vtargetmap + maxVerts;
    }

    /* mirror vertex coordinates */
    mv_prev = CDDM_get_verts(result);
    mv = mv_prev + maxVerts;
    for (i = 0; i < maxVerts; i++, mv++, mv_prev++) {
        mul_m4_v3(mtx, mv->co);

        if (do_vtargetmap) {
            /* compare location of the original and mirrored vertex, to see if they
             * should be mapped for merging */
            if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
                *vtmap_a = maxVerts + i;
                is_vtargetmap = TRUE;
            }
            else {
                *vtmap_a = -1;
            }

            *vtmap_b = -1; /* fill here to avoid 2x loops */

            vtmap_a++;
            vtmap_b++;
        }
    }

    /* handle shape keys */
    totshape = CustomData_number_of_layers(&result->vertData, CD_SHAPEKEY);
    for (a = 0; a < totshape; a++) {
        float (*cos)[3] = CustomData_get_layer_n(&result->vertData, CD_SHAPEKEY, a);
        for (i = maxVerts; i < result->numVertData; i++) {
            mul_m4_v3(mtx, cos[i]);
        }
    }

    /* adjust mirrored edge vertex indices */
    me = CDDM_get_edges(result) + maxEdges;
    for (i = 0; i < maxEdges; i++, me++) {
        me->v1 += maxVerts;
        me->v2 += maxVerts;
    }

    /* adjust mirrored poly loopstart indices, and reverse loop order (normals) */
    mp = CDDM_get_polys(result) + maxPolys;
    ml = CDDM_get_loops(result);
    for (i = 0; i < maxPolys; i++, mp++) {
        MLoop *ml2;
        int e;

        /* reverse the loop, but we keep the first vertex in the face the same,
         * to ensure that quads are split the same way as on the other side */
        DM_copy_loop_data(result, result, mp->loopstart, mp->loopstart + maxLoops, 1);
        for (j = 1; j < mp->totloop; j++)
            DM_copy_loop_data(result, result, mp->loopstart + j, mp->loopstart + maxLoops + mp->totloop - j, 1);

        ml2 = ml + mp->loopstart + maxLoops;
        e = ml2[0].e;
        for (j = 0; j < mp->totloop - 1; j++) {
            ml2[j].e = ml2[j + 1].e;
        }
        ml2[mp->totloop - 1].e = e;

        mp->loopstart += maxLoops;
    }

    /* adjust mirrored loop vertex and edge indices */
    ml = CDDM_get_loops(result) + maxLoops;
    for (i = 0; i < maxLoops; i++, ml++) {
        ml->v += maxVerts;
        ml->e += maxEdges;
    }

    /* handle uvs,
     * let tessface recalc handle updating the MTFace data */
    if (mmd->flag & (MOD_MIR_MIRROR_U | MOD_MIR_MIRROR_V)) {
        const int do_mirr_u = (mmd->flag & MOD_MIR_MIRROR_U) != 0;
        const int do_mirr_v = (mmd->flag & MOD_MIR_MIRROR_V) != 0;

        const int totuv = CustomData_number_of_layers(&result->loopData, CD_MLOOPUV);

        for (a = 0; a < totuv; a++) {
            MLoopUV *dmloopuv = CustomData_get_layer_n(&result->loopData, CD_MLOOPUV, a);
            int j = maxLoops;
            dmloopuv += j; /* second set of loops only */
            for (; j-- > 0; dmloopuv++) {
                if (do_mirr_u) dmloopuv->uv[0] = 1.0f - dmloopuv->uv[0];
                if (do_mirr_v) dmloopuv->uv[1] = 1.0f - dmloopuv->uv[1];
            }
        }
    }

    /* handle vgroup stuff */
    if ((mmd->flag & MOD_MIR_VGROUP) && CustomData_has_layer(&result->vertData, CD_MDEFORMVERT)) {
        MDeformVert *dvert = (MDeformVert *) CustomData_get_layer(&result->vertData, CD_MDEFORMVERT) + maxVerts;
        int *flip_map = NULL, flip_map_len = 0;

        flip_map = defgroup_flip_map(ob, &flip_map_len, FALSE);

        if (flip_map) {
            for (i = 0; i < maxVerts; dvert++, i++) {
                /* merged vertices get both groups, others get flipped */
                if (do_vtargetmap && (vtargetmap[i] != -1))
                    defvert_flip_merged(dvert, flip_map, flip_map_len);
                else
                    defvert_flip(dvert, flip_map, flip_map_len);
            }

            MEM_freeN(flip_map);
        }
    }

    if (do_vtargetmap) {
        /* slow - so only call if one or more merge verts are found,
         * users may leave this on and not realize there is nothing to merge - campbell */
        if (is_vtargetmap) {
            result = CDDM_merge_verts(result, vtargetmap);
        }
        MEM_freeN(vtargetmap);
    }

    return result;
}
コード例 #25
0
static void do_bake_shade(void *handle, int x, int y, float u, float v)
{
	BakeShade *bs = handle;
	VlakRen *vlr = bs->vlr;
	ObjectInstanceRen *obi = bs->obi;
	Object *ob = obi->obr->ob;
	float l, *v1, *v2, *v3, tvn[3], ttang[4];
	int quad;
	ShadeSample *ssamp = &bs->ssamp;
	ShadeInput *shi = ssamp->shi;

	/* fast threadsafe break test */
	if (R.test_break(R.tbh))
		return;

	/* setup render coordinates */
	if (bs->quad) {
		v1 = vlr->v1->co;
		v2 = vlr->v3->co;
		v3 = vlr->v4->co;
	}
	else {
		v1 = vlr->v1->co;
		v2 = vlr->v2->co;
		v3 = vlr->v3->co;
	}

	l = 1.0f - u - v;

	/* shrink barycentric coordinates inwards slightly to avoid some issues
	 * where baking selected to active might just miss the other face at the
	 * near the edge of a face */
	if (bs->actob) {
		const float eps = 1.0f - 1e-4f;
		float invsum;

		u = (u - 0.5f) * eps + 0.5f;
		v = (v - 0.5f) * eps + 0.5f;
		l = (l - 0.5f) * eps + 0.5f;

		invsum = 1.0f / (u + v + l);

		u *= invsum;
		v *= invsum;
		l *= invsum;
	}

	/* renderco */
	shi->co[0] = l * v3[0] + u * v1[0] + v * v2[0];
	shi->co[1] = l * v3[1] + u * v1[1] + v * v2[1];
	shi->co[2] = l * v3[2] + u * v1[2] + v * v2[2];

	/* avoid self shadow with vertex bake from adjacent faces [#33729] */
	if ((bs->vcol != NULL) && (bs->actob == NULL)) {
		madd_v3_v3fl(shi->co, vlr->n, 0.0001f);
	}

	if (obi->flag & R_TRANSFORMED)
		mul_m4_v3(obi->mat, shi->co);

	copy_v3_v3(shi->dxco, bs->dxco);
	copy_v3_v3(shi->dyco, bs->dyco);

	quad = bs->quad;
	bake_set_shade_input(obi, vlr, shi, quad, 0, x, y, u, v);

	if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT) {
		shade_input_set_shade_texco(shi);
		copy_v3_v3(tvn, shi->nmapnorm);
		copy_v4_v4(ttang, shi->nmaptang);
	}

	/* if we are doing selected to active baking, find point on other face */
	if (bs->actob) {
		Isect isec, minisec;
		float co[3], minco[3], dist, mindist = 0.0f;
		int hit, sign, dir = 1;

		/* intersect with ray going forward and backward*/
		hit = 0;
		memset(&minisec, 0, sizeof(minisec));
		minco[0] = minco[1] = minco[2] = 0.0f;

		copy_v3_v3(bs->dir, shi->vn);

		for (sign = -1; sign <= 1; sign += 2) {
			memset(&isec, 0, sizeof(isec));
			isec.mode = RE_RAY_MIRROR;

			isec.orig.ob   = obi;
			isec.orig.face = vlr;
			isec.userdata = bs->actob;
			isec.check = RE_CHECK_VLR_BAKE;
			isec.skip = RE_SKIP_VLR_NEIGHBOUR;

			if (bake_intersect_tree(R.raytree, &isec, shi->co, shi->vn, sign, co, &dist)) {
				if (!hit || len_squared_v3v3(shi->co, co) < len_squared_v3v3(shi->co, minco)) {
					minisec = isec;
					mindist = dist;
					copy_v3_v3(minco, co);
					hit = 1;
					dir = sign;
				}
			}
		}

		if (ELEM(bs->type, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE)) {
			if (hit)
				bake_displacement(handle, shi, (dir == -1) ? mindist : -mindist, x, y);
			else
				bake_displacement(handle, shi, 0.0f, x, y);
			return;
		}

		/* if hit, we shade from the new point, otherwise from point one starting face */
		if (hit) {
			obi = (ObjectInstanceRen *)minisec.hit.ob;
			vlr = (VlakRen *)minisec.hit.face;
			quad = (minisec.isect == 2);
			copy_v3_v3(shi->co, minco);

			u = -minisec.u;
			v = -minisec.v;
			bake_set_shade_input(obi, vlr, shi, quad, 1, x, y, u, v);
		}
	}

	if (bs->type == RE_BAKE_NORMALS && R.r.bake_normal_space == R_BAKE_SPACE_TANGENT)
		bake_shade(handle, ob, shi, quad, x, y, u, v, tvn, ttang);
	else
		bake_shade(handle, ob, shi, quad, x, y, u, v, NULL, NULL);
}
コード例 #26
0
ファイル: shrinkwrap.c プロジェクト: Walid-Shouman/Blender
/*
 * Shrinkwrap moving vertexs to the nearest surface point on the target
 *
 * it builds a BVHTree from the target mesh and then performs a
 * NN matches for each vertex
 */
static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
{
	int i;

	BVHTreeFromMesh treeData = NULL_BVHTreeFromMesh;
	BVHTreeNearest nearest  = NULL_BVHTreeNearest;

	/* Create a bvh-tree of the given target */
	bvhtree_from_mesh_faces(&treeData, calc->target, 0.0, 2, 6);
	if (treeData.tree == NULL) {
		OUT_OF_MEMORY();
		return;
	}

	/* Setup nearest */
	nearest.index = -1;
	nearest.dist_sq = FLT_MAX;


	/* Find the nearest vertex */
#ifndef __APPLE__
#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static)
#endif
	for (i = 0; i < calc->numVerts; ++i) {
		float *co = calc->vertexCos[i];
		float tmp_co[3];
		float weight = defvert_array_find_weight_safe(calc->dvert, i, calc->vgroup);
		if (weight == 0.0f) continue;

		/* Convert the vertex to tree coordinates */
		if (calc->vert) {
			copy_v3_v3(tmp_co, calc->vert[i].co);
		}
		else {
			copy_v3_v3(tmp_co, co);
		}
		space_transform_apply(&calc->local2target, tmp_co);

		/* Use local proximity heuristics (to reduce the nearest search)
		 *
		 * If we already had an hit before.. we assume this vertex is going to have a close hit to that other vertex
		 * so we can initiate the "nearest.dist" with the expected value to that last hit.
		 * This will lead in pruning of the search tree. */
		if (nearest.index != -1)
			nearest.dist_sq = len_squared_v3v3(tmp_co, nearest.co);
		else
			nearest.dist_sq = FLT_MAX;

		BLI_bvhtree_find_nearest(treeData.tree, tmp_co, &nearest, treeData.nearest_callback, &treeData);

		/* Found the nearest vertex */
		if (nearest.index != -1) {
			if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) {
				/* Make the vertex stay on the front side of the face */
				madd_v3_v3v3fl(tmp_co, nearest.co, nearest.no, calc->keepDist);
			}
			else {
				/* Adjusting the vertex weight,
				 * so that after interpolating it keeps a certain distance from the nearest position */
				const float dist = sasqrt(nearest.dist_sq);
				if (dist > FLT_EPSILON) {
					/* linear interpolation */
					interp_v3_v3v3(tmp_co, tmp_co, nearest.co, (dist - calc->keepDist) / dist);
				}
				else {
					copy_v3_v3(tmp_co, nearest.co);
				}
			}

			/* Convert the coordinates back to mesh coordinates */
			space_transform_invert(&calc->local2target, tmp_co);
			interp_v3_v3v3(co, co, tmp_co, weight);  /* linear interpolation */
		}
	}

	free_bvhtree_from_mesh(&treeData);
}
コード例 #27
0
ファイル: bmesh_intersect.c プロジェクト: LucaRood/Blender
static enum ISectType intersect_line_tri(
        const float p0[3], const float p1[3],
        const float *t_cos[3], const float t_nor[3],
        float r_ix[3],
        const struct ISectEpsilon *e)
{
	float p_dir[3];
	unsigned int i_t0;
	float fac;

	sub_v3_v3v3(p_dir, p0, p1);
	normalize_v3(p_dir);

	for (i_t0 = 0; i_t0 < 3; i_t0++) {
		const unsigned int i_t1 = (i_t0 + 1) % 3;
		float te_dir[3];

		sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
		normalize_v3(te_dir);
		if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) {
			/* co-linear */
		}
		else {
			float ix_pair[2][3];
			int ix_pair_type;

			ix_pair_type = isect_line_line_epsilon_v3(p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f);

			if (ix_pair_type != 0) {
				if (ix_pair_type == 1) {
					copy_v3_v3(ix_pair[1], ix_pair[0]);
				}

				if ((ix_pair_type == 1) ||
				    (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq))
				{
					fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]);
					if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
						fac = line_point_factor_v3(ix_pair[0], p0, p1);
						if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
							copy_v3_v3(r_ix, ix_pair[0]);
							return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0);
						}
					}
				}
			}
		}
	}

	/* check ray isn't planar with tri */
	if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) {
		if (isect_line_segment_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) {
			if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
				interp_v3_v3v3(r_ix, p0, p1, fac);
				if (min_fff(len_squared_v3v3(t_cos[0], r_ix),
				            len_squared_v3v3(t_cos[1], r_ix),
				            len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq)
				{
					return IX_EDGE_TRI;
				}
			}
		}
	}

	/* r_ix may be unset */
	return IX_NONE;
}
コード例 #28
0
/**
 * Find nearest vertex and/or edge and/or face, for each vertex (adapted from shrinkwrap.c).
 */
static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
                                   float *dist_v, float *dist_e, float *dist_f,
                                   DerivedMesh *target, const SpaceTransform *loc2trgt)
{
	int i;
	BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh;
	BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh;
	BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh;
	BVHTreeNearest nearest_v   = NULL_BVHTreeNearest;
	BVHTreeNearest nearest_e   = NULL_BVHTreeNearest;
	BVHTreeNearest nearest_f   = NULL_BVHTreeNearest;

	if (dist_v) {
		/* Create a bvh-tree of the given target's verts. */
		bvhtree_from_mesh_verts(&treeData_v, target, 0.0, 2, 6);
		if (treeData_v.tree == NULL) {
			OUT_OF_MEMORY();
			return;
		}
	}
	if (dist_e) {
		/* Create a bvh-tree of the given target's edges. */
		bvhtree_from_mesh_edges(&treeData_e, target, 0.0, 2, 6);
		if (treeData_e.tree == NULL) {
			OUT_OF_MEMORY();
			return;
		}
	}
	if (dist_f) {
		/* Create a bvh-tree of the given target's faces. */
		bvhtree_from_mesh_faces(&treeData_f, target, 0.0, 2, 6);
		if (treeData_f.tree == NULL) {
			OUT_OF_MEMORY();
			return;
		}
	}

	/* Setup nearest. */
	nearest_v.index = nearest_e.index = nearest_f.index = -1;
	/*nearest_v.dist  = nearest_e.dist  = nearest_f.dist  = FLT_MAX;*/
	/* Find the nearest vert/edge/face. */
#ifndef __APPLE__
#pragma omp parallel for default(none) private(i) firstprivate(nearest_v,nearest_e,nearest_f) \
                         shared(treeData_v,treeData_e,treeData_f,numVerts,v_cos,dist_v,dist_e, \
                                dist_f,loc2trgt) \
                         schedule(static)
#endif
	for (i = 0; i < numVerts; i++) {
		float tmp_co[3];

		/* Convert the vertex to tree coordinates. */
		copy_v3_v3(tmp_co, v_cos[i]);
		space_transform_apply(loc2trgt, tmp_co);

		/* Use local proximity heuristics (to reduce the nearest search).
		 *
		 * If we already had an hit before, we assume this vertex is going to have a close hit to
		 * that other vertex, so we can initiate the "nearest.dist" with the expected value to that
		 * last hit.
		 * This will lead in prunning of the search tree.
		 */
		if (dist_v) {
			nearest_v.dist = nearest_v.index != -1 ? len_squared_v3v3(tmp_co, nearest_v.co) : FLT_MAX;
			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(treeData_v.tree, tmp_co, &nearest_v, treeData_v.nearest_callback, &treeData_v);
			dist_v[i] = sqrtf(nearest_v.dist);
		}
		if (dist_e) {
			nearest_e.dist = nearest_e.index != -1 ? len_squared_v3v3(tmp_co, nearest_e.co) : FLT_MAX;
			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(treeData_e.tree, tmp_co, &nearest_e, treeData_e.nearest_callback, &treeData_e);
			dist_e[i] = sqrtf(nearest_e.dist);
		}
		if (dist_f) {
			nearest_f.dist = nearest_f.index != -1 ? len_squared_v3v3(tmp_co, nearest_f.co) : FLT_MAX;
			/* Compute and store result. If invalid (-1 idx), keep FLT_MAX dist. */
			BLI_bvhtree_find_nearest(treeData_f.tree, tmp_co, &nearest_f, treeData_f.nearest_callback, &treeData_f);
			dist_f[i] = sqrtf(nearest_f.dist);
		}
	}

	if (dist_v)
		free_bvhtree_from_mesh(&treeData_v);
	if (dist_e)
		free_bvhtree_from_mesh(&treeData_e);
	if (dist_f)
		free_bvhtree_from_mesh(&treeData_f);
}
コード例 #29
0
/**
 * This function populates pixel_array and returns TRUE if things are correct
 */
static bool cast_ray_highpoly(
        BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakePixel *pixel_array, BakeHighPolyData *highpoly,
        const float co[3], const float dir[3], const int pixel_id, const int tot_highpoly,
        const float du_dx, const float du_dy, const float dv_dx, const float dv_dy)
{
	int i;
	int primitive_id = -1;
	float uv[2];
	int hit_mesh = -1;
	float hit_distance = FLT_MAX;

	BVHTreeRayHit *hits;
	hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");

	for (i = 0; i < tot_highpoly; i++) {
		float co_high[3], dir_high[3];

		hits[i].index = -1;
		/* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
		hits[i].dist = 10000.0f;

		/* transform the ray from the world space to the highpoly space */
		mul_v3_m4v3(co_high, highpoly[i].imat, co);

		/* rotates */
		mul_v3_mat3_m4v3(dir_high, highpoly[i].imat, dir);
		normalize_v3(dir_high);

		/* cast ray */
		if (treeData[i].tree) {
			BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]);
		}

		if (hits[i].index != -1) {
			/* cull backface */
			const float dot = dot_v3v3(dir_high, hits[i].no);
			if (dot < 0.0f) {
				float distance;
				float hit_world[3];

				/* distance comparison in world space */
				mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
				distance = len_squared_v3v3(hit_world, co);

				if (distance < hit_distance) {
					hit_mesh = i;
					hit_distance = distance;
				}
			}
		}
	}

	if (hit_mesh != -1) {
		calc_barycentric_from_point(triangles[hit_mesh], hits[hit_mesh].index, hits[hit_mesh].co, &primitive_id, uv);
		pixel_array[pixel_id].primitive_id = primitive_id;
		pixel_array[pixel_id].object_id = hit_mesh;
		copy_v2_v2(pixel_array[pixel_id].uv, uv);

		/* the differentials are relative to the UV/image space, so the highpoly differentials
		 * are the same as the low poly differentials */
		pixel_array[pixel_id].du_dx = du_dx;
		pixel_array[pixel_id].du_dy = du_dy;
		pixel_array[pixel_id].dv_dx = dv_dx;
		pixel_array[pixel_id].dv_dy = dv_dy;
	}
	else {
		pixel_array[pixel_id].primitive_id = -1;
		pixel_array[pixel_id].object_id = -1;
	}

	MEM_freeN(hits);
	return hit_mesh != -1;
}
コード例 #30
0
/**
 * Makes an NGon from an un-ordered set of verts
 *
 * assumes...
 * - that verts are only once in the list.
 * - that the verts have roughly planer bounds
 * - that the verts are roughly circular
 * there can be concave areas but overlapping folds from the center point will fail.
 *
 * a brief explanation of the method used
 * - find the center point
 * - find the normal of the vcloud
 * - order the verts around the face based on their angle to the normal vector at the center point.
 *
 * \note Since this is a vcloud there is no direction.
 */
void BM_verts_sort_radial_plane(BMVert **vert_arr, int len)
{
	struct SortIntByFloat *vang = BLI_array_alloca(vang, len);
	BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len);

	float totv_inv = 1.0f / (float)len;
	int i = 0;

	float cent[3], nor[3];

	const float *far = NULL, *far_cross = NULL;

	float far_vec[3];
	float far_cross_vec[3];
	float sign_vec[3]; /* work out if we are pos/neg angle */

	float far_dist_sq, far_dist_max_sq;
	float far_cross_dist, far_cross_best = 0.0f;

	/* get the center point and collect vector array since we loop over these a lot */
	zero_v3(cent);
	for (i = 0; i < len; i++) {
		madd_v3_v3fl(cent, vert_arr[i]->co, totv_inv);
	}


	/* find the far point from cent */
	far_dist_max_sq = 0.0f;
	for (i = 0; i < len; i++) {
		far_dist_sq = len_squared_v3v3(vert_arr[i]->co, cent);
		if (far_dist_sq > far_dist_max_sq || far == NULL) {
			far = vert_arr[i]->co;
			far_dist_max_sq = far_dist_sq;
		}
	}

	sub_v3_v3v3(far_vec, far, cent);
	// far_dist = len_v3(far_vec); /* real dist */ /* UNUSED */

	/* --- */

	/* find a point 90deg about to compare with */
	far_cross_best = 0.0f;
	for (i = 0; i < len; i++) {

		if (far == vert_arr[i]->co) {
			continue;
		}

		sub_v3_v3v3(far_cross_vec, vert_arr[i]->co, cent);
		far_cross_dist = normalize_v3(far_cross_vec);

		/* more of a weight then a distance */
		far_cross_dist = (/* first we want to have a value close to zero mapped to 1 */
		                  1.0f - fabsf(dot_v3v3(far_vec, far_cross_vec)) *

		                  /* second  we multiply by the distance
		                   * so points close to the center are not preferred */
		                  far_cross_dist);

		if (far_cross_dist > far_cross_best || far_cross == NULL) {
			far_cross = vert_arr[i]->co;
			far_cross_best = far_cross_dist;
		}
	}

	sub_v3_v3v3(far_cross_vec, far_cross, cent);

	/* --- */

	/* now we have 2 vectors we can have a cross product */
	cross_v3_v3v3(nor, far_vec, far_cross_vec);
	normalize_v3(nor);
	cross_v3_v3v3(sign_vec, far_vec, nor); /* this vector should match 'far_cross_vec' closely */

	/* --- */

	/* now calculate every points angle around the normal (signed) */
	for (i = 0; i < len; i++) {
		vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor);
		vang[i].data = i;
		vert_arr_map[i] = vert_arr[i];
	}

	/* sort by angle and magic! - we have our ngon */
	qsort(vang, len, sizeof(*vang), BLI_sortutil_cmp_float);

	/* --- */

	for (i = 0; i < len; i++) {
		vert_arr[i] = vert_arr_map[vang[i].data];
	}
}