/**
* Apply smooth for thickness to stroke point (use pressure)
* \param gps: Stroke to smooth
* \param i: Point index
* \param inf: Amount of smoothing to apply
*/
bool gp_smooth_stroke_thickness(bGPDstroke *gps, int i, float inf)
{
	bGPDspoint *ptb = &gps->points[i];

	/* Do nothing if not enough points */
	if (gps->totpoints <= 2) {
		return false;
	}

	/* Compute theoretical optimal value using distances */
	bGPDspoint *pta, *ptc;
	int before = i - 1;
	int after = i + 1;

	CLAMP_MIN(before, 0);
	CLAMP_MAX(after, gps->totpoints - 1);

	pta = &gps->points[before];
	ptc = &gps->points[after];

	/* the optimal value is the corresponding to the interpolation of the pressure
	 * at the distance of point b
	 */
	float fac = line_point_factor_v3(&ptb->x, &pta->x, &ptc->x);
	float optimal = (1.0f - fac) * pta->pressure + fac * ptc->pressure;

	/* Based on influence factor, blend between original and optimal */
	ptb->pressure = (1.0f - inf) * ptb->pressure + inf * optimal;

	return true;
}
Exemple #2
0
/* 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);
			}
		}
	}
}
Exemple #3
0
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;
}
/* from/to_world_space : whether from/to particles are in world or hair space
 * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
 */
