Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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++;
	}
}
Exemplo n.º 3
0
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);
	}
}
Exemplo n.º 4
0
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;
    }
  }
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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);
}
Exemplo n.º 7
0
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);
	}
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 9
0
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;
}
Exemplo n.º 10
0
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;
}
Exemplo n.º 11
0
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;
	}
}
Exemplo n.º 12
0
/* 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;
}
Exemplo n.º 13
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;
}
Exemplo n.º 14
0
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);
}
Exemplo n.º 15
0
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;
}
Exemplo n.º 16
0
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;
}
Exemplo n.º 17
0
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);	
	}
}