Commit: adb4dd911b9183e1fb903e553f75a4a0df2d6717 Author: Hans Goudey Date: Mon Jan 2 10:49:57 2023 -0500 Branches: master https://developer.blender.org/rBadb4dd911b9183e1fb903e553f75a4a0df2d6717
Point Cloud: Support set origin and apply scale operators Move some functions for transforming a span of vectors to a header and call them from these functions, just like was done for curves objects recently. Resolves T102027, T102026 Differential Revision: https://developer.blender.org/D16883 =================================================================== M source/blender/editors/object/object_transform.cc =================================================================== diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index 672c04d8db6..539260cd27f 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -19,6 +19,7 @@ #include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_object_types.h" +#include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "BLI_array.hh" @@ -44,6 +45,7 @@ #include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_object.h" +#include "BKE_pointcloud.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_tracking.h" @@ -639,6 +641,17 @@ static bool apply_objects_internal_need_single_user(bContext *C) return (ID_REAL_USERS(ob->data) > CTX_DATA_COUNT(C, selected_editable_objects)); } +static void transform_positions(blender::MutableSpan<blender::float3> positions, + const blender::float4x4 &matrix) +{ + using namespace blender; + threading::parallel_for(positions.index_range(), 1024, [&](const IndexRange range) { + for (float3 &position : positions.slice(range)) { + position = matrix * position; + } + }); +} + static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_loc, @@ -647,6 +660,7 @@ static int apply_objects_internal(bContext *C, bool do_props, bool do_single_user) { + using namespace blender; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); @@ -696,7 +710,8 @@ static int apply_objects_internal(bContext *C, OB_SURF, OB_FONT, OB_GPENCIL, - OB_CURVES)) { + OB_CURVES, + OB_POINTCLOUD)) { ID *obdata = static_cast<ID *>(ob->data); if (!do_multi_user && ID_REAL_USERS(obdata) > 1) { BKE_reportf(reports, @@ -932,6 +947,14 @@ static int apply_objects_internal(bContext *C, blender::bke::CurvesGeometry::wrap(curves.geometry).transform(mat); blender::bke::CurvesGeometry::wrap(curves.geometry).calculate_bezier_auto_handles(); } + else if (ob->type == OB_POINTCLOUD) { + PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); + bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write(); + bke::SpanAttributeWriter position = attributes.lookup_or_add_for_write_span<float3>( + "position", ATTR_DOMAIN_POINT); + transform_positions(position.span, float4x4(mat)); + position.finish(); + } else if (ob->type == OB_CAMERA) { MovieClip *clip = BKE_object_movieclip_get(scene, ob, false); @@ -1230,8 +1253,29 @@ enum { ORIGIN_TO_CENTER_OF_MASS_VOLUME, }; +static float3 calculate_mean(const blender::Span<blender::float3> values) +{ + if (values.is_empty()) { + return float3(0); + } + /* TODO: Use a method that avoids overflow. */ + return std::accumulate(values.begin(), values.end(), float3(0)) / values.size(); +} + +static void translate_positions(blender::MutableSpan<blender::float3> positions, + const blender::float3 &translation) +{ + using namespace blender; + threading::parallel_for(positions.index_range(), 2048, [&](const IndexRange range) { + for (float3 &position : positions.slice(range)) { + position += translation; + } + }); +} + static int object_origin_set_exec(bContext *C, wmOperator *op) { + using namespace blender; Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); @@ -1653,9 +1697,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } } else if (around == V3D_AROUND_CENTER_MEDIAN) { - Span<float3> positions = curves.positions(); - cent = std::accumulate(positions.begin(), positions.end(), float3(0)) / - curves.points_num(); + cent = calculate_mean(curves.positions()); } tot_change++; @@ -1663,6 +1705,39 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) curves_id.id.tag |= LIB_TAG_DOIT; do_inverse_offset = true; } + else if (ob->type == OB_POINTCLOUD) { + PointCloud &pointcloud = *static_cast<PointCloud *>(ob->data); + bke::MutableAttributeAccessor attributes = pointcloud.attributes_for_write(); + bke::SpanAttributeWriter positions = attributes.lookup_or_add_for_write_span<float3>( + "position", ATTR_DOMAIN_POINT); + if (ELEM(centermode, ORIGIN_TO_CENTER_OF_MASS_SURFACE, ORIGIN_TO_CENTER_OF_MASS_VOLUME) || + !ELEM(around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN)) { + BKE_report(op->reports, + RPT_WARNING, + "Point cloud object does not support this set origin operation"); + continue; + } + + if (centermode == ORIGIN_TO_CURSOR) { + /* 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); + } + } + else if (around == V3D_AROUND_CENTER_MEDIAN) { + cent = calculate_mean(positions.span); + } + + tot_change++; + translate_positions(positions.span, -cent); + positions.finish(); + pointcloud.id.tag |= LIB_TAG_DOIT; + do_inverse_offset = true; + } /* offset other selected objects */ if (do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) { _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
