Cleanup: Access geometry bounds more directly
More consistently return geometry bounds with the `Bounds` type that holds the min and max in one variable. This simplifies some code and reduces the need to initialize separate min and max variables first. Meshes now use the same `bounds_min_max()` function as curves and point clouds, though the wrapper mesh isn't affected yet. The motivation is to make some of the changes for #96968 simpler.
This commit is contained in:
@@ -258,12 +258,9 @@ class CurvesGeometry : public ::CurvesGeometry {
|
||||
MutableSpan<float2> surface_uv_coords_for_write();
|
||||
|
||||
/**
|
||||
* Calculate the largest and smallest position values, only including control points
|
||||
* (rather than evaluated points). The existing values of `min` and `max` are taken into account.
|
||||
*
|
||||
* \return Whether there are any points. If the curve is empty, the inputs will be unaffected.
|
||||
* The largest and smallest position values of evaluated points.
|
||||
*/
|
||||
bool bounds_min_max(float3 &min, float3 &max) const;
|
||||
std::optional<Bounds<float3>> bounds_min_max() const;
|
||||
|
||||
private:
|
||||
/* --------------------------------------------------------------------
|
||||
|
||||
@@ -8,13 +8,12 @@
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
|
||||
#include "BLI_bounds_types.hh"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
|
||||
@@ -194,7 +193,7 @@ struct GeometrySet {
|
||||
*/
|
||||
Vector<const GeometryComponent *> get_components_for_read() const;
|
||||
|
||||
bool compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const;
|
||||
std::optional<Bounds<float3>> compute_boundbox_without_instances() const;
|
||||
|
||||
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);
|
||||
|
||||
|
||||
@@ -265,7 +265,6 @@ void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, st
|
||||
/* vertex level transformations & checks (no derived mesh) */
|
||||
|
||||
/* basic vertex data functions */
|
||||
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
|
||||
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys);
|
||||
void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys);
|
||||
|
||||
@@ -512,7 +511,6 @@ bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
|
||||
* use when we want to ignore vertex locations that don't have connected faces.
|
||||
*/
|
||||
bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]);
|
||||
bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
|
||||
bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
|
||||
/**
|
||||
* \note Mesh must be manifold with consistent face-winding,
|
||||
|
||||
@@ -192,6 +192,7 @@ void *BKE_curves_add(Main *bmain, const char *name)
|
||||
|
||||
BoundBox *BKE_curves_boundbox_get(Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
BLI_assert(ob->type == OB_CURVES);
|
||||
const Curves *curves_id = static_cast<const Curves *>(ob->data);
|
||||
|
||||
@@ -201,17 +202,13 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
|
||||
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
|
||||
const blender::bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
|
||||
float3 min(FLT_MAX);
|
||||
float3 max(-FLT_MAX);
|
||||
if (!curves.bounds_min_max(min, max)) {
|
||||
min = float3(-1);
|
||||
max = float3(1);
|
||||
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
if (const std::optional<Bounds<float3>> bounds = curves.bounds_min_max()) {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
|
||||
}
|
||||
else {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
}
|
||||
|
||||
return ob->runtime.bb;
|
||||
|
||||
@@ -1096,19 +1096,14 @@ void CurvesGeometry::transform(const float4x4 &matrix)
|
||||
this->tag_positions_changed();
|
||||
}
|
||||
|
||||
bool CurvesGeometry::bounds_min_max(float3 &min, float3 &max) const
|
||||
std::optional<Bounds<float3>> CurvesGeometry::bounds_min_max() const
|
||||
{
|
||||
if (this->points_num() == 0) {
|
||||
return false;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
this->runtime->bounds_cache.ensure(
|
||||
[&](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(this->evaluated_positions()); });
|
||||
|
||||
const Bounds<float3> &bounds = this->runtime->bounds_cache.data();
|
||||
min = math::min(bounds.min, min);
|
||||
max = math::max(bounds.max, max);
|
||||
return true;
|
||||
return this->runtime->bounds_cache.data();
|
||||
}
|
||||
|
||||
CurvesGeometry curves_copy_point_selection(
|
||||
|
||||
@@ -33,9 +33,7 @@ TEST(curves_geometry, Empty)
|
||||
{
|
||||
CurvesGeometry empty(0, 0);
|
||||
empty.cyclic();
|
||||
float3 min;
|
||||
float3 max;
|
||||
EXPECT_FALSE(empty.bounds_min_max(min, max));
|
||||
EXPECT_FALSE(empty.bounds_min_max());
|
||||
}
|
||||
|
||||
TEST(curves_geometry, Move)
|
||||
@@ -52,9 +50,7 @@ TEST(curves_geometry, Move)
|
||||
EXPECT_EQ(curves.curve_offsets, nullptr); /* NOLINT: bugprone-use-after-move */
|
||||
|
||||
/* Just a basic check that the new curves work okay. */
|
||||
float3 min;
|
||||
float3 max;
|
||||
EXPECT_TRUE(other.bounds_min_max(min, max));
|
||||
EXPECT_TRUE(other.bounds_min_max());
|
||||
|
||||
curves = std::move(other);
|
||||
|
||||
|
||||
@@ -196,24 +196,30 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
|
||||
return components;
|
||||
}
|
||||
|
||||
bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const
|
||||
std::optional<Bounds<float3>> GeometrySet::compute_boundbox_without_instances() const
|
||||
{
|
||||
using namespace blender;
|
||||
bool have_minmax = false;
|
||||
std::optional<Bounds<float3>> bounds;
|
||||
if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) {
|
||||
have_minmax |= pointcloud->bounds_min_max(*r_min, *r_max);
|
||||
bounds = bounds::merge(bounds, pointcloud->bounds_min_max());
|
||||
}
|
||||
if (const Mesh *mesh = this->get_mesh_for_read()) {
|
||||
have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max);
|
||||
Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
|
||||
float3(std::numeric_limits<float>::min())};
|
||||
if (BKE_mesh_wrapper_minmax(mesh, mesh_bounds.min, mesh_bounds.max)) {
|
||||
bounds = bounds::merge(bounds, {mesh_bounds});
|
||||
}
|
||||
}
|
||||
if (const Volume *volume = this->get_volume_for_read()) {
|
||||
have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max);
|
||||
Bounds<float3> volume_bounds{float3(std::numeric_limits<float>::max()),
|
||||
float3(std::numeric_limits<float>::min())};
|
||||
if (BKE_volume_min_max(volume, volume_bounds.min, volume_bounds.max)) {
|
||||
bounds = bounds::merge(bounds, {volume_bounds});
|
||||
}
|
||||
}
|
||||
if (const Curves *curves_id = this->get_curves_for_read()) {
|
||||
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
|
||||
have_minmax |= curves.bounds_min_max(*r_min, *r_max);
|
||||
bounds = bounds::merge(bounds, curves_id->geometry.wrap().bounds_min_max());
|
||||
}
|
||||
return have_minmax;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "BKE_material.h"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_bounds.hh"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_memarena.h"
|
||||
@@ -699,25 +700,21 @@ GreasePencil *BKE_grease_pencil_new_nomain()
|
||||
|
||||
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
BLI_assert(ob->type == OB_GREASE_PENCIL);
|
||||
const GreasePencil *grease_pencil = static_cast<const GreasePencil *>(ob->data);
|
||||
|
||||
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
}
|
||||
|
||||
float3 min(FLT_MAX);
|
||||
float3 max(-FLT_MAX);
|
||||
|
||||
if (!grease_pencil->bounds_min_max(min, max)) {
|
||||
min = float3(-1);
|
||||
max = float3(1);
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
if (const std::optional<Bounds<float3>> bounds = grease_pencil->bounds_min_max()) {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
|
||||
}
|
||||
else {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
|
||||
}
|
||||
|
||||
return ob->runtime.bb;
|
||||
@@ -1109,21 +1106,19 @@ void GreasePencil::foreach_editable_drawing(
|
||||
foreach_drawing_ex(*this, frame, EDITABLE, function);
|
||||
}
|
||||
|
||||
bool GreasePencil::bounds_min_max(float3 &min, float3 &max) const
|
||||
std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max() const
|
||||
{
|
||||
bool found = false;
|
||||
using namespace blender;
|
||||
/* FIXME: this should somehow go through the visible drawings. We don't have access to the
|
||||
* scene time here, so we probably need to cache the visible drawing for each layer somehow. */
|
||||
std::optional<Bounds<float3>> bounds;
|
||||
for (int i = 0; i < this->drawing_array_num; i++) {
|
||||
GreasePencilDrawingBase *drawing_base = this->drawing_array[i];
|
||||
switch (drawing_base->type) {
|
||||
case GP_DRAWING: {
|
||||
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
|
||||
const blender::bke::CurvesGeometry &curves = drawing->geometry.wrap();
|
||||
|
||||
if (curves.bounds_min_max(min, max)) {
|
||||
found = true;
|
||||
}
|
||||
const bke::CurvesGeometry &curves = drawing->geometry.wrap();
|
||||
bounds = bounds::merge(bounds, curves.bounds_min_max());
|
||||
break;
|
||||
}
|
||||
case GP_DRAWING_REFERENCE: {
|
||||
@@ -1133,7 +1128,7 @@ bool GreasePencil::bounds_min_max(float3 &min, float3 &max) const
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
return bounds;
|
||||
}
|
||||
|
||||
blender::Span<const blender::bke::greasepencil::Layer *> GreasePencil::layers() const
|
||||
|
||||
@@ -244,32 +244,7 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
|
||||
BoundBox *BKE_mball_boundbox_get(Object *ob)
|
||||
{
|
||||
BLI_assert(ob->type == OB_MBALL);
|
||||
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
}
|
||||
|
||||
/* Expect that this function is only called for evaluated objects. */
|
||||
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
|
||||
float min[3];
|
||||
float max[3];
|
||||
if (mesh_eval) {
|
||||
INIT_MINMAX(min, max);
|
||||
if (!BKE_mesh_minmax(mesh_eval, min, max)) {
|
||||
copy_v3_fl(min, -1.0f);
|
||||
copy_v3_fl(max, 1.0f);
|
||||
}
|
||||
}
|
||||
else {
|
||||
copy_v3_fl(min, 0.0f);
|
||||
copy_v3_fl(max, 0.0f);
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
|
||||
|
||||
BKE_object_boundbox_calc_from_evaluated_geometry(ob);
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
@@ -704,14 +679,5 @@ void BKE_mball_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
|
||||
|
||||
ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh));
|
||||
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
}
|
||||
float3 min(std::numeric_limits<float>::max());
|
||||
float3 max(-std::numeric_limits<float>::max());
|
||||
if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
|
||||
min = float3(0);
|
||||
max = float3(0);
|
||||
}
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
BKE_object_boundbox_calc_from_evaluated_geometry(ob);
|
||||
};
|
||||
|
||||
@@ -1502,21 +1502,15 @@ void BKE_mesh_looptri_get_real_edges(const blender::int2 *edges,
|
||||
}
|
||||
}
|
||||
|
||||
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3])
|
||||
std::optional<blender::Bounds<blender::float3>> Mesh::bounds_min_max() const
|
||||
{
|
||||
using namespace blender;
|
||||
if (me->totvert == 0) {
|
||||
return false;
|
||||
if (this->totvert == 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
me->runtime->bounds_cache.ensure(
|
||||
[me](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(me->vert_positions()); });
|
||||
|
||||
const Bounds<float3> &bounds = me->runtime->bounds_cache.data();
|
||||
copy_v3_v3(r_min, math::min(bounds.min, float3(r_min)));
|
||||
copy_v3_v3(r_max, math::max(bounds.max, float3(r_max)));
|
||||
|
||||
return true;
|
||||
this->runtime->bounds_cache.ensure(
|
||||
[&](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(this->vert_positions()); });
|
||||
return this->runtime->bounds_cache.data();
|
||||
}
|
||||
|
||||
void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds)
|
||||
|
||||
@@ -276,18 +276,6 @@ bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
|
||||
return (me->totpoly != 0);
|
||||
}
|
||||
|
||||
bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
|
||||
{
|
||||
float min[3], max[3];
|
||||
INIT_MINMAX(min, max);
|
||||
if (BKE_mesh_minmax(me, min, max)) {
|
||||
mid_v3_v3v3(r_cent, min, max);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
|
||||
{
|
||||
float poly_area;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_task.hh"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
@@ -153,12 +154,19 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
|
||||
|
||||
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
|
||||
{
|
||||
using namespace blender;
|
||||
switch (me->runtime->wrapper_type) {
|
||||
case ME_WRAPPER_TYPE_BMESH:
|
||||
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max);
|
||||
case ME_WRAPPER_TYPE_MDATA:
|
||||
case ME_WRAPPER_TYPE_SUBD:
|
||||
return BKE_mesh_minmax(me, min, max);
|
||||
case ME_WRAPPER_TYPE_SUBD: {
|
||||
if (const std::optional<Bounds<float3>> bounds = me->bounds_min_max()) {
|
||||
copy_v3_v3(min, math::min(bounds->min, float3(min)));
|
||||
copy_v3_v3(max, math::max(bounds->max, float3(max)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return false;
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_bounds.hh"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_listbase.h"
|
||||
@@ -3847,19 +3848,17 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
|
||||
|
||||
bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
|
||||
{
|
||||
float3 min(FLT_MAX);
|
||||
float3 max(-FLT_MAX);
|
||||
using namespace blender;
|
||||
|
||||
std::optional<Bounds<float3>> bounds;
|
||||
if (ob->runtime.geometry_set_eval) {
|
||||
if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
|
||||
min = float3(0);
|
||||
max = float3(0);
|
||||
}
|
||||
bounds = ob->runtime.geometry_set_eval->compute_boundbox_without_instances();
|
||||
}
|
||||
else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
|
||||
if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) {
|
||||
min = float3(0);
|
||||
max = float3(0);
|
||||
Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
|
||||
float3(std::numeric_limits<float>::min())};
|
||||
if (BKE_mesh_wrapper_minmax(mesh_eval, mesh_bounds.min, mesh_bounds.max)) {
|
||||
bounds = bounds::merge(bounds, {mesh_bounds});
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -3869,8 +3868,12 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
}
|
||||
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
if (bounds) {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
|
||||
}
|
||||
else {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(0), float3(0));
|
||||
}
|
||||
|
||||
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
|
||||
|
||||
|
||||
@@ -263,12 +263,12 @@ void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, PointCloud
|
||||
BKE_id_free(nullptr, pointcloud_src);
|
||||
}
|
||||
|
||||
bool PointCloud::bounds_min_max(blender::float3 &min, blender::float3 &max) const
|
||||
std::optional<blender::Bounds<blender::float3>> PointCloud::bounds_min_max() const
|
||||
{
|
||||
using namespace blender;
|
||||
using namespace blender::bke;
|
||||
if (this->totpoint == 0) {
|
||||
return false;
|
||||
return std::nullopt;
|
||||
}
|
||||
this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) {
|
||||
const AttributeAccessor attributes = this->attributes();
|
||||
@@ -281,34 +281,35 @@ bool PointCloud::bounds_min_max(blender::float3 &min, blender::float3 &max) cons
|
||||
r_bounds = *bounds::min_max(positions);
|
||||
}
|
||||
});
|
||||
const Bounds<float3> &bounds = this->runtime->bounds_cache.data();
|
||||
min = math::min(bounds.min, min);
|
||||
max = math::max(bounds.max, max);
|
||||
return true;
|
||||
return this->runtime->bounds_cache.data();
|
||||
}
|
||||
|
||||
BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
BLI_assert(ob->type == OB_POINTCLOUD);
|
||||
|
||||
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
if (ob->runtime.bb == nullptr) {
|
||||
ob->runtime.bb = static_cast<BoundBox *>(MEM_callocN(sizeof(BoundBox), "pointcloud boundbox"));
|
||||
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
|
||||
}
|
||||
|
||||
float3 min, max;
|
||||
INIT_MINMAX(min, max);
|
||||
if (ob->runtime.geometry_set_eval != nullptr) {
|
||||
ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
|
||||
std::optional<Bounds<float3>> bounds;
|
||||
if (ob->runtime.geometry_set_eval) {
|
||||
bounds = ob->runtime.geometry_set_eval->compute_boundbox_without_instances();
|
||||
}
|
||||
else {
|
||||
const PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
|
||||
pointcloud->bounds_min_max(min, max);
|
||||
bounds = pointcloud->bounds_min_max();
|
||||
}
|
||||
|
||||
if (bounds) {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
|
||||
}
|
||||
else {
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
|
||||
}
|
||||
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
|
||||
|
||||
return ob->runtime.bb;
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace blender::bounds {
|
||||
/**
|
||||
* Find the smallest and largest values element-wise in the span.
|
||||
*/
|
||||
template<typename T> inline std::optional<Bounds<T>> min_max(Span<T> values)
|
||||
template<typename T> [[nodiscard]] inline std::optional<Bounds<T>> min_max(Span<T> values)
|
||||
{
|
||||
if (values.is_empty()) {
|
||||
return std::nullopt;
|
||||
@@ -48,7 +48,8 @@ template<typename T> inline std::optional<Bounds<T>> min_max(Span<T> values)
|
||||
* first. The template type T is expected to have an addition operator implemented with RadiusT.
|
||||
*/
|
||||
template<typename T, typename RadiusT>
|
||||
inline std::optional<Bounds<T>> min_max_with_radii(Span<T> values, Span<RadiusT> radii)
|
||||
[[nodiscard]] inline std::optional<Bounds<T>> min_max_with_radii(Span<T> values,
|
||||
Span<RadiusT> radii)
|
||||
{
|
||||
BLI_assert(values.size() == radii.size());
|
||||
if (values.is_empty()) {
|
||||
@@ -72,4 +73,25 @@ inline std::optional<Bounds<T>> min_max_with_radii(Span<T> values, Span<RadiusT>
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T> [[nodiscard]] inline Bounds<T> merge(const Bounds<T> &a, const Bounds<T> &b)
|
||||
{
|
||||
return {math::min(a.min, b.min), math::max(a.max, b.max)};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] inline std::optional<Bounds<T>> merge(const std::optional<Bounds<T>> &a,
|
||||
const std::optional<Bounds<T>> &b)
|
||||
{
|
||||
if (a.has_value() && b.has_value()) {
|
||||
return merge(*a, *b);
|
||||
}
|
||||
if (a.has_value()) {
|
||||
return a;
|
||||
}
|
||||
if (b.has_value()) {
|
||||
return b;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace blender::bounds
|
||||
|
||||
@@ -1444,7 +1444,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
|
||||
BKE_mesh_center_of_volume(me, cent);
|
||||
}
|
||||
else if (around == V3D_AROUND_CENTER_BOUNDS) {
|
||||
BKE_mesh_center_bounds(me, cent);
|
||||
if (const std::optional<Bounds<float3>> bounds = me->bounds_min_max()) {
|
||||
cent = math::midpoint(bounds->min, bounds->max);
|
||||
}
|
||||
}
|
||||
else { /* #V3D_AROUND_CENTER_MEDIAN. */
|
||||
BKE_mesh_center_median(me, cent);
|
||||
@@ -1696,11 +1698,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
|
||||
/* done */
|
||||
}
|
||||
else if (around == V3D_AROUND_CENTER_BOUNDS) {
|
||||
float3 min(std::numeric_limits<float>::max());
|
||||
float3 max(-std::numeric_limits<float>::max());
|
||||
if (curves.bounds_min_max(min, max)) {
|
||||
cent = math::midpoint(min, max);
|
||||
}
|
||||
const Bounds<float3> bounds = *curves.bounds_min_max();
|
||||
cent = math::midpoint(bounds.min, bounds.max);
|
||||
}
|
||||
else if (around == V3D_AROUND_CENTER_MEDIAN) {
|
||||
cent = calculate_mean(curves.positions());
|
||||
@@ -1729,10 +1728,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
|
||||
/* Done. */
|
||||
}
|
||||
else if (around == V3D_AROUND_CENTER_BOUNDS) {
|
||||
float3 min(std::numeric_limits<float>::max());
|
||||
float3 max(-std::numeric_limits<float>::max());
|
||||
if (pointcloud.bounds_min_max(min, max)) {
|
||||
cent = math::midpoint(min, max);
|
||||
if (const std::optional<Bounds<float3>> bounds = pointcloud.bounds_min_max()) {
|
||||
cent = math::midpoint(bounds->min, bounds->max);
|
||||
}
|
||||
}
|
||||
else if (around == V3D_AROUND_CENTER_MEDIAN) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
@@ -792,21 +793,20 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
|
||||
/** \name Texture Paint Toggle Operator
|
||||
* \{ */
|
||||
|
||||
static void paint_init_pivot_mesh(Object *ob, float location[3])
|
||||
static blender::float3 paint_init_pivot_mesh(Object *ob)
|
||||
{
|
||||
using namespace blender;
|
||||
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
|
||||
if (!me_eval) {
|
||||
me_eval = (const Mesh *)ob->data;
|
||||
}
|
||||
|
||||
float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
|
||||
|
||||
if (!BKE_mesh_minmax(me_eval, min, max)) {
|
||||
zero_v3(location);
|
||||
zero_v3(max);
|
||||
const std::optional<Bounds<float3>> bounds = me_eval->bounds_min_max();
|
||||
if (!bounds) {
|
||||
return float3(0.0f);
|
||||
}
|
||||
|
||||
interp_v3_v3v3(location, min, max, 0.5f);
|
||||
return math::midpoint(bounds->min, bounds->max);
|
||||
}
|
||||
|
||||
static void paint_init_pivot_curves(Object *ob, float location[3])
|
||||
@@ -824,11 +824,11 @@ static void paint_init_pivot_grease_pencil(Object *ob, float location[3])
|
||||
void paint_init_pivot(Object *ob, Scene *scene)
|
||||
{
|
||||
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
|
||||
float location[3];
|
||||
|
||||
blender::float3 location;
|
||||
switch (ob->type) {
|
||||
case OB_MESH:
|
||||
paint_init_pivot_mesh(ob, location);
|
||||
location = paint_init_pivot_mesh(ob);
|
||||
break;
|
||||
case OB_CURVES:
|
||||
paint_init_pivot_curves(ob, location);
|
||||
|
||||
@@ -2413,14 +2413,13 @@ static bool lineart_geometry_check_visible(double model_view_proj[4][4],
|
||||
double shift_y,
|
||||
Mesh *use_mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
if (!use_mesh) {
|
||||
return false;
|
||||
}
|
||||
float mesh_min[3], mesh_max[3];
|
||||
INIT_MINMAX(mesh_min, mesh_max);
|
||||
BKE_mesh_minmax(use_mesh, mesh_min, mesh_max);
|
||||
const Bounds<float3> bounds = *use_mesh->bounds_min_max();
|
||||
BoundBox bb;
|
||||
BKE_boundbox_init_from_minmax(&bb, mesh_min, mesh_max);
|
||||
BKE_boundbox_init_from_minmax(&bb, bounds.min, bounds.max);
|
||||
|
||||
double co[8][4];
|
||||
double tmp[3];
|
||||
|
||||
@@ -323,13 +323,12 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
||||
}
|
||||
|
||||
/* Blender grows its bounds cache to cover animated meshes, so only author once. */
|
||||
float bound_min[3];
|
||||
float bound_max[3];
|
||||
INIT_MINMAX(bound_min, bound_max);
|
||||
BKE_mesh_minmax(mesh, bound_min, bound_max);
|
||||
pxr::VtArray<pxr::GfVec3f> extent{pxr::GfVec3f{bound_min[0], bound_min[1], bound_min[2]},
|
||||
pxr::GfVec3f{bound_max[0], bound_max[1], bound_max[2]}};
|
||||
usd_mesh.CreateExtentAttr().Set(extent);
|
||||
if (const std::optional<Bounds<float3>> bounds = mesh->bounds_min_max()) {
|
||||
pxr::VtArray<pxr::GfVec3f> extent{
|
||||
pxr::GfVec3f{bounds->min[0], bounds->min[1], bounds->min[2]},
|
||||
pxr::GfVec3f{bounds->max[0], bounds->max[1], bounds->max[2]}};
|
||||
usd_mesh.CreateExtentAttr().Set(extent);
|
||||
}
|
||||
}
|
||||
|
||||
static void get_vertices(const Mesh *mesh, USDMeshData &usd_mesh_data)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_bounds_types.hh"
|
||||
# include "BLI_function_ref.hh"
|
||||
# include "BLI_map.hh"
|
||||
# include "BLI_math_vector_types.hh"
|
||||
@@ -457,7 +458,7 @@ typedef struct GreasePencil {
|
||||
void foreach_editable_drawing(int frame,
|
||||
blender::FunctionRef<void(int, GreasePencilDrawing &)> function);
|
||||
|
||||
bool bounds_min_max(blender::float3 &min, blender::float3 &max) const;
|
||||
std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;
|
||||
|
||||
/* For debugging purposes. */
|
||||
void print_layer_tree();
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
/** Workaround to forward-declare C++ type in C header. */
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include <optional>
|
||||
|
||||
# include "BLI_bounds_types.hh"
|
||||
# include "BLI_math_vector_types.hh"
|
||||
# include "BLI_offset_indices.hh"
|
||||
@@ -302,6 +304,12 @@ typedef struct Mesh {
|
||||
*/
|
||||
blender::Span<int> looptri_polys() const;
|
||||
|
||||
/**
|
||||
* Calculate the largest and smallest position values of vertices.
|
||||
* \note Does not take non-mesh data (edit mesh) into account, see #BKE_mesh_wrapper_minmax,
|
||||
*/
|
||||
std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;
|
||||
|
||||
/** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */
|
||||
void bounds_set_eager(const blender::Bounds<blender::float3> &bounds);
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "DNA_customdata_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include <optional>
|
||||
|
||||
# include "BLI_bounds_types.hh"
|
||||
# include "BLI_math_vector_types.hh"
|
||||
# include "BLI_span.hh"
|
||||
#endif
|
||||
@@ -63,7 +66,7 @@ typedef struct PointCloud {
|
||||
void tag_positions_changed();
|
||||
void tag_radii_changed();
|
||||
|
||||
bool bounds_min_max(blender::float3 &min, blender::float3 &max) const;
|
||||
std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;
|
||||
#endif
|
||||
|
||||
PointCloudRuntimeHandle *runtime;
|
||||
|
||||
@@ -378,6 +378,7 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
const ModifierEvalContext *ctx,
|
||||
Mesh *mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
if (mesh->totvert == 0) {
|
||||
return mesh;
|
||||
}
|
||||
@@ -458,12 +459,9 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd,
|
||||
}
|
||||
|
||||
if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
|
||||
float min[3], max[3];
|
||||
INIT_MINMAX(min, max);
|
||||
BKE_mesh_minmax(mesh, min, max);
|
||||
|
||||
const Bounds<float3> bounds = *mesh->bounds_min_max();
|
||||
for (j = 3; j--;) {
|
||||
offset[3][j] += amd->scale[j] * (max[j] - min[j]);
|
||||
offset[3][j] += amd->scale[j] * (bounds.max[j] - bounds.min[j]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -151,18 +151,17 @@ static bool can_use_mesh_for_orco_evaluation(MeshSeqCacheModifierData *mcmd,
|
||||
static Mesh *generate_bounding_box_mesh(const Mesh *org_mesh)
|
||||
{
|
||||
using namespace blender;
|
||||
float3 min(std::numeric_limits<float>::max());
|
||||
float3 max(-std::numeric_limits<float>::max());
|
||||
if (!BKE_mesh_minmax(org_mesh, min, max)) {
|
||||
const std::optional<Bounds<float3>> bounds = org_mesh->bounds_min_max();
|
||||
if (!bounds) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Mesh *result = geometry::create_cuboid_mesh(max - min, 2, 2, 2);
|
||||
Mesh *result = geometry::create_cuboid_mesh(bounds->max - bounds->min, 2, 2, 2);
|
||||
if (org_mesh->mat) {
|
||||
result->mat = static_cast<Material **>(MEM_dupallocN(org_mesh->mat));
|
||||
result->totcol = org_mesh->totcol;
|
||||
}
|
||||
BKE_mesh_translate(result, math::midpoint(min, max), false);
|
||||
BKE_mesh_translate(result, math::midpoint(bounds->min, bounds->max), false);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -306,11 +306,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
||||
psys_sim_data_init(&sim);
|
||||
|
||||
if (psys->flag & (PSYS_HAIR_DONE | PSYS_KEYED) || psys->pointcache->flag & PTCACHE_BAKED) {
|
||||
float min[3], max[3];
|
||||
INIT_MINMAX(min, max);
|
||||
BKE_mesh_minmax(mesh, min, max);
|
||||
min_co = min[track];
|
||||
max_co = max[track];
|
||||
if (const std::optional<blender::Bounds<blender::float3>> bounds = mesh->bounds_min_max()) {
|
||||
min_co = bounds->min[track];
|
||||
max_co = bounds->max[track];
|
||||
}
|
||||
}
|
||||
|
||||
result = BKE_mesh_new_nomain_from_template(mesh, maxvert, maxedge, maxpoly, maxloop);
|
||||
|
||||
@@ -71,8 +71,9 @@ static void init_dualcon_mesh(DualConInput *input, Mesh *mesh)
|
||||
input->tri_stride = sizeof(MLoopTri);
|
||||
input->tottri = BKE_mesh_runtime_looptri_len(mesh);
|
||||
|
||||
INIT_MINMAX(input->min, input->max);
|
||||
BKE_mesh_minmax(mesh, input->min, input->max);
|
||||
const blender::Bounds<blender::float3> bounds = *mesh->bounds_min_max();
|
||||
copy_v3_v3(input->min, bounds.min);
|
||||
copy_v3_v3(input->max, bounds.max);
|
||||
}
|
||||
|
||||
/* simple structure to hold the output: a CDDM and two counters to
|
||||
|
||||
@@ -22,16 +22,14 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
|
||||
/* Compute the min and max of all realized geometry for the two
|
||||
* vector outputs, which are only meant to consider real geometry. */
|
||||
float3 min = float3(FLT_MAX);
|
||||
float3 max = float3(-FLT_MAX);
|
||||
geometry_set.compute_boundbox_without_instances(&min, &max);
|
||||
if (min == float3(FLT_MAX)) {
|
||||
const std::optional<Bounds<float3>> bounds = geometry_set.compute_boundbox_without_instances();
|
||||
if (!bounds) {
|
||||
params.set_output("Min", float3(0));
|
||||
params.set_output("Max", float3(0));
|
||||
}
|
||||
else {
|
||||
params.set_output("Min", min);
|
||||
params.set_output("Max", max);
|
||||
params.set_output("Min", bounds->min);
|
||||
params.set_output("Max", bounds->max);
|
||||
}
|
||||
|
||||
/* Generate the bounding box meshes inside each unique geometry set (including individually for
|
||||
@@ -39,24 +37,22 @@ static void node_geo_exec(GeoNodeExecParams params)
|
||||
* repurpose the original geometry sets for the output. */
|
||||
if (params.output_is_required("Bounding Box")) {
|
||||
geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
|
||||
float3 sub_min = float3(FLT_MAX);
|
||||
float3 sub_max = float3(-FLT_MAX);
|
||||
std::optional<Bounds<float3>> sub_bounds;
|
||||
|
||||
/* Reuse the min and max calculation if this is the main "real" geometry set. */
|
||||
if (&sub_geometry == &geometry_set) {
|
||||
sub_min = min;
|
||||
sub_max = max;
|
||||
sub_bounds = bounds;
|
||||
}
|
||||
else {
|
||||
sub_geometry.compute_boundbox_without_instances(&sub_min, &sub_max);
|
||||
sub_bounds = sub_geometry.compute_boundbox_without_instances();
|
||||
}
|
||||
|
||||
if (sub_min == float3(FLT_MAX)) {
|
||||
if (!sub_bounds) {
|
||||
sub_geometry.remove_geometry_during_modify();
|
||||
}
|
||||
else {
|
||||
const float3 scale = sub_max - sub_min;
|
||||
const float3 center = sub_min + scale / 2.0f;
|
||||
const float3 scale = sub_bounds->max - sub_bounds->min;
|
||||
const float3 center = sub_bounds->min + scale / 2.0f;
|
||||
Mesh *mesh = geometry::create_cuboid_mesh(scale, 2, 2, 2, "uv_map");
|
||||
transform_mesh(*mesh, center, float3(0), float3(1));
|
||||
sub_geometry.replace_mesh(mesh);
|
||||
|
||||
Reference in New Issue
Block a user