Beispiel #1
0
int nextFixedSubdivision(ToolSettings *toolsettings, BArcIterator *iter, int start, int end, float UNUSED(head[3]), float p[3])
{
	static float stroke_length = 0;
	static float current_length;
	static char n;
	float *v1, *v2;
	float length_threshold;
	int i;
	
	if (stroke_length == 0)
	{
		current_length = 0;

		IT_peek(iter, start);
		v1 = iter->p;
		
		for (i = start + 1; i <= end; i++)
		{
			IT_peek(iter, i);
			v2 = iter->p;

			stroke_length += len_v3v3(v1, v2);
			
			v1 = v2;
		}
		
		n = 0;
		current_length = 0;
	}
	
	n++;
	
	length_threshold = n * stroke_length / toolsettings->skgen_subdivision_number;
	
	IT_peek(iter, start);
	v1 = iter->p;

	/* < and not <= because we don't care about end, it is P_EXACT anyway */
	for (i = start + 1; i < end; i++)
	{
		IT_peek(iter, i);
		v2 = iter->p;

		current_length += len_v3v3(v1, v2);

		if (current_length >= length_threshold)
		{
			VECCOPY(p, v2);
			return i;
		}
		
		v1 = v2;
	}
	
	stroke_length = 0;
	
	return -1;
}
Beispiel #2
0
float angle_normalized_v3v3(const float v1[3], const float v2[3])
{
	/* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
	if (dot_v3v3(v1, v2) < 0.0f) {
		float vec[3];
		
		vec[0]= -v2[0];
		vec[1]= -v2[1];
		vec[2]= -v2[2];
		
		return (float)M_PI - 2.0f*(float)saasin(len_v3v3(vec, v1)/2.0f);
	}
	else
		return 2.0f*(float)saasin(len_v3v3(v2, v1)/2.0f);
}
Beispiel #3
0
static int meshdeform_intersect(MeshDeformBind *mdb, MeshDeformIsect *isec)
{
	MFace *mface;
	float face[4][3], co[3], uvw[3], len, nor[3], end[3];
	int f, hit, is= 0, totface;

	isec->labda= 1e10;

	mface= mdb->cagedm->getFaceArray(mdb->cagedm);
	totface= mdb->cagedm->getNumFaces(mdb->cagedm);

	add_v3_v3v3(end, isec->start, isec->vec);

	for(f=0; f<totface; f++, mface++) {
		copy_v3_v3(face[0], mdb->cagecos[mface->v1]);
		copy_v3_v3(face[1], mdb->cagecos[mface->v2]);
		copy_v3_v3(face[2], mdb->cagecos[mface->v3]);

		if(mface->v4) {
			copy_v3_v3(face[3], mdb->cagecos[mface->v4]);
			hit = meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);

			if(hit) {
				normal_tri_v3( nor,face[0], face[1], face[2]);
			}
			else {
				hit= meshdeform_tri_intersect(isec->start, end, face[0], face[2], face[3], co, uvw);
				normal_tri_v3( nor,face[0], face[2], face[3]);
			}
		}
		else {
			hit= meshdeform_tri_intersect(isec->start, end, face[0], face[1], face[2], co, uvw);
			normal_tri_v3( nor,face[0], face[1], face[2]);
		}

		if(hit) {
			len= len_v3v3(isec->start, co)/len_v3v3(isec->start, end);
			if(len < isec->labda) {
				isec->labda= len;
				isec->face = mface;
				isec->isect= (INPR(isec->vec, nor) <= 0.0f);
				is= 1;
			}
		}
	}

	return is;
}
Beispiel #4
0
float angle_normalized_v3v3(const float v1[3], const float v2[3])
{
	/* double check they are normalized */
	BLI_ASSERT_UNIT_V3(v1);
	BLI_ASSERT_UNIT_V3(v2);

	/* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */
	if (dot_v3v3(v1, v2) >= 0.0f) {
		return 2.0f * saasin(len_v3v3(v1, v2) / 2.0f);
	}
	else {
		float v2_n[3];
		negate_v3_v3(v2_n, v2);
		return (float)M_PI - 2.0f * saasin(len_v3v3(v1, v2_n) / 2.0f);
	}
}
static void ruler_item_as_string(RulerItem *ruler_item, UnitSettings *unit,
                                 char *numstr, size_t numstr_size, int prec)
{
	const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;

	if (ruler_item->flag & RULERITEM_USE_ANGLE) {
		const float ruler_angle = angle_v3v3v3(ruler_item->co[0],
		                                       ruler_item->co[1],
		                                       ruler_item->co[2]);

		if (unit->system == USER_UNIT_NONE) {
			BLI_snprintf(numstr, numstr_size, "%.*f°", prec, RAD2DEGF(ruler_angle));
		}
		else {
			bUnit_AsString(numstr, numstr_size,
			               (double)ruler_angle,
			               prec, unit->system, B_UNIT_ROTATION, do_split, false);
		}
	}
	else {
		const float ruler_len = len_v3v3(ruler_item->co[0],
		                                 ruler_item->co[2]);

		if (unit->system == USER_UNIT_NONE) {
			BLI_snprintf(numstr, numstr_size, "%.*f", prec, ruler_len);
		}
		else {
			bUnit_AsString(numstr, numstr_size,
			               (double)(ruler_len * unit->scale_length),
			               prec, unit->system, B_UNIT_LENGTH, do_split, false);
		}
	}

}
/**
 * \brief get the ID from the screen.
 */
