WIP: uv-simple-select #1

Closed
Chris Blackbourn wants to merge 182 commits from uv-simple-select into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
Showing only changes of commit e8c827c6a7 - Show all commits

View File

@ -357,9 +357,9 @@ static void apply_selection_operation_at_index(GMutableSpan selection,
} }
/** /**
* Helper struct for `find_closest_point_to_screen_co`. * Helper struct for `select_pick`.
*/ */
struct FindClosestPointData { struct FindClosestData {
int index = -1; int index = -1;
float distance = FLT_MAX; float distance = FLT_MAX;
}; };
@ -371,7 +371,7 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
const bke::CurvesGeometry &curves, const bke::CurvesGeometry &curves,
float2 mouse_pos, float2 mouse_pos,
float radius, float radius,
FindClosestPointData &closest_data) FindClosestData &closest_data)
{ {
float4x4 projection; float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr()); ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr());
@ -380,12 +380,12 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object); bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object);
const float radius_sq = pow2f(radius); const float radius_sq = pow2f(radius);
auto [min_point_index, min_distance] = threading::parallel_reduce( closest_data = threading::parallel_reduce(
curves.points_range(), curves.points_range(),
1024, 1024,
FindClosestPointData(), FindClosestData(),
[&](const IndexRange point_range, const FindClosestPointData &init) { [&](const IndexRange point_range, const FindClosestData &init) {
FindClosestPointData best_match = init; FindClosestData best_match = init;
for (const int point_i : point_range) { for (const int point_i : point_range) {
const float3 pos = deformation.positions[point_i]; const float3 pos = deformation.positions[point_i];
@ -400,7 +400,7 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
continue; continue;
} }
FindClosestPointData better_candidate; FindClosestData better_candidate;
better_candidate.index = point_i; better_candidate.index = point_i;
better_candidate.distance = std::sqrt(distance_proj_sq); better_candidate.distance = std::sqrt(distance_proj_sq);
@ -408,18 +408,104 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph,
} }
return best_match; return best_match;
}, },
[](const FindClosestPointData &a, const FindClosestPointData &b) { [](const FindClosestData &a, const FindClosestData &b) {
if (a.distance < b.distance) {
return a;
}
return b;
});
if (closest_data.index > 0) {
return true;
}
return false;
}
static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph,
const ARegion *region,
const RegionView3D *rv3d,
const Object &object,
const bke::CurvesGeometry &curves,
float2 mouse_pos,
float radius,
FindClosestData &closest_data)
{
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr());
const bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object);
const float radius_sq = pow2f(radius);
const OffsetIndices points_by_curve = curves.points_by_curve();
closest_data = threading::parallel_reduce(
curves.curves_range(),
256,
FindClosestData(),
[&](const IndexRange curves_range, const FindClosestData &init) {
FindClosestData best_match = init;
for (const int curve_i : curves_range) {
if (points_by_curve.size(curve_i) == 1) {
const float3 pos = deformation.positions[points_by_curve[curve_i].first()];
/* Find the position of the point in screen space. */
float2 pos_proj;
ED_view3d_project_float_v2_m4(region, pos, pos_proj, projection.ptr());
const float distance_proj_sq = math::distance_squared(pos_proj, mouse_pos);
if (distance_proj_sq > radius_sq ||
distance_proj_sq > best_match.distance * best_match.distance) {
/* Ignore the point because it's too far away or there is already a better point.
*/
continue;
}
FindClosestData better_candidate;
better_candidate.index = curve_i;
better_candidate.distance = std::sqrt(distance_proj_sq);
best_match = better_candidate;
continue;
}
for (const int segment_i : points_by_curve[curve_i].drop_back(1)) {
const float3 pos1 = deformation.positions[segment_i];
const float3 pos2 = deformation.positions[segment_i + 1];
float2 pos1_proj, pos2_proj;
ED_view3d_project_float_v2_m4(region, pos1, pos1_proj, projection.ptr());
ED_view3d_project_float_v2_m4(region, pos2, pos2_proj, projection.ptr());
const float distance_proj_sq = dist_squared_to_line_segment_v2(
mouse_pos, pos1_proj, pos2_proj);
if (distance_proj_sq > radius_sq ||
distance_proj_sq > best_match.distance * best_match.distance) {
/* Ignore the segment because it's too far away or there is already a better point.
*/
continue;
}
FindClosestData better_candidate;
better_candidate.index = curve_i;
better_candidate.distance = std::sqrt(distance_proj_sq);
best_match = better_candidate;
}
}
return best_match;
},
[](const FindClosestData &a, const FindClosestData &b) {
if (a.distance < b.distance) { if (a.distance < b.distance) {
return a; return a;
} }
return b; return b;
}); });
if (min_point_index > 0) { if (closest_data.index > 0) {
closest_data.index = min_point_index;
closest_data.distance = min_distance;
return true; return true;
} }
return false; return false;
} }
@ -429,15 +515,28 @@ bool select_pick(const ViewContext &vc,
const SelectPick_Params &params, const SelectPick_Params &params,
const int2 coord) const int2 coord)
{ {
FindClosestPointData closest_point; FindClosestData closest;
bool found = find_closest_point_to_screen_co(*vc.depsgraph, bool found = false;
if (selection_domain == ATTR_DOMAIN_POINT) {
found = find_closest_point_to_screen_co(*vc.depsgraph,
vc.region, vc.region,
vc.rv3d, vc.rv3d,
*vc.obact, *vc.obact,
curves, curves,
float2(coord), float2(coord),
ED_view3d_select_dist_px(), ED_view3d_select_dist_px(),
closest_point); closest);
}
else if (selection_domain == ATTR_DOMAIN_CURVE) {
found = find_closest_curve_to_screen_co(*vc.depsgraph,
vc.region,
vc.rv3d,
*vc.obact,
curves,
float2(coord),
ED_view3d_select_dist_px(),
closest);
}
bool changed = false; bool changed = false;
if (params.sel_op == SEL_OP_SET) { if (params.sel_op == SEL_OP_SET) {
@ -453,17 +552,7 @@ bool select_pick(const ViewContext &vc,
if (found) { if (found) {
bke::GSpanAttributeWriter selection = ensure_selection_attribute( bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL); curves, selection_domain, CD_PROP_BOOL);
apply_selection_operation_at_index(selection.span, closest.index, params.sel_op);
int elem_index = closest_point.index;
if (selection_domain == ATTR_DOMAIN_CURVE) {
/* Find the curve index for the found point. */
auto it = std::upper_bound(
curves.offsets().begin(), curves.offsets().end(), closest_point.index);
BLI_assert(it != curves.offsets().end());
elem_index = std::distance(curves.offsets().begin(), it) - 1;
}
apply_selection_operation_at_index(selection.span, elem_index, params.sel_op);
selection.finish(); selection.finish();
} }
@ -507,13 +596,29 @@ bool select_box(const ViewContext &vc,
else if (selection_domain == ATTR_DOMAIN_CURVE) { else if (selection_domain == ATTR_DOMAIN_CURVE) {
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) { threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) { for (const int curve_i : curves_range) {
for (const int point_i : points_by_curve[curve_i]) { if (points_by_curve.size(curve_i) == 1) {
float2 pos_proj; float2 pos_proj;
ED_view3d_project_float_v2_m4( ED_view3d_project_float_v2_m4(vc.region,
vc.region, deformation.positions[point_i], pos_proj, projection.ptr()); deformation.positions[points_by_curve[curve_i].first()],
pos_proj,
projection.ptr());
if (BLI_rcti_isect_pt_v(&rect, int2(pos_proj))) { if (BLI_rcti_isect_pt_v(&rect, int2(pos_proj))) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op); apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true; changed = true;
}
continue;
}
for (const int segment_i : points_by_curve[curve_i].drop_back(1)) {
const float3 pos1 = deformation.positions[segment_i];
const float3 pos2 = deformation.positions[segment_i + 1];
float2 pos1_proj, pos2_proj;
ED_view3d_project_float_v2_m4(vc.region, pos1, pos1_proj, projection.ptr());
ED_view3d_project_float_v2_m4(vc.region, pos2, pos2_proj, projection.ptr());
if (BLI_rcti_isect_segment(&rect, int2(pos1_proj), int2(pos2_proj))) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break; break;
} }
} }
@ -569,16 +674,40 @@ bool select_lasso(const ViewContext &vc,
else if (selection_domain == ATTR_DOMAIN_CURVE) { else if (selection_domain == ATTR_DOMAIN_CURVE) {
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) { threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) { for (const int curve_i : curves_range) {
for (const int point_i : points_by_curve[curve_i]) { if (points_by_curve.size(curve_i) == 1) {
float2 pos_proj; float2 pos_proj;
ED_view3d_project_float_v2_m4( ED_view3d_project_float_v2_m4(vc.region,
vc.region, deformation.positions[point_i], pos_proj, projection.ptr()); deformation.positions[points_by_curve[curve_i].first()],
pos_proj,
projection.ptr());
/* Check the lasso bounding box first as an optimization. */ /* Check the lasso bounding box first as an optimization. */
if (BLI_rcti_isect_pt_v(&bbox, int2(pos_proj)) && if (BLI_rcti_isect_pt_v(&bbox, int2(pos_proj)) &&
BLI_lasso_is_point_inside( BLI_lasso_is_point_inside(
coord_array, coords.size(), int(pos_proj.x), int(pos_proj.y), IS_CLIPPED)) { coord_array, coords.size(), int(pos_proj.x), int(pos_proj.y), IS_CLIPPED)) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op); apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true; changed = true;
}
continue;
}
for (const int segment_i : points_by_curve[curve_i].drop_back(1)) {
const float3 pos1 = deformation.positions[segment_i];
const float3 pos2 = deformation.positions[segment_i + 1];
float2 pos1_proj, pos2_proj;
ED_view3d_project_float_v2_m4(vc.region, pos1, pos1_proj, projection.ptr());
ED_view3d_project_float_v2_m4(vc.region, pos2, pos2_proj, projection.ptr());
/* Check the lasso bounding box first as an optimization. */
if (BLI_rcti_isect_segment(&bbox, int2(pos1_proj), int2(pos2_proj)) &&
BLI_lasso_is_edge_inside(coord_array,
coords.size(),
int(pos1_proj.x),
int(pos1_proj.y),
int(pos2_proj.x),
int(pos2_proj.y),
IS_CLIPPED)) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break; break;
} }
} }
@ -629,13 +758,31 @@ bool select_circle(const ViewContext &vc,
else if (selection_domain == ATTR_DOMAIN_CURVE) { else if (selection_domain == ATTR_DOMAIN_CURVE) {
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) { threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) { for (const int curve_i : curves_range) {
for (const int point_i : points_by_curve[curve_i]) { if (points_by_curve.size(curve_i) == 1) {
float2 pos_proj; float2 pos_proj;
ED_view3d_project_float_v2_m4( ED_view3d_project_float_v2_m4(vc.region,
vc.region, deformation.positions[point_i], pos_proj, projection.ptr()); deformation.positions[points_by_curve[curve_i].first()],
pos_proj,
projection.ptr());
if (math::distance_squared(pos_proj, float2(coord)) <= radius_sq) { if (math::distance_squared(pos_proj, float2(coord)) <= radius_sq) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op); apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true; changed = true;
}
continue;
}
for (const int segment_i : points_by_curve[curve_i].drop_back(1)) {
const float3 pos1 = deformation.positions[segment_i];
const float3 pos2 = deformation.positions[segment_i + 1];
float2 pos1_proj, pos2_proj;
ED_view3d_project_float_v2_m4(vc.region, pos1, pos1_proj, projection.ptr());
ED_view3d_project_float_v2_m4(vc.region, pos2, pos2_proj, projection.ptr());
const float distance_proj_sq = dist_squared_to_line_segment_v2(
float2(coord), pos1_proj, pos2_proj);
if (distance_proj_sq <= radius_sq) {
apply_selection_operation_at_index(selection.span, curve_i, sel_op);
changed = true;
break; break;
} }
} }