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; }
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); }
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; }
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); }
/* * 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; }
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; }
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; }
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; } }
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; } } }
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; }
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 */ } }
/* 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); } }
/* 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); } }
/* 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; }
/* 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)); } }
/* 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; }
/* * 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; }