Exemple #1
0
/* Project screenspace coordinates to 3D-space
 * NOTE: We include this as a utility function, since the standard method
 *       involves quite a few steps, which are invariably always the same
 *       for all GPencil operations. So, it's nicer to just centralise these.
 * WARNING: Assumes that it is getting called in a 3D view only
 */
bool gp_point_xy_to_3d(GP_SpaceConversion *gsc, Scene *scene, const float screen_co[2], float r_out[3])
{
	View3D *v3d = gsc->sa->spacedata.first;
	RegionView3D *rv3d = gsc->ar->regiondata;
	float *rvec = ED_view3d_cursor3d_get(scene, v3d);
	float ref[3] = {rvec[0], rvec[1], rvec[2]};
	float zfac = ED_view3d_calc_zfac(rv3d, rvec, NULL);
	
	float mval_f[2], mval_prj[2];
	float dvec[3];
	
	copy_v2_v2(mval_f, screen_co);
	
	if (ED_view3d_project_float_global(gsc->ar, ref, mval_prj, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
		sub_v2_v2v2(mval_f, mval_prj, mval_f);
		ED_view3d_win_to_delta(gsc->ar, mval_f, dvec, zfac);
		sub_v3_v3v3(r_out, rvec, dvec);
		
		return true;
	}
	else {
		zero_v3(r_out);
		
		return false;
	}
}
/**
 * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
 *
 * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
 * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
 *
 * \param r_x: [out] The screen-space x-coordinate of the point
 * \param r_y: [out] The screen-space y-coordinate of the point
 *
 * \warning This assumes that the caller has already checked whether the stroke in question can be drawn
 */
void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
                       float *r_x, float *r_y)
{
	ARegion *ar = gsc->ar;
	View2D *v2d = gsc->v2d;
	rctf *subrect = gsc->subrect;
	float xyval[2];

	/* sanity checks */
	BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
	BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));


	if (gps->flag & GP_STROKE_3DSPACE) {
		if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
			*r_x = xyval[0];
			*r_y = xyval[1];
		}
		else {
			*r_x = 0.0f;
			*r_y = 0.0f;
		}
	}
	else if (gps->flag & GP_STROKE_2DSPACE) {
		float vec[3] = {pt->x, pt->y, 0.0f};
		int t_x, t_y;

		mul_m4_v3(gsc->mat, vec);
		UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);

		if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
			/* XXX: Or should we just always use the values as-is? */
			*r_x = 0.0f;
			*r_y = 0.0f;
		}
		else {
			*r_x = (float)t_x;
			*r_y = (float)t_y;
		}
	}
	else {
		if (subrect == NULL) {
			/* normal 3D view (or view space) */
			*r_x = (pt->x / 100.0f * ar->winx);
			*r_y = (pt->y / 100.0f * ar->winy);
		}
		else {
			/* camera view, use subrect */
			*r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
			*r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
		}
	}
}
Exemple #3
0
static void ApplySnapTranslation(TransInfo *t, float vec[3])
{
	float point[3];
	getSnapPoint(t, point);

	if (t->spacetype == SPACE_NODE) {
		char border = t->tsnap.snapNodeBorder;
		if (border & (NODE_LEFT | NODE_RIGHT))
			vec[0] = point[0] - t->tsnap.snapTarget[0];
		if (border & (NODE_BOTTOM | NODE_TOP))
			vec[1] = point[1] - t->tsnap.snapTarget[1];
	}
	else {
		if (t->spacetype == SPACE_VIEW3D) {
			if (t->options & CTX_PAINT_CURVE) {
				if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
					zero_v3(point);  /* no good answer here... */
				}
			}
		}

		sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
	}
}
Exemple #4
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;
}
static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
	bool do_draw = false;
	int exit_code = OPERATOR_RUNNING_MODAL;
	RulerInfo *ruler_info = op->customdata;
	ScrArea *sa = ruler_info->sa;
	ARegion *ar = ruler_info->ar;
	RegionView3D *rv3d = ar->regiondata;

	/* its possible to change  spaces while running the operator [#34894] */
	if (UNLIKELY(ar != CTX_wm_region(C))) {
		exit_code = OPERATOR_FINISHED;
		goto exit;
	}

	switch (event->type) {
		case LEFTMOUSE:
			if (event->val == KM_RELEASE) {
				if (ruler_info->state == RULER_STATE_DRAG) {
					/* rubber-band angle removal */
					RulerItem *ruler_item = ruler_item_active_get(ruler_info);
					if (ruler_item && (ruler_item->co_index == 1) && (ruler_item->flag & RULERITEM_USE_ANGLE)) {
						if (!BLI_rcti_isect_pt_v(&ar->winrct, &event->x)) {
							ruler_item->flag &= ~RULERITEM_USE_ANGLE;
							do_draw = true;
						}
					}
					if (ruler_info->snap_flag & RULER_SNAP_OK) {
						ruler_info->snap_flag &= ~RULER_SNAP_OK;
						do_draw = true;
					}
					ruler_info->state = RULER_STATE_NORMAL;
				}
			}
			else {
				if (ruler_info->state == RULER_STATE_NORMAL) {

					if (event->ctrl ||
					    /* weak - but user friendly */
					    BLI_listbase_is_empty(&ruler_info->items))
					{
						View3D *v3d = CTX_wm_view3d(C);
						const bool use_depth = (v3d->drawtype >= OB_SOLID);

						/* Create new line */
						RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info);
						RulerItem *ruler_item;
						/* check if we want to drag an existing point or add a new one */
						ruler_info->state = RULER_STATE_DRAG;

						ruler_item = ruler_item_add(ruler_info);
						ruler_item_active_set(ruler_info, ruler_item);

						if (use_depth) {
							/* snap the first point added, not essential but handy */
							ruler_item->co_index = 0;
							view3d_ruler_item_mousemove(C, ruler_info, event->mval, false, true);
							copy_v3_v3(ruler_info->drag_start_co, ruler_item->co[ruler_item->co_index]);
						}
						else {
							/* initial depth either previous ruler, view offset */
							if (ruler_item_prev) {
								copy_v3_v3(ruler_info->drag_start_co, ruler_item_prev->co[ruler_item_prev->co_index]);
							}
							else {
								negate_v3_v3(ruler_info->drag_start_co, rv3d->ofs);
							}

							copy_v3_v3(ruler_item->co[0], ruler_info->drag_start_co);
							view3d_ruler_item_project(ruler_info, ruler_item->co[0], event->mval);
						}

						copy_v3_v3(ruler_item->co[2], ruler_item->co[0]);
						ruler_item->co_index = 2;

						do_draw = true;
					}
					else {
						float mval_fl[2] = {UNPACK2(event->mval)};
						RulerItem *ruler_item_pick;
						int co_index;

						/* select and drag */
						if (view3d_ruler_pick(ruler_info, mval_fl, &ruler_item_pick, &co_index)) {
							if (co_index == -1) {
								if ((ruler_item_pick->flag & RULERITEM_USE_ANGLE) == 0) {
									/* Add Center Point */
									ruler_item_active_set(ruler_info, ruler_item_pick);
									ruler_item_pick->flag |= RULERITEM_USE_ANGLE;
									ruler_item_pick->co_index = 1;
									ruler_info->state = RULER_STATE_DRAG;

									/* find the factor */
									{
										float co_ss[2][2];
										float fac;

										ED_view3d_project_float_global(ar, ruler_item_pick->co[0], co_ss[0], V3D_PROJ_TEST_NOP);
										ED_view3d_project_float_global(ar, ruler_item_pick->co[2], co_ss[1], V3D_PROJ_TEST_NOP);

										fac = line_point_factor_v2(mval_fl, co_ss[0], co_ss[1]);
										CLAMP(fac, 0.0f, 1.0f);

										interp_v3_v3v3(ruler_item_pick->co[1],
										               ruler_item_pick->co[0],
										               ruler_item_pick->co[2], fac);
									}

									/* update the new location */
									view3d_ruler_item_mousemove(C, ruler_info, event->mval,
									                            event->shift != 0, event->ctrl != 0);
									do_draw = true;
								}
							}
							else {
								ruler_item_active_set(ruler_info, ruler_item_pick);
								ruler_item_pick->co_index = co_index;
								ruler_info->state = RULER_STATE_DRAG;

								/* store the initial depth */
								copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]);

								do_draw = true;
							}
						}
						else {
							exit_code = OPERATOR_PASS_THROUGH;
						}

					}
				}
			}
			break;
		case CKEY:
		{
			if (event->ctrl) {
				RulerItem *ruler_item = ruler_item_active_get(ruler_info);
				if (ruler_item) {
					const int prec = 8;
					char numstr[256];
					Scene *scene = CTX_data_scene(C);
					UnitSettings *unit = &scene->unit;

					ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);
					WM_clipboard_text_set((void *) numstr, false);
				}
			}
			break;
		}
		case RIGHTCTRLKEY:
		case LEFTCTRLKEY:
		{
			WM_event_add_mousemove(C);
			break;
		}
		case MOUSEMOVE:
		{
			if (ruler_info->state == RULER_STATE_DRAG) {
				if (view3d_ruler_item_mousemove(C, ruler_info, event->mval,
				                                event->shift != 0, event->ctrl != 0))
				{
					do_draw = true;
				}
			}
			break;
		}
		case ESCKEY:
		{
			do_draw = true;
			exit_code = OPERATOR_CANCELLED;
			break;
		}
		case RETKEY:
		{
			view3d_ruler_to_gpencil(C, ruler_info);
			do_draw = true;
			exit_code = OPERATOR_FINISHED;
			break;
		}
		case DELKEY:
		{
			if (event->val == KM_PRESS) {
				if (ruler_info->state == RULER_STATE_NORMAL) {
					RulerItem *ruler_item = ruler_item_active_get(ruler_info);
					if (ruler_item) {
						RulerItem *ruler_item_other = ruler_item->prev ? ruler_item->prev : ruler_item->next;
						ruler_item_remove(ruler_info, ruler_item);
						ruler_item_active_set(ruler_info, ruler_item_other);
						do_draw = true;
					}
				}
			}
			break;
		}
		default:
			exit_code = OPERATOR_PASS_THROUGH;
			break;

	}

	if (do_draw) {
		view3d_ruler_header_update(sa);

		/* all 3d views draw rulers */
		WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
	}

