static bool testVoronoiEdge(const float site[2], const float point[2], const VoronoiEdge *edge) { float p[2]; if (isect_seg_seg_v2_point(site, point, edge->start, edge->end, p) == 1) { if (len_squared_v2v2(p, edge->start) > VORONOI_EPS && len_squared_v2v2(p, edge->end) > VORONOI_EPS) { return false; } } return true; }
static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather_points)[2], float (*diff_points)[2], const unsigned int tot_diff_point, const float ofs, const bool do_test) { unsigned int k_prev = tot_diff_point - 2; unsigned int k_curr = tot_diff_point - 1; unsigned int k_next = 0; unsigned int k; float d_prev[2]; float d_next[2]; float d[2]; const float *co_prev; const float *co_curr; const float *co_next; const float ofs_squared = ofs * ofs; co_prev = diff_points[k_prev]; co_curr = diff_points[k_curr]; co_next = diff_points[k_next]; /* precalc */ sub_v2_v2v2(d_prev, co_prev, co_curr); normalize_v2(d_prev); for (k = 0; k < tot_diff_point; k++) { /* co_prev = diff_points[k_prev]; */ /* precalc */ co_curr = diff_points[k_curr]; co_next = diff_points[k_next]; /* sub_v2_v2v2(d_prev, co_prev, co_curr); */ /* precalc */ sub_v2_v2v2(d_next, co_curr, co_next); /* normalize_v2(d_prev); */ /* precalc */ normalize_v2(d_next); if ((do_test == FALSE) || (len_squared_v2v2(diff_feather_points[k], diff_points[k]) < ofs_squared)) { add_v2_v2v2(d, d_prev, d_next); normalize_v2(d); diff_feather_points[k][0] = diff_points[k][0] + ( d[1] * ofs); diff_feather_points[k][1] = diff_points[k][1] + (-d[0] * ofs); } /* use next iter */ copy_v2_v2(d_prev, d_next); /* k_prev = k_curr; */ /* precalc */ k_curr = k_next; k_next++; } }
static int edge_isect_ls_sort_cb(void *thunk, void *def_a_ptr, void *def_b_ptr) { const float *co = thunk; ScanFillIsect *i_a = (ScanFillIsect *)(((LinkData *)def_a_ptr)->data); ScanFillIsect *i_b = (ScanFillIsect *)(((LinkData *)def_b_ptr)->data); const float a = len_squared_v2v2(co, i_a->co); const float b = len_squared_v2v2(co, i_b->co); if (a > b) { return -1; } else { return (a < b); } }
static void voronoi_createBoundaryEdges(ListBase *edges, int width, int height) { const float corners[4][2] = { {width - 1, 0.0f}, {width - 1, height - 1}, {0.0f, height - 1}, {0.0f, 0.0f}}; int i, dim = 0, dir = 1; float coord[2] = {0.0f, 0.0f}; float next_coord[2] = {0.0f, 0.0f}; for (i = 0; i < 4; i++) { while (voronoi_getNextSideCoord(edges, coord, dim, dir, next_coord)) { VoronoiEdge *edge = MEM_callocN(sizeof(VoronoiEdge), "boundary edge"); copy_v2_v2(edge->start, coord); copy_v2_v2(edge->end, next_coord); BLI_addtail(edges, edge); copy_v2_v2(coord, next_coord); } if (len_squared_v2v2(coord, corners[i]) > VORONOI_EPS) { VoronoiEdge *edge = MEM_callocN(sizeof(VoronoiEdge), "boundary edge"); copy_v2_v2(edge->start, coord); copy_v2_v2(edge->end, corners[i]); BLI_addtail(edges, edge); copy_v2_v2(coord, corners[i]); } dim = dim ? 0 : 1; if (i == 1) { dir = -1; } } }
static int voronoi_getNextSideCoord(ListBase *edges, float coord[2], int dim, int dir, float next_coord[2]) { VoronoiEdge *edge = edges->first; float distance = FLT_MAX; int other_dim = dim ? 0 : 1; while (edge) { int ok = FALSE; float co[2], cur_distance; if (fabsf(edge->start[other_dim] - coord[other_dim]) < VORONOI_EPS && len_squared_v2v2(coord, edge->start) > VORONOI_EPS) { copy_v2_v2(co, edge->start); ok = TRUE; } if (fabsf(edge->end[other_dim] - coord[other_dim]) < VORONOI_EPS && len_squared_v2v2(coord, edge->end) > VORONOI_EPS) { copy_v2_v2(co, edge->end); ok = TRUE; } if (ok) { if (dir > 0 && coord[dim] > co[dim]) { ok = FALSE; } else if (dir < 0 && coord[dim] < co[dim]) { ok = FALSE; } } if (ok) { cur_distance = len_squared_v2v2(coord, co); if (cur_distance < distance) { copy_v2_v2(next_coord, co); distance = cur_distance; } } edge = edge->next; } return distance < FLT_MAX; }
static float get_shortest_pattern_side(MovieTrackingMarker *marker) { int i, next; float len_sq = FLT_MAX; for (i = 0; i < 4; i++) { float cur_len; next = (i + 1) % 4; cur_len = len_squared_v2v2(marker->pattern_corners[i], marker->pattern_corners[next]); len_sq = min_ff(cur_len, len_sq); } return sqrtf(len_sq); }
static void vpaint_proj_dm_map_cosnos_update__map_cb( void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) { struct VertProjUpdate *vp_update = userData; struct VertProjHandle *vp_handle = vp_update->vp_handle; DMCoNo *co_no = &vp_handle->vcosnos[index]; /* find closest vertex */ { /* first find distance to this vertex */ float co_ss[2]; /* screenspace */ if (ED_view3d_project_float_object( vp_update->ar, co, co_ss, V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK) { const float dist_sq = len_squared_v2v2(vp_update->mval_fl, co_ss); if (dist_sq > vp_handle->dists_sq[index]) { /* bail out! */ return; } vp_handle->dists_sq[index] = dist_sq; } else if (vp_handle->dists_sq[index] != FLT_MAX) { /* already initialized & couldn't project this 'co' */ return; } } /* continue with regular functionality */ copy_v3_v3(co_no->co, co); if (no_f) { copy_v3_v3(co_no->no, no_f); } else { normal_short_to_float_v3(co_no->no, no_s); } }
static void voronoi_checkCircle(VoronoiProcess *process, VoronoiParabola *b) { VoronoiParabola *lp = voronoiParabola_getLeftParent(b); VoronoiParabola *rp = voronoiParabola_getRightParent(b); VoronoiParabola *a = voronoiParabola_getLeftChild(lp); VoronoiParabola *c = voronoiParabola_getRightChild(rp); VoronoiEvent *event; float ly = process->current_y; float s[2], dx, dy, d; if (!a || !c || len_squared_v2v2(a->site, c->site) < VORONOI_EPS) { return; } if (!voronoi_getEdgeIntersection(lp->edge, rp->edge, s)) { return; } dx = a->site[0] - s[0]; dy = a->site[1] - s[1]; d = sqrtf((dx * dx) + (dy * dy)); if (s[1] - d >= ly) { return; } event = MEM_callocN(sizeof(VoronoiEvent), "voronoi circle event"); event->type = voronoiEventType_Circle; event->site[0] = s[0]; event->site[1] = s[1] - d; b->event = event; event->parabola = b; voronoi_insertEvent(process, event); }
eRedrawFlag updateSelectedSnapPoint(TransInfo *t) { eRedrawFlag status = TREDRAW_NOTHING; if (t->tsnap.status & MULTI_POINTS) { TransSnapPoint *p, *closest_p = NULL; float dist_min_sq = TRANSFORM_SNAP_MAX_PX; const float mval_fl[2] = {t->mval[0], t->mval[1]}; float screen_loc[2]; for (p = t->tsnap.points.first; p; p = p->next) { float dist_sq; if (ED_view3d_project_float_global(t->ar, p->co, screen_loc, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { continue; } dist_sq = len_squared_v2v2(mval_fl, screen_loc); if (dist_sq < dist_min_sq) { closest_p = p; dist_min_sq = dist_sq; } } if (closest_p) { if (t->tsnap.selectedPoint != closest_p) { status = TREDRAW_HARD; } t->tsnap.selectedPoint = closest_p; } } return status; }
bool ED_mask_feather_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold, MaskLayer **masklay_r, MaskSpline **spline_r, MaskSplinePoint **point_r, MaskSplinePointUW **uw_r, float *score) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); MaskLayer *masklay, *point_masklay = NULL; MaskSpline *point_spline = NULL; MaskSplinePoint *point = NULL; MaskSplinePointUW *uw = NULL; const float threshold_sq = threshold * threshold; float len = FLT_MAX, co[2]; float scalex, scaley; int width, height; ED_mask_get_size(sa, &width, &height); ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley); co[0] = normal_co[0] * scalex; co[1] = normal_co[1] * scaley; for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; for (spline = masklay->splines.first; spline; spline = spline->next) { //MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); int i, tot_feather_point; float (*feather_points)[2], (*fp)[2]; if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { continue; } feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point); for (i = 0; i < spline->tot_point; i++) { int j; MaskSplinePoint *cur_point = &spline->points[i]; for (j = 0; j <= cur_point->tot_uw; j++) { float cur_len_sq, vec[2]; vec[0] = (*fp)[0] * scalex; vec[1] = (*fp)[1] * scaley; cur_len_sq = len_squared_v2v2(vec, co); if (point == NULL || cur_len_sq < len) { if (j == 0) uw = NULL; else uw = &cur_point->uw[j - 1]; point_masklay = masklay; point_spline = spline; point = cur_point; len = cur_len_sq; } fp++; } } MEM_freeN(feather_points); } } if (len < threshold_sq) { if (masklay_r) *masklay_r = point_masklay; if (spline_r) *spline_r = point_spline; if (point_r) *point_r = point; if (uw_r) *uw_r = uw; if (score) *score = sqrtf(len); return TRUE; } if (masklay_r) *masklay_r = NULL; if (spline_r) *spline_r = NULL; if (point_r) *point_r = NULL; return FALSE; }
static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], RulerItem **r_ruler_item, int *r_co_index) { ARegion *ar = ruler_info->ar; RulerItem *ruler_item; float dist_best = RULER_PICK_DIST_SQ; RulerItem *ruler_item_best = NULL; int co_index_best = -1; for (ruler_item = ruler_info->items.first; ruler_item; ruler_item = ruler_item->next) { float co_ss[3][2]; float dist; int j; /* should these be checked? - ok for now not to */ for (j = 0; j < 3; j++) { ED_view3d_project_float_global(ar, ruler_item->co[j], co_ss[j], V3D_PROJ_TEST_NOP); } if (ruler_item->flag & RULERITEM_USE_ANGLE) { dist = min_ff(dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[1]), dist_squared_to_line_segment_v2(mval, co_ss[1], co_ss[2])); if (dist < dist_best) { dist_best = dist; ruler_item_best = ruler_item; { const float dist_points[3] = { len_squared_v2v2(co_ss[0], mval), len_squared_v2v2(co_ss[1], mval), len_squared_v2v2(co_ss[2], mval), }; if (min_fff(UNPACK3(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = min_axis_v3(dist_points); } else { co_index_best = -1; } } } } else { dist = dist_squared_to_line_segment_v2(mval, co_ss[0], co_ss[2]); if (dist < dist_best) { dist_best = dist; ruler_item_best = ruler_item; { const float dist_points[2] = { len_squared_v2v2(co_ss[0], mval), len_squared_v2v2(co_ss[2], mval), }; if (min_ff(UNPACK2(dist_points)) < RULER_PICK_DIST_SQ) { co_index_best = (dist_points[0] < dist_points[1]) ? 0 : 2; } else { co_index_best = -1; } } } } } if (ruler_item_best) { *r_ruler_item = ruler_item_best; *r_co_index = co_index_best; return true; } else { *r_ruler_item = NULL; *r_co_index = -1; return false; } }
/* thresh is threshold for comparing vertices, uvs, vertex colors, * weights, etc.*/ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, const float thresh) { const float thresh_sq = thresh * thresh; CustomDataLayer *l1, *l2; int i, i1 = 0, i2 = 0, tot, j; for (i = 0; i < c1->totlayer; i++) { if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i1++; } } for (i = 0; i < c2->totlayer; i++) { if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i2++; } } if (i1 != i2) return MESHCMP_CDLAYERS_MISMATCH; l1 = c1->layers; l2 = c2->layers; tot = i1; i1 = 0; i2 = 0; for (i = 0; i < tot; i++) { while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i1++, l1++; } while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT)) { i2++, l2++; } if (l1->type == CD_MVERT) { MVert *v1 = l1->data; MVert *v2 = l2->data; int vtot = m1->totvert; for (j = 0; j < vtot; j++, v1++, v2++) { if (len_v3v3(v1->co, v2->co) > thresh) return MESHCMP_VERTCOMISMATCH; /* I don't care about normals, let's just do coodinates */ } } /*we're order-agnostic for edges here*/ if (l1->type == CD_MEDGE) { MEdge *e1 = l1->data; MEdge *e2 = l2->data; int etot = m1->totedge; EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); for (j = 0; j < etot; j++, e1++) { BLI_edgehash_insert(eh, e1->v1, e1->v2, e1); } for (j = 0; j < etot; j++, e2++) { if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2)) return MESHCMP_EDGEUNKNOWN; } BLI_edgehash_free(eh, NULL); } if (l1->type == CD_MPOLY) { MPoly *p1 = l1->data; MPoly *p2 = l2->data; int ptot = m1->totpoly; for (j = 0; j < ptot; j++, p1++, p2++) { MLoop *lp1, *lp2; int k; if (p1->totloop != p2->totloop) return MESHCMP_POLYMISMATCH; lp1 = m1->mloop + p1->loopstart; lp2 = m2->mloop + p2->loopstart; for (k = 0; k < p1->totloop; k++, lp1++, lp2++) { if (lp1->v != lp2->v) return MESHCMP_POLYVERTMISMATCH; } } } if (l1->type == CD_MLOOP) { MLoop *lp1 = l1->data; MLoop *lp2 = l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { if (lp1->v != lp2->v) return MESHCMP_LOOPMISMATCH; } } if (l1->type == CD_MLOOPUV) { MLoopUV *lp1 = l1->data; MLoopUV *lp2 = l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { if (len_squared_v2v2(lp1->uv, lp2->uv) > thresh_sq) return MESHCMP_LOOPUVMISMATCH; } } if (l1->type == CD_MLOOPCOL) { MLoopCol *lp1 = l1->data; MLoopCol *lp2 = l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { if (ABS(lp1->r - lp2->r) > thresh || ABS(lp1->g - lp2->g) > thresh || ABS(lp1->b - lp2->b) > thresh || ABS(lp1->a - lp2->a) > thresh) { return MESHCMP_LOOPCOLMISMATCH; } } } if (l1->type == CD_MDEFORMVERT) { MDeformVert *dv1 = l1->data; MDeformVert *dv2 = l2->data; int dvtot = m1->totvert; for (j = 0; j < dvtot; j++, dv1++, dv2++) { int k; MDeformWeight *dw1 = dv1->dw, *dw2 = dv2->dw; if (dv1->totweight != dv2->totweight) return MESHCMP_DVERT_TOTGROUPMISMATCH; for (k = 0; k < dv1->totweight; k++, dw1++, dw2++) { if (dw1->def_nr != dw2->def_nr) return MESHCMP_DVERT_GROUPMISMATCH; if (ABS(dw1->weight - dw2->weight) > thresh) return MESHCMP_DVERT_WEIGHTMISMATCH; } } } } return 0; }
static VChar *freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) { const float scale = vfd->scale; const float eps = 0.0001f; const float eps_sq = eps * eps; /* Blender */ struct Nurb *nu; struct VChar *che; struct BezTriple *bezt; /* Freetype2 */ FT_GlyphSlot glyph; FT_UInt glyph_index; FT_Outline ftoutline; float dx, dy; int j, k, l, m = 0; /* * Generate the character 3D data * * Get the FT Glyph index and load the Glyph */ glyph_index = FT_Get_Char_Index(face, charcode); err = FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); /* If loading succeeded, convert the FT glyph to the internal format */ if (!err) { int *npoints; int *onpoints; /* First we create entry for the new character to the character list */ che = (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char"); /* Take some data for modifying purposes */ glyph = face->glyph; ftoutline = glyph->outline; /* Set the width and character code */ che->index = charcode; che->width = glyph->advance.x * scale; BLI_ghash_insert(vfd->characters, SET_UINT_IN_POINTER(che->index), che); /* Start converting the FT data */ npoints = (int *)MEM_mallocN((ftoutline.n_contours) * sizeof(int), "endpoints"); onpoints = (int *)MEM_callocN((ftoutline.n_contours) * sizeof(int), "onpoints"); /* calculate total points of each contour */ for (j = 0; j < ftoutline.n_contours; j++) { if (j == 0) npoints[j] = ftoutline.contours[j] + 1; else npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; } /* get number of on-curve points for beziertriples (including conic virtual on-points) */ for (j = 0; j < ftoutline.n_contours; j++) { for (k = 0; k < npoints[j]; k++) { l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k; if (ftoutline.tags[l] == FT_Curve_Tag_On) onpoints[j]++; if (k < npoints[j] - 1) { if (ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) { onpoints[j]++; } } } } /* contour loop, bezier & conic styles merged */ for (j = 0; j < ftoutline.n_contours; j++) { /* add new curve */ nu = (Nurb *)MEM_callocN(sizeof(struct Nurb), "objfnt_nurb"); bezt = (BezTriple *)MEM_callocN((onpoints[j]) * sizeof(BezTriple), "objfnt_bezt"); BLI_addtail(&che->nurbsbase, nu); nu->type = CU_BEZIER; nu->pntsu = onpoints[j]; nu->resolu = 8; nu->flag = CU_2D; nu->flagu = CU_NURB_CYCLIC; nu->bezt = bezt; /* individual curve loop, start-end */ for (k = 0; k < npoints[j]; k++) { if (j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; if (k == 0) m = l; /* virtual conic on-curve points */ if (k < npoints[j] - 1) { if (ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) { dx = (ftoutline.points[l].x + ftoutline.points[l + 1].x) * scale / 2.0f; dy = (ftoutline.points[l].y + ftoutline.points[l + 1].y) * scale / 2.0f; /* left handle */ bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x) * scale) / 3.0f; bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y) * scale) / 3.0f; /* midpoint (virtual on-curve point) */ bezt->vec[1][0] = dx; bezt->vec[1][1] = dy; /* right handle */ bezt->vec[2][0] = (dx + (2 * ftoutline.points[l + 1].x) * scale) / 3.0f; bezt->vec[2][1] = (dy + (2 * ftoutline.points[l + 1].y) * scale) / 3.0f; bezt->h1 = bezt->h2 = HD_ALIGN; bezt->radius = 1.0f; bezt++; } } /* on-curve points */ if (ftoutline.tags[l] == FT_Curve_Tag_On) { /* left handle */ if (k > 0) { if (ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { bezt->vec[0][0] = ftoutline.points[l - 1].x * scale; bezt->vec[0][1] = ftoutline.points[l - 1].y * scale; bezt->h1 = HD_FREE; } else if (ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x)) * scale / 3.0f; bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y)) * scale / 3.0f; bezt->h1 = HD_FREE; } else { bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l - 1].x) * scale / 3.0f; bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l - 1].y) * scale / 3.0f; bezt->h1 = HD_VECT; } } else { /* first point on curve */ if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; bezt->h1 = HD_FREE; } else if (ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x)) * scale / 3.0f; bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y)) * scale / 3.0f; bezt->h1 = HD_FREE; } else { bezt->vec[0][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x) * scale / 3.0f; bezt->vec[0][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y) * scale / 3.0f; bezt->h1 = HD_VECT; } } /* midpoint (on-curve point) */ bezt->vec[1][0] = ftoutline.points[l].x * scale; bezt->vec[1][1] = ftoutline.points[l].y * scale; /* right handle */ if (k < (npoints[j] - 1)) { if (ftoutline.tags[l + 1] == FT_Curve_Tag_Cubic) { bezt->vec[2][0] = ftoutline.points[l + 1].x * scale; bezt->vec[2][1] = ftoutline.points[l + 1].y * scale; bezt->h2 = HD_FREE; } else if (ftoutline.tags[l + 1] == FT_Curve_Tag_Conic) { bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l + 1].x)) * scale / 3.0f; bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l + 1].y)) * scale / 3.0f; bezt->h2 = HD_FREE; } else { bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[l + 1].x) * scale / 3.0f; bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[l + 1].y) * scale / 3.0f; bezt->h2 = HD_VECT; } } else { /* last point on curve */ if (ftoutline.tags[m] == FT_Curve_Tag_Cubic) { bezt->vec[2][0] = ftoutline.points[m].x * scale; bezt->vec[2][1] = ftoutline.points[m].y * scale; bezt->h2 = HD_FREE; } else if (ftoutline.tags[m] == FT_Curve_Tag_Conic) { bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x)) * scale / 3.0f; bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y)) * scale / 3.0f; bezt->h2 = HD_FREE; } else { bezt->vec[2][0] = ftoutline.points[l].x * scale - (ftoutline.points[l].x - ftoutline.points[m].x) * scale / 3.0f; bezt->vec[2][1] = ftoutline.points[l].y * scale - (ftoutline.points[l].y - ftoutline.points[m].y) * scale / 3.0f; bezt->h2 = HD_VECT; } } /* get the handles that are aligned, tricky... * - check if one of them is a vector handle. * - dist_squared_to_line_v2, check if the three beztriple points are on one line * - len_squared_v2v2, see if there's a distance between the three points * - len_squared_v2v2 again, to check the angle between the handles */ if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) && (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) < (0.001f * 0.001f)) && (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) && (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) && (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) && (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2])))) { bezt->h1 = bezt->h2 = HD_ALIGN; } bezt->radius = 1.0f; bezt++; } } } if (npoints) MEM_freeN(npoints); if (onpoints) MEM_freeN(onpoints); return che; } return NULL; }
static void setup_vertex_point( Mask *mask, MaskSpline *spline, MaskSplinePoint *new_point, const float point_co[2], const float u, const float ctime, const MaskSplinePoint *reference_point, const bool reference_adjacent) { const MaskSplinePoint *reference_parent_point = NULL; BezTriple *bezt; float co[3]; copy_v2_v2(co, point_co); co[2] = 0.0f; /* point coordinate */ bezt = &new_point->bezt; bezt->h1 = bezt->h2 = HD_ALIGN; if (reference_point) { if (reference_point->bezt.h1 == HD_VECT && reference_point->bezt.h2 == HD_VECT) { /* If the reference point is sharp try using some smooth point as reference * for handles. */ int point_index = reference_point - spline->points; int delta = new_point == spline->points ? 1 : -1; int i = 0; for (i = 0; i < spline->tot_point - 1; ++i) { MaskSplinePoint *current_point; point_index += delta; if (point_index == -1 || point_index >= spline->tot_point) { if (spline->flag & MASK_SPLINE_CYCLIC) { if (point_index == -1) { point_index = spline->tot_point - 1; } else if (point_index >= spline->tot_point) { point_index = 0; } } else { break; } } current_point = &spline->points[point_index]; if (current_point->bezt.h1 != HD_VECT || current_point->bezt.h2 != HD_VECT) { bezt->h1 = bezt->h2 = MAX2(current_point->bezt.h2, current_point->bezt.h1); break; } } } else { bezt->h1 = bezt->h2 = MAX2(reference_point->bezt.h2, reference_point->bezt.h1); } reference_parent_point = reference_point; } else if (reference_adjacent) { if (spline->tot_point != 1) { MaskSplinePoint *prev_point, *next_point, *close_point; const int index = (int)(new_point - spline->points); if (spline->flag & MASK_SPLINE_CYCLIC) { prev_point = &spline->points[mod_i(index - 1, spline->tot_point)]; next_point = &spline->points[mod_i(index + 1, spline->tot_point)]; } else { prev_point = (index != 0) ? &spline->points[index - 1] : NULL; next_point = (index != spline->tot_point - 1) ? &spline->points[index + 1] : NULL; } if (prev_point && next_point) { close_point = (len_squared_v2v2(new_point->bezt.vec[1], prev_point->bezt.vec[1]) < len_squared_v2v2(new_point->bezt.vec[1], next_point->bezt.vec[1])) ? prev_point : next_point; } else { close_point = prev_point ? prev_point : next_point; } /* handle type */ char handle_type = 0; if (prev_point) { handle_type = prev_point->bezt.h2; } if (next_point) { handle_type = MAX2(next_point->bezt.h2, handle_type); } bezt->h1 = bezt->h2 = handle_type; /* parent */ reference_parent_point = close_point; /* note, we may want to copy other attributes later, radius? pressure? color? */ } } copy_v3_v3(bezt->vec[0], co); copy_v3_v3(bezt->vec[1], co); copy_v3_v3(bezt->vec[2], co); if (reference_parent_point) { new_point->parent = reference_parent_point->parent; if (new_point->parent.id) { float parent_matrix[3][3]; BKE_mask_point_parent_matrix_get(new_point, ctime, parent_matrix); invert_m3(parent_matrix); mul_m3_v2(parent_matrix, new_point->bezt.vec[1]); } } else { BKE_mask_parent_init(&new_point->parent); } if (spline->tot_point != 1) { BKE_mask_calc_handle_adjacent_interp(spline, new_point, u); } /* select new point */ MASKPOINT_SEL_ALL(new_point); ED_mask_select_flush_all(mask); }
MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold, MaskLayer **masklay_r, MaskSpline **spline_r, bool *is_handle_r, float *score) { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); MaskLayer *masklay; MaskLayer *point_masklay = NULL; MaskSpline *point_spline = NULL; MaskSplinePoint *point = NULL; float co[2]; const float threshold_sq = threshold * threshold; float len_sq = FLT_MAX, scalex, scaley; int is_handle = FALSE, width, height; ED_mask_get_size(sa, &width, &height); ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley); co[0] = normal_co[0] * scalex; co[1] = normal_co[1] * scaley; for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) { continue; } for (spline = masklay->splines.first; spline; spline = spline->next) { MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline); int i; for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *cur_point = &spline->points[i]; MaskSplinePoint *cur_point_deform = &points_array[i]; float cur_len_sq, vec[2], handle[2]; vec[0] = cur_point_deform->bezt.vec[1][0] * scalex; vec[1] = cur_point_deform->bezt.vec[1][1] * scaley; if (BKE_mask_point_has_handle(cur_point)) { BKE_mask_point_handle(cur_point_deform, handle); handle[0] *= scalex; handle[1] *= scaley; cur_len_sq = len_squared_v2v2(co, handle); if (cur_len_sq < len_sq) { point_masklay = masklay; point_spline = spline; point = cur_point; len_sq = cur_len_sq; is_handle = TRUE; } } cur_len_sq = len_squared_v2v2(co, vec); if (cur_len_sq < len_sq) { point_spline = spline; point_masklay = masklay; point = cur_point; len_sq = cur_len_sq; is_handle = FALSE; } } } } if (len_sq < threshold_sq) { if (masklay_r) *masklay_r = point_masklay; if (spline_r) *spline_r = point_spline; if (is_handle_r) *is_handle_r = is_handle; if (score) *score = sqrtf(len_sq); return point; } if (masklay_r) *masklay_r = NULL; if (spline_r) *spline_r = NULL; if (is_handle_r) *is_handle_r = FALSE; return NULL; }
static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) { SlidePointData *data = (SlidePointData *)op->customdata; BezTriple *bezt = &data->point->bezt; float co[2], dco[2]; switch (event->type) { case LEFTALTKEY: case RIGHTALTKEY: case LEFTSHIFTKEY: case RIGHTSHIFTKEY: if (ELEM(event->type, LEFTALTKEY, RIGHTALTKEY)) { if (data->action == SLIDE_ACTION_FEATHER) data->overall_feather = (event->val == KM_PRESS); else data->curvature_only = (event->val == KM_PRESS); } if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) data->accurate = (event->val == KM_PRESS); /* fall-through */ /* update CV position */ case MOUSEMOVE: { ScrArea *sa = CTX_wm_area(C); ARegion *ar = CTX_wm_region(C); ED_mask_mouse_pos(sa, ar, event->mval, co); sub_v2_v2v2(dco, co, data->co); if (data->action == SLIDE_ACTION_HANDLE) { float delta[2], offco[2]; sub_v2_v2v2(delta, data->handle, data->co); sub_v2_v2v2(offco, co, data->co); if (data->accurate) mul_v2_fl(offco, 0.2f); add_v2_v2(offco, data->co); add_v2_v2(offco, delta); BKE_mask_point_set_handle(data->point, offco, data->curvature_only, data->handle, data->vec); } else if (data->action == SLIDE_ACTION_POINT) { float delta[2]; copy_v2_v2(delta, dco); if (data->accurate) mul_v2_fl(delta, 0.2f); add_v2_v2v2(bezt->vec[0], data->vec[0], delta); add_v2_v2v2(bezt->vec[1], data->vec[1], delta); add_v2_v2v2(bezt->vec[2], data->vec[2], delta); } else if (data->action == SLIDE_ACTION_FEATHER) { float vec[2], no[2], p[2], c[2], w, offco[2]; float *weight = NULL; float weight_scalar = 1.0f; int overall_feather = data->overall_feather || data->initial_feather; add_v2_v2v2(offco, data->feather, dco); if (data->uw) { /* project on both sides and find the closest one, * prevents flickering when projecting onto both sides can happen */ const float u_pos = BKE_mask_spline_project_co(data->spline, data->point, data->uw->u, offco, MASK_PROJ_NEG); const float u_neg = BKE_mask_spline_project_co(data->spline, data->point, data->uw->u, offco, MASK_PROJ_POS); float dist_pos = FLT_MAX; float dist_neg = FLT_MAX; float co_pos[2]; float co_neg[2]; float u; if (u_pos > 0.0f && u_pos < 1.0f) { BKE_mask_point_segment_co(data->spline, data->point, u_pos, co_pos); dist_pos = len_squared_v2v2(offco, co_pos); } if (u_neg > 0.0f && u_neg < 1.0f) { BKE_mask_point_segment_co(data->spline, data->point, u_neg, co_neg); dist_neg = len_squared_v2v2(offco, co_neg); } u = dist_pos < dist_neg ? u_pos : u_neg; if (u > 0.0f && u < 1.0f) { data->uw->u = u; data->uw = BKE_mask_point_sort_uw(data->point, data->uw); weight = &data->uw->w; weight_scalar = BKE_mask_point_weight_scalar(data->spline, data->point, u); if (weight_scalar != 0.0f) { weight_scalar = 1.0f / weight_scalar; } BKE_mask_point_normal(data->spline, data->point, data->uw->u, no); BKE_mask_point_segment_co(data->spline, data->point, data->uw->u, p); } } else { weight = &bezt->weight; /* weight_scalar = 1.0f; keep as is */ copy_v2_v2(no, data->no); copy_v2_v2(p, bezt->vec[1]); } if (weight) { sub_v2_v2v2(c, offco, p); project_v2_v2v2(vec, c, no); w = len_v2(vec); if (overall_feather) { float delta; if (dot_v2v2(no, vec) <= 0.0f) w = -w; delta = w - data->weight * data->weight_scalar; if (data->orig_spline == NULL) { /* restore weight for currently sliding point, so orig_spline would be created * with original weights used */ *weight = data->weight; data->orig_spline = BKE_mask_spline_copy(data->spline); } slide_point_delta_all_feather(data, delta); } else { if (dot_v2v2(no, vec) <= 0.0f) w = 0.0f; if (data->orig_spline) { /* restore possible overall feather changes */ slide_point_restore_spline(data); BKE_mask_spline_free(data->orig_spline); data->orig_spline = NULL; } if (weight_scalar != 0.0f) { *weight = w * weight_scalar; } } } } WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask); DAG_id_tag_update(&data->mask->id, 0); break; } case LEFTMOUSE: if (event->val == KM_RELEASE) { Scene *scene = CTX_data_scene(C); /* dont key sliding feather uw's */ if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == FALSE) { if (IS_AUTOKEY_ON(scene)) { ED_mask_layer_shape_auto_key(data->masklay, CFRA); } } WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask); DAG_id_tag_update(&data->mask->id, 0); free_slide_point_data(op->customdata); /* keep this last! */ return OPERATOR_FINISHED; } break; case ESCKEY: cancel_slide_point(op->customdata); WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask); DAG_id_tag_update(&data->mask->id, 0); free_slide_point_data(op->customdata); /* keep this last! */ return OPERATOR_CANCELLED; } return OPERATOR_RUNNING_MODAL; }
static void freetypechar_to_vchar(FT_Face face, FT_ULong charcode, VFontData *vfd) { // Blender struct Nurb *nu; struct VChar *che; struct BezTriple *bezt; // Freetype2 FT_GlyphSlot glyph; FT_UInt glyph_index; FT_Outline ftoutline; float scale, height; float dx, dy; int j,k,l,m=0; // adjust font size height= ((double) face->bbox.yMax - (double) face->bbox.yMin); if(height != 0.0) scale = 1.0 / height; else scale = 1.0 / 1000.0; // // Generate the character 3D data // // Get the FT Glyph index and load the Glyph glyph_index= FT_Get_Char_Index(face, charcode); err= FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP); // If loading succeeded, convert the FT glyph to the internal format if(!err) { int *npoints; int *onpoints; // First we create entry for the new character to the character list che= (VChar *) MEM_callocN(sizeof(struct VChar), "objfnt_char"); BLI_addtail(&vfd->characters, che); // Take some data for modifying purposes glyph= face->glyph; ftoutline= glyph->outline; // Set the width and character code che->index= charcode; che->width= glyph->advance.x * scale; // Start converting the FT data npoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"endpoints") ; onpoints = (int *)MEM_callocN((ftoutline.n_contours)* sizeof(int),"onpoints") ; // calculate total points of each contour for(j = 0; j < ftoutline.n_contours; j++) { if(j == 0) npoints[j] = ftoutline.contours[j] + 1; else npoints[j] = ftoutline.contours[j] - ftoutline.contours[j - 1]; } // get number of on-curve points for beziertriples (including conic virtual on-points) for(j = 0; j < ftoutline.n_contours; j++) { for(k = 0; k < npoints[j]; k++) { if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; if(ftoutline.tags[l] == FT_Curve_Tag_On) onpoints[j]++; if(k < npoints[j] - 1 ) if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) onpoints[j]++; } } //contour loop, bezier & conic styles merged for(j = 0; j < ftoutline.n_contours; j++) { // add new curve nu = (Nurb*)MEM_callocN(sizeof(struct Nurb),"objfnt_nurb"); bezt = (BezTriple*)MEM_callocN((onpoints[j])* sizeof(BezTriple),"objfnt_bezt") ; BLI_addtail(&che->nurbsbase, nu); nu->type= CU_BEZIER; nu->pntsu = onpoints[j]; nu->resolu= 8; nu->flag= CU_2D; nu->flagu= CU_NURB_CYCLIC; nu->bezt = bezt; //individual curve loop, start-end for(k = 0; k < npoints[j]; k++) { if(j > 0) l = k + ftoutline.contours[j - 1] + 1; else l = k; if(k == 0) m = l; //virtual conic on-curve points if(k < npoints[j] - 1 ) { if( ftoutline.tags[l] == FT_Curve_Tag_Conic && ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { dx = (ftoutline.points[l].x + ftoutline.points[l+1].x)* scale / 2.0; dy = (ftoutline.points[l].y + ftoutline.points[l+1].y)* scale / 2.0; //left handle bezt->vec[0][0] = (dx + (2 * ftoutline.points[l].x)* scale) / 3.0; bezt->vec[0][1] = (dy + (2 * ftoutline.points[l].y)* scale) / 3.0; //midpoint (virtual on-curve point) bezt->vec[1][0] = dx; bezt->vec[1][1] = dy; //right handle bezt->vec[2][0] = (dx + (2 * ftoutline.points[l+1].x)* scale) / 3.0; bezt->vec[2][1] = (dy + (2 * ftoutline.points[l+1].y)* scale) / 3.0; bezt->h1= bezt->h2= HD_ALIGN; bezt->radius= 1.0f; bezt++; } } //on-curve points if(ftoutline.tags[l] == FT_Curve_Tag_On) { //left handle if(k > 0) { if(ftoutline.tags[l - 1] == FT_Curve_Tag_Cubic) { bezt->vec[0][0] = ftoutline.points[l-1].x* scale; bezt->vec[0][1] = ftoutline.points[l-1].y* scale; bezt->h1= HD_FREE; } else if(ftoutline.tags[l - 1] == FT_Curve_Tag_Conic) { bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l - 1].x))* scale / 3.0; bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l - 1].y))* scale / 3.0; bezt->h1= HD_FREE; } else { bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l-1].x)* scale / 3.0; bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l-1].y)* scale / 3.0; bezt->h1= HD_VECT; } } else { //first point on curve if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Cubic) { bezt->vec[0][0] = ftoutline.points[ftoutline.contours[j]].x * scale; bezt->vec[0][1] = ftoutline.points[ftoutline.contours[j]].y * scale; bezt->h1= HD_FREE; } else if(ftoutline.tags[ftoutline.contours[j]] == FT_Curve_Tag_Conic) { bezt->vec[0][0] = (ftoutline.points[l].x + (2 * ftoutline.points[ftoutline.contours[j]].x))* scale / 3.0 ; bezt->vec[0][1] = (ftoutline.points[l].y + (2 * ftoutline.points[ftoutline.contours[j]].y))* scale / 3.0 ; bezt->h1= HD_FREE; } else { bezt->vec[0][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[ftoutline.contours[j]].x)* scale / 3.0; bezt->vec[0][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[ftoutline.contours[j]].y)* scale / 3.0; bezt->h1= HD_VECT; } } //midpoint (on-curve point) bezt->vec[1][0] = ftoutline.points[l].x* scale; bezt->vec[1][1] = ftoutline.points[l].y* scale; //right handle if(k < (npoints[j] - 1)) { if(ftoutline.tags[l+1] == FT_Curve_Tag_Cubic) { bezt->vec[2][0] = ftoutline.points[l+1].x* scale; bezt->vec[2][1] = ftoutline.points[l+1].y* scale; bezt->h2= HD_FREE; } else if(ftoutline.tags[l+1] == FT_Curve_Tag_Conic) { bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[l+1].x))* scale / 3.0; bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[l+1].y))* scale / 3.0; bezt->h2= HD_FREE; } else { bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[l+1].x)* scale / 3.0; bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[l+1].y)* scale / 3.0; bezt->h2= HD_VECT; } } else { //last point on curve if(ftoutline.tags[m] == FT_Curve_Tag_Cubic) { bezt->vec[2][0] = ftoutline.points[m].x* scale; bezt->vec[2][1] = ftoutline.points[m].y* scale; bezt->h2= HD_FREE; } else if(ftoutline.tags[m] == FT_Curve_Tag_Conic) { bezt->vec[2][0] = (ftoutline.points[l].x + (2 * ftoutline.points[m].x))* scale / 3.0 ; bezt->vec[2][1] = (ftoutline.points[l].y + (2 * ftoutline.points[m].y))* scale / 3.0 ; bezt->h2= HD_FREE; } else { bezt->vec[2][0] = ftoutline.points[l].x* scale - (ftoutline.points[l].x - ftoutline.points[m].x)* scale / 3.0; bezt->vec[2][1] = ftoutline.points[l].y* scale - (ftoutline.points[l].y - ftoutline.points[m].y)* scale / 3.0; bezt->h2= HD_VECT; } } // get the handles that are aligned, tricky... // dist_to_line_v2, check if the three beztriple points are on one line // len_squared_v2v2, see if there's a distance between the three points // len_squared_v2v2 again, to check the angle between the handles // finally, check if one of them is a vector handle if((dist_to_line_v2(bezt->vec[0],bezt->vec[1],bezt->vec[2]) < 0.001) && (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > 0.0001*0.0001) && (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > 0.0001*0.0001) && (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > 0.0002*0.0001) && (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > MAX2(len_squared_v2v2(bezt->vec[0], bezt->vec[1]), len_squared_v2v2(bezt->vec[1], bezt->vec[2]))) && bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) { bezt->h1= bezt->h2= HD_ALIGN; } bezt->radius= 1.0f; bezt++; } } } if(npoints) MEM_freeN(npoints); if(onpoints) MEM_freeN(onpoints); } }