static void depthdropper_depth_sample_pt(
    bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth)
{
  /* we could use some clever */
  bScreen *screen = CTX_wm_screen(C);
  ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my);
  Scene *scene = CTX_data_scene(C);

  ScrArea *area_prev = CTX_wm_area(C);
  ARegion *ar_prev = CTX_wm_region(C);

  ddr->name[0] = '\0';

  if (sa) {
    if (sa->spacetype == SPACE_VIEW3D) {
      ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my);
      if (ar) {
        struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
        View3D *v3d = sa->spacedata.first;
        RegionView3D *rv3d = ar->regiondata;
        /* weak, we could pass in some reference point */
        const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
        const int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin};
        float co[3];

        CTX_wm_area_set(C, sa);
        CTX_wm_region_set(C, ar);

        /* grr, always draw else we leave stale text */
        ED_region_tag_redraw(ar);

        view3d_operator_needs_opengl(C);

        if (ED_view3d_autodist(depsgraph, ar, v3d, mval, co, true, NULL)) {
          const float mval_center_fl[2] = {(float)ar->winx / 2, (float)ar->winy / 2};
          float co_align[3];

          /* quick way to get view-center aligned point */
          ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align);

          *r_depth = len_v3v3(view_co, co_align);

          bUnit_AsString2(ddr->name,
                          sizeof(ddr->name),
                          (double)*r_depth,
                          4,
                          B_UNIT_LENGTH,
                          &scene->unit,
                          false);
        }
        else {
          BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
        }
      }
    }
  }

  CTX_wm_area_set(C, area_prev);
  CTX_wm_region_set(C, ar_prev);
}
/* helper */
static void gp_stroke_to_bezier_add_point(tGpTimingData *gtd, BezTriple *bezt,
                                          const float p[3], const float h1[3], const float h2[3], const float prev_p[3],
                                          const bool do_gtd, const double inittime, const float time,
                                          const float width, const float rad_fac, float minmax_weights[2])
{
	copy_v3_v3(bezt->vec[0], h1);
	copy_v3_v3(bezt->vec[1], p);
	copy_v3_v3(bezt->vec[2], h2);
	
	/* set settings */
	bezt->h1 = bezt->h2 = HD_FREE;
	bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
	bezt->radius = width * rad_fac;
	bezt->weight = width;
	CLAMP(bezt->weight, 0.0f, 1.0f);
	if (bezt->weight < minmax_weights[0]) {
		minmax_weights[0] = bezt->weight;
	}
	else if (bezt->weight > minmax_weights[1]) {
		minmax_weights[1] = bezt->weight;
	}
	
	/* Update timing data */
	if (do_gtd) {
		gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
	}
}
void BlenderFileLoader::addTriangle(struct LoaderState *ls, float v1[3], float v2[3], float v3[3],
                                    float n1[3], float n2[3], float n3[3],
                                    bool fm, bool em1, bool em2, bool em3)
{
	float *fv[3], *fn[3], len;
	unsigned int i, j;
	IndexedFaceSet::FaceEdgeMark marks = 0;

	// initialize the bounding box by the first vertex
	if (ls->currentIndex == 0) {
		copy_v3_v3(ls->minBBox, v1);
		copy_v3_v3(ls->maxBBox, v1);
	}

	fv[0] = v1; fn[0] = n1;
	fv[1] = v2; fn[1] = n2;
	fv[2] = v3; fn[2] = n3;
	for (i = 0; i < 3; i++) {

		copy_v3_v3(ls->pv, fv[i]);
		copy_v3_v3(ls->pn, fn[i]);

		// update the bounding box
		for (j = 0; j < 3; j++) {
			if (ls->minBBox[j] > ls->pv[j])
				ls->minBBox[j] = ls->pv[j];

			if (ls->maxBBox[j] < ls->pv[j])
				ls->maxBBox[j] = ls->pv[j];
		}

		len = len_v3v3(fv[i], fv[(i + 1) % 3]);
		if (_minEdgeSize > len)
			_minEdgeSize = len;

		*ls->pvi = ls->currentIndex;
		*ls->pni = ls->currentIndex;
		*ls->pmi = ls->currentMIndex;

		ls->currentIndex += 3;
		ls->pv += 3;
		ls->pn += 3;

		ls->pvi++;
		ls->pni++;
		ls->pmi++;
	}

	if (fm)
		marks |= IndexedFaceSet::FACE_MARK;
	if (em1)
		marks |= IndexedFaceSet::EDGE_MARK_V1V2;
	if (em2)
		marks |= IndexedFaceSet::EDGE_MARK_V2V3;
	if (em3)
		marks |= IndexedFaceSet::EDGE_MARK_V3V1;
	*(ls->pm++) = marks;
}
static void valuefn(float *out, TexParams *p, bNode *UNUSED(node), bNodeStack **in, short thread)
{
	float co1[3], co2[3];

	tex_input_vec(co1, in[0], p, thread);
	tex_input_vec(co2, in[1], p, thread);

	*out = len_v3v3(co2, co1);
}
Beispiel #10
0
/*
 * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
 * Returns TRUE if "hit" was updated.
 * Opts control whether an hit is valid or not
 * Supported options are:
 *	MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
 *	MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
 */
