Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/publish_eigen_to_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:

- name: Install build packages
run: |
conda install pip "swig<4.4.0" eigen -cconda-forge
conda install pip "swig<4.4.0" "eigen<4.0.0" -c conda-forge
conda list
pip install build cibuildwheel==2.21.3

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish_matlab_eigen_binaries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ jobs:
mkdir -p $BUILD_FOLDER
cd $BUILD_FOLDER
cmake .. \
-G"Visual Studio 17 2022" \
-G"Visual Studio 18 2026" \
-Ax64 \
-DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH \
-DMATH_LIBRARY_BACKEND="Eigen3" \
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/run_casadi_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ jobs:
mkdir -p $BUILD_FOLDER
cd $BUILD_FOLDER
cmake .. \
-G"Visual Studio 17 2022" \
-G"Visual Studio 18 2026" \
-Ax64 -DMATH_LIBRARY_BACKEND="Casadi" \
-DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH \
-DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=ON \
Expand Down Expand Up @@ -131,7 +131,7 @@ jobs:
mkdir -p $BUILD_FOLDER
cd $BUILD_FOLDER
cmake .. \
-G"Visual Studio 17 2022" \
-G"Visual Studio 18 2026" \
-Ax64 \
-DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH \
-DCMAKE_BUILD_TYPE=Release
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/run_eigen_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jobs:
mkdir -p $BUILD_FOLDER
cd $BUILD_FOLDER
cmake .. \
-G"Visual Studio 17 2022" \
-G"Visual Studio 18 2026" \
-Ax64 \
-DMATH_LIBRARY_BACKEND="Eigen3" \
-DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH \
Expand Down Expand Up @@ -162,7 +162,7 @@ jobs:
mkdir -p $BUILD_FOLDER
cd $BUILD_FOLDER
cmake .. \
-G"Visual Studio 17 2022" \
-G"Visual Studio 18 2026" \
-Ax64 \
-DCMAKE_INSTALL_PREFIX=$CONDA_ENV_PATH \
-DCMAKE_BUILD_TYPE=Release
Expand Down Expand Up @@ -190,4 +190,4 @@ jobs:
- name: Run MATLAB binder tests
run: |
# We cannot run the tests as we do not have a license.
# At least we know it compiles
# At least we know it compiles
4 changes: 2 additions & 2 deletions .github/workflows/run_pip_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:

- name: Install dependencies
run: |
conda install -cconda-forge "swig<4.4.0" pip eigen
conda install -cconda-forge "swig<4.4.0" pip "eigen<4.0.0"
conda list

- name: Setup Linux dependencies
Expand Down Expand Up @@ -71,4 +71,4 @@ jobs:
# BIORBD_FOLDER=`pwd`
# cd
# python -c "import biorbd_casadi"
# cd $BIORBD_FOLDER
# cd $BIORBD_FOLDER
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.17)

project(biorbd VERSION 1.12.2)
project(biorbd VERSION 1.12.3)
set(BIORBD_ROOT_FOLDER ${PROJECT_SOURCE_DIR})
set (BIORBD_NAME_NO_SUFFIX ${PROJECT_NAME})
set (CMAKE_CXX_STANDARD 11)
Expand Down
216 changes: 160 additions & 56 deletions src/ModelReader.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#define BIORBD_API_EXPORTS
#include "ModelReader.h"

#include <fstream>
#include <limits.h>
#include <sstream>

