Blender V4.5
transform_mode_bend.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib>
10
11#include "MEM_guardedalloc.h"
12
13#include "BLI_math_geom.h"
14#include "BLI_math_matrix.h"
15#include "BLI_math_rotation.h"
16#include "BLI_math_vector.h"
17#include "BLI_string.h"
18#include "BLI_task.hh"
19
20#include "BKE_unit.hh"
21
22#include "ED_screen.hh"
23
24#include "WM_api.hh"
25#include "WM_types.hh"
26
27#include "UI_interface.hh"
28
29#include "BLT_translation.hh"
30
31#include "transform.hh"
32#include "transform_convert.hh"
33#include "transform_snap.hh"
34
35#include "transform_mode.hh"
36
37namespace blender::ed::transform {
38
39/* -------------------------------------------------------------------- */
42
47 /* All values are in global space. */
48 float warp_sta[3];
49 float warp_end[3];
50
51 float warp_nor[3];
52 float warp_tan[3];
53
54 /* For applying the mouse distance. */
56};
57
59
60/* -------------------------------------------------------------------- */
63
64static void transdata_elem_bend(const TransInfo *t,
65 const TransDataContainer *tc,
66 TransData *td,
67 float angle,
68 const BendCustomData *bend_data,
69 const float warp_sta_local[3],
70 const float /*warp_end_local*/[3],
71 const float warp_end_radius_local[3],
72 const float pivot_local[3],
73
74 bool is_clamp)
75{
76 if (UNLIKELY(angle == 0.0f)) {
77 copy_v3_v3(td->loc, td->iloc);
78 return;
79 }
80
81 float vec[3];
82 float mat[3][3];
83 float delta[3];
84 float fac, fac_scaled;
85
86 copy_v3_v3(vec, td->iloc);
87 mul_m3_v3(td->mtx, vec);
88
89 fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
90 if (is_clamp) {
91 CLAMP(fac, 0.0f, 1.0f);
92 }
93
95 /* Grease pencil multi-frame falloff. */
96 float *gp_falloff = static_cast<float *>(td->extra);
97 if (gp_falloff != nullptr) {
98 fac_scaled = fac * td->factor * *gp_falloff;
99 }
100 else {
101 fac_scaled = fac * td->factor;
102 }
103 }
104 else {
105 fac_scaled = fac * td->factor;
106 }
107
108 axis_angle_normalized_to_mat3(mat, bend_data->warp_nor, angle * fac_scaled);
109 interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
110 sub_v3_v3(delta, warp_sta_local);
111
112 /* Delta is subtracted, rotation adds back this offset. */
113 sub_v3_v3(vec, delta);
114
115 sub_v3_v3(vec, pivot_local);
116 mul_m3_v3(mat, vec);
117 add_v3_v3(vec, pivot_local);
118
119 mul_m3_v3(td->smtx, vec);
120
121 /* Rotation. */
122 if ((t->flag & T_POINTS) == 0) {
124 }
125
126 /* Location. */
127 copy_v3_v3(td->loc, vec);
128}
129
131
132/* -------------------------------------------------------------------- */
135
136static eRedrawFlag handleEventBend(TransInfo * /*t*/, const wmEvent *event)
137{
139
140 if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
141 status = TREDRAW_HARD;
142 }
143
144 return status;
145}
146
147static void Bend(TransInfo *t)
148{
149 float pivot_global[3];
150 float warp_end_radius_global[3];
151 char str[UI_MAX_DRAW_STR];
152 const BendCustomData *bend_data = static_cast<const BendCustomData *>(t->custom.mode.data);
153 const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
154
155 union {
156 struct {
157 float angle, scale;
158 };
159 float vector[2];
160 } values;
161
162 /* Amount of radians for bend. */
163 copy_v2_v2(values.vector, t->values);
164
165#if 0
166 snapGrid(t, angle_rad);
167#else
168 /* Hrmf, snapping radius is using 'angle' steps, need to convert to something else
169 * this isn't essential but nicer to give reasonable snapping values for radius. */
171 const float radius_snap = 0.1f;
172 const float snap_hack = (t->snap[0] * bend_data->warp_init_dist) / radius_snap;
173 values.scale *= snap_hack;
174 transform_snap_increment(t, values.vector);
175 values.scale /= snap_hack;
176 }
177#endif
178
179 if (applyNumInput(&t->num, values.vector)) {
180 values.scale = values.scale / bend_data->warp_init_dist;
181 }
182
183 copy_v2_v2(t->values_final, values.vector);
184
185 /* Header print for NumInput. */
186 if (hasNumInput(&t->num)) {
187 char c[NUM_STR_REP_LEN * 2];
188
189 outputNumInput(&(t->num), c, t->scene->unit);
190
192 IFACE_("Bend Angle: %s, Radius: %s, Alt: Clamp %s"),
193 &c[0],
194 &c[NUM_STR_REP_LEN],
195 WM_bool_as_string(is_clamp));
196 }
197 else {
198 /* Default header print. */
200 IFACE_("Bend Angle: %.3f, Radius: %.4f, Alt: Clamp %s"),
201 RAD2DEGF(values.angle),
202 values.scale * bend_data->warp_init_dist,
203 WM_bool_as_string(is_clamp));
204 }
205
206 values.angle *= -1.0f;
207 values.scale *= bend_data->warp_init_dist;
208
209 /* Calculate `data->warp_end` from `data->warp_end_init`. */
210 copy_v3_v3(warp_end_radius_global, bend_data->warp_end);
211 dist_ensure_v3_v3fl(warp_end_radius_global, bend_data->warp_sta, values.scale);
212 /* Done. */
213
214 /* Calculate pivot. */
215 copy_v3_v3(pivot_global, bend_data->warp_sta);
216 if (values.angle > 0.0f) {
217 madd_v3_v3fl(pivot_global,
218 bend_data->warp_tan,
219 -values.scale * shell_angle_to_dist(float(M_PI_2) - values.angle));
220 }
221 else {
222 madd_v3_v3fl(pivot_global,
223 bend_data->warp_tan,
224 +values.scale * shell_angle_to_dist(float(M_PI_2) + values.angle));
225 }
226
227 /* TODO(@ideasman42): xform, compensate object center. */
229
230 float warp_sta_local[3];
231 float warp_end_local[3];
232 float warp_end_radius_local[3];
233 float pivot_local[3];
234
235 if (tc->use_local_mat) {
236 sub_v3_v3v3(warp_sta_local, bend_data->warp_sta, tc->mat[3]);
237 sub_v3_v3v3(warp_end_local, bend_data->warp_end, tc->mat[3]);
238 sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
239 sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
240 }
241 else {
242 copy_v3_v3(warp_sta_local, bend_data->warp_sta);
243 copy_v3_v3(warp_end_local, bend_data->warp_end);
244 copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
245 copy_v3_v3(pivot_local, pivot_global);
246 }
247
248 threading::parallel_for(IndexRange(tc->data_len), 1024, [&](const IndexRange range) {
249 for (const int i : range) {
250 TransData *td = &tc->data[i];
251 if (td->flag & TD_SKIP) {
252 continue;
253 }
254 transdata_elem_bend(t,
255 tc,
256 td,
257 values.angle,
258 bend_data,
259 warp_sta_local,
260 warp_end_local,
261 warp_end_radius_local,
262 pivot_local,
263 is_clamp);
264 }
265 });
266 }
267
268 recalc_data(t);
269
270 ED_area_status_text(t->area, str);
271}
272
273static void initBend(TransInfo *t, wmOperator * /*op*/)
274{
275 const float *curs;
276 float tvec[3];
278
279 t->mode = TFM_BEND;
280
282
283 t->idx_max = 1;
284 t->num.idx_max = 1;
286
287 copy_v3_fl(t->num.val_inc, t->snap[0]);
288 t->num.unit_sys = t->scene->unit.system;
292
293 // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
294 if ((t->flag & T_OVERRIDE_CENTER) == 0) {
296 }
298
300
301 curs = t->scene->cursor.location;
302 copy_v3_v3(data->warp_sta, curs);
304 (View3D *)t->area->spacedata.first, t->region, curs, t->mval, data->warp_end);
305
306 copy_v3_v3(data->warp_nor, t->viewinv[2]);
307 normalize_v3(data->warp_nor);
308
309 /* Tangent. */
310 sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
311 cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
312 normalize_v3(data->warp_tan);
313
314 data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
315
316 t->custom.mode.data = data;
317 t->custom.mode.use_free = true;
318}
319
321
323 /*flags*/ T_NO_CONSTRAINT,
324 /*init_fn*/ initBend,
325 /*transform_fn*/ Bend,
326 /*transform_matrix_fn*/ nullptr,
327 /*handle_event_fn*/ handleEventBend,
328 /*snap_distance_fn*/ nullptr,
329 /*snap_apply_fn*/ nullptr,
330 /*draw_fn*/ nullptr,
331};
332
333} // namespace blender::ed::transform
@ B_UNIT_LENGTH
Definition BKE_unit.hh:124
@ B_UNIT_ROTATION
Definition BKE_unit.hh:128
#define M_PI_2
#define RAD2DEGF(_rad)
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
MINLINE float shell_angle_to_dist(float angle)
void mul_m3_v3(const float M[3][3], float r[3])
void axis_angle_normalized_to_mat3(float R[3][3], const float axis[3], float angle)
MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void copy_v3_fl(float r[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], float dist)
MINLINE float normalize_v3(float n[3])
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
#define CLAMP(a, b, c)
#define UNLIKELY(x)
#define IFACE_(msgid)
@ USER_UNIT_ROT_RADIANS
@ SCE_SNAP_TO_INCREMENT
@ V3D_AROUND_LOCAL_ORIGINS
#define NUM_STR_REP_LEN
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:189
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:87
bool hasNumInput(const NumInput *n)
Definition numinput.cc:170
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:872
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define UI_MAX_DRAW_STR
@ KM_PRESS
Definition WM_types.hh:308
BMesh const char void * data
#define str(s)
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void calculateCenterLocal(TransInfo *t, const float center_global[3])
void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
void recalc_data(TransInfo *t)
static void Bend(TransInfo *t)
bool transform_snap_increment(const TransInfo *t, float *r_val)
void ElementRotation(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3], const short around)
static eRedrawFlag handleEventBend(TransInfo *, const wmEvent *event)
static void transdata_elem_bend(const TransInfo *t, const TransDataContainer *tc, TransData *td, float angle, const BendCustomData *bend_data, const float warp_sta_local[3], const float[3], const float warp_end_radius_local[3], const float pivot_local[3], bool is_clamp)
void initSnapAngleIncrements(TransInfo *t)
void calculateCenterCursor(TransInfo *t, float r_center[3])
static void initBend(TransInfo *t, wmOperator *)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
void * first
short idx_max
float val_inc[NUM_MAX_ELEMENTS]
int unit_type[NUM_MAX_ELEMENTS]
bool unit_use_radians
View3DCursor cursor
struct UnitSettings unit
ListBase spacedata
TransCustomDataContainer custom
Definition transform.hh:968
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
Definition transform.hh:42
conversion and adaptation of different datablocks to a common struct.
transform modes used by different operators.
@ MIDDLEMOUSE
const char * WM_bool_as_string(bool test)