Blender V5.0
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_utf8.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 "BLT_translation.hh"
28
29#include "UI_interface_types.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 TransDataExtension *td_ext,
68 float angle,
69 const BendCustomData *bend_data,
70 const float warp_sta_local[3],
71 const float /*warp_end_local*/[3],
72 const float warp_end_radius_local[3],
73 const float pivot_local[3],
74
75 bool is_clamp)
76{
77 if (UNLIKELY(angle == 0.0f)) {
78 copy_v3_v3(td->loc, td->iloc);
79 return;
80 }
81
82 float vec[3];
83 float mat[3][3];
84 float delta[3];
85 float fac, fac_scaled;
86
87 copy_v3_v3(vec, td->iloc);
88 mul_m3_v3(td->mtx, vec);
89
90 fac = line_point_factor_v3(vec, warp_sta_local, warp_end_radius_local);
91 if (is_clamp) {
92 CLAMP(fac, 0.0f, 1.0f);
93 }
94
96 /* Grease pencil multi-frame falloff. */
97 float *gp_falloff = static_cast<float *>(td->extra);
98 if (gp_falloff != nullptr) {
99 fac_scaled = fac * td->factor * *gp_falloff;
100 }
101 else {
102 fac_scaled = fac * td->factor;
103 }
104 }
105 else {
106 fac_scaled = fac * td->factor;
107 }
108
109 axis_angle_normalized_to_mat3(mat, bend_data->warp_nor, angle * fac_scaled);
110 interp_v3_v3v3(delta, warp_sta_local, warp_end_radius_local, fac_scaled);
111 sub_v3_v3(delta, warp_sta_local);
112
113 /* Delta is subtracted, rotation adds back this offset. */
114 sub_v3_v3(vec, delta);
115
116 sub_v3_v3(vec, pivot_local);
117 mul_m3_v3(mat, vec);
118 add_v3_v3(vec, pivot_local);
119
120 mul_m3_v3(td->smtx, vec);
121
122 /* Rotation. */
123 if ((t->flag & T_POINTS) == 0) {
124 ElementRotation(t, tc, td, td_ext, mat, V3D_AROUND_LOCAL_ORIGINS);
125 }
126
127 /* Location. */
128 copy_v3_v3(td->loc, vec);
129}
130
132
133/* -------------------------------------------------------------------- */
136
137static eRedrawFlag handleEventBend(TransInfo * /*t*/, const wmEvent *event)
138{
140
141 if (event->type == MIDDLEMOUSE && event->val == KM_PRESS) {
143 }
144
145 return status;
146}
147
148static void Bend(TransInfo *t)
149{
150 float pivot_global[3];
151 float warp_end_radius_global[3];
152 char str[UI_MAX_DRAW_STR];
153 const BendCustomData *bend_data = static_cast<const BendCustomData *>(t->custom.mode.data);
154 const bool is_clamp = (t->flag & T_ALT_TRANSFORM) == 0;
155
156 union {
157 struct {
158 float angle, scale;
159 };
160 float vector[2];
161 } values;
162
163 /* Amount of radians for bend. */
164 copy_v2_v2(values.vector, t->values);
165
166#if 0
167 snapGrid(t, angle_rad);
168#else
169 /* Hrmf, snapping radius is using 'angle' steps, need to convert to something else
170 * this isn't essential but nicer to give reasonable snapping values for radius. */
172 const float radius_snap = 0.1f;
173 const float snap_hack = (t->increment[0] * bend_data->warp_init_dist) / radius_snap;
174 values.scale *= snap_hack;
175 transform_snap_increment(t, values.vector);
176 values.scale /= snap_hack;
177 }
178#endif
179
180 if (applyNumInput(&t->num, values.vector)) {
181 values.scale = values.scale / bend_data->warp_init_dist;
182 }
183
184 copy_v2_v2(t->values_final, values.vector);
185
186 /* Header print for NumInput. */
187 if (hasNumInput(&t->num)) {
188 char c[NUM_STR_REP_LEN * 2];
189
190 outputNumInput(&(t->num), c, t->scene->unit);
191
193 IFACE_("Bend Angle: %s, Radius: %s, Alt: Clamp %s"),
194 &c[0],
195 &c[NUM_STR_REP_LEN],
196 WM_bool_as_string(is_clamp));
197 }
198 else {
199 /* Default header print. */
201 IFACE_("Bend Angle: %.3f, Radius: %.4f, Alt: Clamp %s"),
202 RAD2DEGF(values.angle),
203 values.scale * bend_data->warp_init_dist,
204 WM_bool_as_string(is_clamp));
205 }
206
207 values.angle *= -1.0f;
208 values.scale *= bend_data->warp_init_dist;
209
210 /* Calculate `data->warp_end` from `data->warp_end_init`. */
211 copy_v3_v3(warp_end_radius_global, bend_data->warp_end);
212 dist_ensure_v3_v3fl(warp_end_radius_global, bend_data->warp_sta, values.scale);
213 /* Done. */
214
215 /* Calculate pivot. */
216 copy_v3_v3(pivot_global, bend_data->warp_sta);
217 if (values.angle > 0.0f) {
218 madd_v3_v3fl(pivot_global,
219 bend_data->warp_tan,
220 -values.scale * shell_angle_to_dist(float(M_PI_2) - values.angle));
221 }
222 else {
223 madd_v3_v3fl(pivot_global,
224 bend_data->warp_tan,
225 +values.scale * shell_angle_to_dist(float(M_PI_2) + values.angle));
226 }
227
228 /* TODO(@ideasman42): xform, compensate object center. */
230
231 float warp_sta_local[3];
232 float warp_end_local[3];
233 float warp_end_radius_local[3];
234 float pivot_local[3];
235
236 if (tc->use_local_mat) {
237 sub_v3_v3v3(warp_sta_local, bend_data->warp_sta, tc->mat[3]);
238 sub_v3_v3v3(warp_end_local, bend_data->warp_end, tc->mat[3]);
239 sub_v3_v3v3(warp_end_radius_local, warp_end_radius_global, tc->mat[3]);
240 sub_v3_v3v3(pivot_local, pivot_global, tc->mat[3]);
241 }
242 else {
243 copy_v3_v3(warp_sta_local, bend_data->warp_sta);
244 copy_v3_v3(warp_end_local, bend_data->warp_end);
245 copy_v3_v3(warp_end_radius_local, warp_end_radius_global);
246 copy_v3_v3(pivot_local, pivot_global);
247 }
248
249 threading::parallel_for(IndexRange(tc->data_len), 1024, [&](const IndexRange range) {
250 for (const int i : range) {
251 TransData *td = &tc->data[i];
252 TransDataExtension *td_ext = tc->data_ext ? &tc->data_ext[i] : nullptr;
253 if (td->flag & TD_SKIP) {
254 continue;
255 }
256 transdata_elem_bend(t,
257 tc,
258 td,
259 td_ext,
260 values.angle,
261 bend_data,
262 warp_sta_local,
263 warp_end_local,
264 warp_end_radius_local,
265 pivot_local,
266 is_clamp);
267 }
268 });
269 }
270
271 recalc_data(t);
272
273 ED_area_status_text(t->area, str);
274}
275
276static void initBend(TransInfo *t, wmOperator * /*op*/)
277{
278 const float *curs;
279 float tvec[3];
281
282 t->mode = TFM_BEND;
283
285
286 t->idx_max = 1;
287 t->num.idx_max = 1;
289
290 copy_v3_fl(t->num.val_inc, t->increment[0]);
291 t->num.unit_sys = t->scene->unit.system;
295
296 // copy_v3_v3(t->center, ED_view3d_cursor3d_get(t->scene, t->view));
297 if ((t->flag & T_OVERRIDE_CENTER) == 0) {
299 }
301
303
304 curs = t->scene->cursor.location;
305 copy_v3_v3(data->warp_sta, curs);
307 (View3D *)t->area->spacedata.first, t->region, curs, t->mval, data->warp_end);
308
309 copy_v3_v3(data->warp_nor, t->viewinv[2]);
310 normalize_v3(data->warp_nor);
311
312 /* Tangent. */
313 sub_v3_v3v3(tvec, data->warp_end, data->warp_sta);
314 cross_v3_v3v3(data->warp_tan, tvec, data->warp_nor);
315 normalize_v3(data->warp_tan);
316
317 data->warp_init_dist = len_v3v3(data->warp_end, data->warp_sta);
318
319 t->custom.mode.data = data;
320 t->custom.mode.use_free = true;
321}
322
324
326 /*flags*/ T_NO_CONSTRAINT,
327 /*init_fn*/ initBend,
328 /*transform_fn*/ Bend,
329 /*transform_matrix_fn*/ nullptr,
330 /*handle_event_fn*/ handleEventBend,
331 /*snap_distance_fn*/ nullptr,
332 /*snap_apply_fn*/ nullptr,
333 /*draw_fn*/ nullptr,
334};
335
336} // namespace blender::ed::transform
@ B_UNIT_LENGTH
Definition BKE_unit.hh:137
@ B_UNIT_ROTATION
Definition BKE_unit.hh:141
#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_UTF8(dst, format,...)
#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:190
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:88
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
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:311
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)
static eRedrawFlag handleEventBend(TransInfo *, const wmEvent *event)
void initSnapAngleIncrements(TransInfo *t)
static void transdata_elem_bend(const TransInfo *t, const TransDataContainer *tc, TransData *td, TransDataExtension *td_ext, 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 ElementRotation(const TransInfo *t, const TransDataContainer *tc, TransData *td, TransDataExtension *td_ext, const float mat[3][3], const short around)
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
const int status
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:974
wmEventType type
Definition WM_types.hh:757
short val
Definition WM_types.hh:759
#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)