exit:
	if (ELEM(exit_code, OPERATOR_FINISHED, OPERATOR_CANCELLED)) {
		WM_cursor_modal_restore(ruler_info->win);

		view3d_ruler_end(C, ruler_info);
		view3d_ruler_free(ruler_info);
		op->customdata = NULL;

		ED_area_headerprint(sa, NULL);
	}

	return exit_code;
}
static void ruler_info_draw_pixel(const struct bContext *C, ARegion *ar, void *arg)
{
	Scene *scene = CTX_data_scene(C);
	UnitSettings *unit = &scene->unit;
	RulerItem *ruler_item;
	RulerInfo *ruler_info = arg;
	RegionView3D *rv3d = ruler_info->ar->regiondata;
//	ARegion *ar = ruler_info->ar;
	const float cap_size = 4.0f;
	const float bg_margin = 4.0f * U.pixelsize;
	const float bg_radius = 4.0f * U.pixelsize;
	const float arc_size = 64.0f * U.pixelsize;
#define ARC_STEPS 24
	const int arc_steps = ARC_STEPS;
	int i;
	//unsigned int color_act = 0x666600;
	unsigned int color_act = 0xffffff;
	unsigned int color_base = 0x0;
	unsigned char color_back[4] = {0xff, 0xff, 0xff, 0x80};
	unsigned char color_text[3];
	unsigned char color_wire[3];

	/* anti-aliased lines for more consistent appearance */
	glEnable(GL_LINE_SMOOTH);

	BLF_enable(blf_mono_font, BLF_ROTATION);
	BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi);
	BLF_rotation(blf_mono_font, 0.0f);

	UI_GetThemeColor3ubv(TH_TEXT, color_text);
	UI_GetThemeColor3ubv(TH_WIRE, color_wire);

	for (ruler_item = ruler_info->items.first, i = 0; ruler_item; ruler_item = ruler_item->next, i++) {
		const bool is_act = (i == ruler_info->item_active);
		float dir_ruler[2];
		float co_ss[3][2];
		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);
		}

		glEnable(GL_BLEND);

		cpack(is_act ? color_act : color_base);

		if (ruler_item->flag & RULERITEM_USE_ANGLE) {
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j++) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			cpack(0xaaaaaa);
			setlinestyle(3);
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j++) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			setlinestyle(0);

			/* arc */
			{
				float dir_tmp[3];
				float co_tmp[3];
				float arc_ss_coords[ARC_STEPS + 1][2];

				float dir_a[3];
				float dir_b[3];
				float quat[4];
				float axis[3];
				float angle;
				const float px_scale = (ED_view3d_pixel_size(rv3d, ruler_item->co[1]) *
				                        min_fff(arc_size,
				                                len_v2v2(co_ss[0], co_ss[1]) / 2.0f,
				                                len_v2v2(co_ss[2], co_ss[1]) / 2.0f));

				sub_v3_v3v3(dir_a, ruler_item->co[0], ruler_item->co[1]);
				sub_v3_v3v3(dir_b, ruler_item->co[2], ruler_item->co[1]);
				normalize_v3(dir_a);
				normalize_v3(dir_b);

				cross_v3_v3v3(axis, dir_a, dir_b);
				angle = angle_normalized_v3v3(dir_a, dir_b);

				axis_angle_to_quat(quat, axis, angle / arc_steps);

				copy_v3_v3(dir_tmp, dir_a);

				glColor3ubv(color_wire);

				for (j = 0; j <= arc_steps; j++) {
					madd_v3_v3v3fl(co_tmp, ruler_item->co[1], dir_tmp, px_scale);
					ED_view3d_project_float_global(ar, co_tmp, arc_ss_coords[j], V3D_PROJ_TEST_NOP);
					mul_qt_v3(quat, dir_tmp);
				}

				glEnableClientState(GL_VERTEX_ARRAY);
				glVertexPointer(2, GL_FLOAT, 0, arc_ss_coords);
				glDrawArrays(GL_LINE_STRIP, 0, arc_steps + 1);
				glDisableClientState(GL_VERTEX_ARRAY);
			}

			/* text */
			{
				char numstr[256];
				float numstr_size[2];
				float pos[2];
				const int prec = 2;  /* XXX, todo, make optional */

				ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);

				BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);

				pos[0] = co_ss[1][0] + (cap_size * 2.0f);
				pos[1] = co_ss[1][1] - (numstr_size[1] / 2.0f);

				/* draw text (bg) */
				glColor4ubv(color_back);
				uiSetRoundBox(UI_CNR_ALL);
				uiRoundBox(pos[0] - bg_margin,                  pos[1] - bg_margin,
				           pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
				           bg_radius);
				/* draw text */
				glColor3ubv(color_text);
				BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
				BLF_rotation(blf_mono_font, 0.0f);
				BLF_draw(blf_mono_font, numstr, sizeof(numstr));
			}

			/* capping */
			{
				float rot_90_vec_a[2];
				float rot_90_vec_b[2];
				float cap[2];

				sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[1]);
				rot_90_vec_a[0] = -dir_ruler[1];
				rot_90_vec_a[1] =  dir_ruler[0];
				normalize_v2(rot_90_vec_a);

				sub_v2_v2v2(dir_ruler, co_ss[1], co_ss[2]);
				rot_90_vec_b[0] = -dir_ruler[1];
				rot_90_vec_b[1] =  dir_ruler[0];
				normalize_v2(rot_90_vec_b);

				glEnable(GL_BLEND);

				glColor3ubv(color_wire);

				glBegin(GL_LINES);

				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec_a, -cap_size);
				glVertex2fv(cap);

				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec_b, -cap_size);
				glVertex2fv(cap);

				/* angle vertex */
				glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] - cap_size);
				glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] + cap_size);
				glVertex2f(co_ss[1][0] - cap_size, co_ss[1][1] + cap_size);
				glVertex2f(co_ss[1][0] + cap_size, co_ss[1][1] - cap_size);
				glEnd();

				glDisable(GL_BLEND);
			}
		}
		else {
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j += 2) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			cpack(0xaaaaaa);
			setlinestyle(3);
			glBegin(GL_LINE_STRIP);
			for (j = 0; j < 3; j += 2) {
				glVertex2fv(co_ss[j]);
			}
			glEnd();
			setlinestyle(0);

			sub_v2_v2v2(dir_ruler, co_ss[0], co_ss[2]);

			/* text */
			{
				char numstr[256];
				float numstr_size[2];
				const int prec = 6;  /* XXX, todo, make optional */
				float pos[2];

				ruler_item_as_string(ruler_item, unit, numstr, sizeof(numstr), prec);

				BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]);

				mid_v2_v2v2(pos, co_ss[0], co_ss[2]);

				/* center text */
				pos[0] -= numstr_size[0] / 2.0f;
				pos[1] -= numstr_size[1] / 2.0f;

				/* draw text (bg) */
				glColor4ubv(color_back);
				uiSetRoundBox(UI_CNR_ALL);
				uiRoundBox(pos[0] - bg_margin,                  pos[1] - bg_margin,
				           pos[0] + bg_margin + numstr_size[0], pos[1] + bg_margin + numstr_size[1],
				           bg_radius);
				/* draw text */
				glColor3ubv(color_text);
				BLF_position(blf_mono_font, pos[0], pos[1], 0.0f);
				BLF_draw(blf_mono_font, numstr, sizeof(numstr));
			}

			/* capping */
			{
				float rot_90_vec[2] = {-dir_ruler[1], dir_ruler[0]};
				float cap[2];

				normalize_v2(rot_90_vec);

				glEnable(GL_BLEND);
				glColor3ubv(color_wire);

				glBegin(GL_LINES);
				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[0], rot_90_vec, -cap_size);
				glVertex2fv(cap);

				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, cap_size);
				glVertex2fv(cap);
				madd_v2_v2v2fl(cap, co_ss[2], rot_90_vec, -cap_size);
				glVertex2fv(cap);
				glEnd();

				glDisable(GL_BLEND);
			}
		}
	}

	glDisable(GL_LINE_SMOOTH);

	BLF_disable(blf_mono_font, BLF_ROTATION);