int normal_projection_project_vertex(char options, const float *vert, const float *dir, const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit, BVHTree_RayCastCallback callback, void *userdata)
{
	float tmp_co[3], tmp_no[3];
	const float *co, *no;
	BVHTreeRayHit hit_tmp;

	//Copy from hit (we need to convert hit rays from one space coordinates to the other
	memcpy(&hit_tmp, hit, sizeof(hit_tmp));

	//Apply space transform (TODO readjust dist)
	if (transf) {
		copy_v3_v3(tmp_co, vert);
		space_transform_apply(transf, tmp_co);
		co = tmp_co;

		copy_v3_v3(tmp_no, dir);
		space_transform_apply_normal(transf, tmp_no);
		no = tmp_no;

		hit_tmp.dist *= mat4_to_scale(((SpaceTransform*)transf)->local2target);
	}
	else {
		co = vert;
		no = dir;
	}

	hit_tmp.index = -1;

	BLI_bvhtree_ray_cast(tree, co, no, 0.0f, &hit_tmp, callback, userdata);

	if (hit_tmp.index != -1) {
		/* invert the normal first so face culling works on rotated objects */
		if (transf) {
			space_transform_invert_normal(transf, hit_tmp.no);
		}

		if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE|MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
			/* apply backface */
			const float dot= dot_v3v3(dir, hit_tmp.no);
			if (	((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
				((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) && dot >= 0.0f)
			) {
				return FALSE; /* Ignore hit */
			}
		}

		if (transf) {
			/* Inverting space transform (TODO make coeherent with the initial dist readjust) */
			space_transform_invert(transf, hit_tmp.co);
			hit_tmp.dist = len_v3v3((float *)vert, hit_tmp.co);
		}

		memcpy(hit, &hit_tmp, sizeof(hit_tmp));
		return TRUE;
	}
	return FALSE;
}
Beispiel #11
0
void ED_armature_ebone_from_mat3(EditBone *ebone, float mat[3][3])
{
	float vec[3], roll;
	const float len = len_v3v3(ebone->head, ebone->tail);

	mat3_to_vec_roll(mat, vec, &roll);

	madd_v3_v3v3fl(ebone->tail, ebone->head, vec, len);
	ebone->roll = roll;
}
Beispiel #12
0
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, float *co1, float *co2)
{
	MDefBoundIsect *isect;
	MeshDeformIsect isec;
	float (*cagecos)[3];
	MFace *mface;
	float vert[4][3], len, end[3];
	static float epsilon[3]= {0, 0, 0}; //1e-4, 1e-4, 1e-4};

	/* setup isec */
	memset(&isec, 0, sizeof(isec));
	isec.labda= 1e10f;

	VECADD(isec.start, co1, epsilon);
	VECADD(end, co2, epsilon);
	sub_v3_v3v3(isec.vec, end, isec.start);

	if(meshdeform_intersect(mdb, &isec)) {
		len= isec.labda;
		mface=(MFace*)isec.face;

		/* create MDefBoundIsect */
		isect= BLI_memarena_alloc(mdb->memarena, sizeof(*isect));

		/* compute intersection coordinate */
		isect->co[0]= co1[0] + isec.vec[0]*len;
		isect->co[1]= co1[1] + isec.vec[1]*len;
		isect->co[2]= co1[2] + isec.vec[2]*len;

		isect->len= len_v3v3(co1, isect->co);
		if(isect->len < MESHDEFORM_LEN_THRESHOLD)
			isect->len= MESHDEFORM_LEN_THRESHOLD;

		isect->v[0]= mface->v1;
		isect->v[1]= mface->v2;
		isect->v[2]= mface->v3;
		isect->v[3]= mface->v4;
		isect->nvert= (mface->v4)? 4: 3;

		isect->facing= isec.isect;

		/* compute mean value coordinates for interpolation */
		cagecos= mdb->cagecos;
		copy_v3_v3(vert[0], cagecos[mface->v1]);
		copy_v3_v3(vert[1], cagecos[mface->v2]);
		copy_v3_v3(vert[2], cagecos[mface->v3]);
		if(mface->v4) copy_v3_v3(vert[3], cagecos[mface->v4]);
		interp_weights_poly_v3( isect->uvw,vert, isect->nvert, isect->co);

		return isect;
	}

	return NULL;
}
Beispiel #13
0
void BLI_removeDoubleNodes(BGraph *graph, float 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_v3v3(node_replaced->p, node_src->p) <= limit) {
				BLI_replaceNode(graph, node_src, node_replaced);
			}
		}
	}
	
}
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;
	}
}
Beispiel #15
0
unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height)
{
	float max_segment = 0.01f;
	unsigned int i, resol = 1;

	if (width != 0 && height != 0) {
		max_segment = 1.0f / (float)max_ii(width, height);
	}

	for (i = 0; i < spline->tot_point; i++) {
		MaskSplinePoint *point = &spline->points[i];
		BezTriple *bezt_curr, *bezt_next;
		float a, b, c, len;
		unsigned int cur_resol;

		bezt_curr = &point->bezt;
		bezt_next = BKE_mask_spline_point_next_bezt(spline, spline->points, point);

		if (bezt_next == NULL) {
			break;
		}

		a = len_v3v3(bezt_curr->vec[1], bezt_curr->vec[2]);
		b = len_v3v3(bezt_curr->vec[2], bezt_next->vec[0]);
		c = len_v3v3(bezt_next->vec[0], bezt_next->vec[1]);

		len = a + b + c;
		cur_resol = len / max_segment;

		resol = MAX2(resol, cur_resol);

		if (resol >= MASK_RESOL_MAX) {
			break;
		}
	}

	return CLAMPIS(resol, 1, MASK_RESOL_MAX);
}
/**
 * Returns the real distance between a vertex and another reference object.
 * Note that it works in final world space (i.e. with constraints etc. applied).
 */
