diff --git a/source/blender/blenkernel/BKE_armature.hh b/source/blender/blenkernel/BKE_armature.hh index 5ab4d39746e..20f38ac2ddd 100644 --- a/source/blender/blenkernel/BKE_armature.hh +++ b/source/blender/blenkernel/BKE_armature.hh @@ -183,12 +183,16 @@ void BKE_pchan_minmax(const Object *ob, /** * Calculate the axis aligned bounds of the pose of `ob` in world-space. * - * `r_min` and `r_max` are expanded to fit `ob->pose` so the caller must initialize them - * (typically using #INIT_MINMAX). + * This only considers visible bones. When they are either directly (via a flag on the bone) or + * indirectly (via bone collections) hidden, they are not part of the bounds calculation. When a + * bone has a custom bone shape, that is included in the bounding box. * * \note This uses #BKE_pchan_minmax, see its documentation for details on bounds calculation. + * + * \param use_select When true, only consider selected bones. When false, selection state is + * ignored and all bones are included in the bounds. */ -bool BKE_pose_minmax(const Object *ob, float r_min[3], float r_max[3], bool use_select); +std::optional> BKE_pose_minmax(const Object *ob, bool use_select); /** * Finds the best possible extension to the name on a particular axis. diff --git a/source/blender/blenkernel/intern/armature.cc b/source/blender/blenkernel/intern/armature.cc index 29748b0b35f..cd4665738d6 100644 --- a/source/blender/blenkernel/intern/armature.cc +++ b/source/blender/blenkernel/intern/armature.cc @@ -3023,21 +3023,18 @@ void BKE_pose_where_is(Depsgraph *depsgraph, Scene *scene, Object *ob) std::optional> BKE_armature_min_max(const Object *ob) { - BLI_assert(ob->data); - BLI_assert(ob->type == OB_ARMATURE); - BLI_assert(GS(static_cast(ob->data)->name) == ID_AR); + std::optional> bounds_world = BKE_pose_minmax(ob, false); - blender::float3 min(std::numeric_limits::max()); - blender::float3 max(std::numeric_limits::lowest()); - - const bool has_minmax = BKE_pose_minmax(ob, &min[0], &max[0], false); - - if (!has_minmax) { + if (!bounds_world) { return std::nullopt; } - return blender::Bounds{math::transform_point(ob->world_to_object(), min), - math::transform_point(ob->world_to_object(), max)}; + /* NOTE: this is not correct (after rotation the AABB may not be the smallest enclosing AABB any + * more), but acceptable because this is called via BKE_object_boundbox_get(), which is called by + * BKE_object_minmax(), which does the opposite transform. */ + return blender::Bounds{ + math::transform_point(ob->world_to_object(), bounds_world->min), + math::transform_point(ob->world_to_object(), bounds_world->max)}; } void BKE_pchan_minmax(const Object *ob, @@ -3088,12 +3085,16 @@ void BKE_pchan_minmax(const Object *ob, } } -bool BKE_pose_minmax(const Object *ob, float r_min[3], float r_max[3], bool use_select) +std::optional> BKE_pose_minmax(const Object *ob, + const bool use_select) { if (!ob->pose) { - return false; + return std::nullopt; } + blender::float3 min(std::numeric_limits::max()); + blender::float3 max(std::numeric_limits::lowest()); + BLI_assert(ob->type == OB_ARMATURE); const bArmature *arm = static_cast(ob->data); @@ -3110,11 +3111,16 @@ bool BKE_pose_minmax(const Object *ob, float r_min[3], float r_max[3], bool use_ if (use_select && !(pchan->bone->flag & BONE_SELECTED)) { continue; } - BKE_pchan_minmax(ob, pchan, false, r_min, r_max); + + BKE_pchan_minmax(ob, pchan, false, &min[0], &max[0]); found_pchan = true; } - return found_pchan; + if (!found_pchan) { + return std::nullopt; + } + + return blender::Bounds(min, max); } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_navigate_view_all.cc b/source/blender/editors/space_view3d/view3d_navigate_view_all.cc index ccc2ca884de..234f15a1cd5 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_view_all.cc +++ b/source/blender/editors/space_view3d/view3d_navigate_view_all.cc @@ -399,7 +399,12 @@ static int viewselected_exec(bContext *C, wmOperator *op) FOREACH_OBJECT_IN_MODE_BEGIN ( scene_eval, view_layer_eval, v3d, ob_eval->type, ob_eval->mode, ob_eval_iter) { - ok |= BKE_pose_minmax(ob_eval_iter, min, max, true); + const std::optional> bounds = BKE_pose_minmax(ob_eval_iter, true); + if (bounds) { + minmax_v3v3_v3(min, max, bounds->min); + minmax_v3v3_v3(min, max, bounds->max); + ok = true; + } } FOREACH_OBJECT_IN_MODE_END; }