Skip to content

Commit a18d9f6

Browse files
cdtwiggmeta-codesync[bot]
authored andcommitted
Migrate kd-tree operations to numpy arrays with RowMajor storage fix (#970)
Summary: Pull Request resolved: #970 Migrated find_closest_points, find_closest_points_with_normals, and find_closest_points_on_mesh from torch tensors to numpy arrays. This continues the broader migration of pymomentum geometry operations from PyTorch to numpy. The key technical challenge was ensuring correct memory layout for the SimdKdTree library. Eigen matrices use column-major storage by default, but SimdKdTree expects row-major data where each point's coordinates are contiguous. Added a conditional toMatrix() method to VectorArrayAccessor that uses RowMajor storage for multi-dimensional points (Dim > 1) while preserving ColMajor for column vectors (Dim == 1) as required by Eigen. Reviewed By: jeongseok-meta Differential Revision: D89891110
1 parent 6ef02d1 commit a18d9f6

File tree

8 files changed

+1087
-71
lines changed

8 files changed

+1087
-71
lines changed

pymomentum/array_utility/geometry_accessors.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,32 @@ void VectorArrayAccessor<T, Dim>::set(
586586
}
587587
}
588588

589+
template <typename T, int Dim>
590+
Eigen::Matrix<T, Eigen::Dynamic, Dim, (Dim > 1) ? Eigen::RowMajor : Eigen::ColMajor>
591+
VectorArrayAccessor<T, Dim>::toMatrix(const std::vector<py::ssize_t>& batchIndices) const {
592+
const auto offset = computeOffset(batchIndices);
593+
594+
// Create matrix with nElements rows and Dim columns
595+
// Use RowMajor storage for Dim > 1 to ensure each point's coordinates are contiguous in memory
596+
// Use ColMajor (default) for Dim == 1 (column vectors) as required by Eigen
597+
Eigen::Matrix<T, Eigen::Dynamic, Dim, (Dim > 1) ? Eigen::RowMajor : Eigen::ColMajor> result(
598+
nElements_, Dim);
599+
600+
// Copy data row by row, handling arbitrary strides
601+
for (py::ssize_t i = 0; i < nElements_; ++i) {
602+
const auto elemOffset = offset + i * rowStride_;
603+
for (int d = 0; d < Dim; ++d) {
604+
result(i, d) = data_[elemOffset + d * colStride_];
605+
}
606+
}
607+
608+
return result;
609+
}
610+
589611
// Explicit template instantiations for VectorArrayAccessor
612+
template class VectorArrayAccessor<int32_t, 1>;
613+
template class VectorArrayAccessor<float, 2>;
614+
template class VectorArrayAccessor<double, 2>;
590615
template class VectorArrayAccessor<float, 3>;
591616
template class VectorArrayAccessor<double, 3>;
592617
template class VectorArrayAccessor<int, 3>;

pymomentum/array_utility/geometry_accessors.h

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,14 @@ class VectorArrayAccessor {
364364
// Set all vectors for the given batch indices (bulk operation).
365365
void set(const std::vector<py::ssize_t>& batchIndices, const std::vector<VectorType>& values);
366366

367+
// Convert to Eigen matrix format (nElements x Dim) with appropriate storage.
368+
// This is useful for algorithms that expect Eigen::MatrixX3 or similar formats.
369+
// Creates a new matrix with copied data, handling arbitrary strides.
370+
// Uses RowMajor storage for Dim > 1 to ensure each point's coordinates are contiguous in memory.
371+
// Uses ColMajor (default) for Dim == 1 (column vectors) as required by Eigen.
372+
Eigen::Matrix<T, Eigen::Dynamic, Dim, (Dim > 1) ? Eigen::RowMajor : Eigen::ColMajor> toMatrix(
373+
const std::vector<py::ssize_t>& batchIndices) const;
374+
367375
private:
368376
T* data_;
369377
py::ssize_t nElements_{};
@@ -415,6 +423,50 @@ class IntVectorArrayAccessor {
415423
// Returns {min, max}. For empty views, returns {INT_MAX, INT_MIN}.
416424
[[nodiscard]] std::pair<int, int> minmax() const;
417425

426+
// Convert to Eigen matrix format with int values.
427+
// This performs a single switch on dtype for the entire conversion,
428+
// avoiding per-element overhead. Template parameter allows caller to
429+
// specify the desired output matrix type (e.g., Eigen::MatrixX3i for
430+
// column-major, or Eigen::Matrix<int, Dynamic, 3, RowMajor> for row-major).
431+
template <typename MatrixType = Eigen::Matrix<int, Eigen::Dynamic, Dim>>
432+
[[nodiscard]] MatrixType toMatrix() const {
433+
MatrixType result(nElements_, Dim);
434+
435+
if (nElements_ == 0) {
436+
return result;
437+
}
438+
439+
// Helper lambda to copy data for a given source type
440+
auto copyData = [&]<typename SourceT>() {
441+
const auto elemStride = rowStride_ / static_cast<py::ssize_t>(sizeof(SourceT));
442+
const auto compStride = colStride_ / static_cast<py::ssize_t>(sizeof(SourceT));
443+
const auto* ptr = static_cast<const SourceT*>(data_);
444+
445+
for (py::ssize_t i = 0; i < nElements_; ++i) {
446+
for (int d = 0; d < Dim; ++d) {
447+
result(i, d) = static_cast<int>(ptr[i * elemStride + d * compStride]);
448+
}
449+
}
450+
};
451+
452+
switch (dtype_) {
453+
case SourceDtype::Int32:
454+
copyData.template operator()<int32_t>();
455+
break;
456+
case SourceDtype::Int64:
457+
copyData.template operator()<int64_t>();
458+
break;
459+
case SourceDtype::UInt32:
460+
copyData.template operator()<uint32_t>();
461+
break;
462+
case SourceDtype::UInt64:
463+
copyData.template operator()<uint64_t>();
464+
break;
465+
}
466+
467+
return result;
468+
}
469+
418470
private:
419471
friend class IntVectorArrayAccessor;
420472

pymomentum/cmake/build_variables.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ tensor_ik_test_sources = [
119119
geometry_public_headers = [
120120
"geometry/array_blend_shape.h",
121121
"geometry/array_joint_parameters_to_positions.h",
122+
"geometry/array_kd_tree.h",
122123
"geometry/array_parameter_transform.h",
123124
"geometry/array_skeleton_state.h",
124125
"geometry/array_skinning.h",
@@ -138,6 +139,7 @@ geometry_public_headers = [
138139
geometry_sources = [
139140
"geometry/array_blend_shape.cpp",
140141
"geometry/array_joint_parameters_to_positions.cpp",
142+
"geometry/array_kd_tree.cpp",
141143
"geometry/array_parameter_transform.cpp",
142144
"geometry/array_skeleton_state.cpp",
143145
"geometry/array_skinning.cpp",

0 commit comments

Comments
 (0)