static void get_vert2ob_distance(int numVerts, float (*v_cos)[3], float *dist,
                                 Object *ob, Object *obr)
{
	/* Vertex and ref object coordinates. */
	float v_wco[3];
	unsigned int i = numVerts;

	while (i-- > 0) {
		/* Get world-coordinates of the vertex (constraints and anim included). */
		mul_v3_m4v3(v_wco, ob->obmat, v_cos[i]);
		/* Return distance between both coordinates. */
		dist[i] = len_v3v3(v_wco, obr->obmat[3]);
	}
}
void BKE_camera_to_gpu_dof(struct Object *camera, struct GPUFXSettings *r_fx_settings)
{
	if (camera->type == OB_CAMERA) {
		Camera *cam = camera->data;
		r_fx_settings->dof = &cam->gpu_dof;
		r_fx_settings->dof->focal_length = cam->lens;
		r_fx_settings->dof->sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y);
		if (cam->dof_ob) {
			r_fx_settings->dof->focus_distance = len_v3v3(cam->dof_ob->obmat[3], camera->obmat[3]);
		}
		else {
			r_fx_settings->dof->focus_distance = cam->YF_dofdist;
		}
	}
}
Beispiel #18
0
BNode * BLI_FindNodeByPosition(BGraph *graph, float *p, float limit)
{
	BNode *closest_node = NULL, *node;
	float min_distance = 0.0f;
	
	for (node = graph->nodes.first; node; node = node->next) {
		float distance = len_v3v3(p, node->p); 
		if (distance <= limit && (closest_node == NULL || distance < min_distance)) {
			closest_node = node;
			min_distance = distance;
		}
	}
	
	return closest_node;
}
static float curve_calc_dist_pair(const Nurb *nu, int a, int b)
{
	const float *a_fl, *b_fl;

	if (nu->type == CU_BEZIER) {
		a_fl = nu->bezt[a].vec[1];
		b_fl = nu->bezt[b].vec[1];
	}
	else {
		a_fl = nu->bp[a].vec;
		b_fl = nu->bp[b].vec;
	}

	return len_v3v3(a_fl, b_fl);
}
BMFace *BKE_bmbvh_find_face_segment(BMBVHTree *bmtree, const float co_a[3], const float co_b[3],
                                    float *r_fac, float r_hitout[3], float r_cagehit[3])
{
	BVHTreeRayHit hit;
	struct SegmentUserData bmcb_data;
	const float dist = len_v3v3(co_a, co_b);
	float dir[3];

	if (bmtree->cos_cage) BLI_assert(!(bmtree->bm->elem_index_dirty & BM_VERT));

	sub_v3_v3v3(dir, co_b, co_a);

	hit.dist = dist;
	hit.index = -1;

	/* ok to leave 'uv' uninitialized */
	bmcb_data.looptris = (const BMLoop *(*)[3])bmtree->looptris;
	bmcb_data.cos_cage = (const float (*)[3])bmtree->cos_cage;
	bmcb_data.co_a = co_a;
	bmcb_data.co_b = co_b;

	BLI_bvhtree_ray_cast(bmtree->tree, co_a, dir, 0.0f, &hit, bmbvh_find_face_segment_cb, &bmcb_data);
	if (hit.index != -1 && hit.dist != dist) {
		/* duplicate of BKE_bmbvh_ray_cast() */
		if (r_hitout) {
			if (bmtree->flag & BMBVH_RETURN_ORIG) {
				BMLoop **ltri = bmtree->looptris[hit.index];
				interp_v3_v3v3v3_uv(r_hitout, ltri[0]->v->co, ltri[1]->v->co, ltri[2]->v->co, bmcb_data.uv);
			}
			else {
				copy_v3_v3(r_hitout, hit.co);
			}

			if (r_cagehit) {
				copy_v3_v3(r_cagehit, hit.co);
			}
		}
		/* end duplicate */

		if (r_fac) {
			*r_fac = hit.dist / dist;
		}

		return bmtree->looptris[hit.index][0]->f;
	}

	return NULL;
}
Beispiel #21
0
static void testAxialSymmetry(BGraph *graph, BNode* root_node, BNode* node1, BNode* node2, BArc* arc1, BArc* arc2, float axis[3], float limit, int group)
{
	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 (abs(nor[0]) > abs(nor[1]) && abs(nor[0]) > abs(nor[2]) && nor[0] < 0) {
		negate_v3(nor);
	}
	else if (abs(nor[1]) > abs(nor[0]) && abs(nor[1]) > abs(nor[2]) && nor[1] < 0) {
		negate_v3(nor);
	}
	else if (abs(nor[2]) > abs(nor[1]) && abs(nor[2]) > abs(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_v3v3(node1->p, p) <= limit) {
		/* 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 */
	}
}
Beispiel #22
0
/* Update spring rest lenght, for dynamically deformable cloth */
static void cloth_update_spring_lengths( ClothModifierData *clmd, DerivedMesh *dm )
{
	Cloth *cloth = clmd->clothObject;
	LinkNode *search = cloth->springs;
	unsigned int struct_springs = 0;
	unsigned int i = 0;
	unsigned int mvert_num = (unsigned int)dm->getNumVerts(dm);
	float shrink_factor;

	clmd->sim_parms->avg_spring_len = 0.0f;

	for (i = 0; i < mvert_num; i++) {
		cloth->verts[i].avg_spring_len = 0.0f;
	}

	while (search) {
		ClothSpring *spring = search->link;

		if ( spring->type != CLOTH_SPRING_TYPE_SEWING ) {
			if ( spring->type & (CLOTH_SPRING_TYPE_STRUCTURAL | CLOTH_SPRING_TYPE_SHEAR | CLOTH_SPRING_TYPE_BENDING) )
				shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
			else
				shrink_factor = 1.0f;

			spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest) * shrink_factor;
		}

		if ( spring->type == CLOTH_SPRING_TYPE_STRUCTURAL ) {
			clmd->sim_parms->avg_spring_len += spring->restlen;
			cloth->verts[spring->ij].avg_spring_len += spring->restlen;
			cloth->verts[spring->kl].avg_spring_len += spring->restlen;
			struct_springs++;
		}

		search = search->next;
	}

	if (struct_springs > 0)
		clmd->sim_parms->avg_spring_len /= struct_springs;

	for (i = 0; i < mvert_num; i++) {
		if (cloth->verts[i].spring_count > 0)
			cloth->verts[i].avg_spring_len = cloth->verts[i].avg_spring_len * 0.49f / ((float)cloth->verts[i].spring_count);
	}
}
Beispiel #23
0
/* Helper, does all the point-spherecast work actually. */
static void mesh_verts_spherecast_do(
	const BVHTreeFromMesh *UNUSED(data), int index, const float v[3], const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
	float dist;
	const float *r1;
	float r2[3], i1[3];
	r1 = ray->origin;
	add_v3_v3v3(r2, r1, ray->direction);

	closest_to_line_segment_v3(i1, v, r1, r2);

	/* No hit if closest point is 'behind' the origin of the ray, or too far away from it. */
	if ((dot_v3v3v3(r1, i1, r2) >= 0.0f) && ((dist = len_v3v3(r1, i1)) < hit->dist)) {
		hit->index = index;
		hit->dist = dist;
		copy_v3_v3(hit->co, i1);
	}
}
Beispiel #24
0
/* get the camera's dof value, takes the dof object into account */
float BKE_camera_object_dof_distance(Object *ob)
{
	Camera *cam = (Camera *)ob->data;
	if (ob->type != OB_CAMERA)
		return 0.0f;
	if (cam->dof_ob) {
#if 0
		/* too simple, better to return the distance on the view axis only */
		return len_v3v3(ob->obmat[3], cam->dof_ob->obmat[3]);
#else
		float view_dir[3], dof_dir[3];
		normalize_v3_v3(view_dir, ob->obmat[2]);
		sub_v3_v3v3(dof_dir, ob->obmat[3], cam->dof_ob->obmat[3]);
		return fabsf(dot_v3v3(view_dir, dof_dir));
#endif
	}
	return cam->YF_dofdist;
}
Beispiel #25
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);
			}
		}
	}
}
static void harmonic_ray_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
{
	struct MeshRayCallbackData *data = userdata;
	MeshDeformBind *mdb = data->mdb;
	const MLoop *mloop = mdb->cagedm_cache.mloop;
	const MLoopTri *looptri = mdb->cagedm_cache.looptri, *lt;
	const float (*poly_nors)[3] = mdb->cagedm_cache.poly_nors;
	MeshDeformIsect *isec = data->isec;
	float no[3], co[3], end[3], uvw[3], dist;
	float *face[3];
	
	lt = &looptri[index];
	
	face[0] = mdb->cagecos[mloop[lt->tri[0]].v];
	face[1] = mdb->cagecos[mloop[lt->tri[1]].v];
	face[2] = mdb->cagecos[mloop[lt->tri[2]].v];
	
	add_v3_v3v3(end, isec->start, isec->vec);
	
	if (!meshdeform_tri_intersect(ray->origin, end, UNPACK3(face), co, uvw))
		return;

	if (poly_nors) {
		copy_v3_v3(no, poly_nors[lt->poly]);
	}
	else {
		normal_tri_v3(no, UNPACK3(face));
	}

	dist = len_v3v3(ray->origin, co) / isec->vec_length;
	if (dist < hit->dist) {
		hit->index = index;
		hit->dist = dist;
		copy_v3_v3(hit->co, co);
		
		isec->isect = (dot_v3v3(no, ray->direction) <= 0.0f);
		isec->lambda = dist;
	}
}
/* helper */
static void gp_stroke_to_path_add_point(tGpTimingData *gtd, BPoint *bp, const float p[3], const float prev_p[3],
                                        const bool do_gtd, const double inittime, const float time,
                                        const float width, const float rad_fac, float minmax_weights[2])
{
	copy_v3_v3(bp->vec, p);
	bp->vec[3] = 1.0f;
	
	/* set settings */
	bp->f1 = SELECT;
	bp->radius = width * rad_fac;
	bp->weight = width;
	CLAMP(bp->weight, 0.0f, 1.0f);
	if (bp->weight < minmax_weights[0]) {
		minmax_weights[0] = bp->weight;
	}
	else if (bp->weight > minmax_weights[1]) {
		minmax_weights[1] = bp->weight;
	}
	
	/* Update timing data */
	if (do_gtd) {
		gp_timing_data_add_point(gtd, inittime, time, len_v3v3(prev_p, p));
	}
}
Beispiel #28
0
/* only creates a table for a single channel in CurveMapping */
static void curvemap_make_table(CurveMap *cuma, rctf *clipr)
{
	CurveMapPoint *cmp = cuma->curve;
	BezTriple *bezt;
	float *fp, *allpoints, *lastpoint, curf, range;
	int a, totpoint;
	
	if (cuma->curve == NULL) return;
	
	/* default rect also is table range */
	cuma->mintable = clipr->xmin;
	cuma->maxtable = clipr->xmax;
	
	/* hrmf... we now rely on blender ipo beziers, these are more advanced */
	bezt = MEM_callocN(cuma->totpoint * sizeof(BezTriple), "beztarr");
	
	for (a = 0; a < cuma->totpoint; a++) {
		cuma->mintable = MIN2(cuma->mintable, cmp[a].x);
		cuma->maxtable = MAX2(cuma->maxtable, cmp[a].x);
		bezt[a].vec[1][0] = cmp[a].x;
		bezt[a].vec[1][1] = cmp[a].y;
		if (cmp[a].flag & CUMA_VECTOR)
			bezt[a].h1 = bezt[a].h2 = HD_VECT;
		else
			bezt[a].h1 = bezt[a].h2 = HD_AUTO;
	}
	
	for (a = 0; a < cuma->totpoint; a++) {
		if (a == 0)
			calchandle_curvemap(bezt, NULL, bezt + 1, 0);
		else if (a == cuma->totpoint - 1)
			calchandle_curvemap(bezt + a, bezt + a - 1, NULL, 0);
		else
			calchandle_curvemap(bezt + a, bezt + a - 1, bezt + a + 1, 0);
	}
	
	/* first and last handle need correction, instead of pointing to center of next/prev, 
	 * we let it point to the closest handle */
	if (cuma->totpoint > 2) {
		float hlen, nlen, vec[3];
		
		if (bezt[0].h2 == HD_AUTO) {
			
			hlen = len_v3v3(bezt[0].vec[1], bezt[0].vec[2]); /* original handle length */
			/* clip handle point */
			copy_v3_v3(vec, bezt[1].vec[0]);
			if (vec[0] < bezt[0].vec[1][0])
				vec[0] = bezt[0].vec[1][0];
			
			sub_v3_v3(vec, bezt[0].vec[1]);
			nlen = len_v3(vec);
			if (nlen > FLT_EPSILON) {
				mul_v3_fl(vec, hlen / nlen);
				add_v3_v3v3(bezt[0].vec[2], vec, bezt[0].vec[1]);
				sub_v3_v3v3(bezt[0].vec[0], bezt[0].vec[1], vec);
			}
		}
		a = cuma->totpoint - 1;
		if (bezt[a].h2 == HD_AUTO) {
			
			hlen = len_v3v3(bezt[a].vec[1], bezt[a].vec[0]); /* original handle length */
			/* clip handle point */
			copy_v3_v3(vec, bezt[a - 1].vec[2]);
			if (vec[0] > bezt[a].vec[1][0])
				vec[0] = bezt[a].vec[1][0];
			
			sub_v3_v3(vec, bezt[a].vec[1]);
			nlen = len_v3(vec);
			if (nlen > FLT_EPSILON) {
				mul_v3_fl(vec, hlen / nlen);
				add_v3_v3v3(bezt[a].vec[0], vec, bezt[a].vec[1]);
				sub_v3_v3v3(bezt[a].vec[2], bezt[a].vec[1], vec);
			}
		}
	}	
	/* make the bezier curve */
	if (cuma->table)
		MEM_freeN(cuma->table);
	totpoint = (cuma->totpoint - 1) * CM_RESOL;
	fp = allpoints = MEM_callocN(totpoint * 2 * sizeof(float), "table");
	
	for (a = 0; a < cuma->totpoint - 1; a++, fp += 2 * CM_RESOL) {
		correct_bezpart(bezt[a].vec[1], bezt[a].vec[2], bezt[a + 1].vec[0], bezt[a + 1].vec[1]);
		BKE_curve_forward_diff_bezier(bezt[a].vec[1][0], bezt[a].vec[2][0], bezt[a + 1].vec[0][0], bezt[a + 1].vec[1][0], fp, CM_RESOL - 1, 2 * sizeof(float));
		BKE_curve_forward_diff_bezier(bezt[a].vec[1][1], bezt[a].vec[2][1], bezt[a + 1].vec[0][1], bezt[a + 1].vec[1][1], fp + 1, CM_RESOL - 1, 2 * sizeof(float));
	}
	
	/* store first and last handle for extrapolation, unit length */
	cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
	cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
	range = sqrt(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
	cuma->ext_in[0] /= range;
	cuma->ext_in[1] /= range;

	a = cuma->totpoint - 1;
	cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0];
	cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1];
	range = sqrt(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
	cuma->ext_out[0] /= range;
	cuma->ext_out[1] /= range;
	
	/* cleanup */
	MEM_freeN(bezt);

	range = CM_TABLEDIV * (cuma->maxtable - cuma->mintable);
	cuma->range = 1.0f / range;
	
	/* now make a table with CM_TABLE equal x distances */
	fp = allpoints;
	lastpoint = allpoints + 2 * (totpoint - 1);
	cmp = MEM_callocN((CM_TABLE + 1) * sizeof(CurveMapPoint), "dist table");

	for (a = 0; a <= CM_TABLE; a++) {
		curf = cuma->mintable + range * (float)a;
		cmp[a].x = curf;
		
		/* get the first x coordinate larger than curf */
		while (curf >= fp[0] && fp != lastpoint) {
			fp += 2;
		}
		if (fp == allpoints || (curf >= fp[0] && fp == lastpoint))
			cmp[a].y = curvemap_calc_extend(cuma, curf, allpoints, lastpoint);
		else {
			float fac1 = fp[0] - fp[-2];
			float fac2 = fp[0] - curf;
			if (fac1 > FLT_EPSILON)
				fac1 = fac2 / fac1;
			else
				fac1 = 0.0f;
			cmp[a].y = fac1 * fp[-1] + (1.0f - fac1) * fp[1];
		}
	}
	
	MEM_freeN(allpoints);
	cuma->table = cmp;
}
Beispiel #29
0
/*
 * This function raycast a single vertex and updates the hit if the "hit" is considered valid.
 * Returns true if "hit" was updated.
 * Opts control whether an hit is valid or not
 * Supported options are:
 *	MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE (front faces hits are ignored)
 *	MOD_SHRINKWRAP_CULL_TARGET_BACKFACE (back faces hits are ignored)
 */
