57 {0,
nullptr, 0,
nullptr,
nullptr},
81 const float threshold_distance)
const
83 const float threshold_distance_sq = threshold_distance * threshold_distance;
85 if (new_distance_squared > threshold_distance_sq) {
89 float old_priority = 1.0f;
90 float new_priority = 1.0f;
97 if (new_distance_squared <
117 if (new_distance_squared * old_priority < this->
distance_squared * new_priority) {
129 const int drawing_index,
137 const IndexRange points = points_by_curve[curve_i];
138 for (
const int point_i : points) {
161 const int drawing_index,
177 r_closest_element.
curve_index = point_to_curve_map[point_i];
193 r_closest_element.
curve_index = point_to_curve_map[point_i];
208 const float2 dif_l = pos_2 - pos_1;
210 const float l2 =
math::dot(dif_l, dif_l);
213 return dif_l * t + pos_1;
221 const int drawing_index,
233 const IndexRange src_points = points_by_curve[curve_i];
234 const IndexRange eval_points = evaluated_points_by_curve[curve_i];
238 const int src_i_1 = src_i + src_points.
first();
239 const int src_i_2 = (src_i + 1) % src_points.
size() + src_points.
first();
244 pos_1_proj, pos_2_proj, mouse_co, local_t);
247 const float t = local_t;
254 r_closest_element.
edge_t = t;
262 const Span<int> offsets =
curves.bezier_evaluated_offsets_for_curve(curve_i);
266 const int point_num = eval_range.
size() - 1;
268 for (
const int eval_i :
IndexRange(point_num)) {
269 const int eval_point_i_1 = eval_range.
first() + eval_i;
270 const int eval_point_i_2 = (eval_range.
first() + eval_i + 1 - eval_points.
first()) %
274 evaluated_positions[eval_point_i_1]);
276 evaluated_positions[eval_point_i_2]);
279 pos_1_proj, pos_2_proj, mouse_co, local_t);
282 const float t = (eval_i + local_t) /
float(point_num);
290 r_closest_element.
edge_t = t;
315 ptd,
curves, editable_curves, layer_to_object, curves_index, mouse_co, closest_element);
317 ptd,
curves, bezier_points, layer_to_object, curves_index, mouse_co, closest_element);
319 ptd,
curves, editable_curves, layer_to_object, curves_index, mouse_co, closest_element);
321 return closest_element;
335 using namespace math;
336 const float sin225 =
sin(AngleRadian::from_degree(22.5f));
352 const IndexRange points = points_by_curve[curve_i];
357 const float3 depth_point = positions[point_i1];
359 const float3 P0 = positions[point_i1];
360 const float3 P3 = positions[point_i2];
361 const float3 p1 = handles_right[point_i1];
362 const float3 p2 = handles_left[point_i2];
363 const float3 k2 = p1 - p2;
366 const float t_sq = t * t;
367 const float t_cu = t_sq * t;
368 const float one_minus_t = 1.0f - t;
369 const float one_minus_t_sq = one_minus_t * one_minus_t;
370 const float one_minus_t_cu = one_minus_t_sq * one_minus_t;
392 const float denom = 3.0f * one_minus_t * t;
397 const float3 P1 = (Pm - one_minus_t_cu * P0 - t_cu * P3) / denom + k2 * t;
398 const float3 P2 = P1 - k2;
400 handles_right[point_i1] = P1;
401 handles_left[point_i2] = P2;
413 curves.calculate_bezier_auto_handles();
441 const float3 depth_point = positions[point_i];
445 !(left_selected[point_i] || right_selected[point_i])) ||
452 handles_left[point_i] = ptd.
screen_to_layer(layer_to_world, pos_left + offset, depth_point);
454 layer_to_world, pos_right + offset, depth_point);
458 const bool is_left = !right_selected[point_i];
463 layer_to_world, pos_left + offset, depth_point);
468 layer_to_world, pos_right + offset, depth_point);
493 handle_types_left[point_i] = handle_types_right[point_i];
499 handles_left[point_i] = ptd.
project(center_point + offset);
503 layer_to_world, center_point + offset, depth_point);
507 handles_right[point_i] = 2.0f * depth_point - handles_left[point_i];
514 handle_types_right[point_i] = handle_types_left[point_i];
520 handles_right[point_i] = ptd.
project(center_point + offset);
524 layer_to_world, center_point + offset, depth_point);
528 handles_left[point_i] = 2.0f * depth_point - handles_right[point_i];
533 curves.calculate_bezier_auto_handles();
560 Vector<bool> dst_selected_center(old_points_num,
false);
568 int point_offset = 0;
570 const IndexRange curve_points = points_by_curve[curve_index];
572 if (src_cyclic[curve_index] && curve_points.
size() != 1) {
577 bool first_selected = point_selection[curve_points.
first()];
579 first_selected |= left_selected[curve_points.
first()];
580 first_selected |= right_selected[curve_points.
first()];
583 bool last_selected = point_selection[curve_points.
last()];
585 last_selected |= left_selected[curve_points.
last()];
586 last_selected |= right_selected[curve_points.
last()];
589 if (first_selected) {
590 if (curve_points.
size() != 1) {
592 dst_to_src_points.insert(curve_points.
first() + point_offset, curve_points.
first());
593 dst_selected_start.
insert(curve_points.
first() + point_offset,
true);
594 dst_selected_center.
insert(curve_points.
first() + point_offset, !is_bezier);
595 dst_selected_end.
insert(curve_points.
first() + point_offset,
false);
596 dst_curve_counts[curve_index]++;
603 dst_to_src_points.insert(curve_points.
last() + point_offset + 1, curve_points.
last());
604 dst_selected_end.
insert(curve_points.
last() + point_offset + 1,
true);
605 dst_selected_center.
insert(curve_points.
last() + point_offset + 1, !is_bezier);
606 dst_selected_start.
insert(curve_points.
last() + point_offset + 1,
false);
607 dst_curve_counts[curve_index]++;
612 if (point_offset == 0) {
647 {
".selection",
".selection_handle_left",
".selection_handle_right"}),
658 for (
const int i : dst_to_src_points.index_range()) {
659 if (!(dst_selected_end[
i] || dst_selected_start[
i])) {
662 const float3 depth_point = src_positions[dst_to_src_points[
i]];
669 dst_cyclic[dst_point_to_curve_map[
i]] =
false;
683 points_by_curve[curve_index].
size() == dst_points_by_curve[curve_index].
size();
701 const int dst_point_index = src_point_index + 1;
703 const IndexRange points = points_by_curve[curve_index];
704 const int src_point_index_2 = (src_point_index + 1 - points.
first()) % points.
size() +
706 const int dst_point_index_2 = (dst_point_index - points.
first() + 1) % (points.
size() + 1) +
716 dst_to_src_points.
insert(src_point_index + 1, src_point_index);
717 dst_curve_counts[curve_index]++;
730 for (
const StringRef selection_attribute_name :
738 selection_writer.
finish();
747 {
".selection",
".selection_handle_left",
".selection_handle_right"}),
763 src_positions[src_point_index],
764 src_handles_right[src_point_index],
765 src_handles_left[src_point_index_2],
766 src_positions[src_point_index_2],
769 dst_positions[dst_point_index] = inserted_point.
position;
770 dst_handles_left[dst_point_index] = inserted_point.
left_handle;
771 dst_handles_right[dst_point_index] = inserted_point.
right_handle;
772 dst_handles_right[dst_point_index - 1] = inserted_point.
handle_prev;
773 dst_handles_left[dst_point_index_2] = inserted_point.
handle_next;
788 points_by_curve[curve_index].
size() == dst_points_by_curve[curve_index].
size();
798 src = std::move(dst);
812 curves.positions_for_write().last() = depth_point;
814 curve_attributes_to_skip.
add(
"curve_type");
817 curves.update_curve_types();
818 curves.resolution_for_write().last() = 12;
819 curve_attributes_to_skip.
add(
"resolution");
822 if (material_index != -1) {
827 material_indexes.
span.last() = material_index;
828 material_indexes.
finish();
829 curve_attributes_to_skip.
add(
"material_index");
840 for (
const StringRef selection_attribute_name :
862 ".selection_handle_left",
863 ".selection_handle_right"}),
864 curves.points_range().take_back(1));
868 curves.curves_range().take_back(1));
874 const bool clear_selection)
876 bool changed =
false;
878 for (
const StringRef selection_attribute_name :
894 curves.calculate_bezier_auto_handles();
898 if (clear_selection) {
903 if ((selection_attribute_name ==
".selection" &&
905 (selection_attribute_name ==
".selection_handle_left" &&
907 (selection_attribute_name ==
".selection_handle_right" &&
917 selection_writer.
finish();
941 const int curve_i = point_to_curve_map[point_i];
942 const IndexRange points = points_by_curve[curve_i];
945 if (cyclic[curve_i] && points.
size() != 1) {
949 if (point_i != points.
first() && point_i != points.
last()) {
970 std::atomic<bool> changed =
false;
971 std::atomic<bool> point_added =
false;
972 std::atomic<bool> point_removed =
false;
975 for (const int curves_index : curves_range) {
976 bke::CurvesGeometry &curves = ptd.get_curves(curves_index);
978 if (curves.is_empty()) {
982 if (ptd.closest_element.element_mode == ElementMode::Edge) {
983 add_single.store(false, std::memory_order_relaxed);
984 if (ptd.insert_point && ptd.closest_element.drawing_index == curves_index) {
985 insert_point_to_curve(ptd, curves);
986 ptd.tag_curve_changed(curves_index);
987 changed.store(true, std::memory_order_relaxed);
992 if (ptd.closest_element.element_mode == ElementMode::None) {
993 if (ptd.extrude_point) {
994 IndexMaskMemory memory;
995 const IndexMask editable_curves = ptd.editable_curves(curves_index, memory);
996 const float4x4 &layer_to_object = ptd.layer_to_object_per_curves[curves_index];
998 if (std::optional<bke::CurvesGeometry> result = extrude_curves(
999 ptd, curves, layer_to_object, editable_curves))
1001 curves = std::move(*result);
1004 for (const StringRef selection_attribute_name :
1005 ed::curves::get_curves_selection_attribute_names(curves))
1007 bke::GSpanAttributeWriter selection_writer = ed::curves::ensure_selection_attribute(
1008 curves, bke::AttrDomain::Point, bke::AttrType::Bool, selection_attribute_name);
1009 ed::curves::fill_selection_false(selection_writer.span);
1010 selection_writer.finish();
1015 add_single.store(false, std::memory_order_relaxed);
1016 point_added.store(true, std::memory_order_relaxed);
1017 ptd.tag_curve_changed(curves_index);
1019 changed.store(true, std::memory_order_relaxed);
1026 if (curves_index != ptd.closest_element.drawing_index) {
1027 if (event->val != KM_DBL_CLICK && !ptd.delete_point) {
1028 for (const StringRef selection_attribute_name :
1029 ed::curves::get_curves_selection_attribute_names(curves))
1031 bke::GSpanAttributeWriter selection_writer = ed::curves::ensure_selection_attribute(
1032 curves, bke::AttrDomain::Point, bke::AttrType::Bool, selection_attribute_name);
1033 ed::curves::fill_selection_false(selection_writer.span);
1034 selection_writer.finish();
1041 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
1042 const IndexRange points = points_by_curve[ptd.closest_element.curve_index];
1044 if (event->val == KM_DBL_CLICK && ptd.cycle_handle_type) {
1045 const int8_t handle_type = curves.handle_types_right()[ptd.closest_element.point_index];
1047 const int8_t new_handle_type = (handle_type + 1) % CURVE_HANDLE_TYPES_NUM;
1049 curves.handle_types_left_for_write()[ptd.closest_element.point_index] = new_handle_type;
1050 curves.handle_types_right_for_write()[ptd.closest_element.point_index] = new_handle_type;
1051 curves.calculate_bezier_auto_handles();
1052 ptd.tag_curve_changed(curves_index);
1053 add_single.store(false, std::memory_order_relaxed);
1056 if (ptd.delete_point) {
1057 curves.remove_points(IndexRange::from_single(ptd.closest_element.point_index), {});
1058 add_single.store(false, std::memory_order_relaxed);
1059 point_removed.store(true, std::memory_order_relaxed);
1060 ptd.tag_curve_changed(curves_index);
1064 const bool clear_selection = event->val != KM_DBL_CLICK && !ptd.delete_point;
1065 if (close_curve_and_select(ptd, curves, points, clear_selection)) {
1066 ptd.tag_curve_changed(curves_index);
1067 add_single.store(false, std::memory_order_relaxed);
1070 changed.store(true, std::memory_order_relaxed);
1075 if (ptd.can_create_new_curve(op)) {
1076 const int curves_index = *ptd.active_drawing_index;
1078 const float4x4 &layer_to_world = ptd.layer_to_world_per_curves[curves_index];
1082 ptd.single_point_attributes(
curves, curves_index);
1083 ptd.tag_curve_changed(curves_index);
1085 changed.store(
true, std::memory_order_relaxed);
1090 ptd.point_added = point_added;
1091 ptd.point_removed = point_removed;
1100 const int handle_display,
1107 return curves.points_range();
1127 const bool is_selected = selected_point[point_i] || selected_left[point_i] ||
1128 selected_right[point_i];
1130 return is_selected && is_bezier;
1133 return selected_points;
1137 const float3 &point)
const
1145 const float3 &depth_point_layer)
const
1192 if (std::optional<wmOperatorStatus>
result = this->
initialize(C, op, event)) {
1238 std::atomic<bool> changed =
false;
1248 changed.store(
true, std::memory_order_relaxed);
1261 changed.store(
true, std::memory_order_relaxed);
1289 const Curves *curves_id = this->all_curves[curves_index];
1296 const Curves *curves_id = this->all_curves[curves_index];
1299 curves, this->
vc.v3d->overlay.handle_display, memory);
1304 const Curves *curves_id = this->all_curves[curves_index];
1306 return curves.curves_range();
1311 Curves *curves_id = this->all_curves[curves_index];
1313 curves.tag_topology_changed();
1318 Curves *curves_id = this->all_curves[curves_index];
1344 for (
Curves *curves_id : this->all_curves) {
1376 for (
Curves *curves_id : unique_curves) {
1377 this->all_curves.
append(curves_id);
1382 return std::nullopt;
1438 "Add a point connected to the last selected point");
1443 "Extrude Handle Type",
1444 "Type of the extruded handle");
1445 RNA_def_boolean(
ot->srna,
"delete_point",
false,
"Delete Point",
"Delete an existing point");
1447 ot->srna,
"insert_point",
false,
"Insert Point",
"Insert Point into a curve segment");
1448 RNA_def_boolean(
ot->srna,
"move_segment",
false,
"Move Segment",
"Delete an existing point");
1450 ot->srna,
"select_point",
false,
"Select Point",
"Select a point or its handles");
1451 RNA_def_boolean(
ot->srna,
"move_point",
false,
"Move Point",
"Move a point or its handles");
1453 "cycle_handle_type",
1455 "Cycle Handle Type",
1456 "Cycle between all four handle types");
1467 "Move Current Handle",
1468 "Move the current handle of the control point freely"},
1472 "Move Entire Point",
1473 "Move the entire point using its handles"},
1478 "Snap the handle angle to 45 degrees"},
1479 {0,
nullptr, 0,
nullptr,
nullptr},
1500 ot->name =
"Curves Pen";
1501 ot->idname =
"CURVES_OT_pen";
1502 ot->description =
"Construct and edit Bézier curves";
#define CTX_DATA_BEGIN(C, Type, instance, member)
wmWindow * CTX_wm_window(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Main * CTX_data_main(const bContext *C)
Low-level operations for curves.
Low-level operations for curves.
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
void BKE_report(ReportList *reports, eReportType type, const char *message)
ATTR_WARN_UNUSED_RESULT const size_t num
void DEG_id_tag_update(ID *id, unsigned int flags)
@ NURBS_KNOT_MODE_ENDPOINT
@ OP_IS_MODAL_CURSOR_REGION
void ED_workspace_status_text(bContext *C, const char *str)
void ED_region_tag_redraw(ARegion *region)
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
float ED_view3d_select_dist_px()
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])
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Span< T > as_span() const
MutableSpan< T > as_mutable_span()
void copy_from(GSpan values)
GMutableSpan slice(const int64_t start, int64_t size) const
static IndexMask from_predicate(const IndexMask &universe, GrainSize grain_size, IndexMaskMemory &memory, Fn &&predicate)
constexpr int64_t first() const
constexpr IndexRange shift(int64_t n) const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
static constexpr IndexRange from_single(const int64_t index)
constexpr IndexRange index_range() const
static constexpr IndexRange from_begin_end_inclusive(const int64_t begin, const int64_t last)
constexpr MutableSpan drop_back(const int64_t n) const
constexpr T & last(const int64_t n=0) const
static VArray from_single(T value, const int64_t size)
void add_new(const Key &key)
void append(const T &value)
void insert(const int64_t insert_index, const T &value)
IndexRange index_range() const
MutableSpan< T > as_mutable_span()
Span< T > as_span() const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
MutableSpan< float3 > positions_for_write()
Array< int > point_to_curve_map() const
OffsetIndices< int > points_by_curve() const
MutableSpan< int8_t > handle_types_right_for_write()
IndexRange curves_range() const
void update_curve_types()
MutableSpan< float3 > handle_positions_left_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
VArray< int8_t > nurbs_knots_modes() const
std::optional< Span< float3 > > handle_positions_left() const
Span< float3 > positions() const
MutableSpan< float > radius_for_write()
std::optional< Span< float3 > > handle_positions_right() const
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
bool nurbs_has_custom_knots() const
VArray< int8_t > curve_types() const
VArray< bool > cyclic() const
void calculate_bezier_auto_handles()
MutableSpan< bool > cyclic_for_write()
MutableSpan< int8_t > handle_types_left_for_write()
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
static float is_left(const float2 &p0, const float2 &p1, const float2 &p2)
static void move_segment(const ViewContext *vc, MoveSegmentData *seg_data, const wmEvent *event)
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > float3
void copy(const GVArray &src, GMutableSpan dst, int64_t grain_size=4096)
void fill_index_range(MutableSpan< T > span, const T start=0)
Insertion insert(const float3 &point_prev, const float3 &handle_prev, const float3 &handle_next, const float3 &point_next, float parameter)
void gather_custom_knots(const bke::CurvesGeometry &src, const IndexMask &src_curves, int dst_curve_offset, bke::CurvesGeometry &dst)
void update_custom_knot_modes(const IndexMask &mask, const KnotsMode mode_for_regular, const KnotsMode mode_for_cyclic, bke::CurvesGeometry &curves)
auto attribute_filter_from_skip_ref(const Span< StringRef > skip)
void fill_attribute_range_default(MutableAttributeAccessor dst_attributes, AttrDomain domain, const AttributeFilter &attribute_filter, IndexRange range)
void copy_attributes(const AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, MutableAttributeAccessor dst_attributes)
void gather_attributes(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
static bool has_anything_selected(const Span< Curves * > curves_ids)
IndexMask retrieve_all_selected_points(const bke::CurvesGeometry &curves, const int handle_display, IndexMaskMemory &memory)
void fill_selection_false(GMutableSpan selection)
bool object_has_editable_curves(const Main &bmain, const Object &object)
void ED_curves_pentool_modal_keymap(wmKeyConfig *keyconf)
void fill_selection_true(GMutableSpan selection)
Span< StringRef > get_curves_selection_attribute_names(const bke::CurvesGeometry &curves)
void ED_operatortypes_curves_pen()
static void CURVES_OT_pen(wmOperatorType *ot)
bke::GSpanAttributeWriter ensure_selection_attribute(bke::CurvesGeometry &curves, bke::AttrDomain selection_domain, bke::AttrType create_type, StringRef attribute_name)
void add_single_curve(bke::CurvesGeometry &curves, const bool at_end)
T clamp(const T &a, const T &min, const T &max)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
CartesianBasis invert(const CartesianBasis &basis)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void copy_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
float RNA_float_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_float_distance(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
ListBase vertex_group_names
static MatBase identity()
MutableVArraySpan< T > span
struct ReportList * reports
struct wmOperatorType * type
void WM_cursor_modal_set(wmWindow *win, int val)
void WM_cursor_modal_restore(wmWindow *win)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
void WM_operator_properties_mouse_select(wmOperatorType *ot)
void WM_operatortype_append(void(*opfunc)(wmOperatorType *))