#undef ARC_STEPS

	/* draw snap */
	if ((ruler_info->snap_flag & RULER_SNAP_OK) && (ruler_info->state == RULER_STATE_DRAG)) {
		ruler_item = ruler_item_active_get(ruler_info);
		if (ruler_item) {
			/* size from drawSnapping */
			const float size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
			float co_ss[3];
			ED_view3d_project_float_global(ar, ruler_item->co[ruler_item->co_index], co_ss, V3D_PROJ_TEST_NOP);

			cpack(color_act);
			circ(co_ss[0], co_ss[1], size * U.pixelsize);
		}
	}

}
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;
	}
}
Exemple #8
0
void applyProject(TransInfo *t)
{
	/* XXX FLICKER IN OBJECT MODE */
	if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0) {
		TransData *td = t->data;
		float tvec[3];
		float imat[4][4];
		int i;
	
		if (t->flag & (T_EDIT | T_POSE)) {
			Object *ob = t->obedit ? t->obedit : t->poseobj;
			invert_m4_m4(imat, ob->obmat);
		}

		for (i = 0; i < t->total; i++, td++) {
			float iloc[3], loc[3], no[3];
			float mval_fl[2];
			float dist_px = TRANSFORM_DIST_MAX_PX;
			
			if (td->flag & TD_NOACTION)
				break;
			
			if (td->flag & TD_SKIP)
				continue;

			if ((t->flag & T_PROP_EDIT) && (td->factor == 0.0f))
				continue;
			
			copy_v3_v3(iloc, td->loc);
			if (t->flag & (T_EDIT | T_POSE)) {
				Object *ob = t->obedit ? t->obedit : t->poseobj;
				mul_m4_v3(ob->obmat, iloc);
			}
			else if (t->flag & T_OBJECT) {
				/* TODO(sergey): Ideally force update is not needed here. */
				td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME;
				BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob);
				copy_v3_v3(iloc, td->ob->obmat[3]);
			}
			
			if (ED_view3d_project_float_global(t->ar, iloc, mval_fl, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
				if (snapObjectsTransform(
				        t, mval_fl, &dist_px,
				        loc, no))
				{
//					if (t->flag & (T_EDIT|T_POSE)) {
//						mul_m4_v3(imat, loc);
//					}

					sub_v3_v3v3(tvec, loc, iloc);

					mul_m3_v3(td->smtx, tvec);

					add_v3_v3(td->loc, tvec);

					if (t->tsnap.align && (t->flag & T_OBJECT)) {
						/* handle alignment as well */
						const float *original_normal;
						float mat[3][3];

						/* In pose mode, we want to align normals with Y axis of bones... */
						original_normal = td->axismtx[2];

						rotation_between_vecs_to_mat3(mat, original_normal, no);

						transform_data_ext_rotate(td, mat, true);

						/* TODO support constraints for rotation too? see ElementRotation */
					}
				}
			}
			
			//XXX constraintTransLim(t, td);
		}
	}
}