diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 8d43e10d608..2aea46eb596 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -345,11 +345,8 @@ jobs: PYTAG="-cp$(echo ${{ env.python_version }} | tr -d '.')" mkdir universal_wheels pip install delocate - delocate-fuse -v x64_wheels/open3d-*${PYTAG}*.whl arm64_wheels/open3d-*${PYTAG}*.whl - # Normalize file name as delocate-fuse doesn't update it - OLD_WHL_NAME=$(basename x64_wheels/open3d-*${PYTAG}*.whl) - NEW_WHL_NAME=${OLD_WHL_NAME/x86_64/universal2} - mv x64_wheels/${OLD_WHL_NAME} universal_wheels/${NEW_WHL_NAME} + delocate-merge -v -w universal_wheels x64_wheels/open3d-*${PYTAG}*.whl arm64_wheels/open3d-*${PYTAG}*.whl + NEW_WHL_NAME=$(basename universal_wheels/open3d-*${PYTAG}*.whl) echo "PIP_PKG_NAME=$NEW_WHL_NAME" >> $GITHUB_ENV - name: Upload merged wheels diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cb9bed658f..f0e48d95d00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ - Split pybind declarations/definitions to avoid C++ types in Python docs (PR #6869) - Fix minimal oriented bounding box of MeshBase derived classes and add new unit tests (PR #6898) - Fix projection of point cloud to Depth/RGBD image if no position attribute is provided (PR #6880) +- Support lowercase types when reading PCD files (PR #6930) - Unified cloud initializer pipeline for ICP (fixes segfault colored ICP) (PR #6942) ## 0.13 diff --git a/cpp/open3d/io/file_format/FilePCD.cpp b/cpp/open3d/io/file_format/FilePCD.cpp index ce04f2e2d5b..17aa080cd29 100644 --- a/cpp/open3d/io/file_format/FilePCD.cpp +++ b/cpp/open3d/io/file_format/FilePCD.cpp @@ -220,7 +220,8 @@ bool ReadPCDHeader(FILE *file, PCDHeader &header) { double UnpackBinaryPCDElement(const char *data_ptr, const char type, const int size) { - if (type == 'I') { + const char type_uppercase = std::toupper(type, std::locale()); + if (type_uppercase == 'I') { if (size == 1) { std::int8_t data; memcpy(&data, data_ptr, sizeof(data)); @@ -236,7 +237,7 @@ double UnpackBinaryPCDElement(const char *data_ptr, } else { return 0.0; } - } else if (type == 'U') { + } else if (type_uppercase == 'U') { if (size == 1) { std::uint8_t data; memcpy(&data, data_ptr, sizeof(data)); @@ -252,7 +253,7 @@ double UnpackBinaryPCDElement(const char *data_ptr, } else { return 0.0; } - } else if (type == 'F') { + } else if (type_uppercase == 'F') { if (size == 4) { float data; memcpy(&data, data_ptr, sizeof(data)); @@ -281,11 +282,12 @@ double UnpackASCIIPCDElement(const char *data_ptr, const char type, const int size) { char *end; - if (type == 'I') { + const char type_uppercase = std::toupper(type, std::locale()); + if (type_uppercase == 'I') { return (double)std::strtol(data_ptr, &end, 0); - } else if (type == 'U') { + } else if (type_uppercase == 'U') { return (double)std::strtoul(data_ptr, &end, 0); - } else if (type == 'F') { + } else if (type_uppercase == 'F') { return std::strtod(data_ptr, &end); } return 0.0; @@ -297,13 +299,14 @@ Eigen::Vector3d UnpackASCIIPCDColor(const char *data_ptr, if (size == 4) { std::uint8_t data[4] = {0, 0, 0, 0}; char *end; - if (type == 'I') { + const char type_uppercase = std::toupper(type, std::locale()); + if (type_uppercase == 'I') { std::int32_t value = std::strtol(data_ptr, &end, 0); memcpy(data, &value, 4); - } else if (type == 'U') { + } else if (type_uppercase == 'U') { std::uint32_t value = std::strtoul(data_ptr, &end, 0); memcpy(data, &value, 4); - } else if (type == 'F') { + } else if (type_uppercase == 'F') { float value = std::strtof(data_ptr, &end); memcpy(data, &value, 4); } diff --git a/cpp/open3d/t/io/file_format/FilePCD.cpp b/cpp/open3d/t/io/file_format/FilePCD.cpp index 4aa229c0d55..2670e133d5a 100644 --- a/cpp/open3d/t/io/file_format/FilePCD.cpp +++ b/cpp/open3d/t/io/file_format/FilePCD.cpp @@ -89,30 +89,34 @@ struct WriteAttributePtr { }; static core::Dtype GetDtypeFromPCDHeaderField(char type, int size) { - if (type == 'I') { + char type_uppercase = std::toupper(type, std::locale()); + if (type_uppercase == 'I') { if (size == 1) return core::Dtype::Int8; if (size == 2) return core::Dtype::Int16; if (size == 4) return core::Dtype::Int32; if (size == 8) return core::Dtype::Int64; else - utility::LogError("Unsupported data type."); - } else if (type == 'U') { + utility::LogError("Unsupported size {} for data type {}.", size, + type); + } else if (type_uppercase == 'U') { if (size == 1) return core::Dtype::UInt8; if (size == 2) return core::Dtype::UInt16; if (size == 4) return core::Dtype::UInt32; if (size == 8) return core::Dtype::UInt64; else - utility::LogError("Unsupported data type."); - } else if (type == 'F') { + utility::LogError("Unsupported size {} for data type {}.", size, + type); + } else if (type_uppercase == 'F') { if (size == 4) return core::Dtype::Float32; if (size == 8) return core::Dtype::Float64; else - utility::LogError("Unsupported data type."); + utility::LogError("Unsupported size {} for data type {}.", size, + type); } else { - utility::LogError("Unsupported data type."); + utility::LogError("Unsupported data type {}.", type); } } @@ -305,13 +309,14 @@ static void ReadASCIIPCDColorsFromField(ReadAttributePtr &attr, if (field.size == 4) { std::uint8_t data[4] = {0}; char *end; - if (field.type == 'I') { + char type_uppercase = std::toupper(field.type, std::locale()); + if (type_uppercase == 'I') { std::int32_t value = std::strtol(data_ptr, &end, 0); std::memcpy(data, &value, sizeof(std::int32_t)); - } else if (field.type == 'U') { + } else if (type_uppercase == 'U') { std::uint32_t value = std::strtoul(data_ptr, &end, 0); std::memcpy(data, &value, sizeof(std::uint32_t)); - } else if (field.type == 'F') { + } else if (type_uppercase == 'F') { float value = std::strtof(data_ptr, &end); std::memcpy(data, &value, sizeof(float)); } diff --git a/cpp/pybind/geometry/boundingvolume.cpp b/cpp/pybind/geometry/boundingvolume.cpp index e178adfe19b..4ffcbf8a52d 100644 --- a/cpp/pybind/geometry/boundingvolume.cpp +++ b/cpp/pybind/geometry/boundingvolume.cpp @@ -83,6 +83,27 @@ The returned bounding box is an approximation to the minimal bounding box. open3d.geometry.OrientedBoundingBox: The oriented bounding box. The bounding box is oriented such that the axes are ordered with respect to the principal components. +)doc") + .def_static("create_from_points_minimal", + &OrientedBoundingBox::CreateFromPointsMinimal, + "points"_a, "robust"_a = false, + R"doc( +Creates the oriented bounding box with the smallest volume. + +The algorithm makes use of the fact that at least one edge of +the convex hull must be collinear with an edge of the minimum +bounding box: for each triangle in the convex hull, calculate +the minimal axis aligned box in the frame of that triangle. +at the end, return the box with the smallest volume + +Args: + points (open3d.utility.Vector3dVector): Input points. + robust (bool): If set to true uses a more robust method which works in + degenerate cases but introduces noise to the points coordinates. + +Returns: + open3d.geometry.OrientedBoundingBox: The oriented bounding box. The + bounding box is oriented such that its volume is minimized. )doc") .def("volume", &OrientedBoundingBox::Volume, "Returns the volume of the bounding box.")