bool BKE_shrinkwrap_project_normal(
        char options, const float vert[3],
        const float dir[3], const SpaceTransform *transf,
        BVHTree *tree, BVHTreeRayHit *hit,
        BVHTree_RayCastCallback callback, void *userdata)
{
	/* don't use this because this dist value could be incompatible
	 * this value used by the callback for comparing prev/new dist values.
	 * also, at the moment there is no need to have a corrected 'dist' value */
// #define USE_DIST_CORRECT

	float tmp_co[3], tmp_no[3];
	const float *co, *no;
	BVHTreeRayHit hit_tmp;

	/* Copy from hit (we need to convert hit rays from one space coordinates to the other */
	memcpy(&hit_tmp, hit, sizeof(hit_tmp));

	/* Apply space transform (TODO readjust dist) */
	if (transf) {
		copy_v3_v3(tmp_co, vert);
		space_transform_apply(transf, tmp_co);
		co = tmp_co;

		copy_v3_v3(tmp_no, dir);
		space_transform_apply_normal(transf, tmp_no);
		no = tmp_no;

#ifdef USE_DIST_CORRECT
		hit_tmp.dist *= mat4_to_scale(((SpaceTransform *)transf)->local2target);
#endif
	}
	else {
		co = vert;
		no = dir;
	}

	hit_tmp.index = -1;

	BLI_bvhtree_ray_cast(tree, co, no, 0.0f, &hit_tmp, callback, userdata);

	if (hit_tmp.index != -1) {
		/* invert the normal first so face culling works on rotated objects */
		if (transf) {
			space_transform_invert_normal(transf, hit_tmp.no);
		}

		if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
			/* apply backface */
			const float dot = dot_v3v3(dir, hit_tmp.no);
			if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
			    ((options & MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)  && dot >= 0.0f))
			{
				return false;  /* Ignore hit */
			}
		}

		if (transf) {
			/* Inverting space transform (TODO make coeherent with the initial dist readjust) */
			space_transform_invert(transf, hit_tmp.co);
#ifdef USE_DIST_CORRECT
			hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
#endif
		}

		BLI_assert(hit_tmp.dist <= hit->dist);

		memcpy(hit, &hit_tmp, sizeof(hit_tmp));
		return true;
	}
	return false;
}
static MDefBoundIsect *meshdeform_ray_tree_intersect(MeshDeformBind *mdb, const float co1[3], const float co2[3])
{
	BVHTreeRayHit hit;
	MeshDeformIsect isect_mdef;
	struct MeshRayCallbackData data = {
		mdb,
		&isect_mdef,
	};
	float end[3], vec_normal[3];

	/* happens binding when a cage has no faces */
	if (UNLIKELY(mdb->bvhtree == NULL))
		return NULL;

	/* setup isec */
	memset(&isect_mdef, 0, sizeof(isect_mdef));
	isect_mdef.lambda = 1e10f;

	copy_v3_v3(isect_mdef.start, co1);
	copy_v3_v3(end, co2);
	sub_v3_v3v3(isect_mdef.vec, end, isect_mdef.start);
	isect_mdef.vec_length = normalize_v3_v3(vec_normal, isect_mdef.vec);

	hit.index = -1;
	hit.dist = BVH_RAYCAST_DIST_MAX;
	if (BLI_bvhtree_ray_cast(mdb->bvhtree, isect_mdef.start, vec_normal,
	                         0.0, &hit, harmonic_ray_callback, &data) != -1)
	{
		const MLoop *mloop = mdb->cagedm_cache.mloop;
		const MLoopTri *lt = &mdb->cagedm_cache.looptri[hit.index];
		const MPoly *mp = &mdb->cagedm_cache.mpoly[lt->poly];
		const float (*cagecos)[3] = mdb->cagecos;
		const float len = isect_mdef.lambda;
		MDefBoundIsect *isect;

		float (*mp_cagecos)[3] = BLI_array_alloca(mp_cagecos, mp->totloop);
		int i;

		/* create MDefBoundIsect, and extra for 'poly_weights[]' */
		isect = BLI_memarena_alloc(mdb->memarena, sizeof(*isect) + (sizeof(float) * mp->totloop));

		/* compute intersection coordinate */
		madd_v3_v3v3fl(isect->co, co1, isect_mdef.vec, len);

		isect->facing = isect_mdef.isect;

		isect->poly_index = lt->poly;

		isect->len = max_ff(len_v3v3(co1, isect->co), MESHDEFORM_LEN_THRESHOLD);

		/* compute mean value coordinates for interpolation */
		for (i = 0; i < mp->totloop; i++) {
			copy_v3_v3(mp_cagecos[i], cagecos[mloop[mp->loopstart + i].v]);
		}

		interp_weights_poly_v3(isect->poly_weights, mp_cagecos, mp->totloop, isect->co);

		return isect;
	}

	return NULL;
}