static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
                               Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
                               float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
	ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
	ParticleData *pa, *tpa;
	PTCacheEditPoint *edit_point;
	PTCacheEditKey *ekey;
	BVHTreeFromMesh bvhtree= {NULL};
	MFace *mface = NULL, *mf;
	MEdge *medge = NULL, *me;
	MVert *mvert;
	DerivedMesh *dm, *target_dm;
	int numverts;
	int i, k;
	float from_ob_imat[4][4], to_ob_imat[4][4];
	float from_imat[4][4], to_imat[4][4];

	if (!target_psmd->dm)
		return false;
	if (!psys->part || psys->part->type != PART_HAIR)
		return false;
	if (!target_psys->part || target_psys->part->type != PART_HAIR)
		return false;
	
	edit_point = target_edit ? target_edit->points : NULL;
	
	invert_m4_m4(from_ob_imat, ob->obmat);
	invert_m4_m4(to_ob_imat, target_ob->obmat);
	invert_m4_m4(from_imat, from_mat);
	invert_m4_m4(to_imat, to_mat);
	
	if (target_psmd->dm->deformedOnly) {
		/* we don't want to mess up target_psmd->dm when converting to global coordinates below */
		dm = target_psmd->dm;
	}
	else {
		/* warning: this rebuilds target_psmd->dm! */
		dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH | CD_MASK_MFACE);
	}
	target_dm = target_psmd->dm;
	/* don't modify the original vertices */
	dm = CDDM_copy(dm);

	/* BMESH_ONLY, deform dm may not have tessface */
	DM_ensure_tessface(dm);

	numverts = dm->getNumVerts(dm);
	mvert = dm->getVertArray(dm);

	/* convert to global coordinates */
	for (i=0; i<numverts; i++)
		mul_m4_v3(to_mat, mvert[i].co);

	if (dm->getNumTessFaces(dm) != 0) {
		mface = dm->getTessFaceArray(dm);
		bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
	}
	else if (dm->getNumEdges(dm) != 0) {
		medge = dm->getEdgeArray(dm);
		bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6);
	}
	else {
		dm->release(dm);
		return false;
	}

	for (i = 0, tpa = target_psys->particles, pa = psys->particles;
	     i < target_psys->totpart;
	     i++, tpa++, pa++) {

		float from_co[3];
		BVHTreeNearest nearest;

		if (from_global)
			mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
		else
			mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
		mul_m4_v3(from_mat, from_co);

		nearest.index = -1;
		nearest.dist_sq = FLT_MAX;

		BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);

		if (nearest.index == -1) {
			if (G.debug & G_DEBUG)
				printf("No nearest point found for hair root!");
			continue;
		}

		if (mface) {
			float v[4][3];
			
			mf = &mface[nearest.index];

			copy_v3_v3(v[0], mvert[mf->v1].co);
			copy_v3_v3(v[1], mvert[mf->v2].co);
			copy_v3_v3(v[2], mvert[mf->v3].co);
			if (mf->v4) {
				copy_v3_v3(v[3], mvert[mf->v4].co);
				interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
			}
			else
				interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->fuv, NULL);
		}
		else {
			me = &medge[nearest.index];

			tpa->fuv[1] = line_point_factor_v3(nearest.co,
			                                   mvert[me->v1].co,
			                                   mvert[me->v2].co);
			tpa->fuv[0] = 1.0f - tpa->fuv[1];
			tpa->fuv[2] = tpa->fuv[3] = 0.0f;
			tpa->foffset = 0.0f;

			tpa->num = nearest.index;
			tpa->num_dmcache = -1;
		}

		/* translate hair keys */
		{
			HairKey *key, *tkey;
			float hairmat[4][4], imat[4][4];
			float offset[3];
			
			if (to_global)
				copy_m4_m4(imat, target_ob->obmat);
			else {
				/* note: using target_dm here, which is in target_ob object space and has full modifiers */
				psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
				invert_m4_m4(imat, hairmat);
			}
			mul_m4_m4m4(imat, imat, to_imat);
			
			/* offset in world space */
			sub_v3_v3v3(offset, nearest.co, from_co);
			
			if (edit_point) {
				for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) {
					float co_orig[3];
					
					if (from_global)
						mul_v3_m4v3(co_orig, from_ob_imat, key->co);
					else
						mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
					mul_m4_v3(from_mat, co_orig);
					
					add_v3_v3v3(tkey->co, co_orig, offset);
					
					mul_m4_v3(imat, tkey->co);
					
					ekey->flag |= PEK_USE_WCO;
				}
				
				edit_point++;
			}
			else {
				for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
					float co_orig[3];
					
					if (from_global)
						mul_v3_m4v3(co_orig, from_ob_imat, key->co);
					else
						mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
					mul_m4_v3(from_mat, co_orig);
					
					add_v3_v3v3(tkey->co, co_orig, offset);
					
					mul_m4_v3(imat, tkey->co);
				}
			}
		}
	}

	free_bvhtree_from_mesh(&bvhtree);
	dm->release(dm);

	psys_free_path_cache(target_psys, target_edit);

	PE_update_object(scene, target_ob, 0);

	return true;
}
static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObject *args)
{
	VectorObject *line_a, *line_b, *sphere_co;
	float sphere_radius;
	int clip = TRUE;

	float isect_a[3];
	float isect_b[3];

	if (!PyArg_ParseTuple(args, "O!O!O!f|i:intersect_line_sphere",
	                      &vector_Type, &line_a,
	                      &vector_Type, &line_b,
	                      &vector_Type, &sphere_co,
	                      &sphere_radius, &clip))
	{
		return NULL;
	}

	if (BaseMath_ReadCallback(line_a) == -1 ||
	    BaseMath_ReadCallback(line_b) == -1 ||
	    BaseMath_ReadCallback(sphere_co) == -1)
	{
		return NULL;
	}

	if (ELEM3(2, line_a->size, line_b->size, sphere_co->size)) {
		PyErr_SetString(PyExc_ValueError,
		                "geometry.intersect_line_sphere(...): "
		                " can't use 2D Vectors");
		return NULL;
	}
	else {
		short use_a = TRUE;
		short use_b = TRUE;
		float lambda;

		PyObject *ret = PyTuple_New(2);

		switch (isect_line_sphere_v3(line_a->vec, line_b->vec, sphere_co->vec, sphere_radius, isect_a, isect_b)) {
			case 1:
				if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE;
				use_b = FALSE;
				break;
			case 2:
				if (!(!clip || (((lambda = line_point_factor_v3(isect_a, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_a = FALSE;
				if (!(!clip || (((lambda = line_point_factor_v3(isect_b, line_a->vec, line_b->vec)) >= 0.0f) && (lambda <= 1.0f)))) use_b = FALSE;
				break;
			default:
				use_a = FALSE;
				use_b = FALSE;
		}

		if (use_a) { PyTuple_SET_ITEM(ret, 0,  Vector_CreatePyObject(isect_a, 3, Py_NEW, NULL)); }
		else       { PyTuple_SET_ITEM(ret, 0,  Py_None); Py_INCREF(Py_None); }

		if (use_b) { PyTuple_SET_ITEM(ret, 1,  Vector_CreatePyObject(isect_b, 3, Py_NEW, NULL)); }
		else       { PyTuple_SET_ITEM(ret, 1,  Py_None); Py_INCREF(Py_None); }

		return ret;
	}
}