#include "BiorbdModel.h"
#include "RigidBody/GeneralizedCoordinates.h"
Expand Down Expand Up @@ -293,20 +295,21 @@ void Reader::readModelFile(const utils::Path &path, Model *model) {
utils::String filePathInString;
file.read(filePathInString);
utils::Path filePath(meshFolderPrefix + filePathInString);
if (!filePath.extension().compare("bioMesh")) {
utils::String extension(filePath.extension().tolower());
if (!extension.compare("biomesh")) {
mesh = readMeshFileBiorbdSegments(
path.folder() + filePath.relativePath());
} else if (!filePath.extension().compare("ply")) {
} else if (!extension.compare("ply")) {
mesh = readMeshFilePly(path.folder() + filePath.relativePath());
} else if (!filePath.extension().compare("obj")) {
} else if (!extension.compare("obj")) {
mesh = readMeshFileObj(path.folder() + filePath.relativePath());
}
#ifdef MODULE_VTP_FILES_READER
else if (!filePath.extension().compare("vtp")) {
else if (!extension.compare("vtp")) {
mesh = readMeshFileVtp(path.folder() + filePath.relativePath());
}
#endif
else if (!filePath.extension().tolower().compare("stl")) {
else if (!extension.compare("stl")) {
mesh = readMeshFileStl(path.folder() + filePath.relativePath());
} else {
utils::Error::raise(
Expand Down Expand Up @@ -2183,68 +2186,169 @@ rigidbody::Mesh Reader::readMeshFileBiorbdSegments(const utils::Path &path) {
}

rigidbody::Mesh Reader::readMeshFilePly(const utils::Path &path) {
// Read a bone file

// Open file
// std::cout << "Loading marker file: " << path << std::endl;
// Read a polygon file format mesh file
#ifdef _WIN32
utils::IfStream file(
utils::Path::toWindowsFormat(path.absolutePath()).c_str(), std::ios::in);
utils::String filepath(
utils::Path::toWindowsFormat(path.absolutePath()).c_str());
#else
utils::IfStream file(path.absolutePath().c_str(), std::ios::in);
utils::String filepath(path.absolutePath().c_str());
#endif

// Read file
utils::String tp;

// Know the number of points
file.reachSpecificTag("element");
file.readSpecificTag("vertex", tp);
size_t nVertex(static_cast<size_t>(atoi(tp.c_str())));
int nVertexProperties(file.countTagsInAConsecutiveLines("property"));

// Find the number of columns for the vertex
file.reachSpecificTag("element");
file.readSpecificTag("face", tp);
size_t nFaces(static_cast<size_t>(atoi(tp.c_str())));
int nFacesProperties(file.countTagsInAConsecutiveLines("property"));
std::ifstream file(filepath.c_str(), std::ios::in);
utils::Error::check(file.is_open(), "Failed to load file " + filepath);

struct PlyProperty {
PlyProperty(const utils::String &name, bool isList)
: name(name), isList(isList) {}
utils::String name;
bool isList;
};

struct PlyElement {
PlyElement(const utils::String &name, size_t count)
: name(name), count(count) {}
utils::String name;
size_t count;
std::vector<PlyProperty> properties;
};

utils::String line;
std::getline(file, line);
std::stringstream firstLine(line);
utils::String plyTag;
firstLine >> plyTag;
utils::Error::check(
!plyTag.tolower().compare("ply"),
filepath + " is not a valid PLY file");

std::vector<PlyElement> elements;
bool isAscii(false);
int currentElement(-1);
while (std::getline(file, line)) {
std::stringstream ss(line);
utils::String tag;
ss >> tag;
tag = tag.tolower();
if (!tag.compare("comment") || tag.empty()) {
continue;
} else if (!tag.compare("format")) {
utils::String format;
ss >> format;
isAscii = !format.tolower().compare("ascii");
} else if (!tag.compare("element")) {
utils::String name;
size_t count;
ss >> name >> count;
elements.push_back(PlyElement(name.tolower(), count));
currentElement = static_cast<int>(elements.size()) - 1;
} else if (!tag.compare("property")) {
utils::Error::check(
currentElement >= 0, "PLY property found before any element");
utils::String propertyType;
ss >> propertyType;
if (!propertyType.tolower().compare("list")) {
utils::String countType, valueType, name;
ss >> countType >> valueType >> name;
elements[static_cast<size_t>(currentElement)].properties.push_back(
PlyProperty(name.tolower(), true));
} else {
utils::String name;
ss >> name;
elements[static_cast<size_t>(currentElement)].properties.push_back(
PlyProperty(name.tolower(), false));
}
} else if (!tag.compare("end_header")) {
break;
}
}

// Trouver le nombre de ??
file.reachSpecificTag("end_header");
utils::Error::check(
isAscii,
utils::String("Only ASCII PLY files are supported for meshfile: ") +
filepath);

rigidbody::Mesh mesh;
mesh.setPath(path);
std::map<utils::Equation, double> variable =
std::map<utils::Equation, double>();
// Get all the points
for (size_t iPoints = 0; iPoints < nVertex; ++iPoints) {
utils::Vector3d nodeTp(0, 0, 0);
readVector3d(file, variable, nodeTp);
mesh.addPoint(nodeTp);
// Ignore the columns post XYZ
for (int i = 0; i < nVertexProperties - 3; ++i) {
double dump;
file.read(dump);
}
}

for (size_t iPoints = 0; iPoints < nFaces; ++iPoints) {
rigidbody::MeshFace patchTp;
size_t nVertices;
file.read(nVertices);
if (nVertices != 3) {
utils::Error::raise("Patches must be 3 vertices!");
}
for (size_t i = 0; i < nVertices; ++i) {
file.read(patchTp(i));
}
int dump;
// Remove if there are too many columns
for (int i = 0; i < nFacesProperties - 1; ++i) {
file.read(dump);
for (size_t iElement = 0; iElement < elements.size(); ++iElement) {
const PlyElement &element(elements[iElement]);

for (size_t iRecord = 0; iRecord < element.count; ++iRecord) {
if (!element.name.compare("vertex")) {
utils::Vector3d vertex(0, 0, 0);
for (size_t iProperty = 0; iProperty < element.properties.size();
++iProperty) {
const PlyProperty &property(element.properties[iProperty]);
if (property.isList) {
size_t nValues;
double dump;
file >> nValues;
for (size_t i = 0; i < nValues; ++i) {
file >> dump;
}
} else {
double value;
file >> value;
if (!property.name.compare("x")) {
vertex[0] = value;
} else if (!property.name.compare("y")) {
vertex[1] = value;
} else if (!property.name.compare("z")) {
vertex[2] = value;
}
}
}
mesh.addPoint(vertex);
} else if (!element.name.compare("face")) {
std::vector<int> vertexIndices;
for (size_t iProperty = 0; iProperty < element.properties.size();
++iProperty) {
const PlyProperty &property(element.properties[iProperty]);
if (property.isList) {
size_t nValues;
file >> nValues;
for (size_t i = 0; i < nValues; ++i) {
int value;
file >> value;
if (
!property.name.compare("vertex_indices") ||
!property.name.compare("vertex_index")) {
vertexIndices.push_back(value);
}
}
} else {
double dump;
file >> dump;
}
}

utils::Error::check(
vertexIndices.size() >= 3,
"PLY faces must have at least 3 vertices");
for (size_t i = 1; i + 1 < vertexIndices.size(); ++i) {
mesh.addFace(
{vertexIndices[0], vertexIndices[i], vertexIndices[i + 1]});
}
} else {
for (size_t iProperty = 0; iProperty < element.properties.size();
++iProperty) {
const PlyProperty &property(element.properties[iProperty]);
if (property.isList) {
size_t nValues;
double dump;
file >> nValues;
for (size_t i = 0; i < nValues; ++i) {
file >> dump;
}
} else {
double dump;
file >> dump;
}
}
}
}
mesh.addFace(patchTp);
}

return mesh;
}

Expand Down
28 changes: 28 additions & 0 deletions test/models/meshFiles/cube.PLY
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
ply
format ascii 1.0
comment cube with quad faces and scalar face properties
element vertex 8
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
element face 6
property list uchar int vertex_indices
property uchar material
end_header
-1 -1 -1 255 255 255
-1 -1 1 255 255 255
-1 1 1 255 255 255
-1 1 -1 255 255 255
1 -1 -1 255 255 255
1 -1 1 255 255 255
1 1 1 255 255 255
1 1 -1 255 255 255
4 0 1 2 3 0
4 0 4 5 1 1
4 1 5 6 2 2
4 2 6 7 3 3
4 3 7 4 0 4
4 4 7 6 5 5
5 changes: 5 additions & 0 deletions test/models/simpleWithPlyMeshFile.bioMod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
version 4

segment Segment1
meshfile meshFiles/cube.PLY
endsegment
Loading
Loading