From 97efab3d952c64e68c50de887747dd27e5236024 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Fri, 31 Jul 2026 15:45:57 +0200 Subject: [PATCH 01/12] [My Componenet] Creating an export of the skeleton VTK --- CMakeLists.txt | 13 +- .../MySkeleton/SkeletonizationLoader.cpp | 19 ++ .../MySkeleton/SkeletonizationLoader.h | 170 ++++++++++++ .../MySkeleton/SkeletonizationLoader.inl | 119 ++++++++ .../VesselTree/VesselTree.h | 47 ++++ .../VesselTree/VesselTree.inl | 254 ++++++++++++++++++ src/MeshSkeletonizationPlugin/init.cpp | 2 + 7 files changed, 617 insertions(+), 7 deletions(-) create mode 100644 src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp create mode 100644 src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h create mode 100644 src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl create mode 100644 src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h create mode 100644 src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dfdd3c..3ca4b4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,11 +4,9 @@ project(MeshSkeletonizationPlugin VERSION 0.1) # Dependencies find_package(Sofa.Config REQUIRED) sofa_find_package(Sofa.Core REQUIRED) - sofa_find_package(CGAL REQUIRED) message(STATUS "CGAL VERSION = ${CGAL_VERSION}") - set(PLUGIN_SKELETONIZATION_SRC_DIR src/MeshSkeletonizationPlugin) set(HEADER_FILES @@ -16,11 +14,15 @@ set(HEADER_FILES ${PLUGIN_SKELETONIZATION_SRC_DIR}/init.h ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.h ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.inl + ${PLUGIN_SKELETONIZATION_SRC_DIR}/VesselTree/VesselTree.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/VesselTree/VesselTree.inl + ${PLUGIN_SKELETONIZATION_SRC_DIR}/MySkeleton/SkeletonizationLoader.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/MySkeleton/SkeletonizationLoader.inl ) - set(SOURCE_FILES ${PLUGIN_SKELETONIZATION_SRC_DIR}/init.cpp ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.cpp + ${PLUGIN_SKELETONIZATION_SRC_DIR}/MySkeleton/SkeletonizationLoader.cpp ) set(README_FILES README.md) @@ -36,7 +38,6 @@ endif() target_link_libraries(${PROJECT_NAME} PUBLIC Sofa.Core) target_link_libraries(${PROJECT_NAME} PUBLIC CGAL::CGAL) - # Install rules for the library and the headers; CMake package configurations files sofa_create_package_with_targets( PACKAGE_NAME ${PROJECT_NAME} @@ -45,6 +46,4 @@ sofa_create_package_with_targets( INCLUDE_SOURCE_DIR "src" INCLUDE_INSTALL_DIR "MeshSkeletonizationPlugin" RELOCATABLE "plugins" - ) - - + ) \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp new file mode 100644 index 0000000..55d8e64 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp @@ -0,0 +1,19 @@ +#define SKELETONIZATIONLOADER_CPP +#include + +#include +#include + +namespace meshskeletonizationplugin +{ +using namespace sofa::defaulttype; + +void registerSkeletonizationLoader(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData( + "Load a mesh skeleton and build a rooted father/children tree, exported as SWC") + .add< SkeletonizationLoader >()); +} + +template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonizationLoader; +} \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h new file mode 100644 index 0000000..921f559 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h @@ -0,0 +1,170 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include +#include + + +#include +#include +#include + +//// Skeletonization function +#include +#include +#include + +// My addition +#include + +//// Typedefs CGAL +typedef CGAL::Simple_cartesian Kernel; +typedef CGAL::Polyhedron_3 Polyhedron; +typedef Polyhedron::HalfedgeDS HalfedgeDS; +typedef Kernel::Point_3 Point; + +typedef CGAL::Mean_curvature_flow_skeletonization Skeletonization; +typedef Skeletonization::Skeleton Skeleton; +typedef Skeleton::vertex_descriptor Skeleton_vertex; +typedef Skeleton::edge_descriptor Skeleton_edge; + +using namespace sofa; +using namespace sofa::defaulttype; + +namespace meshskeletonizationplugin +{ + +template +class SkeletonizationLoader: public sofa::core::DataEngine +{ +public: + SOFA_CLASS(SOFA_TEMPLATE(SkeletonizationLoader,DataTypes),sofa::core::DataEngine); + + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::VecCoord VecCoord; + typedef typename Coord::value_type Real; + typedef type::Vec<3,Real> Vec3; + + // Typedefs SOFA Topology + using Triangle = sofa::core::topology::BaseMeshTopology::Triangle; + using SeqTriangles = sofa::core::topology::BaseMeshTopology::SeqTriangles; + + // Inputs + sofa::core::objectmodel::Data d_inVertices; ///< List of vertices + sofa::core::objectmodel::Data d_inTriangles; ///< List of triangles + + // Parameters + sofa::core::objectmodel::DataFileName d_inMeshFilename; + sofa::core::objectmodel::DataFileName d_outSkeletonFilename; ///< File path to export skeleton + + // My addition: entry point + rooted-tree export + sofa::core::objectmodel::Data d_inEntryPoint; ///< Approx. 3D position of the vessel entry point; closest skeleton vertex becomes the tree root + sofa::core::objectmodel::DataFileName d_outTreeFilename; ///< File path to export the rooted father/children tree (SWC format) + +private: + SkeletonizationLoader(); + virtual ~SkeletonizationLoader() = default; + + void init() override; + void doUpdate() override; + + void draw(const sofa::core::visual::VisualParams* vparams) override; + + // convert a set of vertices and tringles to polyhedron + void geometryToPolyhedron(Polyhedron &s); + + // Members + Skeleton m_skeleton; + //My addition + VesselTree m_vesselTree; + + + template + class geometryToPolyhedronOp : public CGAL::Modifier_base + { + public: + typedef typename DataTypes::Real Real; + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::VecCoord VecCoord; + + typedef HDS Halfedge_data_structure; + + private: + VecCoord m_vertices; + SeqTriangles m_triangles; + + public: + geometryToPolyhedronOp(const VecCoord &vertices, const SeqTriangles &triangles) { + m_vertices = vertices; + m_triangles = triangles; + } + + void operator()( HDS& hds) + { + unsigned int numVertices = m_vertices.size(); + unsigned int numTriangles = m_triangles.size(); + + CGAL::Polyhedron_incremental_builder_3 builder(hds, true); + builder.begin_surface(numVertices, numTriangles); + + for (unsigned int i = 0; i < numVertices; i++) + { + builder.add_vertex( Point( m_vertices[i][0], m_vertices[i][1], m_vertices[i][2] )); + } + + for (unsigned int i = 0; i < numTriangles; i++ ) + { + builder.begin_facet(); + for ( int j = 0; j < 3; j++ ) + { + builder.add_vertex_to_facet( m_triangles[i][j] ); + } + builder.end_facet(); + } + + if (builder.check_unconnected_vertices()) + { + builder.remove_unconnected_vertices(); + } + + builder.end_surface(); + } + }; + + + struct Export_polylines + { + const Skeleton& skeleton; + std::ofstream& OutputP; + + Export_polylines(const Skeleton& skeleton, std::ofstream& OutputP) + : skeleton(skeleton), OutputP(OutputP) + { } + + void start_new_polyline() { + + } + + void add_node(Skeleton_vertex v) { + OutputP << skeleton[v].point[0] << " " << skeleton[v].point[1] << " " << skeleton[v].point[2] << "\n"; + } + + void end_polyline() { + OutputP << "\n"; + } + }; + +}; + + +#if !defined(SKELETONIZATIONLOADER_CPP) +extern template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonizationLoader; +#endif + +} // namespace meshskeletonizationplugin \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl new file mode 100644 index 0000000..e570bf2 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl @@ -0,0 +1,119 @@ +#pragma once + +#include + +using namespace sofa::core::objectmodel; + +namespace meshskeletonizationplugin +{ + +template +SkeletonizationLoader::SkeletonizationLoader() + : d_inVertices(initData (&d_inVertices, "inputVertices", "List of input mesh vertices")) + , d_inTriangles(initData(&d_inTriangles, "inputTriangles", "List of input mesh triangles")) + , d_outSkeletonFilename(initData(&d_outSkeletonFilename, "outputSkeleton", "File path to output skeleton file")) + , d_inMeshFilename(initData (&d_inMeshFilename, "filename", "Input mesh in .off format")) + , d_inEntryPoint(initData(&d_inEntryPoint, Vec3(0,0,0), "entryPoint", "Approx. entry point; closest skeleton vertex becomes the tree root")) + , d_outTreeFilename(initData(&d_outTreeFilename, "outputTree", "File path to export the rooted tree (SWC)")) +{ + addInput(&d_inVertices); + addInput(&d_inTriangles); + addInput(&d_inMeshFilename); + addInput(&d_inEntryPoint); + + addOutput(&d_outSkeletonFilename); + addOutput(&d_outTreeFilename); +} + + +template +void SkeletonizationLoader::init() +{ + //Input + if(d_outSkeletonFilename.getValue().empty()) + { + msg_error() << "No input File to store the skeleton data, please set a inputFile path."; + return; + } +} + + +template +void SkeletonizationLoader::geometryToPolyhedron(Polyhedron &s) +{ + VecCoord inVertices = d_inVertices.getValue(); + SeqTriangles inTriangles = d_inTriangles.getValue(); + + geometryToPolyhedronOp gen(inVertices, inTriangles); + s.delegate(gen); +} + + +template +void SkeletonizationLoader::doUpdate() +{ + Polyhedron tmesh; + + if(d_inMeshFilename.getFullPath() != "") + { + const char* filename = d_inMeshFilename.getFullPath().c_str(); + std::ifstream input(filename); + input >> tmesh; + msg_info() << "Loading Polyhedron from file."; + } + else + { + geometryToPolyhedron(tmesh); + msg_info() << "Number of vertices of the input mesh: " << boost::num_vertices(tmesh); + } + + if (!CGAL::is_triangle_mesh(tmesh)) + { + msg_error() << "Input geometry is not triangulated."; + return; + } + + CGAL::extract_mean_curvature_flow_skeleton(tmesh, m_skeleton); + msg_info() << "Number of vertices of the output skeleton: " << boost::num_vertices(m_skeleton); + msg_info() << "Number of edges of the output skeleton: " << boost::num_edges(m_skeleton); + + if (d_outSkeletonFilename.isSet()) + { + std::ofstream OutputP(d_outSkeletonFilename.getFullPath(), std::ofstream::out | std::ofstream::trunc); + Export_polylines extractor(m_skeleton, OutputP); + CGAL::split_graph_into_polylines(m_skeleton, extractor); + OutputP.close(); + } + + auto root = m_vesselTree.findClosestVertex(m_skeleton, d_inEntryPoint.getValue()); + m_vesselTree.build(m_skeleton, root); + msg_info() << "Vessel tree built: " << m_vesselTree.parents().size() + 1 + << " node(s) reached, " << m_vesselTree.loopEdges().size() / 2 + << " loop edge(s) detected."; + + if (d_outTreeFilename.isSet()) + m_vesselTree.exportToSWC(m_skeleton, d_outTreeFilename.getFullPath()); +} + + +template +void SkeletonizationLoader::draw(const sofa::core::visual::VisualParams* vparams) +{ + using Color = sofa::type::RGBAColor; + std::vector< type::Vec3 > dvec; + + for(const Skeleton_edge& e : CGAL::make_range(edges(m_skeleton))) + { + const Point& s = m_skeleton[source(e, m_skeleton)].point; + const Point& t = m_skeleton[target(e, m_skeleton)].point; + + + dvec.emplace_back(Coord(s[0], s[1], s[2])); + dvec.emplace_back(Coord(t[0], t[1], t[2])); + + vparams->drawTool()->drawLines( dvec, 40, Color::red()); + dvec.clear(); + } +} + +} // namespace meshskeletonizationplugin \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h b/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h new file mode 100644 index 0000000..79101c5 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h @@ -0,0 +1,47 @@ +#pragma once + +#include + +#include +#include +#include +#include + +namespace meshskeletonizationplugin +{ +template +class VesselTree +{ +public: + using Vertex = typename boost::graph_traits::vertex_descriptor; + using Edge = typename boost::graph_traits::edge_descriptor; + + template + Vertex findClosestVertex(const Graph& g, const Point3& p) const; + void build(const Graph& g, Vertex root); + + + void exportToSWC(const Graph& g, const std::string& filename) const; + void exportToVTK(const Graph& g, const std::string& filename) const; + + const std::map& parents() const { return m_parent; } + const std::map>& children() const { return m_children; } + const std::vector>& loopEdges() const { return m_loopEdges; } + Vertex root() const { return m_root; } + bool hasRoot() const { return m_hasRoot; } + std::vector subtree(Vertex node) const; + +private: + /// Stable sequential id per reached vertex, root always id 0. + std::map assignVertexIds() const; + + std::map m_parent; + std::map> m_children; + std::vector> m_loopEdges; + Vertex m_root{}; + bool m_hasRoot = false; +}; + +} // namespace meshskeletonizationplugin + +#include \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl b/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl new file mode 100644 index 0000000..316bcbe --- /dev/null +++ b/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl @@ -0,0 +1,254 @@ + +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace meshskeletonizationplugin +{ + +template +template +typename VesselTree::Vertex +VesselTree::findClosestVertex(const Graph& g, const Point3& p) const +{ + Vertex best{}; + double bestDist = std::numeric_limits::max(); + + for (const Vertex& v : boost::make_iterator_range(boost::vertices(g))) + { + const auto& s = g[v].point; + double dx = s[0] - p[0]; + double dy = s[1] - p[1]; + double dz = s[2] - p[2]; + double d2 = dx*dx + dy*dy + dz*dz; + if (d2 < bestDist) + { + bestDist = d2; + best = v; + } + } + return best; +} + + +template +void VesselTree::build(const Graph& g, Vertex root) +{ + m_parent.clear(); + m_children.clear(); + m_loopEdges.clear(); + + std::map visited; + std::queue q; + + m_root = root; + m_hasRoot = true; + visited[root] = true; + q.push(root); + + while (!q.empty()) + { + Vertex u = q.front(); + q.pop(); + + for (const Edge& e : boost::make_iterator_range(boost::out_edges(u, g))) + { + Vertex v = boost::target(e, g); + + if (!visited[v]) + { + visited[v] = true; + m_parent[v] = u; + m_children[u].push_back(v); + q.push(v); + } + else + { + // v already reached. Skip the edge we just arrived from; + // anything else is a real loop / anastomosis, not a tree edge. + auto itParentU = m_parent.find(u); + bool cameFromV = (itParentU != m_parent.end() && itParentU->second == v); + if (!cameFromV) + m_loopEdges.emplace_back(u, v); + } + } + } +} + + +template +std::map::Vertex, int> +VesselTree::assignVertexIds() const +{ + std::map vertexId; + if (!m_hasRoot) + return vertexId; + vertexId[m_root] = 0; + int nextId = 1; + for (const auto& kv : m_parent) + if (!vertexId.count(kv.first)) vertexId[kv.first] = nextId++; + return vertexId; +} + + +template +std::vector::Vertex> +VesselTree::subtree(Vertex node) const +{ + std::vector out{node}; + std::vector stack{node}; + while (!stack.empty()) + { + Vertex n = stack.back(); + stack.pop_back(); + auto it = m_children.find(n); + if (it != m_children.end()) + { + for (Vertex c : it->second) + { + out.push_back(c); + stack.push_back(c); + } + } + } + return out; +} + + +template +void VesselTree::exportToSWC(const Graph& g, const std::string& filename) const +{ + if (!m_hasRoot) + return; + + std::map vertexId = assignVertexIds(); + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "# id type x y z radius parent\n"; + for (const auto& loop : m_loopEdges) + { + int a = vertexId.at(loop.first); + int b = vertexId.at(loop.second); + if (a < b) // each undirected loop is recorded from both ends; write once + out << "# loop " << a << " " << b << "\n"; + } + + out << std::fixed << std::setprecision(6); + for (const auto& kv : vertexId) + { + Vertex v = kv.first; + int id = kv.second; + const auto& p = g[v].point; + + int deg = static_cast(boost::degree(v, g)); + int type = (v == m_root) ? 1 : (deg == 1 ? 6 : 5); // 1=root, 6=terminal, 5=branch/regular + + int parentId = -1; + auto itParent = m_parent.find(v); + if (itParent != m_parent.end()) + parentId = vertexId.at(itParent->second); + + out << id << " " << type << " " + << p[0] << " " << p[1] << " " << p[2] << " " + << 0.0 << " " << parentId << "\n"; + } +} + +template +void VesselTree::exportToVTK(const Graph& g, const std::string& filename) const +{ + if (!m_hasRoot) + return; + + std::map vertexId = assignVertexIds(); + + // depth(v) = number of edges from root, computed by walking each vertex's + // parent chain up to a vertex whose depth is already known (memoized). + std::map depth; + depth[m_root] = 0; + for (const auto& kv : vertexId) + { + Vertex v = kv.first; + if (depth.count(v)) continue; + std::vector path; + Vertex cur = v; + while (!depth.count(cur)) + { + path.push_back(cur); + auto it = m_parent.find(cur); + if (it == m_parent.end()) break; // only the root has no parent + cur = it->second; + } + int d = depth.count(cur) ? depth[cur] : 0; + for (auto it = path.rbegin(); it != path.rend(); ++it) + depth[*it] = ++d; + } + + // POINTS, in id order + std::vector orderedVerts(vertexId.size()); + for (const auto& kv : vertexId) + orderedVerts[kv.second] = kv.first; + + // LINES: tree edges (child -> parent) + deduplicated loop edges + std::vector> lines; + for (const auto& kv : m_parent) + lines.emplace_back(vertexId.at(kv.second), vertexId.at(kv.first)); + + std::vector isLoop(lines.size(), 0); + for (const auto& loop : m_loopEdges) + { + int a = vertexId.at(loop.first); + int b = vertexId.at(loop.second); + if (a < b) + { + lines.emplace_back(a, b); + isLoop.push_back(1); + } + } + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "# vtk DataFile Version 3.0\n"; + out << "Vessel tree (VesselTree module)\n"; + out << "ASCII\n"; + out << "DATASET POLYDATA\n"; + + out << "POINTS " << orderedVerts.size() << " float\n"; + out << std::fixed << std::setprecision(6); + for (Vertex v : orderedVerts) + { + const auto& p = g[v].point; + out << p[0] << " " << p[1] << " " << p[2] << "\n"; + } + + out << "LINES " << lines.size() << " " << (lines.size() * 3) << "\n"; + for (const auto& l : lines) + out << "2 " << l.first << " " << l.second << "\n"; + + out << "POINT_DATA " << orderedVerts.size() << "\n"; + out << "SCALARS type int 1\n"; + out << "LOOKUP_TABLE default\n"; + for (Vertex v : orderedVerts) + { + int deg = static_cast(boost::degree(v, g)); + int type = (v == m_root) ? 1 : (deg == 1 ? 6 : 5); // 1=root, 5=branch, 6=terminal + out << type << "\n"; + } + out << "SCALARS depth int 1\n"; + out << "LOOKUP_TABLE default\n"; + for (Vertex v : orderedVerts) + out << depth[v] << "\n"; + + out << "CELL_DATA " << lines.size() << "\n"; + out << "SCALARS is_loop int 1\n"; + out << "LOOKUP_TABLE default\n"; + for (int flag : isLoop) + out << flag << "\n"; +} + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/init.cpp b/src/MeshSkeletonizationPlugin/init.cpp index 087590d..aeec420 100644 --- a/src/MeshSkeletonizationPlugin/init.cpp +++ b/src/MeshSkeletonizationPlugin/init.cpp @@ -28,6 +28,7 @@ namespace meshskeletonizationplugin { extern void registerMeshSkeletonization(sofa::core::ObjectFactory* factory); +extern void registerSkeletonizationLoader(sofa::core::ObjectFactory* factory); //Here are just several convenient functions to help users know what the plugin contains extern "C" { @@ -79,6 +80,7 @@ void init() void registerObjects(sofa::core::ObjectFactory* factory) { registerMeshSkeletonization(factory); + registerSkeletonizationLoader(factory); } } From 89c204345118c1612b91fb0fd2a3ac4195cc8d68 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Thu, 6 Aug 2026 14:24:17 +0200 Subject: [PATCH 02/12] (New Component) Translation of the txt file to vtk and export feature --- .gitignore | 6 + CMakeLists.txt | 13 +- data/skeletons/output_elephant_skeleton.txt | 343 ------------ data/skeletons/output_raptor_skeleton.txt | 488 ------------------ data/skeletons/output_vessels_skeleton.txt | 235 --------- .../MySkeleton/SkeletonizationLoader.cpp | 19 - .../MySkeleton/SkeletonizationLoader.h | 170 ------ .../MySkeleton/SkeletonizationLoader.inl | 119 ----- .../SkeletonGraph/SkeletonGraph.cpp | 298 +++++++++++ .../SkeletonGraph/SkeletonGraph.h | 60 +++ .../SkeletonGraph/SkeletonNode.h | 67 +++ .../SkeletonGraph/SkeletonReader.cpp | 21 + .../SkeletonGraph/SkeletonReader.h | 68 +++ .../SkeletonGraph/SkeletonReader.inl | 100 ++++ .../VesselTree/VesselTree.h | 47 -- .../VesselTree/VesselTree.inl | 254 --------- src/MeshSkeletonizationPlugin/init.cpp | 6 +- 17 files changed, 632 insertions(+), 1682 deletions(-) create mode 100644 .gitignore delete mode 100644 data/skeletons/output_elephant_skeleton.txt delete mode 100644 data/skeletons/output_raptor_skeleton.txt delete mode 100644 data/skeletons/output_vessels_skeleton.txt delete mode 100644 src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp delete mode 100644 src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h delete mode 100644 src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl create mode 100644 src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp create mode 100644 src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h create mode 100644 src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h create mode 100644 src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.cpp create mode 100644 src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h create mode 100644 src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl delete mode 100644 src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h delete mode 100644 src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..05b678c --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +/data/ +/scenes/ +.gitignore +*.vtk +*.obj +*.sxn \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ca4b4e..3b0951f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,15 +14,18 @@ set(HEADER_FILES ${PLUGIN_SKELETONIZATION_SRC_DIR}/init.h ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.h ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.inl - ${PLUGIN_SKELETONIZATION_SRC_DIR}/VesselTree/VesselTree.h - ${PLUGIN_SKELETONIZATION_SRC_DIR}/VesselTree/VesselTree.inl - ${PLUGIN_SKELETONIZATION_SRC_DIR}/MySkeleton/SkeletonizationLoader.h - ${PLUGIN_SKELETONIZATION_SRC_DIR}/MySkeleton/SkeletonizationLoader.inl + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonNode.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonGraph.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonReader.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonReader.inl ) set(SOURCE_FILES ${PLUGIN_SKELETONIZATION_SRC_DIR}/init.cpp ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.cpp - ${PLUGIN_SKELETONIZATION_SRC_DIR}/MySkeleton/SkeletonizationLoader.cpp + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonGraph.cpp + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonReader.cpp + + ) set(README_FILES README.md) diff --git a/data/skeletons/output_elephant_skeleton.txt b/data/skeletons/output_elephant_skeleton.txt deleted file mode 100644 index 6d4fbf2..0000000 --- a/data/skeletons/output_elephant_skeleton.txt +++ /dev/null @@ -1,343 +0,0 @@ -0.304274 -0.291248 -0.250424 -0.302647 -0.289881 -0.248977 -0.297276 -0.285308 -0.244199 -0.292146 -0.280944 -0.239594 -0.289038 -0.278274 -0.236786 -0.285683 -0.275382 -0.233752 -0.280481 -0.271073 -0.229049 -0.271949 -0.264133 -0.221328 -0.265036 -0.258818 -0.215034 -0.259161 -0.254284 -0.20969 -0.251482 -0.250092 -0.201727 -0.243137 -0.245727 -0.192981 -0.235305 -0.241678 -0.184764 -0.227833 -0.237815 -0.176925 -0.218513 -0.232993 -0.167147 -0.215076 -0.231247 -0.163537 -0.209485 -0.228445 -0.157663 -0.200105 -0.223886 -0.147793 -0.18795 -0.218424 -0.134971 -0.181561 -0.215587 -0.128228 -0.176092 -0.213158 -0.122457 -0.169519 -0.210248 -0.115534 -0.159239 -0.207395 -0.105205 -0.149172 -0.204691 -0.095105 -0.137947 -0.201638 -0.083807 -0.133318 -0.200401 -0.0793757 -0.128658 -0.199008 -0.0749297 -0.122033 -0.196586 -0.0685831 -0.117464 -0.194879 -0.0642338 -0.107746 -0.191164 -0.0550172 -0.102221 -0.188476 -0.0496764 -0.0942284 -0.186856 -0.04298 -0.091142 -0.186444 -0.0404987 -0.0815543 -0.186474 -0.0341091 -0.0649747 -0.182916 -0.0225711 - --0.284054 -0.285435 -0.108735 --0.281476 -0.277091 -0.095993 - --0.115199 -0.442307 -0.0357321 --0.114791 -0.436449 -0.0342161 --0.114423 -0.430905 -0.0328438 --0.113915 -0.423333 -0.0310235 --0.113528 -0.415917 -0.0293852 --0.11289 -0.402413 -0.027104 --0.112333 -0.389729 -0.0249702 --0.111962 -0.381237 -0.0235545 --0.111743 -0.376263 -0.0227249 --0.111171 -0.362224 -0.0204328 --0.110355 -0.347708 -0.0187175 --0.109494 -0.333289 -0.0173042 --0.108793 -0.32167 -0.0162264 --0.107909 -0.307919 -0.0151566 --0.107401 -0.300161 -0.0145633 --0.106697 -0.289765 -0.0137818 --0.106227 -0.275945 -0.0130616 --0.106965 -0.264422 -0.0138855 --0.113892 -0.246007 -0.0161702 - -0.189818 0.462774 0.104523 -0.187338 0.459598 0.110298 -0.185763 0.457199 0.114082 -0.183784 0.454051 0.118868 -0.181637 0.450624 0.124052 -0.179026 0.445831 0.130438 -0.175324 0.438192 0.139638 -0.172154 0.429906 0.147814 -0.171106 0.426589 0.150649 -0.171546 0.411705 0.153946 -0.17207 0.396065 0.157321 -0.172454 0.388647 0.158639 -0.172817 0.383912 0.159234 -0.173071 0.380255 0.159752 -0.17411 0.371378 0.160117 -0.175238 0.362374 0.160337 -0.177473 0.349151 0.159352 -0.179615 0.338348 0.157907 -0.181311 0.330518 0.156218 -0.183558 0.32084 0.153404 -0.185643 0.312285 0.15011 -0.187001 0.306874 0.147965 -0.188495 0.301558 0.146672 -0.189642 0.290314 0.137897 - -0.189642 0.290314 0.137897 -0.186593 0.29258 0.126974 -0.18463 0.294052 0.119816 -0.183383 0.293614 0.110937 -0.184658 0.289383 0.10346 -0.186221 0.284495 0.0957773 -0.188532 0.277531 0.0869771 -0.190133 0.27267 0.0829182 -0.193153 0.263486 0.0754929 -0.196653 0.252591 0.0682734 -0.198372 0.243271 0.0686715 -0.199083 0.239432 0.0688007 -0.199973 0.234519 0.0690452 -0.202457 0.220696 0.0698033 -0.203662 0.213583 0.070449 -0.205036 0.204719 0.0717006 -0.206578 0.193236 0.0738441 -0.207364 0.184075 0.0786544 -0.207658 0.176482 0.0837088 -0.208203 0.173454 0.0925648 - -0.189642 0.290314 0.137897 -0.192508 0.281122 0.139373 -0.193237 0.279028 0.14004 -0.193651 0.277709 0.140253 -0.197763 0.26265 0.139702 - -0.208203 0.173454 0.0925648 -0.2062 0.15505 0.0892159 -0.203246 0.141251 0.0870482 -0.201826 0.135234 0.0853339 -0.199995 0.128554 0.0837052 -0.198312 0.122646 0.0821924 -0.19643 0.116389 0.0805636 -0.194901 0.11217 0.0796708 -0.191994 0.103518 0.0775343 -0.187981 0.0928067 0.0750022 -0.181591 0.0804684 0.0723386 -0.174602 0.0687515 0.0688773 -0.162871 0.0495551 0.0626244 -0.144622 0.0174678 0.0534465 - -0.208203 0.173454 0.0925648 -0.209191 0.177211 0.0985635 -0.211253 0.182546 0.10795 - -0.211253 0.182546 0.10795 -0.208897 0.189732 0.111516 -0.208193 0.194213 0.113584 -0.20772 0.19761 0.115139 -0.206801 0.204195 0.118202 -0.204927 0.215401 0.123471 -0.203727 0.224035 0.127462 -0.202429 0.235278 0.132896 -0.201062 0.242067 0.134738 -0.200512 0.246961 0.136396 -0.199636 0.252468 0.137727 -0.197763 0.26265 0.139702 - -0.211253 0.182546 0.10795 -0.220839 0.171023 0.113297 -0.22612 0.169842 0.118266 -0.234097 0.171724 0.127764 -0.240874 0.173517 0.136012 -0.248823 0.179511 0.147931 -0.256144 0.185382 0.159181 -0.257236 0.192826 0.166081 -0.257077 0.19896 0.170855 -0.256702 0.202209 0.173118 -0.253842 0.212199 0.178484 -0.252163 0.218393 0.181896 -0.249172 0.225069 0.184376 -0.2455 0.23116 0.185565 -0.240919 0.237282 0.185685 -0.235621 0.241758 0.181658 -0.230661 0.245943 0.177868 -0.227254 0.24877 0.175195 -0.220279 0.254464 0.169614 -0.213848 0.259367 0.163787 -0.208629 0.264027 0.158413 -0.203251 0.268621 0.152097 -0.197763 0.26265 0.139702 - -0.0312592 0.0670683 -0.0667248 -0.0599315 0.0644702 -0.0583819 -0.0767565 0.0628558 -0.0526307 -0.094512 0.060636 -0.0395838 -0.101594 0.059674 -0.0340962 -0.115684 0.0576223 -0.0228566 -0.120129 0.0566495 -0.018746 -0.124017 0.0548582 -0.013903 -0.126879 0.0510702 -0.00718614 -0.128626 0.0486502 -0.00289694 -0.130794 0.0456114 0.00243446 -0.135053 0.0390826 0.0134841 -0.136091 0.0346357 0.0200582 -0.136111 0.0197165 0.03358 -0.137016 0.0152211 0.0395288 -0.144622 0.0174678 0.0534465 - --0.302048 -0.391632 -0.208798 --0.298106 -0.383453 -0.202898 --0.294633 -0.375787 -0.196851 --0.292141 -0.37073 -0.192817 --0.2887 -0.363805 -0.187321 --0.284203 -0.354741 -0.180133 --0.279856 -0.345941 -0.173173 --0.272361 -0.332393 -0.1606 --0.265696 -0.321131 -0.149258 --0.259286 -0.309931 -0.13794 --0.250073 -0.290803 -0.116339 --0.242137 -0.278431 -0.102246 - -0.127204 -0.425147 -0.0574258 -0.126583 -0.421892 -0.0566651 -0.125878 -0.418709 -0.0558792 -0.12384 -0.408693 -0.0537444 -0.122911 -0.404134 -0.0527634 -0.121436 -0.397035 -0.0512301 -0.117292 -0.382893 -0.0487983 -0.113957 -0.371877 -0.0470041 -0.112119 -0.365817 -0.0460208 -0.110834 -0.361593 -0.0453406 -0.10986 -0.358391 -0.044825 -0.109118 -0.355958 -0.044436 -0.10658 -0.347696 -0.0431359 -0.103896 -0.339469 -0.0419843 -0.100673 -0.32973 -0.0406093 -0.0985403 -0.323312 -0.0397009 -0.0969321 -0.318473 -0.0390159 -0.0952837 -0.313513 -0.0383138 -0.0923349 -0.30464 -0.0370578 -0.0897077 -0.296722 -0.0359384 -0.0839879 -0.279772 -0.0335958 -0.0740431 -0.256194 -0.0300035 -0.0704178 -0.247997 -0.0285047 -0.0680589 -0.242479 -0.0275265 -0.0565563 -0.218174 -0.0225435 - -0.14466 -0.0722011 0.21965 -0.146898 -0.0700648 0.214693 -0.158245 -0.0529903 0.18072 -0.162953 -0.0458087 0.166493 -0.165656 -0.0411544 0.1571 -0.166954 -0.0365764 0.147221 -0.162764 -0.0324547 0.133813 -0.158633 -0.029193 0.122858 -0.155613 -0.0246965 0.113317 -0.153739 -0.0218487 0.107345 -0.152173 -0.0206481 0.103215 -0.150459 -0.0196591 0.0987635 -0.143452 -0.0150868 0.080126 -0.14106 -0.0131892 0.0734365 -0.13915 -0.0111102 0.0675884 -0.135056 -0.0104941 0.0584959 - --0.281476 -0.277091 -0.095993 --0.288815 -0.274662 -0.0912037 --0.289421 -0.272079 -0.0870304 --0.287181 -0.26529 -0.0770248 --0.285581 -0.261127 -0.0709549 --0.283454 -0.255302 -0.0624267 --0.279494 -0.25109 -0.0569956 --0.276833 -0.248179 -0.0532184 --0.273477 -0.244643 -0.0486664 --0.267589 -0.240061 -0.0432158 --0.26187 -0.23669 -0.0395614 --0.253208 -0.232303 -0.0350579 --0.245789 -0.229232 -0.0323237 --0.23441 -0.227035 -0.0307117 --0.221078 -0.22701 -0.0298457 --0.20866 -0.228311 -0.0295397 --0.202411 -0.229404 -0.02953 --0.197181 -0.230531 -0.029858 --0.181657 -0.236222 -0.0345668 - --0.281476 -0.277091 -0.095993 --0.269182 -0.277241 -0.0979102 --0.265625 -0.277063 -0.0981271 --0.260115 -0.276907 -0.0986034 --0.252659 -0.277541 -0.100125 --0.251168 -0.277555 -0.100292 --0.242137 -0.278431 -0.102246 - --0.242137 -0.278431 -0.102246 --0.23035 -0.270563 -0.0939387 --0.225531 -0.267442 -0.0906574 --0.220725 -0.264524 -0.0876145 --0.211922 -0.260063 -0.0829855 --0.207367 -0.256369 -0.0759794 --0.201498 -0.252203 -0.0679393 --0.195537 -0.247527 -0.0588779 --0.190467 -0.244605 -0.0522582 --0.181657 -0.236222 -0.0345668 - -0.0630898 -0.22993 -0.0253825 -0.0565563 -0.218174 -0.0225435 - -0.144622 0.0174678 0.0534465 -0.138153 0.00188671 0.0538794 -0.136848 -0.00377154 0.0562223 -0.135056 -0.0104941 0.0584959 - -0.0565563 -0.218174 -0.0225435 -0.0607462 -0.205732 -0.0235656 -0.0643782 -0.199627 -0.0248542 -0.0649747 -0.182916 -0.0225711 - --0.113892 -0.246007 -0.0161702 --0.0841498 -0.233673 -0.0121917 --0.0629379 -0.223193 -0.0106843 --0.057161 -0.220163 -0.0102779 --0.0505946 -0.216749 -0.00982099 --0.0434099 -0.213028 -0.0093229 --0.039137 -0.210816 -0.0090266 --0.0253904 -0.204075 -0.00826876 --0.00717342 -0.196874 -0.00821703 -0.00417233 -0.193323 -0.00881139 -0.0174199 -0.189614 -0.0100062 -0.0295343 -0.186516 -0.0116949 -0.033754 -0.186149 -0.0127879 -0.0429554 -0.184416 -0.0149113 -0.0482991 -0.184203 -0.0167819 -0.0649747 -0.182916 -0.0225711 - --0.113892 -0.246007 -0.0161702 --0.13852 -0.240185 -0.0208952 --0.143669 -0.238493 -0.0219281 --0.144427 -0.238233 -0.0220802 --0.149802 -0.23646 -0.0231638 --0.156137 -0.234791 -0.0245356 --0.1614 -0.235246 -0.0269026 --0.164702 -0.235618 -0.0284928 --0.181657 -0.236222 -0.0345668 - -0.0649747 -0.182916 -0.0225711 -0.0681923 -0.166147 -0.0146381 -0.0693256 -0.156639 -0.00957911 -0.0705145 -0.149369 -0.00584912 -0.0713418 -0.141679 -0.00164125 -0.0723211 -0.131416 0.00405148 -0.0727596 -0.124475 0.00806783 -0.0735502 -0.118469 0.0113743 -0.0754863 -0.111152 0.0150937 -0.0782395 -0.104829 0.0177439 -0.0795523 -0.102023 0.0188735 -0.0822176 -0.0965385 0.0210292 -0.0860589 -0.0887214 0.0240766 -0.0885691 -0.0840944 0.0257345 -0.0923387 -0.0772477 0.0281619 -0.0991968 -0.0651448 0.0324166 -0.107639 -0.0515339 0.0379364 -0.111387 -0.0455082 0.0403816 -0.114694 -0.0402136 0.0425654 -0.120319 -0.0312058 0.0462764 -0.125489 -0.0238545 0.0504821 -0.130188 -0.0178832 0.0549454 -0.135056 -0.0104941 0.0584959 - diff --git a/data/skeletons/output_raptor_skeleton.txt b/data/skeletons/output_raptor_skeleton.txt deleted file mode 100644 index 2a440c5..0000000 --- a/data/skeletons/output_raptor_skeleton.txt +++ /dev/null @@ -1,488 +0,0 @@ -0.00261497 6.40846 6.39716 --0.00337782 6.41709 6.36901 --0.00174051 6.43132 6.32109 --0.00349442 6.44424 6.27716 --0.00503459 6.47727 6.14345 --0.0104874 6.49772 6.03833 --0.0145518 6.51146 5.9596 --0.0205835 6.52282 5.8861 --0.025315 6.54452 5.74731 --0.0265846 6.55027 5.65689 --0.0165136 6.5429 5.59899 --0.0119765 6.53285 5.54148 -0.00637587 6.50782 5.43913 -0.0238277 6.48386 5.3297 -0.0815777 6.42106 5.19377 -0.145395 6.38313 5.11974 - -1.01897 0.421997 0.0628335 -1.05207 0.483915 0.0207638 -1.04385 0.60381 -0.0266483 -1.04769 0.719494 -0.0447149 -1.04873 0.803692 -0.037129 -1.05688 0.948858 -0.0163011 -1.06908 1.11593 0.019074 -1.07806 1.22108 0.0469235 -1.08542 1.29973 0.0705155 -1.0943 1.38308 0.101553 -1.10325 1.46892 0.136485 -1.11265 1.56102 0.17715 -1.12134 1.65581 0.222554 -1.13074 1.76412 0.274958 -1.13349 1.91375 0.342186 -1.13688 2.07677 0.416111 -1.11001 2.16321 0.428953 -1.06589 2.27545 0.438655 -1.01605 2.39728 0.448417 -0.992935 2.45145 0.45238 -0.918632 2.6 0.459281 -0.890686 2.65577 0.461853 -0.853058 2.73086 0.465321 -0.822917 2.79103 0.468118 -0.740348 2.95714 0.476183 -0.673261 3.08145 0.481454 -0.595705 3.18157 0.485043 -0.465135 3.34433 0.506643 -0.420818 3.39915 0.515157 -0.373173 3.44317 0.519894 -0.337764 3.47263 0.523159 -0.286422 3.51514 0.527312 -0.201488 3.5808 0.536393 -0.112947 3.64388 0.544562 -0.00924497 3.71398 0.543265 - -1.01897 0.421997 0.0628335 -1.09058 0.370907 0.062301 -1.15937 0.255373 0.0967063 - -1.01897 0.421997 0.0628335 -0.955617 0.412398 0.102279 -0.918204 0.413237 0.142845 -0.893276 0.427925 0.186054 -0.861245 0.452373 0.261602 -0.82301 0.490443 0.361717 -0.812456 0.512409 0.40499 -0.818128 0.555863 0.457885 -0.820141 0.597832 0.517461 -0.82197 0.645579 0.586272 -0.821339 0.670468 0.631549 -0.821271 0.686509 0.684377 -0.821774 0.682353 0.744834 -0.821297 0.665787 0.804401 -0.821022 0.634865 0.862457 -0.820731 0.594921 0.913952 -0.820639 0.55976 0.947377 -0.820505 0.546759 0.956853 - -1.17023 2.82019 3.74835 -0.994379 2.73209 3.87521 -0.959659 2.62263 3.91314 -0.939374 2.52603 3.93137 -0.937979 2.51511 3.93289 -0.923 2.41308 3.93698 -0.912819 2.32148 3.93005 -0.905346 2.24363 3.91626 -0.90095 2.17632 3.89867 -0.890714 2.11473 3.8722 -0.890764 2.03546 3.82541 -0.871828 1.93974 3.71587 -0.86715 1.92094 3.6985 - -1.17023 2.82019 3.74835 -1.17509 2.93362 3.63576 -1.16331 2.9593 3.57418 -1.15197 2.977 3.53013 -1.14474 2.9895 3.49876 -1.13102 3.00907 3.44356 -1.11493 3.01434 3.38832 -1.09936 3.01604 3.33806 -1.05868 3.02036 3.17788 -1.02607 2.97854 3.04569 -0.98641 2.93453 2.8808 -0.970052 2.91572 2.81376 -0.957112 2.91331 2.76943 -0.931795 2.92371 2.69101 -0.90687 2.94497 2.63099 -0.861926 3.01242 2.57112 -0.808956 3.1126 2.53999 -0.760207 3.21046 2.52942 -0.739761 3.24954 2.52577 -0.654307 3.40896 2.51978 -0.563098 3.52488 2.51022 -0.419116 3.69709 2.48888 -0.398789 3.71773 2.47702 -0.287642 3.82297 2.39631 -0.23969 3.86245 2.36216 -0.225347 3.87368 2.35202 -0.138296 3.93495 2.29311 -0.043464 4.00201 2.25083 - -1.17023 2.82019 3.74835 -1.24253 2.75547 3.77854 - --0.0139116 6.07581 4.65773 --0.0130908 6.08357 4.79765 - --0.000111646 4.65926 -8.8909 --0.000167946 4.66852 -8.87191 --0.000285245 4.69151 -8.82333 --0.000372848 4.76282 -8.66742 --0.000463195 4.768 -8.65552 --0.000505209 4.91971 -8.30526 --0.00018484 5.0715 -7.91335 --0.000511521 5.17147 -7.57533 --0.000653166 5.17874 -7.55178 --0.000780947 5.2526 -7.21606 --0.000805166 5.31227 -6.82881 --0.00111204 5.33771 -6.49666 --0.0013606 5.33433 -6.10835 --0.00170417 5.30302 -5.74576 --0.002075 5.24318 -5.39706 --0.00259847 5.16285 -5.1098 --0.00334962 5.15331 -5.08037 --0.00319213 5.01459 -4.71194 --0.00285812 4.92224 -4.46713 --0.00263337 4.86815 -4.32203 --0.00183681 4.67531 -3.80244 --0.00162243 4.61988 -3.64812 --0.00140132 4.56219 -3.48685 --0.00127759 4.52627 -3.38076 --0.00118539 4.49924 -3.30059 --0.00103946 4.45631 -3.17364 --0.000952147 4.43223 -3.09014 --0.000849744 4.40381 -2.99011 --0.000749234 4.3759 -2.89178 --0.000676364 4.35569 -2.82055 --0.000603712 4.33564 -2.74987 --0.000333506 4.29926 -2.62131 --0.000560631 4.27333 -2.53078 --0.000762559 4.23751 -2.32785 --0.000764475 4.21507 -2.19787 --0.000776197 4.20526 -2.14049 --0.000769875 4.19382 -2.07098 -0.000436307 4.14688 -1.73285 -0.000921567 4.1283 -1.59837 -0.00126981 4.11505 -1.50244 -0.0015887 4.10308 -1.41585 -0.00187521 4.09233 -1.33802 -0.00210202 4.08417 -1.27908 -0.002386 4.07321 -1.19971 -0.00277998 4.05844 -1.0923 -0.00291705 4.0483 -1.01495 -0.00282244 4.03826 -0.937637 -0.00134058 4.02428 -0.816976 --0.00250201 4.0017 -0.612006 --0.00283235 3.99807 -0.580665 --0.00409215 3.98547 -0.501697 --0.00505377 3.97722 -0.451004 --0.00629344 3.96634 -0.385796 --0.00741305 3.9564 -0.327044 --0.00886432 3.93922 -0.227114 --0.0108551 3.92652 -0.155893 --0.0152359 3.90714 -0.0559182 --0.0169851 3.88096 0.0177719 --0.0177597 3.87127 0.0436049 --0.02093 3.82804 0.155477 --0.0169732 3.79467 0.238498 --0.0157682 3.76754 0.303001 --0.0149742 3.74263 0.362586 -0.00924497 3.71398 0.543265 - -0.043464 4.00201 2.25083 --0.0663285 3.98551 2.20978 - -0.043464 4.00201 2.25083 --0.00372098 4.10574 2.29997 --0.00377526 4.16519 2.37467 --0.00331632 4.23998 2.46185 -0.000324227 4.32196 2.55514 -0.00363728 4.37874 2.62279 -0.00476475 4.50916 2.76611 -0.00212634 4.61274 2.88122 -0.00127789 4.66954 2.93904 -0.000754877 4.7756 3.07298 --0.000244322 4.84597 3.16198 --0.000900852 4.89369 3.22253 --0.00159029 4.94037 3.28181 --0.00169167 5.01404 3.37698 --0.00183697 5.09564 3.48299 --0.00192279 5.15066 3.55451 --0.00205053 5.20628 3.62708 --0.00207498 5.27969 3.72289 --0.00286731 5.36623 3.83691 --0.000881729 5.45539 3.9547 --0.00592108 5.61662 4.17084 --0.0134564 5.68559 4.27069 --0.0139261 5.72882 4.32264 --0.0154722 5.78927 4.39772 --0.0160784 5.84443 4.45519 --0.0162719 5.86602 4.49471 --0.0169453 5.96829 4.62678 --0.0165677 6.01899 4.69984 --0.0130908 6.08357 4.79765 - --0.00155511 5.20719 5.63145 --0.000112239 5.23777 5.58707 --0.0013004 5.27058 5.53912 -0.00191911 5.32007 5.46784 --0.00462807 5.38123 5.39568 --0.00522766 5.41137 5.36147 --0.00488832 5.54771 5.20637 --0.00194912 5.61685 5.129 --0.00634078 5.71351 5.04538 --0.0112311 5.85823 4.92158 --0.0136633 5.97144 4.85749 --0.0130908 6.08357 4.79765 - --0.0130908 6.08357 4.79765 -0.000713041 6.16159 4.8372 -0.0213682 6.23167 4.89927 -0.0397861 6.28873 4.94993 -0.0571468 6.31584 4.99079 -0.0925364 6.3513 5.05926 -0.145395 6.38313 5.11974 - --1.01931 0.422806 0.075427 --0.919113 0.400184 0.125295 --0.891842 0.42179 0.173281 --0.865098 0.453473 0.247259 --0.848245 0.483677 0.312445 --0.839332 0.502072 0.350585 --0.821532 0.550689 0.443871 --0.819402 0.605129 0.522967 --0.819121 0.645219 0.576111 --0.821396 0.671778 0.629942 --0.822698 0.686302 0.687086 --0.822126 0.681939 0.744683 --0.821363 0.665754 0.8044 --0.821155 0.634592 0.861869 --0.820841 0.600134 0.909646 --0.82077 0.568335 0.940189 --0.820728 0.559211 0.947897 - --1.01931 0.422806 0.075427 --1.04366 0.482545 0.033539 --1.03915 0.574571 -0.0174808 --1.04134 0.650846 -0.0371799 --1.04143 0.736589 -0.0404554 --1.0565 0.925736 -0.00617953 --1.06001 0.978856 0.00333741 --1.06619 1.07198 0.0200443 --1.07402 1.18751 0.0411403 --1.08328 1.28338 0.0693308 --1.08867 1.33514 0.087121 --1.09773 1.41906 0.119035 --1.10259 1.46485 0.13857 --1.10812 1.53024 0.169576 --1.11274 1.58618 0.196325 --1.11559 1.62079 0.212878 --1.12226 1.70154 0.251494 --1.13815 1.89152 0.342425 --1.13961 2.05923 0.414907 --1.12014 2.24315 0.476025 --1.09233 2.38822 0.510812 --1.05031 2.53732 0.533809 --0.865754 2.84428 0.5318 --0.798021 2.94149 0.524323 --0.675642 3.11186 0.513378 --0.57643 3.23766 0.508371 --0.490161 3.34314 0.509535 --0.399438 3.44644 0.50794 --0.315633 3.54052 0.510762 --0.257664 3.58014 0.504731 --0.201317 3.61747 0.50296 --0.103018 3.6639 0.493547 -0.00924497 3.71398 0.543265 - --1.01931 0.422806 0.075427 --1.13663 0.327981 0.0943148 --1.26353 0.22476 0.101754 - --1.26353 0.22476 0.101754 --1.36027 0.184371 0.0873416 --1.40463 0.158929 0.0992558 --1.49838 0.109487 0.127903 --1.56407 0.076331 0.149128 --1.61577 0.0511591 0.166833 --1.71551 0.00407972 0.207825 --1.81566 -0.0324254 0.306125 --1.88191 -0.0639851 0.383817 --1.92842 -0.0745217 0.438116 --1.96344 -0.0828731 0.485337 --1.9983 -0.0950211 0.527875 --2.00815 -0.097902 0.539268 --2.03675 -0.111156 0.573474 --2.04709 -0.116388 0.585573 - --1.26353 0.22476 0.101754 --1.16722 0.213571 0.169484 --1.16376 0.177424 0.202799 --1.17248 0.146532 0.240166 --1.19056 0.111853 0.294862 --1.20859 0.0826745 0.347467 --1.24954 0.0203687 0.468659 --1.28219 -0.024772 0.568378 --1.31958 -0.0470282 0.655177 --1.34654 -0.0673524 0.731502 --1.36002 -0.0749547 0.773755 --1.37828 -0.0924546 0.840585 --1.38963 -0.104232 0.882057 --1.39493 -0.112241 0.904109 - --0.0663285 3.98551 2.20978 --0.129362 3.95112 2.25329 --0.180173 3.91724 2.30826 --0.305861 3.79916 2.39036 --0.392767 3.71271 2.44834 --0.570063 3.51905 2.51174 --0.652651 3.418 2.52467 --0.736124 3.26606 2.53992 --0.771399 3.19851 2.54701 --0.809993 3.1229 2.55772 --0.855696 3.03837 2.58808 --0.875775 3.00325 2.60698 --0.905334 2.96014 2.65164 --0.923948 2.9382 2.68926 --0.95696 2.90795 2.76831 --0.974652 2.93338 2.84662 --1.02338 2.9784 3.04675 --1.05071 3.01058 3.16613 --1.09323 3.01036 3.30952 --1.12562 3.00322 3.41787 --1.15248 2.99137 3.50681 --1.167 2.97166 3.56705 --1.18451 2.94087 3.62239 --1.20828 2.87816 3.6874 --1.19943 2.79677 3.75792 - --0.0663285 3.98551 2.20978 --0.0255949 4.00992 2.09743 --0.0148507 4.02366 1.97545 --0.01296 4.02121 1.91134 --0.0106726 4.02121 1.85884 --0.00841274 4.02102 1.74614 --0.00485643 4.00874 1.58741 --0.00239152 3.99758 1.47522 --0.001096 3.99116 1.41551 -9.17227e-05 3.98406 1.35923 -0.000866527 3.97758 1.32017 -0.00199231 3.9665 1.26094 -0.00472475 3.94671 1.15669 -0.00835773 3.91609 1.00506 -0.000265464 3.9029 0.952975 -0.00652361 3.83791 0.834585 -0.0111034 3.79914 0.761512 -0.0159731 3.77358 0.7148 -0.023216 3.73632 0.646847 -0.00924497 3.71398 0.543265 - --1.19943 2.79677 3.75792 --1.23713 2.73891 3.79696 --1.27427 2.69425 3.82301 --1.29531 2.65664 3.84895 --1.32613 2.54967 3.88623 --1.3468 2.44395 3.90395 --1.36109 2.35268 3.90831 --1.36991 2.26654 3.90344 --1.37532 2.17798 3.8878 --1.3762 2.10149 3.87261 --1.3698 2.03006 3.84114 --1.35855 1.94836 3.7856 --1.33641 1.88198 3.69193 - --1.19943 2.79677 3.75792 --1.01597 2.7195 3.87574 --0.96638 2.61722 3.91259 --0.941273 2.50915 3.93075 --0.923139 2.4165 3.93642 --0.913868 2.32762 3.93005 --0.91279 2.31942 3.92951 --0.904941 2.23996 3.91463 --0.89814 2.17471 3.89397 --0.893007 2.11978 3.87549 --0.890661 2.0953 3.86699 --0.88417 2.02466 3.8162 --0.869144 1.92855 3.70585 - --1.19943 2.79677 3.75792 --1.3809 2.7459 3.67964 --1.50156 2.66742 3.63605 --1.54291 2.56463 3.60231 --1.55574 2.47838 3.57033 --1.54926 2.39617 3.53038 --1.52832 2.32728 3.48821 --1.49782 2.27886 3.45595 --1.46023 2.23834 3.42026 --1.40086 2.19973 3.33452 --1.31818 2.18354 3.22772 - -1.31543 1.86601 3.64226 -1.36023 1.9521 3.77998 - -2.04778 -0.115785 0.587142 -2.03943 -0.112003 0.577252 -2.00184 -0.0974169 0.532404 -1.96484 -0.0843628 0.486345 -1.92989 -0.0769371 0.440746 -1.88128 -0.0707924 0.396185 -1.85317 -0.0583328 0.356398 -1.80429 -0.0339894 0.295681 -1.71758 -0.00408226 0.206552 -1.58534 0.056596 0.155286 -1.48788 0.107882 0.121585 -1.40853 0.151558 0.0955468 -1.33973 0.189062 0.0770308 -1.29481 0.218125 0.0639521 -1.23446 0.253485 0.0581332 -1.15937 0.255373 0.0967063 - -1.39792 -0.114262 0.914281 -1.39532 -0.112442 0.904249 -1.39112 -0.107227 0.888984 -1.38134 -0.0920801 0.847609 -1.37241 -0.088242 0.811562 -1.36471 -0.0818346 0.778999 -1.33614 -0.0697922 0.700069 -1.31296 -0.0469355 0.634475 -1.28429 -0.0272305 0.568022 -1.24217 0.0376124 0.418143 -1.2109 0.081772 0.329428 -1.19152 0.113041 0.269462 -1.17038 0.150212 0.211838 -1.15192 0.185315 0.167312 -1.15937 0.255373 0.0967063 - -0.517272 6.40976 5.26321 -0.331221 6.41377 5.19327 -0.288507 6.41535 5.18103 -0.240938 6.40515 5.16059 -0.145395 6.38313 5.11974 - -1.36023 1.9521 3.77998 -1.36135 1.93871 3.78143 - -1.36023 1.9521 3.77998 -1.36377 2.00475 3.82803 -1.37074 2.046 3.84818 -1.37823 2.10367 3.87008 -1.37812 2.17771 3.88825 -1.37386 2.26046 3.90187 -1.3607 2.35504 3.90806 -1.34362 2.46333 3.90143 -1.31158 2.58219 3.88205 -1.27741 2.67209 3.83482 -1.24253 2.75547 3.77854 - -1.24253 2.75547 3.77854 -1.29622 2.79519 3.70937 -1.38642 2.74501 3.6759 -1.50385 2.66613 3.63419 -1.53984 2.57964 3.60691 -1.54364 2.56817 3.60332 -1.55568 2.47859 3.57019 -1.54919 2.39621 3.53037 -1.52756 2.32745 3.48944 -1.49867 2.27892 3.45459 -1.45124 2.22993 3.40067 -1.35308 2.19445 3.27221 - diff --git a/data/skeletons/output_vessels_skeleton.txt b/data/skeletons/output_vessels_skeleton.txt deleted file mode 100644 index f444a87..0000000 --- a/data/skeletons/output_vessels_skeleton.txt +++ /dev/null @@ -1,235 +0,0 @@ -0.0469689 -0.0056659 0.977742 -0.0453733 -0.00326106 0.977921 -0.0444669 -0.00175594 0.978012 -0.0436379 -0.0011278 0.97811 -0.0430662 -0.000709462 0.978176 -0.0426091 -0.000413168 0.978227 -0.0412855 0.000415358 0.978373 -0.0407007 0.000764932 0.978436 -0.0401557 0.00108358 0.978493 -0.0399571 0.00119796 0.978514 -0.0384383 0.00206047 0.978661 -0.036929 0.00291855 0.978866 -0.035959 0.00331456 0.97897 -0.0350396 0.00366551 0.979008 -0.0338635 0.00411401 0.979053 -0.0317572 0.00497143 0.979171 -0.0301424 0.00558471 0.979242 -0.0283695 0.00618038 0.979326 -0.0274233 0.00651819 0.979372 -0.0262368 0.00688606 0.979407 -0.0246121 0.00736591 0.979453 -0.0234288 0.00768447 0.979489 -0.0224432 0.00792118 0.979535 -0.0210617 0.00812322 0.979633 -0.0202207 0.00824735 0.979685 -0.0194842 0.00835468 0.979731 -0.0176544 0.0086176 0.979832 -0.0171137 0.0086938 0.979856 -0.0163976 0.00879551 0.979889 -0.0158021 0.00887576 0.979917 -0.0149582 0.00898349 0.97996 -0.0144673 0.00900392 0.980002 -0.0136869 0.00902356 0.980073 -0.0125033 0.00905362 0.98018 -0.0116094 0.0090756 0.980261 -0.0106014 0.00909954 0.980351 -0.00931187 0.00912627 0.980466 -0.00632232 0.00917942 0.980743 -0.00449926 0.00891593 0.980864 -0.00312691 0.00872583 0.980968 -0.00242713 0.0086284 0.981021 -0.00144239 0.00849151 0.981097 -2.10942e-05 0.00829513 0.981197 --0.00159382 0.00800114 0.981291 --0.00334763 0.00764906 0.981341 --0.00433567 0.00746926 0.981317 --0.00557796 0.00727182 0.981392 --0.00765726 0.00692089 0.981424 --0.00967463 0.006641 0.981389 --0.0126216 0.00642837 0.981263 --0.0143405 0.00654632 0.981179 --0.0154121 0.00662211 0.981126 --0.0169374 0.00677974 0.981041 --0.0179808 0.00680759 0.98104 --0.0185493 0.0068245 0.981039 --0.0192053 0.00688972 0.98102 --0.0199304 0.00697514 0.980993 - -0.0469689 -0.0056659 0.977742 -0.0491851 -0.00608992 0.977239 -0.0495987 -0.00606291 0.977136 -0.0510828 -0.00558239 0.976732 -0.0519304 -0.00509899 0.976482 -0.053027 -0.00450125 0.976161 -0.0552678 -0.00483177 0.975553 -0.0572031 -0.0051304 0.974996 -0.058274 -0.00531052 0.974669 -0.059374 -0.00549882 0.974325 -0.059884 -0.00558844 0.974161 -0.0606351 -0.00572275 0.973916 -0.0614643 -0.00587599 0.973632 -0.0621898 -0.00601148 0.97338 -0.062863 -0.00613888 0.973141 -0.0638755 -0.0063314 0.972779 -0.0651174 -0.00657165 0.972332 -0.0668889 -0.00692016 0.97168 -0.0678343 -0.00703731 0.971259 -0.0690245 -0.00715766 0.970713 -0.0705755 -0.00729145 0.970052 -0.071647 -0.00730304 0.969539 -0.0725133 -0.00731158 0.969123 -0.0734875 -0.00737542 0.968705 -0.0744318 -0.00728708 0.968205 -0.0752835 -0.00720106 0.967795 -0.0768946 -0.00701639 0.96694 -0.0788049 -0.00665548 0.965886 -0.0796527 -0.00650188 0.965427 -0.0799408 -0.00644836 0.965272 -0.0805082 -0.0063418 0.964967 -0.0816004 -0.00612038 0.964414 -0.0822564 -0.00594323 0.964018 -0.0832025 -0.00564713 0.963511 -0.0843165 -0.00528742 0.962839 -0.0854876 -0.00491056 0.962217 -0.0862224 -0.00465064 0.961793 -0.0871678 -0.00432492 0.961237 - -0.0469689 -0.0056659 0.977742 -0.0474104 -0.0073906 0.977784 -0.0471867 -0.00964572 0.978034 -0.0466351 -0.0116049 0.978337 -0.0465087 -0.0120769 0.978408 -0.0464002 -0.0124773 0.978469 -0.0461282 -0.0133969 0.978614 -0.046003 -0.0138198 0.978681 -0.0458157 -0.0144608 0.978782 -0.0457139 -0.01494 0.978832 -0.0454789 -0.0159139 0.978914 -0.0452061 -0.0169073 0.978989 -0.0449379 -0.0178449 0.979057 -0.0445499 -0.0190518 0.979133 -0.0441777 -0.0201391 0.979195 -0.0438655 -0.0210161 0.979241 -0.0434672 -0.0220856 0.979291 -0.0431126 -0.0230152 0.979331 -0.0428579 -0.0236702 0.979359 -0.0425843 -0.0243568 0.979384 -0.0423474 -0.0250665 0.979448 -0.0419428 -0.0258103 0.979395 -0.0414905 -0.0266215 0.97933 -0.0409368 -0.0275835 0.979242 -0.0401568 -0.0289717 0.97913 -0.0392091 -0.0306304 0.978991 -0.0388309 -0.0312902 0.978935 -0.0379648 -0.0327893 0.978808 -0.0370654 -0.0343439 0.978675 -0.0365495 -0.0352323 0.978597 -0.0350815 -0.0377195 0.978364 -0.0342039 -0.0390422 0.978219 -0.0331458 -0.0405652 0.978026 -0.0324822 -0.0413444 0.977927 - --0.0538581 -0.0181914 0.988229 --0.0531305 -0.0174962 0.988183 --0.0527199 -0.0170608 0.987948 --0.0518517 -0.0161877 0.987708 --0.051147 -0.0154695 0.987589 --0.0502779 -0.0145734 0.987492 --0.0493777 -0.0136567 0.987404 --0.0485589 -0.0128133 0.987278 --0.0474374 -0.0116802 0.98709 --0.0463481 -0.0105776 0.986995 --0.0451136 -0.00938489 0.98689 --0.0443884 -0.00871443 0.986804 --0.0432676 -0.00764483 0.986719 --0.0417977 -0.00633713 0.986419 --0.0402577 -0.00543193 0.98609 --0.0387757 -0.00452052 0.985772 --0.0372883 -0.0036096 0.985459 --0.0358757 -0.00274808 0.985159 --0.0346556 -0.00200516 0.984901 --0.033988 -0.00160233 0.984758 --0.0333219 -0.0012045 0.984616 --0.0327273 -0.00085356 0.984486 --0.0315982 -0.000194698 0.984246 --0.0295469 0.0010164 0.98372 --0.0278505 0.0019718 0.983259 --0.0270032 0.00246915 0.982995 --0.026063 0.00305269 0.982705 --0.0251486 0.00364202 0.982419 --0.0247167 0.00393615 0.982281 --0.0236695 0.00468632 0.981937 --0.0211737 0.00618296 0.981318 --0.0199304 0.00697514 0.980993 - --0.0660678 0.0799506 0.964077 --0.0658798 0.0795537 0.964221 --0.0653773 0.07864 0.964587 --0.0648021 0.0776514 0.964978 --0.0640504 0.0762422 0.965584 --0.0632706 0.0746818 0.966201 --0.0627243 0.0737066 0.966673 --0.0622061 0.0727384 0.967127 --0.0619621 0.0722812 0.967342 --0.0615278 0.0714654 0.967726 --0.0610355 0.0705423 0.96816 --0.0603684 0.0692998 0.968747 --0.0597693 0.0681845 0.969256 --0.0594595 0.0676297 0.969523 --0.0591451 0.0670785 0.969794 --0.057952 0.065016 0.970825 --0.0573795 0.0640712 0.971315 --0.056563 0.0627234 0.972003 --0.0555271 0.0611072 0.972872 --0.0548764 0.0601064 0.973412 --0.0539908 0.0588041 0.974136 --0.053481 0.0580636 0.974514 --0.0526746 0.0569646 0.975096 --0.0519325 0.055968 0.97558 --0.0510737 0.0547354 0.976192 --0.0503021 0.0536787 0.976645 --0.0488239 0.0516112 0.977406 --0.04793 0.0502629 0.977808 --0.0467738 0.0486099 0.97813 --0.0460362 0.0475114 0.978264 --0.0454315 0.0466255 0.978345 --0.0445692 0.0453697 0.978447 --0.0435698 0.0437474 0.978347 --0.042717 0.0423882 0.978248 --0.0418023 0.0409206 0.978202 --0.0413294 0.0402016 0.9781 --0.0410171 0.0397114 0.978055 --0.0405197 0.038961 0.977975 --0.0397913 0.0378635 0.977856 --0.0391843 0.0369495 0.977757 --0.0386396 0.0361301 0.977668 --0.0380864 0.0352985 0.977578 --0.0375341 0.0344686 0.977489 --0.0362419 0.0325285 0.97728 --0.0354917 0.0314035 0.97716 --0.0349144 0.0305385 0.977067 --0.0342245 0.0295067 0.976958 --0.0336931 0.0287121 0.976874 --0.0330931 0.0278155 0.976777 --0.0325939 0.0270715 0.976829 --0.0316355 0.0256521 0.976735 --0.0307614 0.0243718 0.976716 --0.0301657 0.023507 0.976666 --0.0299206 0.0231408 0.976614 --0.0290781 0.0218958 0.976766 --0.0286142 0.0212087 0.976845 --0.0270717 0.0189947 0.977125 --0.0260201 0.0173428 0.977478 --0.0252485 0.0159936 0.977858 --0.0247092 0.0151112 0.978131 --0.0246319 0.0149807 0.978171 --0.0237678 0.0135157 0.978628 --0.0233234 0.0127479 0.978873 --0.0228252 0.0118465 0.979176 --0.0224331 0.0111191 0.979424 --0.0219868 0.0102781 0.979713 --0.0211447 0.00888227 0.980253 --0.0205194 0.00774802 0.980694 --0.0199304 0.00697514 0.980993 - diff --git a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp deleted file mode 100644 index 55d8e64..0000000 --- a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#define SKELETONIZATIONLOADER_CPP -#include - -#include -#include - -namespace meshskeletonizationplugin -{ -using namespace sofa::defaulttype; - -void registerSkeletonizationLoader(sofa::core::ObjectFactory* factory) -{ - factory->registerObjects(sofa::core::ObjectRegistrationData( - "Load a mesh skeleton and build a rooted father/children tree, exported as SWC") - .add< SkeletonizationLoader >()); -} - -template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonizationLoader; -} \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h deleted file mode 100644 index 921f559..0000000 --- a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.h +++ /dev/null @@ -1,170 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include - -#include -#include - - -#include -#include -#include - -//// Skeletonization function -#include -#include -#include - -// My addition -#include - -//// Typedefs CGAL -typedef CGAL::Simple_cartesian Kernel; -typedef CGAL::Polyhedron_3 Polyhedron; -typedef Polyhedron::HalfedgeDS HalfedgeDS; -typedef Kernel::Point_3 Point; - -typedef CGAL::Mean_curvature_flow_skeletonization Skeletonization; -typedef Skeletonization::Skeleton Skeleton; -typedef Skeleton::vertex_descriptor Skeleton_vertex; -typedef Skeleton::edge_descriptor Skeleton_edge; - -using namespace sofa; -using namespace sofa::defaulttype; - -namespace meshskeletonizationplugin -{ - -template -class SkeletonizationLoader: public sofa::core::DataEngine -{ -public: - SOFA_CLASS(SOFA_TEMPLATE(SkeletonizationLoader,DataTypes),sofa::core::DataEngine); - - typedef typename DataTypes::Coord Coord; - typedef typename DataTypes::VecCoord VecCoord; - typedef typename Coord::value_type Real; - typedef type::Vec<3,Real> Vec3; - - // Typedefs SOFA Topology - using Triangle = sofa::core::topology::BaseMeshTopology::Triangle; - using SeqTriangles = sofa::core::topology::BaseMeshTopology::SeqTriangles; - - // Inputs - sofa::core::objectmodel::Data d_inVertices; ///< List of vertices - sofa::core::objectmodel::Data d_inTriangles; ///< List of triangles - - // Parameters - sofa::core::objectmodel::DataFileName d_inMeshFilename; - sofa::core::objectmodel::DataFileName d_outSkeletonFilename; ///< File path to export skeleton - - // My addition: entry point + rooted-tree export - sofa::core::objectmodel::Data d_inEntryPoint; ///< Approx. 3D position of the vessel entry point; closest skeleton vertex becomes the tree root - sofa::core::objectmodel::DataFileName d_outTreeFilename; ///< File path to export the rooted father/children tree (SWC format) - -private: - SkeletonizationLoader(); - virtual ~SkeletonizationLoader() = default; - - void init() override; - void doUpdate() override; - - void draw(const sofa::core::visual::VisualParams* vparams) override; - - // convert a set of vertices and tringles to polyhedron - void geometryToPolyhedron(Polyhedron &s); - - // Members - Skeleton m_skeleton; - //My addition - VesselTree m_vesselTree; - - - template - class geometryToPolyhedronOp : public CGAL::Modifier_base - { - public: - typedef typename DataTypes::Real Real; - typedef typename DataTypes::Coord Coord; - typedef typename DataTypes::VecCoord VecCoord; - - typedef HDS Halfedge_data_structure; - - private: - VecCoord m_vertices; - SeqTriangles m_triangles; - - public: - geometryToPolyhedronOp(const VecCoord &vertices, const SeqTriangles &triangles) { - m_vertices = vertices; - m_triangles = triangles; - } - - void operator()( HDS& hds) - { - unsigned int numVertices = m_vertices.size(); - unsigned int numTriangles = m_triangles.size(); - - CGAL::Polyhedron_incremental_builder_3 builder(hds, true); - builder.begin_surface(numVertices, numTriangles); - - for (unsigned int i = 0; i < numVertices; i++) - { - builder.add_vertex( Point( m_vertices[i][0], m_vertices[i][1], m_vertices[i][2] )); - } - - for (unsigned int i = 0; i < numTriangles; i++ ) - { - builder.begin_facet(); - for ( int j = 0; j < 3; j++ ) - { - builder.add_vertex_to_facet( m_triangles[i][j] ); - } - builder.end_facet(); - } - - if (builder.check_unconnected_vertices()) - { - builder.remove_unconnected_vertices(); - } - - builder.end_surface(); - } - }; - - - struct Export_polylines - { - const Skeleton& skeleton; - std::ofstream& OutputP; - - Export_polylines(const Skeleton& skeleton, std::ofstream& OutputP) - : skeleton(skeleton), OutputP(OutputP) - { } - - void start_new_polyline() { - - } - - void add_node(Skeleton_vertex v) { - OutputP << skeleton[v].point[0] << " " << skeleton[v].point[1] << " " << skeleton[v].point[2] << "\n"; - } - - void end_polyline() { - OutputP << "\n"; - } - }; - -}; - - -#if !defined(SKELETONIZATIONLOADER_CPP) -extern template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonizationLoader; -#endif - -} // namespace meshskeletonizationplugin \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl b/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl deleted file mode 100644 index e570bf2..0000000 --- a/src/MeshSkeletonizationPlugin/MySkeleton/SkeletonizationLoader.inl +++ /dev/null @@ -1,119 +0,0 @@ -#pragma once - -#include - -using namespace sofa::core::objectmodel; - -namespace meshskeletonizationplugin -{ - -template -SkeletonizationLoader::SkeletonizationLoader() - : d_inVertices(initData (&d_inVertices, "inputVertices", "List of input mesh vertices")) - , d_inTriangles(initData(&d_inTriangles, "inputTriangles", "List of input mesh triangles")) - , d_outSkeletonFilename(initData(&d_outSkeletonFilename, "outputSkeleton", "File path to output skeleton file")) - , d_inMeshFilename(initData (&d_inMeshFilename, "filename", "Input mesh in .off format")) - , d_inEntryPoint(initData(&d_inEntryPoint, Vec3(0,0,0), "entryPoint", "Approx. entry point; closest skeleton vertex becomes the tree root")) - , d_outTreeFilename(initData(&d_outTreeFilename, "outputTree", "File path to export the rooted tree (SWC)")) -{ - addInput(&d_inVertices); - addInput(&d_inTriangles); - addInput(&d_inMeshFilename); - addInput(&d_inEntryPoint); - - addOutput(&d_outSkeletonFilename); - addOutput(&d_outTreeFilename); -} - - -template -void SkeletonizationLoader::init() -{ - //Input - if(d_outSkeletonFilename.getValue().empty()) - { - msg_error() << "No input File to store the skeleton data, please set a inputFile path."; - return; - } -} - - -template -void SkeletonizationLoader::geometryToPolyhedron(Polyhedron &s) -{ - VecCoord inVertices = d_inVertices.getValue(); - SeqTriangles inTriangles = d_inTriangles.getValue(); - - geometryToPolyhedronOp gen(inVertices, inTriangles); - s.delegate(gen); -} - - -template -void SkeletonizationLoader::doUpdate() -{ - Polyhedron tmesh; - - if(d_inMeshFilename.getFullPath() != "") - { - const char* filename = d_inMeshFilename.getFullPath().c_str(); - std::ifstream input(filename); - input >> tmesh; - msg_info() << "Loading Polyhedron from file."; - } - else - { - geometryToPolyhedron(tmesh); - msg_info() << "Number of vertices of the input mesh: " << boost::num_vertices(tmesh); - } - - if (!CGAL::is_triangle_mesh(tmesh)) - { - msg_error() << "Input geometry is not triangulated."; - return; - } - - CGAL::extract_mean_curvature_flow_skeleton(tmesh, m_skeleton); - msg_info() << "Number of vertices of the output skeleton: " << boost::num_vertices(m_skeleton); - msg_info() << "Number of edges of the output skeleton: " << boost::num_edges(m_skeleton); - - if (d_outSkeletonFilename.isSet()) - { - std::ofstream OutputP(d_outSkeletonFilename.getFullPath(), std::ofstream::out | std::ofstream::trunc); - Export_polylines extractor(m_skeleton, OutputP); - CGAL::split_graph_into_polylines(m_skeleton, extractor); - OutputP.close(); - } - - auto root = m_vesselTree.findClosestVertex(m_skeleton, d_inEntryPoint.getValue()); - m_vesselTree.build(m_skeleton, root); - msg_info() << "Vessel tree built: " << m_vesselTree.parents().size() + 1 - << " node(s) reached, " << m_vesselTree.loopEdges().size() / 2 - << " loop edge(s) detected."; - - if (d_outTreeFilename.isSet()) - m_vesselTree.exportToSWC(m_skeleton, d_outTreeFilename.getFullPath()); -} - - -template -void SkeletonizationLoader::draw(const sofa::core::visual::VisualParams* vparams) -{ - using Color = sofa::type::RGBAColor; - std::vector< type::Vec3 > dvec; - - for(const Skeleton_edge& e : CGAL::make_range(edges(m_skeleton))) - { - const Point& s = m_skeleton[source(e, m_skeleton)].point; - const Point& t = m_skeleton[target(e, m_skeleton)].point; - - - dvec.emplace_back(Coord(s[0], s[1], s[2])); - dvec.emplace_back(Coord(t[0], t[1], t[2])); - - vparams->drawTool()->drawLines( dvec, 40, Color::red()); - dvec.clear(); - } -} - -} // namespace meshskeletonizationplugin \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp new file mode 100644 index 0000000..b9295c7 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp @@ -0,0 +1,298 @@ +#include "SkeletonGraph.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace meshskeletonizationplugin +{ + +void SkeletonGraph::clear() +{ + m_nodes.clear(); + m_adjacency.clear(); + m_loopEdges.clear(); + m_rootId = -1; +} + +int SkeletonGraph::findOrCreateNode(const std::array& p, double tol) +{ + const double tol2 = tol * tol; + for (const SkeletonNode& n : m_nodes) + { + const auto& q = n.position(); + double dx = q[0] - p[0]; + double dy = q[1] - p[1]; + double dz = q[2] - p[2]; + if (dx * dx + dy * dy + dz * dz <= tol2) + return n.id(); + } + + int newId = static_cast(m_nodes.size()); + m_nodes.emplace_back(newId, p[0], p[1], p[2]); + return newId; +} + +void SkeletonGraph::connect(int a, int b) +{ + if (a == b) + return; + + auto& neighborsA = m_adjacency[a]; + if (std::find(neighborsA.begin(), neighborsA.end(), b) == neighborsA.end()) + neighborsA.push_back(b); + + auto& neighborsB = m_adjacency[b]; + if (std::find(neighborsB.begin(), neighborsB.end(), a) == neighborsB.end()) + neighborsB.push_back(a); +} + +bool SkeletonGraph::loadFromFile(const std::string& filename, double mergeTolerance) +{ + std::ifstream in(filename); + if (!in.is_open()) + return false; + + clear(); + + std::string line; + int previousId = -1; + + while (std::getline(in, line)) + { + // Trim trailing whitespace/CR so blank-line detection works on + // files written or edited on Windows too. + while (!line.empty() && (line.back() == '\r' || line.back() == ' ' || line.back() == '\t')) + line.pop_back(); + + if (line.empty()) + { + previousId = -1; // end of current polyline + continue; + } + + std::istringstream iss(line); + std::array p{}; + if (!(iss >> p[0] >> p[1] >> p[2])) + continue; // skip malformed/comment lines + + int id = findOrCreateNode(p, mergeTolerance); + + if (previousId >= 0) + connect(previousId, id); + + previousId = id; + } + + return true; +} + +int SkeletonGraph::closestNodeId(const std::array& p) const +{ + int best = -1; + double bestDist = std::numeric_limits::max(); + for (const SkeletonNode& n : m_nodes) + { + const auto& q = n.position(); + double dx = q[0] - p[0]; + double dy = q[1] - p[1]; + double dz = q[2] - p[2]; + double d2 = dx * dx + dy * dy + dz * dz; + if (d2 < bestDist) + { + bestDist = d2; + best = n.id(); + } + } + return best; +} + +void SkeletonGraph::buildTree(const std::array& entryPoint) +{ + int root = closestNodeId(entryPoint); + if (root >= 0) + buildTree(root); +} + +void SkeletonGraph::buildTree(int rootId) +{ + m_loopEdges.clear(); + + for (SkeletonNode& n : m_nodes) + { + n = SkeletonNode(n.id(), n.position()[0], n.position()[1], n.position()[2]); + } + + if (rootId < 0 || rootId >= static_cast(m_nodes.size())) + { + m_rootId = -1; + return; + } + + m_rootId = rootId; + + std::vector visited(m_nodes.size(), false); + std::vector parentOf(m_nodes.size(), -1); + std::queue q; + + visited[rootId] = true; + q.push(rootId); + + std::set> seenEdges; // to dedupe loop-edge reporting + + while (!q.empty()) + { + int u = q.front(); + q.pop(); + + auto it = m_adjacency.find(u); + if (it == m_adjacency.end()) + continue; + + for (int v : it->second) + { + if (!visited[v]) + { + visited[v] = true; + parentOf[v] = u; + m_nodes[u].addChildId(v); + m_nodes[v].addParentId(u); + q.push(v); + } + else if (parentOf[u] != v) // don't re-report the edge we arrived from + { + std::pair key = (u < v) ? std::make_pair(u, v) : std::make_pair(v, u); + if (seenEdges.insert(key).second) + { + // Real loop/anastomosis: record extra parent/child links + // without duplicating the primary tree edge. + m_nodes[u].addChildId(v); + m_nodes[v].addParentId(u); + m_loopEdges.emplace_back(u, v); + } + } + } + } +} + +void SkeletonGraph::computeMeshCorrespondence(const std::vector>& meshVertices) +{ + if (meshVertices.empty()) + return; + + for (SkeletonNode& n : m_nodes) + { + const auto& p = n.position(); + int bestVid = -1; + double bestDist2 = std::numeric_limits::max(); + + for (int i = 0; i < static_cast(meshVertices.size()); ++i) + { + const auto& v = meshVertices[i]; + double dx = v[0] - p[0]; + double dy = v[1] - p[1]; + double dz = v[2] - p[2]; + double d2 = dx * dx + dy * dy + dz * dz; + if (d2 < bestDist2) + { + bestDist2 = d2; + bestVid = i; + } + } + + n.setMeshVertexId(bestVid); + n.setDistanceToMesh(std::sqrt(bestDist2)); + } +} + +void SkeletonGraph::exportToVTK(const std::string& filename) const +{ + if (!hasRoot()) + return; + + const int n = static_cast(m_nodes.size()); + + // Node ids are assigned sequentially at creation time (0..n-1), so id == + // vector index and no separate id-remapping table is needed here. + + // depth(v) = number of edges from root, via each node's primary parent + // (parentIds().front()), memoized as we go. + std::vector depth(n, -1); + depth[m_rootId] = 0; + for (int v = 0; v < n; ++v) + { + if (depth[v] >= 0) + continue; + + std::vector path; + int cur = v; + while (depth[cur] < 0) + { + path.push_back(cur); + const auto& parents = m_nodes[cur].parentIds(); + if (parents.empty()) + break; // only the root should have no parent + cur = parents.front(); + } + int d = depth[cur] >= 0 ? depth[cur] : 0; + for (auto it = path.rbegin(); it != path.rend(); ++it) + depth[*it] = ++d; + } + + // LINES: primary tree edge (parentIds()[0] -> id) for every non-root + // node, plus any extra parent entries (index > 0) recorded as loop edges. + std::vector> lines; + std::vector isLoop; + for (const SkeletonNode& node : m_nodes) + { + const auto& parents = node.parentIds(); + for (std::size_t j = 0; j < parents.size(); ++j) + { + lines.emplace_back(parents[j], node.id()); + isLoop.push_back(j == 0 ? 0 : 1); + } + } + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "# vtk DataFile Version 3.0\n"; + out << "Skeleton graph (SkeletonReader module)\n"; + out << "ASCII\n"; + out << "DATASET POLYDATA\n"; + + out << "POINTS " << n << " float\n"; + out << std::fixed << std::setprecision(6); + for (const SkeletonNode& node : m_nodes) + { + const auto& p = node.position(); + out << p[0] << " " << p[1] << " " << p[2] << "\n"; + } + + out << "LINES " << lines.size() << " " << (lines.size() * 3) << "\n"; + for (const auto& l : lines) + out << "2 " << l.first << " " << l.second << "\n"; + + out << "POINT_DATA " << n << "\n"; + out << "SCALARS type int 1\n"; + out << "LOOKUP_TABLE default\n"; + for (const SkeletonNode& node : m_nodes) + { + int type = (node.id() == m_rootId) ? 1 : (node.isLeaf() ? 6 : 5); // 1=root, 5=branch, 6=terminal + out << type << "\n"; + } + out << "SCALARS depth int 1\n"; + out << "LOOKUP_TABLE default\n"; + for (int d : depth) + out << d << "\n"; + + out << "CELL_DATA " << lines.size() << "\n"; + out << "SCALARS is_loop int 1\n"; + out << "LOOKUP_TABLE default\n"; + for (int flag : isLoop) + out << flag << "\n"; +} + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h new file mode 100644 index 0000000..6c084fc --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h @@ -0,0 +1,60 @@ +#pragma once + +#include "SkeletonNode.h" + +#include +#include +#include +#include +#include + +namespace meshskeletonizationplugin +{ + +/// Loads a polyline skeleton file (the format written by +/// MeshSkeletonization/SkeletonizationLoader's Export_polylines: blocks of +/// "x y z" lines separated by a blank line) and stores it as a graph of +/// SkeletonNode, then turns it into a rooted parent/children tree. +class SkeletonGraph +{ +public: + /// Parses the file, merging points that are within `mergeTolerance` of an + /// already-seen point into a single node. Returns false if the file could + /// not be opened. Only fills raw connectivity; call buildTree() afterwards + /// to populate parent/children ids on the nodes. + bool loadFromFile(const std::string& filename, double mergeTolerance = 1e-6); + + /// Picks the node closest to entryPoint as root and (re)computes every + /// node's parentIds/childrenIds via BFS over the raw connectivity. + void buildTree(const std::array& entryPoint); + void buildTree(int rootId); + + /// Best-effort correspondence between each skeleton node and the closest + /// vertex of the input (vessel) mesh; fills meshVertexId/distanceToMesh. + void computeMeshCorrespondence(const std::vector>& meshVertices); + + const std::vector& nodes() const { return m_nodes; } + std::vector& nodes() { return m_nodes; } + + int rootId() const { return m_rootId; } + bool hasRoot() const { return m_rootId >= 0; } + + /// Ids of nodes connected by a loop/anastomosis (extra edge beyond the tree). + const std::vector>& loopEdges() const { return m_loopEdges; } + + void exportToVTK(const std::string& filename) const; + + void clear(); + +private: + int findOrCreateNode(const std::array& p, double tol); + int closestNodeId(const std::array& p) const; + void connect(int a, int b); + + std::vector m_nodes; + std::map> m_adjacency; ///< raw undirected connectivity from the file + std::vector> m_loopEdges; + int m_rootId{ -1 }; +}; + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h new file mode 100644 index 0000000..6deba3d --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h @@ -0,0 +1,67 @@ +#pragma once + +#include +#include + +namespace meshskeletonizationplugin +{ + +/// A single node of a skeletonized structure (e.g. a vessel centerline point). +/// Deliberately has no SOFA/CGAL dependency so it can be reused, tested, +/// and serialized independently of the plugin's simulation types. +class SkeletonNode +{ +public: + SkeletonNode() = default; + SkeletonNode(int id, double x, double y, double z) + : m_id(id), m_position{ x, y, z } + { + } + + int id() const { return m_id; } + void setId(int id) { m_id = id; } + + const std::array& position() const { return m_position; } + void setPosition(double x, double y, double z) { m_position = { x, y, z }; } + + /// Ids of the node(s) this node is connected to towards the root. + /// Usually a single parent; more than one means this node closes a + /// loop/anastomosis in the raw skeleton graph. + const std::vector& parentIds() const { return m_parentIds; } + void addParentId(int id) { m_parentIds.push_back(id); } + + /// Ids of the node(s) reached by moving away from the root. + const std::vector& childrenIds() const { return m_childrenIds; } + void addChildId(int id) { m_childrenIds.push_back(id); } + + bool isRoot() const { return m_parentIds.empty(); } + bool isLeaf() const { return m_childrenIds.empty(); } + bool isBranchPoint() const { return m_childrenIds.size() > 1; } + + // --- Optional relation to the input (vessel) mesh this skeleton came from --- + + /// Index of the closest vertex in the input mesh, -1 if not computed. + int meshVertexId() const { return m_meshVertexId; } + void setMeshVertexId(int vId) { m_meshVertexId = vId; } + + /// Distance from this node to that mesh vertex, <0 if not computed. + double distanceToMesh() const { return m_distanceToMesh; } + void setDistanceToMesh(double d) { m_distanceToMesh = d; } + + /// Estimated local vessel radius at this node, <0 if not available. + double radius() const { return m_radius; } + void setRadius(double r) { m_radius = r; } + +private: + int m_id{ -1 }; + std::array m_position{ 0.0, 0.0, 0.0 }; + + std::vector m_parentIds; + std::vector m_childrenIds; + + int m_meshVertexId{ -1 }; + double m_distanceToMesh{ -1.0 }; + double m_radius{ -1.0 }; +}; + +} // namespace meshskeletonizationplugin \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.cpp new file mode 100644 index 0000000..8187881 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.cpp @@ -0,0 +1,21 @@ +#define SKELETONREADER_CPP +#include + +#include +#include + +namespace meshskeletonizationplugin +{ +using namespace sofa::defaulttype; + +void registerSkeletonReader(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData( + "Read a skeleton polyline file (skeleton.txt) and store it as a graph of " + "nodes, each with its id, parent ids, children ids, and (if an input mesh " + "is given) its correspondence to the closest mesh vertex") + .add< SkeletonReader >()); +} + +template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonReader; +} \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h new file mode 100644 index 0000000..5fbaf59 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h @@ -0,0 +1,68 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include + +using namespace sofa; +using namespace sofa::defaulttype; + +namespace meshskeletonizationplugin +{ + +/// Reads a skeleton polyline file (the "skeleton.txt" format written by +/// MeshSkeletonization / SkeletonizationLoader's Export_polylines) and stores +/// it as a SkeletonGraph: a list of SkeletonNode, each with its id, parent +/// ids, children ids, and - if an input mesh is provided - its correspondence +/// to the closest mesh vertex. +/// +/// This component does not need CGAL: it only re-reads an already-exported +/// polyline file, so it can be used purely as a downstream consumer of +/// MeshSkeletonization/SkeletonizationLoader's output. +template +class SkeletonReader : public sofa::core::DataEngine +{ +public: + SOFA_CLASS(SOFA_TEMPLATE(SkeletonReader, DataTypes), sofa::core::DataEngine); + + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::VecCoord VecCoord; + typedef typename Coord::value_type Real; + typedef type::Vec<3, Real> Vec3; + + // Inputs + sofa::core::objectmodel::DataFileName d_inSkeletonFilename; ///< Path to the skeleton polyline file to read (e.g. skeleton.txt) + sofa::core::objectmodel::Data d_inVertices; ///< Optional input mesh vertices, to link skeleton nodes to the mesh + sofa::core::objectmodel::Data d_inEntryPoint; ///< Approx. entry point; closest node becomes the tree root + + // Outputs + sofa::core::objectmodel::DataFileName d_outVTKFilename; ///< File path to (re-)export the rooted tree as VTK + sofa::core::objectmodel::Data d_outNodeCount; ///< Number of skeleton nodes read + + /// Direct access to the loaded graph, e.g. for another component to query + /// via getContext()->get>()->graph(). + const SkeletonGraph& graph() const { return m_graph; } + +private: + SkeletonReader(); + virtual ~SkeletonReader() = default; + + void init() override; + void doUpdate() override; + + void draw(const sofa::core::visual::VisualParams* vparams) override; + + SkeletonGraph m_graph; +}; + +#if !defined(SKELETONREADER_CPP) +extern template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonReader; +#endif + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl new file mode 100644 index 0000000..5996228 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl @@ -0,0 +1,100 @@ +#pragma once + +#include + +using namespace sofa::core::objectmodel; + +namespace meshskeletonizationplugin +{ + +template +SkeletonReader::SkeletonReader() + : d_inSkeletonFilename(initData(&d_inSkeletonFilename, "filename", "Skeleton polyline file to read (e.g. skeleton.txt)")) + , d_inVertices(initData(&d_inVertices, "inputVertices", "Optional input mesh vertices, to link skeleton nodes to the mesh")) + , d_inEntryPoint(initData(&d_inEntryPoint, Vec3(0, 0, 0), "entryPoint", "Approx. entry point; closest node becomes the tree root")) + , d_outVTKFilename(initData(&d_outVTKFilename, "outputVTK", "File path to export the rooted tree (.vtk)")) + , d_outNodeCount(initData(&d_outNodeCount, 0, "nodeCount", "Number of skeleton nodes read")) +{ + addInput(&d_inSkeletonFilename); + addInput(&d_inVertices); + addInput(&d_inEntryPoint); + + addOutput(&d_outVTKFilename); + addOutput(&d_outNodeCount); +} + + +template +void SkeletonReader::init() +{ + if (d_inSkeletonFilename.getValue().empty()) + { + msg_error() << "No input skeleton file set, please set the 'filename' data."; + return; + } + update(); +} + + +template +void SkeletonReader::doUpdate() +{ + if (d_inSkeletonFilename.getFullPath().empty()) + return; + + if (!m_graph.loadFromFile(d_inSkeletonFilename.getFullPath())) + { + + msg_error() << "Could not open skeleton file: " << d_inSkeletonFilename.getFullPath(); + return; + } + + msg_info() << "Skeleton loaded: " << m_graph.nodes().size() << " node(s)."; + d_outNodeCount.setValue(static_cast(m_graph.nodes().size())); + + const Vec3& entry = d_inEntryPoint.getValue(); + m_graph.buildTree({ double(entry[0]), double(entry[1]), double(entry[2]) }); + + if (m_graph.hasRoot()) + msg_info() << "Tree built, root id " << m_graph.rootId() + << ", " << m_graph.loopEdges().size() << " loop edge(s) detected."; + + if (!d_inVertices.getValue().empty()) + { + std::vector> meshVerts; + meshVerts.reserve(d_inVertices.getValue().size()); + for (const auto& v : d_inVertices.getValue()) + meshVerts.push_back({ double(v[0]), double(v[1]), double(v[2]) }); + m_graph.computeMeshCorrespondence(meshVerts); + } + + if (d_outVTKFilename.isSet()) + m_graph.exportToVTK(d_outVTKFilename.getFullPath()); +} + + +template +void SkeletonReader::draw(const sofa::core::visual::VisualParams* vparams) +{ + using Color = sofa::type::RGBAColor; + std::vector< type::Vec3 > dvec; + + + for (const SkeletonNode& node : m_graph.nodes()) + { + for (int childId : node.childrenIds()) + { + const SkeletonNode& child = m_graph.nodes()[childId]; + const auto& p0 = node.position(); + const auto& p1 = child.position(); + + dvec.emplace_back(Coord(p0[0], p0[1], p0[2])); + dvec.emplace_back(Coord(p1[0], p1[1], p1[2])); + + vparams->drawTool()->drawLines(dvec, 2, Color::blue()); + dvec.clear(); + } + } +} + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h b/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h deleted file mode 100644 index 79101c5..0000000 --- a/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include - -namespace meshskeletonizationplugin -{ -template -class VesselTree -{ -public: - using Vertex = typename boost::graph_traits::vertex_descriptor; - using Edge = typename boost::graph_traits::edge_descriptor; - - template - Vertex findClosestVertex(const Graph& g, const Point3& p) const; - void build(const Graph& g, Vertex root); - - - void exportToSWC(const Graph& g, const std::string& filename) const; - void exportToVTK(const Graph& g, const std::string& filename) const; - - const std::map& parents() const { return m_parent; } - const std::map>& children() const { return m_children; } - const std::vector>& loopEdges() const { return m_loopEdges; } - Vertex root() const { return m_root; } - bool hasRoot() const { return m_hasRoot; } - std::vector subtree(Vertex node) const; - -private: - /// Stable sequential id per reached vertex, root always id 0. - std::map assignVertexIds() const; - - std::map m_parent; - std::map> m_children; - std::vector> m_loopEdges; - Vertex m_root{}; - bool m_hasRoot = false; -}; - -} // namespace meshskeletonizationplugin - -#include \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl b/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl deleted file mode 100644 index 316bcbe..0000000 --- a/src/MeshSkeletonizationPlugin/VesselTree/VesselTree.inl +++ /dev/null @@ -1,254 +0,0 @@ - -#pragma once - -#include - -#include -#include -#include -#include -#include - -namespace meshskeletonizationplugin -{ - -template -template -typename VesselTree::Vertex -VesselTree::findClosestVertex(const Graph& g, const Point3& p) const -{ - Vertex best{}; - double bestDist = std::numeric_limits::max(); - - for (const Vertex& v : boost::make_iterator_range(boost::vertices(g))) - { - const auto& s = g[v].point; - double dx = s[0] - p[0]; - double dy = s[1] - p[1]; - double dz = s[2] - p[2]; - double d2 = dx*dx + dy*dy + dz*dz; - if (d2 < bestDist) - { - bestDist = d2; - best = v; - } - } - return best; -} - - -template -void VesselTree::build(const Graph& g, Vertex root) -{ - m_parent.clear(); - m_children.clear(); - m_loopEdges.clear(); - - std::map visited; - std::queue q; - - m_root = root; - m_hasRoot = true; - visited[root] = true; - q.push(root); - - while (!q.empty()) - { - Vertex u = q.front(); - q.pop(); - - for (const Edge& e : boost::make_iterator_range(boost::out_edges(u, g))) - { - Vertex v = boost::target(e, g); - - if (!visited[v]) - { - visited[v] = true; - m_parent[v] = u; - m_children[u].push_back(v); - q.push(v); - } - else - { - // v already reached. Skip the edge we just arrived from; - // anything else is a real loop / anastomosis, not a tree edge. - auto itParentU = m_parent.find(u); - bool cameFromV = (itParentU != m_parent.end() && itParentU->second == v); - if (!cameFromV) - m_loopEdges.emplace_back(u, v); - } - } - } -} - - -template -std::map::Vertex, int> -VesselTree::assignVertexIds() const -{ - std::map vertexId; - if (!m_hasRoot) - return vertexId; - vertexId[m_root] = 0; - int nextId = 1; - for (const auto& kv : m_parent) - if (!vertexId.count(kv.first)) vertexId[kv.first] = nextId++; - return vertexId; -} - - -template -std::vector::Vertex> -VesselTree::subtree(Vertex node) const -{ - std::vector out{node}; - std::vector stack{node}; - while (!stack.empty()) - { - Vertex n = stack.back(); - stack.pop_back(); - auto it = m_children.find(n); - if (it != m_children.end()) - { - for (Vertex c : it->second) - { - out.push_back(c); - stack.push_back(c); - } - } - } - return out; -} - - -template -void VesselTree::exportToSWC(const Graph& g, const std::string& filename) const -{ - if (!m_hasRoot) - return; - - std::map vertexId = assignVertexIds(); - - std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); - out << "# id type x y z radius parent\n"; - for (const auto& loop : m_loopEdges) - { - int a = vertexId.at(loop.first); - int b = vertexId.at(loop.second); - if (a < b) // each undirected loop is recorded from both ends; write once - out << "# loop " << a << " " << b << "\n"; - } - - out << std::fixed << std::setprecision(6); - for (const auto& kv : vertexId) - { - Vertex v = kv.first; - int id = kv.second; - const auto& p = g[v].point; - - int deg = static_cast(boost::degree(v, g)); - int type = (v == m_root) ? 1 : (deg == 1 ? 6 : 5); // 1=root, 6=terminal, 5=branch/regular - - int parentId = -1; - auto itParent = m_parent.find(v); - if (itParent != m_parent.end()) - parentId = vertexId.at(itParent->second); - - out << id << " " << type << " " - << p[0] << " " << p[1] << " " << p[2] << " " - << 0.0 << " " << parentId << "\n"; - } -} - -template -void VesselTree::exportToVTK(const Graph& g, const std::string& filename) const -{ - if (!m_hasRoot) - return; - - std::map vertexId = assignVertexIds(); - - // depth(v) = number of edges from root, computed by walking each vertex's - // parent chain up to a vertex whose depth is already known (memoized). - std::map depth; - depth[m_root] = 0; - for (const auto& kv : vertexId) - { - Vertex v = kv.first; - if (depth.count(v)) continue; - std::vector path; - Vertex cur = v; - while (!depth.count(cur)) - { - path.push_back(cur); - auto it = m_parent.find(cur); - if (it == m_parent.end()) break; // only the root has no parent - cur = it->second; - } - int d = depth.count(cur) ? depth[cur] : 0; - for (auto it = path.rbegin(); it != path.rend(); ++it) - depth[*it] = ++d; - } - - // POINTS, in id order - std::vector orderedVerts(vertexId.size()); - for (const auto& kv : vertexId) - orderedVerts[kv.second] = kv.first; - - // LINES: tree edges (child -> parent) + deduplicated loop edges - std::vector> lines; - for (const auto& kv : m_parent) - lines.emplace_back(vertexId.at(kv.second), vertexId.at(kv.first)); - - std::vector isLoop(lines.size(), 0); - for (const auto& loop : m_loopEdges) - { - int a = vertexId.at(loop.first); - int b = vertexId.at(loop.second); - if (a < b) - { - lines.emplace_back(a, b); - isLoop.push_back(1); - } - } - - std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); - out << "# vtk DataFile Version 3.0\n"; - out << "Vessel tree (VesselTree module)\n"; - out << "ASCII\n"; - out << "DATASET POLYDATA\n"; - - out << "POINTS " << orderedVerts.size() << " float\n"; - out << std::fixed << std::setprecision(6); - for (Vertex v : orderedVerts) - { - const auto& p = g[v].point; - out << p[0] << " " << p[1] << " " << p[2] << "\n"; - } - - out << "LINES " << lines.size() << " " << (lines.size() * 3) << "\n"; - for (const auto& l : lines) - out << "2 " << l.first << " " << l.second << "\n"; - - out << "POINT_DATA " << orderedVerts.size() << "\n"; - out << "SCALARS type int 1\n"; - out << "LOOKUP_TABLE default\n"; - for (Vertex v : orderedVerts) - { - int deg = static_cast(boost::degree(v, g)); - int type = (v == m_root) ? 1 : (deg == 1 ? 6 : 5); // 1=root, 5=branch, 6=terminal - out << type << "\n"; - } - out << "SCALARS depth int 1\n"; - out << "LOOKUP_TABLE default\n"; - for (Vertex v : orderedVerts) - out << depth[v] << "\n"; - - out << "CELL_DATA " << lines.size() << "\n"; - out << "SCALARS is_loop int 1\n"; - out << "LOOKUP_TABLE default\n"; - for (int flag : isLoop) - out << flag << "\n"; -} - -} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/init.cpp b/src/MeshSkeletonizationPlugin/init.cpp index aeec420..6527428 100644 --- a/src/MeshSkeletonizationPlugin/init.cpp +++ b/src/MeshSkeletonizationPlugin/init.cpp @@ -28,7 +28,8 @@ namespace meshskeletonizationplugin { extern void registerMeshSkeletonization(sofa::core::ObjectFactory* factory); -extern void registerSkeletonizationLoader(sofa::core::ObjectFactory* factory); +//extern void registerSkeletonizationLoader(sofa::core::ObjectFactory* factory); +extern void registerSkeletonReader(sofa::core::ObjectFactory* factory); //Here are just several convenient functions to help users know what the plugin contains extern "C" { @@ -80,7 +81,8 @@ void init() void registerObjects(sofa::core::ObjectFactory* factory) { registerMeshSkeletonization(factory); - registerSkeletonizationLoader(factory); + // registerSkeletonizationLoader(factory); + registerSkeletonReader(factory); } } From f8c458013d0ee18d47816c706f0d14f7ae813a9f Mon Sep 17 00:00:00 2001 From: Kamelia Date: Fri, 7 Aug 2026 15:59:10 +0200 Subject: [PATCH 03/12] [Addition to the component] Creation of new methods and export of csv file that has the needed data --- .gitignore | 4 +- .../SkeletonGraph/SkeletonGraph.cpp | 99 +++++++++++++++++++ .../SkeletonGraph/SkeletonGraph.h | 7 ++ .../SkeletonGraph/SkeletonReader.h | 1 + .../SkeletonGraph/SkeletonReader.inl | 5 + 5 files changed, 115 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 05b678c..bfad0a3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ .gitignore *.vtk *.obj -*.sxn \ No newline at end of file +*.sxn +*.scn +*.csv \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp index b9295c7..6621ded 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp @@ -295,4 +295,103 @@ void SkeletonGraph::exportToVTK(const std::string& filename) const out << flag << "\n"; } +const SkeletonNode* SkeletonGraph::node(int nodeId) const +{ + if (nodeId < 0 || nodeId >= static_cast(m_nodes.size())) + return nullptr; + return &m_nodes[nodeId]; +} +const std::vector& SkeletonGraph::parentsOf(int nodeId) const +{ + static const std::vector empty; + const SkeletonNode* n = node(nodeId); + return n ? n->parentIds() : empty; +} + +const std::vector& SkeletonGraph::childrenOf(int nodeId) const +{ + static const std::vector empty; + const SkeletonNode* n = node(nodeId); + return n ? n->childrenIds() : empty; +} + + +std::vector SkeletonGraph::pathFromRoot(int nodeId) const +{ + std::vector path; + if (!hasRoot() || node(nodeId) == nullptr) return path; + + std::set seen; + int cur = nodeId; + while (true) + { + if (!seen.insert(cur).second) { path.clear(); return path; } + path.push_back(cur); + if (cur == m_rootId) break; + const auto& parents = parentsOf(cur); + if (parents.empty()) return {}; + cur = parents.front(); + } + std::reverse(path.begin(), path.end()); + return path; +} +std::vector SkeletonGraph::subtree(int nodeId) const +{ + std::vector result; + if (node(nodeId) == nullptr) return result; + + std::set visited; + std::queue q; + q.push(nodeId); visited.insert(nodeId); + + while (!q.empty()) + { + int cur = q.front(); q.pop(); + result.push_back(cur); + for (int child : childrenOf(cur)) + if (visited.insert(child).second) q.push(child); + } + return result; +} +static std::string joinIds(const std::vector& ids) +{ + std::string s; + for (size_t i = 0; i < ids.size(); ++i) + { + if (i > 0) s += ";"; + s += std::to_string(ids[i]); + } + return s; +} + +void SkeletonGraph::exportReportCSV(const std::string& filename) const +{ + if (!hasRoot()) + return; + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "id,x,y,z,parentId,childrenIds,pathFromRoot,loopParentIds\n"; + out << std::fixed << std::setprecision(6); + + for (const SkeletonNode& n : m_nodes) + { + const auto& p = n.position(); + const auto& parents = n.parentIds(); + + int primaryParent = parents.empty() ? -1 : parents.front(); + + std::vector loopParents; + if (parents.size() > 1) + loopParents.assign(parents.begin() + 1, parents.end()); + + std::vector path = pathFromRoot(n.id()); + + out << n.id() << "," + << p[0] << "," << p[1] << "," << p[2] << "," + << primaryParent << "," + << "\"" << joinIds(n.childrenIds()) << "\"," + << "\"" << joinIds(path) << "\"," + << "\"" << joinIds(loopParents) << "\"\n"; + } +} } // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h index 6c084fc..f1d6ed0 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h @@ -41,6 +41,13 @@ class SkeletonGraph /// Ids of nodes connected by a loop/anastomosis (extra edge beyond the tree). const std::vector>& loopEdges() const { return m_loopEdges; } + //newzest additions + const SkeletonNode* node(int nodeId) const; + const std::vector& parentsOf(int nodeId) const; + const std::vector& childrenOf(int nodeId) const; + std::vector pathFromRoot(int nodeId) const; + std::vector subtree(int nodeId) const; + void exportReportCSV(const std::string& filename) const; void exportToVTK(const std::string& filename) const; diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h index 5fbaf59..ad90806 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h @@ -40,6 +40,7 @@ class SkeletonReader : public sofa::core::DataEngine sofa::core::objectmodel::DataFileName d_inSkeletonFilename; ///< Path to the skeleton polyline file to read (e.g. skeleton.txt) sofa::core::objectmodel::Data d_inVertices; ///< Optional input mesh vertices, to link skeleton nodes to the mesh sofa::core::objectmodel::Data d_inEntryPoint; ///< Approx. entry point; closest node becomes the tree root + sofa::core::objectmodel::DataFileName d_outReportFilename; /// CSV report that guves out the ide, 3D coordinates, parent vertice and child vertice // Outputs sofa::core::objectmodel::DataFileName d_outVTKFilename; ///< File path to (re-)export the rooted tree as VTK diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl index 5996228..594fecc 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl @@ -13,6 +13,7 @@ SkeletonReader::SkeletonReader() , d_inVertices(initData(&d_inVertices, "inputVertices", "Optional input mesh vertices, to link skeleton nodes to the mesh")) , d_inEntryPoint(initData(&d_inEntryPoint, Vec3(0, 0, 0), "entryPoint", "Approx. entry point; closest node becomes the tree root")) , d_outVTKFilename(initData(&d_outVTKFilename, "outputVTK", "File path to export the rooted tree (.vtk)")) + , d_outReportFilename(initData(&d_outReportFilename, "outputReport", "File path to export a per-node CSV report (id, x, y, z, parentId, childrenIds, pathFromRoot)")) , d_outNodeCount(initData(&d_outNodeCount, 0, "nodeCount", "Number of skeleton nodes read")) { addInput(&d_inSkeletonFilename); @@ -20,6 +21,7 @@ SkeletonReader::SkeletonReader() addInput(&d_inEntryPoint); addOutput(&d_outVTKFilename); + addOutput(&d_outReportFilename); addOutput(&d_outNodeCount); } @@ -70,6 +72,9 @@ void SkeletonReader::doUpdate() if (d_outVTKFilename.isSet()) m_graph.exportToVTK(d_outVTKFilename.getFullPath()); + + if (d_outReportFilename.isSet()) + m_graph.exportReportCSV(d_outReportFilename.getFullPath()); } From fa0a675f4d995508dfe348478b4c3c6e11dc1995 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Fri, 7 Aug 2026 15:59:10 +0200 Subject: [PATCH 04/12] [Addition to the component] Creation of new methods and export of csv file that has the needed data --- .gitignore | 4 +- .../SkeletonGraph/SkeletonGraph.cpp | 99 +++++++++++++++++++ .../SkeletonGraph/SkeletonGraph.h | 7 ++ .../SkeletonGraph/SkeletonReader.h | 1 + .../SkeletonGraph/SkeletonReader.inl | 7 +- 5 files changed, 115 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 6f3c781..a0999f1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ .gitignore *.vtk *.obj -*.sxn \ No newline at end of file +*.sxn +*.scn +*.csv \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp index b9295c7..6621ded 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp @@ -295,4 +295,103 @@ void SkeletonGraph::exportToVTK(const std::string& filename) const out << flag << "\n"; } +const SkeletonNode* SkeletonGraph::node(int nodeId) const +{ + if (nodeId < 0 || nodeId >= static_cast(m_nodes.size())) + return nullptr; + return &m_nodes[nodeId]; +} +const std::vector& SkeletonGraph::parentsOf(int nodeId) const +{ + static const std::vector empty; + const SkeletonNode* n = node(nodeId); + return n ? n->parentIds() : empty; +} + +const std::vector& SkeletonGraph::childrenOf(int nodeId) const +{ + static const std::vector empty; + const SkeletonNode* n = node(nodeId); + return n ? n->childrenIds() : empty; +} + + +std::vector SkeletonGraph::pathFromRoot(int nodeId) const +{ + std::vector path; + if (!hasRoot() || node(nodeId) == nullptr) return path; + + std::set seen; + int cur = nodeId; + while (true) + { + if (!seen.insert(cur).second) { path.clear(); return path; } + path.push_back(cur); + if (cur == m_rootId) break; + const auto& parents = parentsOf(cur); + if (parents.empty()) return {}; + cur = parents.front(); + } + std::reverse(path.begin(), path.end()); + return path; +} +std::vector SkeletonGraph::subtree(int nodeId) const +{ + std::vector result; + if (node(nodeId) == nullptr) return result; + + std::set visited; + std::queue q; + q.push(nodeId); visited.insert(nodeId); + + while (!q.empty()) + { + int cur = q.front(); q.pop(); + result.push_back(cur); + for (int child : childrenOf(cur)) + if (visited.insert(child).second) q.push(child); + } + return result; +} +static std::string joinIds(const std::vector& ids) +{ + std::string s; + for (size_t i = 0; i < ids.size(); ++i) + { + if (i > 0) s += ";"; + s += std::to_string(ids[i]); + } + return s; +} + +void SkeletonGraph::exportReportCSV(const std::string& filename) const +{ + if (!hasRoot()) + return; + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "id,x,y,z,parentId,childrenIds,pathFromRoot,loopParentIds\n"; + out << std::fixed << std::setprecision(6); + + for (const SkeletonNode& n : m_nodes) + { + const auto& p = n.position(); + const auto& parents = n.parentIds(); + + int primaryParent = parents.empty() ? -1 : parents.front(); + + std::vector loopParents; + if (parents.size() > 1) + loopParents.assign(parents.begin() + 1, parents.end()); + + std::vector path = pathFromRoot(n.id()); + + out << n.id() << "," + << p[0] << "," << p[1] << "," << p[2] << "," + << primaryParent << "," + << "\"" << joinIds(n.childrenIds()) << "\"," + << "\"" << joinIds(path) << "\"," + << "\"" << joinIds(loopParents) << "\"\n"; + } +} } // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h index 6c084fc..f1d6ed0 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h @@ -41,6 +41,13 @@ class SkeletonGraph /// Ids of nodes connected by a loop/anastomosis (extra edge beyond the tree). const std::vector>& loopEdges() const { return m_loopEdges; } + //newzest additions + const SkeletonNode* node(int nodeId) const; + const std::vector& parentsOf(int nodeId) const; + const std::vector& childrenOf(int nodeId) const; + std::vector pathFromRoot(int nodeId) const; + std::vector subtree(int nodeId) const; + void exportReportCSV(const std::string& filename) const; void exportToVTK(const std::string& filename) const; diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h index 14aceb0..e35a8a1 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h @@ -39,6 +39,7 @@ class SkeletonReader : public sofa::core::DataEngine sofa::core::objectmodel::DataFileName d_inSkeletonFilename; ///< Path to the skeleton polyline file to read (e.g. skeleton.txt) sofa::core::objectmodel::Data d_inVertices; ///< Optional input mesh vertices, to link skeleton nodes to the mesh sofa::core::objectmodel::Data d_inEntryPoint; ///< Approx. entry point; closest node becomes the tree root + sofa::core::objectmodel::DataFileName d_outReportFilename; /// CSV report that guves out the ide, 3D coordinates, parent vertice and child vertice // Outputs diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl index ad0395b..c463e65 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl @@ -13,6 +13,7 @@ SkeletonReader::SkeletonReader() , d_inVertices(initData(&d_inVertices, "inputVertices", "Optional input mesh vertices, to link skeleton nodes to the mesh")) , d_inEntryPoint(initData(&d_inEntryPoint, Vec3(0, 0, 0), "entryPoint", "Approx. entry point; closest node becomes the tree root")) , d_outVTKFilename(initData(&d_outVTKFilename, "outputVTK", "File path to export the rooted tree (.vtk)")) + , d_outReportFilename(initData(&d_outReportFilename, "outputReport", "File path to export a per-node CSV report (id, x, y, z, parentId, childrenIds, pathFromRoot)")) , d_outNodeCount(initData(&d_outNodeCount, 0, "nodeCount", "Number of skeleton nodes read")) { addInput(&d_inSkeletonFilename); @@ -21,6 +22,7 @@ SkeletonReader::SkeletonReader() addOutput(&d_outVTKFilename); + addOutput(&d_outReportFilename); addOutput(&d_outNodeCount); } @@ -88,8 +90,9 @@ void SkeletonReader::doUpdate() if (d_outVTKFilename.isSet()) m_graph.exportToVTK(d_outVTKFilename.getFullPath()); - - + + if (d_outReportFilename.isSet()) + m_graph.exportReportCSV(d_outReportFilename.getFullPath()); } From 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 Mon Sep 17 00:00:00 2001 From: bouamarakamelia Date: Thu, 13 Aug 2026 13:33:48 +0200 Subject: [PATCH 05/12] Update src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp Co-authored-by: erik pernod --- .../SkeletonGraph/SkeletonGraph.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp index 6621ded..8913fe7 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp @@ -301,11 +301,16 @@ const SkeletonNode* SkeletonGraph::node(int nodeId) const return nullptr; return &m_nodes[nodeId]; } -const std::vector& SkeletonGraph::parentsOf(int nodeId) const +bool SkeletonGraph::parentsOf(int nodeId, std::vector& parents) const { - static const std::vector empty; const SkeletonNode* n = node(nodeId); - return n ? n->parentIds() : empty; + if n->parentIds() + { + parents = n; + return true; + } + else + return false; } const std::vector& SkeletonGraph::childrenOf(int nodeId) const From 32668d2da67faab491a752c61a5dcafbd71fb992 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Thu, 13 Aug 2026 15:10:36 +0200 Subject: [PATCH 06/12] Correction of the issues in the code and addition of the needed comments --- .gitignore | 8 ++-- .../SkeletonGraph/SkeletonGraph.cpp | 43 +++++++++++++------ .../SkeletonGraph/SkeletonGraph.h | 8 ++-- .../SkeletonGraph/SkeletonReader.h | 19 +++----- 4 files changed, 40 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index bfad0a3..744262a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -/data/ +/data/Veins_data/ +/data/LnRobsData/ /scenes/ .gitignore *.vtk -*.obj -*.sxn -*.scn -*.csv \ No newline at end of file +*.obj \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp index 6621ded..2c650e4 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp @@ -301,26 +301,38 @@ const SkeletonNode* SkeletonGraph::node(int nodeId) const return nullptr; return &m_nodes[nodeId]; } -const std::vector& SkeletonGraph::parentsOf(int nodeId) const + + +bool SkeletonGraph::parentsOf(int nodeId, std::vector& parents) const { - static const std::vector empty; + parents.clear(); + const SkeletonNode* n = node(nodeId); - return n ? n->parentIds() : empty; + if (n == nullptr || n->parentIds().empty()) + return false; + + parents = n->parentIds(); + return true; } - -const std::vector& SkeletonGraph::childrenOf(int nodeId) const + +bool SkeletonGraph::childrenOf(int nodeId, std::vector& children) const { - static const std::vector empty; + children.clear(); + const SkeletonNode* n = node(nodeId); - return n ? n->childrenIds() : empty; + if (n == nullptr || n->childrenIds().empty()) + return false; + + children = n->childrenIds(); + return true; } - std::vector SkeletonGraph::pathFromRoot(int nodeId) const { std::vector path; if (!hasRoot() || node(nodeId) == nullptr) return path; + std::vector parents; std::set seen; int cur = nodeId; while (true) @@ -328,8 +340,7 @@ std::vector SkeletonGraph::pathFromRoot(int nodeId) const if (!seen.insert(cur).second) { path.clear(); return path; } path.push_back(cur); if (cur == m_rootId) break; - const auto& parents = parentsOf(cur); - if (parents.empty()) return {}; + if (!parentsOf(cur, parents)) { path.clear(); return path; } cur = parents.front(); } std::reverse(path.begin(), path.end()); @@ -339,17 +350,21 @@ std::vector SkeletonGraph::subtree(int nodeId) const { std::vector result; if (node(nodeId) == nullptr) return result; - + + std::vector children; std::set visited; std::queue q; q.push(nodeId); visited.insert(nodeId); - + while (!q.empty()) { int cur = q.front(); q.pop(); result.push_back(cur); - for (int child : childrenOf(cur)) - if (visited.insert(child).second) q.push(child); + if (childrenOf(cur, children)) + { + for (int child : children) + if (visited.insert(child).second) q.push(child); + } } return result; } diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h index f1d6ed0..6b0cc62 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h @@ -43,14 +43,12 @@ class SkeletonGraph const std::vector>& loopEdges() const { return m_loopEdges; } //newzest additions const SkeletonNode* node(int nodeId) const; - const std::vector& parentsOf(int nodeId) const; - const std::vector& childrenOf(int nodeId) const; + bool parentsOf(int nodeId, std::vector& parents) const; + bool childrenOf(int nodeId, std::vector& children) const; std::vector pathFromRoot(int nodeId) const; std::vector subtree(int nodeId) const; - void exportReportCSV(const std::string& filename) const; - + void exportReportCSV(const std::string& filename) const; //< export CSV report using @sa d_outReportFilename that will give out the ids, 3D coordinates, parent vertex and child vertex void exportToVTK(const std::string& filename) const; - void clear(); private: diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h index ad90806..7341022 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h @@ -16,15 +16,6 @@ using namespace sofa::defaulttype; namespace meshskeletonizationplugin { -/// Reads a skeleton polyline file (the "skeleton.txt" format written by -/// MeshSkeletonization / SkeletonizationLoader's Export_polylines) and stores -/// it as a SkeletonGraph: a list of SkeletonNode, each with its id, parent -/// ids, children ids, and - if an input mesh is provided - its correspondence -/// to the closest mesh vertex. -/// -/// This component does not need CGAL: it only re-reads an already-exported -/// polyline file, so it can be used purely as a downstream consumer of -/// MeshSkeletonization/SkeletonizationLoader's output. template class SkeletonReader : public sofa::core::DataEngine { @@ -40,7 +31,7 @@ class SkeletonReader : public sofa::core::DataEngine sofa::core::objectmodel::DataFileName d_inSkeletonFilename; ///< Path to the skeleton polyline file to read (e.g. skeleton.txt) sofa::core::objectmodel::Data d_inVertices; ///< Optional input mesh vertices, to link skeleton nodes to the mesh sofa::core::objectmodel::Data d_inEntryPoint; ///< Approx. entry point; closest node becomes the tree root - sofa::core::objectmodel::DataFileName d_outReportFilename; /// CSV report that guves out the ide, 3D coordinates, parent vertice and child vertice + sofa::core::objectmodel::DataFileName d_outReportFilename; /// CSV report that gives out the ids, 3D coordinates, parent vertex and child vertex // Outputs sofa::core::objectmodel::DataFileName d_outVTKFilename; ///< File path to (re-)export the rooted tree as VTK @@ -50,14 +41,14 @@ class SkeletonReader : public sofa::core::DataEngine /// via getContext()->get>()->graph(). const SkeletonGraph& graph() const { return m_graph; } + void init() override; + void doUpdate() override; + void draw(const sofa::core::visual::VisualParams* vparams) override; + private: SkeletonReader(); virtual ~SkeletonReader() = default; - void init() override; - void doUpdate() override; - - void draw(const sofa::core::visual::VisualParams* vparams) override; SkeletonGraph m_graph; }; From 06bcc7e7a6c684a893805355143e696c6c654420 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Thu, 13 Aug 2026 15:28:11 +0200 Subject: [PATCH 07/12] small fix to SkeletonReader.h --- src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h index 7341022..47d2829 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.h @@ -19,6 +19,7 @@ namespace meshskeletonizationplugin template class SkeletonReader : public sofa::core::DataEngine { + public: SOFA_CLASS(SOFA_TEMPLATE(SkeletonReader, DataTypes), sofa::core::DataEngine); From 5a02b3ee77b7ad01590b5c1514a4ee40c0a223a3 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Sun, 16 Aug 2026 21:58:10 +0200 Subject: [PATCH 08/12] Removing conflicts --- scenes/BeamFEMSkeleton.scn | 7 +- .../SkeletonGraph/SkeletonReader.inl | 93 +++---------------- 2 files changed, 12 insertions(+), 88 deletions(-) diff --git a/scenes/BeamFEMSkeleton.scn b/scenes/BeamFEMSkeleton.scn index 9c86bd9..b827dab 100644 --- a/scenes/BeamFEMSkeleton.scn +++ b/scenes/BeamFEMSkeleton.scn @@ -12,12 +12,7 @@ - + diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl index 93dfb34..bbf5495 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonReader.inl @@ -1,5 +1,4 @@ #pragma once -<<<<<<< HEAD #include @@ -7,17 +6,6 @@ using namespace sofa::core::objectmodel; namespace meshskeletonizationplugin { - -======= -#include -using namespace sofa::core::objectmodel; - - -namespace meshskeletonizationplugin -{ - - ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 template SkeletonReader::SkeletonReader() : d_inSkeletonFilename(initData(&d_inSkeletonFilename, "filename", "Skeleton polyline file to read (e.g. skeleton.txt)")) @@ -30,11 +18,6 @@ SkeletonReader::SkeletonReader() addInput(&d_inSkeletonFilename); addInput(&d_inVertices); addInput(&d_inEntryPoint); - -<<<<<<< HEAD -======= - ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 addOutput(&d_outVTKFilename); addOutput(&d_outReportFilename); addOutput(&d_outNodeCount); @@ -47,10 +30,7 @@ void SkeletonReader::init() if (d_inSkeletonFilename.getValue().empty()) { msg_error() << "No input skeleton file set, please set the 'filename' data."; -<<<<<<< HEAD -======= d_componentState.setValue(ComponentState::Invalid); ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 return; } update(); @@ -60,63 +40,37 @@ void SkeletonReader::init() template void SkeletonReader::doUpdate() { -<<<<<<< HEAD if (d_inSkeletonFilename.getFullPath().empty()) - return; - - if (!m_graph.loadFromFile(d_inSkeletonFilename.getFullPath())) { - - msg_error() << "Could not open skeleton file: " << d_inSkeletonFilename.getFullPath(); - return; - } - - msg_info() << "Skeleton loaded: " << m_graph.nodes().size() << " node(s)."; - d_outNodeCount.setValue(static_cast(m_graph.nodes().size())); - - const Vec3& entry = d_inEntryPoint.getValue(); - m_graph.buildTree({ double(entry[0]), double(entry[1]), double(entry[2]) }); - -======= - if (d_inSkeletonFilename.getFullPath().empty()){ d_componentState.setValue(ComponentState::Invalid); return; } if (!m_graph.loadFromFile(d_inSkeletonFilename.getFullPath())) { - msg_error() << "Could not open skeleton file: " << d_inSkeletonFilename.getFullPath(); d_componentState.setValue(ComponentState::Invalid); return; } - msg_info() << "Skeleton loaded: " << m_graph.nodes().size() << " node(s)."; d_outNodeCount.setValue(static_cast(m_graph.nodes().size())); - const Vec3& entry = d_inEntryPoint.getValue(); m_graph.buildTree({ double(entry[0]), double(entry[1]), double(entry[2]) }); - if (!m_graph.hasRoot()) { - - + // The file parsed but produced no usable rooted tree, so every + // downstream output would be empty. msg_error() << "No root could be established from: " << d_inSkeletonFilename.getFullPath(); d_componentState.setValue(ComponentState::Invalid); return; } ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 - if (m_graph.hasRoot()) - msg_info() << "Tree built, root id " << m_graph.rootId() - << ", " << m_graph.loopEdges().size() << " loop edge(s) detected."; -<<<<<<< HEAD -======= + msg_info() << "Tree built, root id " << m_graph.rootId() + << ", " << m_graph.loopEdges().size() << " loop edge(s) detected."; ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 if (!d_inVertices.getValue().empty()) { std::vector> meshVerts; @@ -126,35 +80,24 @@ void SkeletonReader::doUpdate() m_graph.computeMeshCorrespondence(meshVerts); } -<<<<<<< HEAD -======= - ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 if (d_outVTKFilename.isSet()) m_graph.exportToVTK(d_outVTKFilename.getFullPath()); - + if (d_outReportFilename.isSet()) m_graph.exportReportCSV(d_outReportFilename.getFullPath()); -} - -<<<<<<< HEAD -======= + d_componentState.setValue(ComponentState::Valid); +} ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 template void SkeletonReader::draw(const sofa::core::visual::VisualParams* vparams) { + if (d_componentState.getValue() != ComponentState::Valid) + return; + using Color = sofa::type::RGBAColor; std::vector< type::Vec3 > dvec; -<<<<<<< HEAD - - -======= - - ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 for (const SkeletonNode& node : m_graph.nodes()) { for (int childId : node.childrenIds()) @@ -163,26 +106,12 @@ void SkeletonReader::draw(const sofa::core::visual::VisualParams* vpa const auto& p0 = node.position(); const auto& p1 = child.position(); -<<<<<<< HEAD - dvec.emplace_back(Coord(p0[0], p0[1], p0[2])); - dvec.emplace_back(Coord(p1[0], p1[1], p1[2])); - -======= - dvec.emplace_back(Coord(p0[0], p0[1], p0[2])); dvec.emplace_back(Coord(p1[0], p1[1], p1[2])); - - ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 vparams->drawTool()->drawLines(dvec, 2, Color::blue()); dvec.clear(); } } } -<<<<<<< HEAD -} // namespace meshskeletonizationplugin -======= - -} // namespace meshskeletonizationplugin ->>>>>>> 6ed8f1f42d6cc1dec475c6b71b62c28f161ebad3 +} // namespace meshskeletonizationplugin \ No newline at end of file From 500aff7f38a738df88344da02a50d7b8bb797c57 Mon Sep 17 00:00:00 2001 From: Kamelia Date: Mon, 24 Aug 2026 12:08:44 +0200 Subject: [PATCH 09/12] Addition of new component to mimic segmentectomy --- CMakeLists.txt | 8 +- .../Patient_08_venoussystem_skeleton.txt | 1330 +++++++++++++++++ .../SegmentMapping/SkeletonSegmentMapper.cpp | 22 + .../SegmentMapping/SkeletonSegmentMapper.h | 79 + .../SegmentMapping/SkeletonSegmentMapper.inl | 273 ++++ .../SkeletonGraph/SkeletonGraph.cpp | 288 ++++ .../SkeletonGraph/SkeletonGraph.h | 67 + .../SkeletonGraph/SkeletonNode.h | 2 - .../SkeletonResectionSimulator.cpp | 22 + .../SkeletonResectionSimulator.h | 95 ++ .../SkeletonResectionSimulator.inl | 269 ++++ src/MeshSkeletonizationPlugin/init.cpp | 6 +- 12 files changed, 2456 insertions(+), 5 deletions(-) create mode 100644 data/patient_08/Patient_08_venoussystem_skeleton.txt create mode 100644 src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.cpp create mode 100644 src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.h create mode 100644 src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.inl create mode 100644 src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.cpp create mode 100644 src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.h create mode 100644 src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.inl diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b0951f..1dc5547 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,14 +18,18 @@ set(HEADER_FILES ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonGraph.h ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonReader.h ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonReader.inl + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SegmentMapping/SkeletonSegmentMapper.inl + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SegmentMapping/SkeletonSegmentMapper.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonResection/SkeletonResectionSimulator.h + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonResection/SkeletonResectionSimulator.inl ) set(SOURCE_FILES ${PLUGIN_SKELETONIZATION_SRC_DIR}/init.cpp ${PLUGIN_SKELETONIZATION_SRC_DIR}/MeshSkeletonization.cpp ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonGraph.cpp ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonGraph/SkeletonReader.cpp - - + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SegmentMapping/SkeletonSegmentMapper.cpp + ${PLUGIN_SKELETONIZATION_SRC_DIR}/SkeletonResection/SkeletonResectionSimulator.cpp ) set(README_FILES README.md) diff --git a/data/patient_08/Patient_08_venoussystem_skeleton.txt b/data/patient_08/Patient_08_venoussystem_skeleton.txt new file mode 100644 index 0000000..e824fde --- /dev/null +++ b/data/patient_08/Patient_08_venoussystem_skeleton.txt @@ -0,0 +1,1330 @@ +124.847 84.4897 34.42 +124.929 84.5022 34.5772 +125.643 84.5831 35.8539 +125.901 84.7885 37.7116 + +123.042 88.3776 54.5085 +123.214 88.515 55.2484 + +194.212 110.69 160.864 +193.643 111.415 161.304 +192.833 112.434 161.934 +192.446 112.91 162.239 +191.02 114.77 163.445 +191.85 115.854 164.196 + +65.8874 136.055 49.1372 +66.6845 135.002 50.0835 +66.8917 134.726 50.3257 +68.0989 133.096 51.7116 +69.0322 131.751 52.7607 +70.0813 130.187 53.8771 +70.8367 128.629 54.3381 +71.6768 126.994 55.2105 +72.1984 126.006 55.8317 +72.5729 125.076 56.1057 +73.9801 119.509 57.1376 + +78.071 158.086 59.845 +78.1325 157.866 60.8743 +78.2282 157.485 62.6068 +78.3101 157.142 64.1188 +78.3664 156.924 65.3104 +78.392 156.826 65.8751 +78.4147 156.996 67.9795 + +60.2039 155.341 71.6785 +60.3399 155.33 72.5722 +60.4304 155.324 73.1424 +60.7675 155.323 75.1102 +61.0034 155.266 77.2087 +61.0796 155.278 78.0135 +61.1706 155.428 79.4894 +61.0173 156.758 81.4062 + +137.163 85.092 74.5876 +137.006 85.1093 75.4299 +136.791 85.1271 76.6176 +136.37 85.1386 78.9678 +136.104 85.3324 82.2544 +136.513 85.7459 84.3486 +136.749 85.9748 85.5818 +136.82 86.2036 87.085 +137.913 86.9824 90.8748 + +104.1 86.5675 70.8634 +102.958 88.3178 71.4794 +102.37 89.953 72.9031 + +59.6024 138.075 81.831 +59.6619 138.109 81.8917 +60.5798 138.655 82.7245 +62.2433 139.653 84.0144 +63.8185 140.449 84.9221 +64.7391 140.795 85.3336 +67.2101 141.299 86.6562 + +125.457 106.864 158.045 +122.632 103.734 149.272 + +125.457 106.864 158.045 +126.737 109.082 159.321 +127.961 111.187 161.484 +128.532 112.153 162.541 +128.794 112.596 163.027 +129.14 113.18 163.665 +129.586 113.948 164.516 +130.03 114.817 165.447 +130.227 116.673 167.898 + +125.457 106.864 158.045 +124.617 105.028 158.788 +124.534 103.932 160.485 +124.681 103.259 161.692 +124.875 102.132 163.675 +124.889 101.083 165.303 +124.797 99.7985 167.085 +124.613 98.9346 168.069 +124.491 98.4369 168.659 + +84.9269 179.043 85.5297 +84.9876 178.452 86.3632 +85.1387 176.786 88.6976 +85.222 175.019 91.0726 +85.2864 173.549 93.0427 +85.3214 172.774 94.0817 +85.3519 172.048 95.0576 +85.4086 170.568 97.0421 +84.8833 168.875 99.1214 +84.3757 167.435 100.86 +83.7539 165.739 102.859 +82.7873 163.469 105.302 +81.7354 162.01 107.086 +81.0079 160.186 108.87 +78.5962 158.884 111.503 + +148.79 75.3299 87.1424 +148.406 75.6382 87.7389 +147.667 76.2275 88.8712 +147.3 76.5477 89.5006 +146.747 77.2283 90.9686 +146.403 77.6623 91.9134 +145.849 78.3654 93.4483 +145.587 78.7011 94.1836 +145.321 79.0457 94.943 +144.671 80.0604 97.4016 +144.557 80.7497 99.5844 +144.551 81.1474 100.942 +143.789 82.3533 103.716 + +61.0173 156.758 81.4062 +60.0179 160.838 81.2346 +59.3482 163.105 80.9458 +58.9502 164.585 80.7231 +58.9488 164.591 80.7222 +58.947 164.597 80.721 + +61.0173 156.758 81.4062 +61.5186 155.006 82.5176 +61.7994 153.031 84.8869 +63.3386 151.021 85.3607 +64.6575 149.411 85.8313 +66.0364 147.811 86.2995 +68.073 144.339 87.0143 +67.2101 141.299 86.6562 + +90.7024 140.89 85.4398 +90.4432 141.064 85.4101 +89.0715 141.99 85.2423 +88.2669 142.511 85.1326 +86.9446 143.145 84.862 +85.5599 143.709 84.6407 +82.6381 144.087 84.6342 +80.3282 144.293 84.7584 + +142.957 87.784 89.5012 +142.26 87.6998 89.5785 +140.827 87.4643 89.6202 +137.913 86.9824 90.8748 + +115.064 95.1406 94.0754 +114.321 98.0252 95.5105 + +115.064 95.1406 94.0754 +116.119 93.7546 97.1936 +116.302 93.6433 97.997 +116.924 93.3885 99.9499 +117.469 93.0765 101.913 +118.322 92.695 103.737 +118.684 92.5415 104.437 +119.342 92.1358 105.522 +121.308 90.1466 110.362 + +115.064 95.1406 94.0754 +114.826 94.7176 92.168 +114.245 94.4389 88.7568 +113.874 94.0078 86.2572 +113.015 93.611 83.2099 +112.247 93.2826 80.8076 +108.779 92.0873 75.342 + +83.0616 116.469 101.194 +83.0746 116.601 101.15 +83.1327 117.256 100.923 +83.2576 118.403 100.523 +83.4035 119.602 100.087 +83.7359 121.925 99.2861 +83.2766 125.401 96.3324 + +60.1339 110.395 99.8877 +60.0678 110.68 100.002 +59.8273 111.751 100.435 +59.5351 113.299 101.053 +59.2226 114.997 101.732 +58.9327 116.846 102.464 +59.3508 118.136 103.057 +60.5475 121.632 104.644 +61.615 124.739 106.053 +61.8904 125.528 106.403 +62.4854 127.186 107.098 +63.0756 128.838 107.795 +63.7248 130.624 108.502 +64.17 131.873 108.995 +64.5734 133.253 109.473 +64.0551 135.842 109.722 +65.7557 138.894 109.509 + +90.3733 123.382 100.082 +88.3308 124.128 99.6338 +87.6055 124.725 99.4783 +85.4958 125.715 98.3503 +83.2766 125.401 96.3324 + +105.728 86.0623 102.144 +105.763 86.9818 103.358 +106.349 88.3762 105.107 +106.883 89.5362 106.576 +105.863 91.6136 109.516 + +59.0806 172.943 102.879 +59.6145 172.107 103.97 +60.5768 170.592 105.928 +61.0244 169.905 106.777 +61.5277 169.14 107.71 +62.047 168.265 108.807 +62.5938 167.02 110.478 +65.2745 163.976 113.788 + +75.289 183.143 109.052 +75.2835 182.848 109.515 + +123.214 88.515 55.2484 +124.06 88.0184 53.2858 +124.334 87.7243 52.0909 +124.835 87.2365 50.1839 +125.645 86.5985 48.0148 + +123.214 88.515 55.2484 +121.99 89.1055 57.8561 +121.431 89.3442 58.8862 +119.522 90.1316 62.2955 +118.835 90.4081 63.4899 +117.418 90.9507 65.7539 +116.89 91.1439 66.5483 +112.438 92.2765 70.8728 +110.461 92.2893 72.2288 + +88.1816 97.2536 110.696 +89.0148 96.5852 110.893 +89.856 95.9571 110.972 +90.8048 95.2674 111.024 +92.7994 92.9853 111.383 + +151.772 79.6779 129.217 +151.394 80.3266 130.898 +150.917 81.1439 133.018 +150.324 82.2103 135.811 +149.825 83.1552 138.307 +149.436 83.9595 140.454 +148.882 85.2101 143.79 +148.467 86.28 146.761 +148.289 87.0198 148.749 +147.851 86.5095 151.619 + +49.9261 142.58 119.632 +50.2884 142.488 119.362 +51.4191 142.121 118.54 +52.2455 141.411 117.977 + +65.3679 171.39 129.221 +66.0789 171.467 128.962 +66.4468 171.508 128.829 +67.8691 171.683 128.31 +69.7787 171.918 127.627 +71.8539 172.404 126.74 +76.4149 173.901 124.526 + +105.486 162.228 145.628 +105.639 161.646 146.29 +105.717 161.328 146.653 +105.961 160.159 147.997 +106.125 159.239 149.051 +105.701 158.994 149.604 +105.232 158.731 150.218 +102.836 158.339 152.718 + +52.9788 155.622 146.398 +54.2184 155.689 147.308 + +58.595 116.628 149.578 +59.5359 117.068 150.013 +60.6451 117.579 150.541 +61.5376 117.98 150.973 +62.7628 117.635 152.398 + +51.8804 157.179 146.412 +53.4637 156.257 147.056 +54.2184 155.689 147.308 + +46.6617 140.452 147.581 +47.146 140.405 147.678 +48.5185 140.264 147.956 +50.9146 139.98 148.448 +53.1244 139.685 148.946 +55.5227 139.344 149.58 +58.2477 138.93 150.348 +60.6974 138.317 151.733 +61.881 137.993 152.521 +62.5414 137.793 152.983 +64.3833 137.64 154.341 +66.0255 137.624 155.595 +69.3503 138.067 158.082 + +147.944 82.6213 150.006 +147.867 83.5909 150.499 +147.787 84.8522 151.226 +147.851 86.5095 151.619 + +99.615 95.6746 147.363 +99.1811 92.8 143.863 +98.5766 91.8938 142.548 +98.3313 91.5686 142.074 +97.8069 90.9323 141.139 +96.6192 89.517 139.041 + +99.615 95.6746 147.363 +102.972 97.3308 149.452 +104.724 97.7544 150.579 + +99.615 95.6746 147.363 +96.1198 96.1695 147.903 +95.0086 96.1916 147.91 +93.1309 96.1242 147.756 +91.1169 95.9514 147.36 +88.2995 95.8544 146.527 +86.8508 95.7558 145.991 +85.4867 95.6793 145.513 +81.8621 95.3218 144.064 +80.0653 95.1249 143.33 +78.6254 94.9421 142.705 +78.1847 94.8804 142.515 + +90.5135 150.292 138.104 +86.8999 147.594 131.34 +85.7142 146.474 129.26 +85.0025 145.966 127.84 +83.4109 144.779 124.722 +81.5923 143.393 121.457 +80.619 142.64 119.533 + +90.5135 150.292 138.104 +90.9449 156.055 135.739 +91.046 156.754 135.604 +91.003 159.158 134.818 +90.9703 160.014 134.535 +90.508 161.847 133.739 +88.8763 164.418 132.233 +88.0501 165.851 131.555 +87.0119 167.71 130.646 +85.5179 171.209 128.274 + +90.5135 150.292 138.104 +91.7676 149.196 141.659 +92.6349 148.853 143.849 +94.066 148.192 147.703 +94.401 146.989 152.587 + +117.221 76.2543 102.398 +117.477 76.6777 103.125 +118.17 77.7991 105.035 +118.751 78.9295 106.95 +119.366 80.2807 109.132 +119.813 81.2675 110.718 +120.326 82.4553 112.487 +120.452 84.0333 114.02 +120.492 84.7095 114.356 +120.903 88.3144 116.109 + +54.2184 155.689 147.308 +57.0426 154.63 149.221 +58.5487 153.913 149.791 +59.8621 153.294 150.305 +60.9499 152.784 150.755 +61.8698 152.348 151.137 +62.8903 151.86 151.561 +64.4202 151.129 152.209 +66.049 150.344 152.905 +68.2328 149.278 153.867 +70.8738 147.886 155.079 +75.1578 146.144 156.294 + +122.632 103.734 149.272 +117.694 103.487 151.503 + +122.632 103.734 149.272 +123.145 102.933 146.461 +123.447 102.248 144.325 +123.82 101.861 142.852 +124.038 101.061 140.313 +124.281 100.052 137.138 +124.09 99.1014 134.701 +123.87 98.2222 132.421 +123.533 97.3655 130.079 +123.059 96.2007 126.885 +122.742 95.3799 124.62 +122.636 94.6555 123.085 +122.51 94.0483 121.798 +122.185 93.2856 120.15 +121.861 92.5243 118.589 +120.903 88.3144 116.109 + +118.701 106.065 155.053 +117.694 103.487 151.503 + +64.4974 164.956 157.59 +64.5156 164.946 157.598 +65.0859 164.625 157.85 +66.3986 163.876 158.422 +67.6684 162.831 158.559 +69.0688 161.62 158.644 +70.9686 159.96 158.75 +72.4147 158.653 158.796 +74.1191 157.101 158.843 +76.2692 154.908 158.734 +77.8233 153.315 158.644 +77.9301 152.355 158.274 +77.9222 151.356 157.794 +77.5416 150.202 157.441 +75.1578 146.144 156.294 + +117.694 103.487 151.503 +115.42 103.032 151.971 +113.722 102.385 151.522 +112.305 101.886 151.08 +110.468 101.446 150.166 + +201.848 162.011 83.8723 +201.124 161.121 84.8928 +200.194 160.251 87.0208 + +67.0005 130.345 158.177 +72.0285 129.975 162.498 +73.639 127.635 164.847 +74.6077 125.423 166.914 +77.3838 122.734 169.568 + +67.0005 130.345 158.177 +63.0468 129.398 156.51 +62.0203 129.257 156.478 +61.0808 129.26 156.412 +59.0677 129.253 156.27 +58.1169 129.26 156.256 +57.6527 129.276 156.318 +57.024 129.303 156.48 + +67.0005 130.345 158.177 +66.4227 127.289 156.419 +66.3024 125.243 155.531 +65.3908 121.006 153.687 +62.7628 117.635 152.398 + +67.0005 130.345 158.177 +69.3503 138.067 158.082 + +95.6139 165.986 154.885 +96.3134 165.368 154.77 +97.102 164.67 154.642 +98.8221 163.138 154.372 +99.7056 161.844 154.137 +100.648 160.434 153.897 +102.836 158.339 152.718 + +219.934 113.058 162.207 +218.951 113.721 162.473 +216.507 115.078 163.08 +213.201 115.421 163.34 +211.098 115.528 163.466 +209.969 115.582 163.532 +209.625 115.598 163.552 +208.593 115.644 163.61 +207.315 115.7 163.682 +206.195 115.747 163.743 +204.462 115.814 163.836 +203.275 115.857 163.897 +201.767 115.91 163.975 +199.614 115.981 164.081 +197.699 116.042 164.174 +195.356 116.063 164.251 +191.85 115.854 164.196 + +153.62 112.901 167.546 +157.111 113.414 167.089 + +153.62 112.901 167.546 +149.791 109.724 169.376 +149.438 108.554 169.871 +149.286 108.163 169.813 +147.6 103.59 168.988 + +153.62 112.901 167.546 +149.915 115.226 166.531 +147.437 116.318 166.089 +145.268 117.172 165.542 +142.772 118.189 164.888 +141.038 119.129 164.274 +139.629 119.958 163.805 +137.462 121.764 162.517 + +113.148 122.841 173.304 +111.953 122.8 173.804 + +113.148 122.841 173.304 +115.304 123.432 172.989 +116.774 123.932 172.879 +118.334 124.481 172.781 +119.206 124.788 172.726 +121.121 125.456 172.597 +123.168 126.268 172.627 +124.975 126.993 172.69 +125.924 127.377 172.74 + +113.148 122.841 173.304 +111.797 122.127 173.146 +109.777 121.373 173.237 +107.475 120.518 173.343 +106.354 120.102 173.396 +104.263 119.326 173.493 +100.703 118.019 173.664 +98.6779 117.373 173.819 +96.9282 117.471 173.852 +96.1139 117.51 173.868 +94.6261 117.581 173.896 +92.7821 117.672 173.929 +84.9554 118.093 174.051 +83.5101 119.082 173.103 +82.7744 119.619 172.59 +81.9479 120.223 172.012 +81.2223 120.752 171.503 +80.35 121.406 170.873 +79.2821 121.689 170.595 +77.3838 122.734 169.568 + +169.647 103.832 166.361 +167.651 106.343 166.082 +166.241 108.065 166.461 +164.779 109.874 166.659 +166.755 112.973 165.526 + +169.647 103.832 166.361 +170.795 103.121 169.698 +171.284 102.76 170.868 +172.046 102.205 172.538 +172.624 101.834 173.708 +173.386 101.603 174.246 + +169.647 103.832 166.361 +170.013 102.384 162.458 +170.805 100.589 159.464 +171.825 98.2257 155.406 +173.033 95.8115 151.423 +174.218 93.5197 147.414 +174.691 92.399 145.017 +175.121 91.4092 142.871 +175.981 89.5399 138.873 +177.245 88.2945 136.794 +178.653 86.4597 133.523 + +144.878 102.899 174.575 +145.926 102.852 172.102 +147.6 103.59 168.988 + +157.111 113.414 167.089 +155.956 112.376 164.095 +155.767 110.934 161.429 +155.805 110.262 160.268 + +157.111 113.414 167.089 +159.262 113.363 166.721 +160.313 113.329 166.517 +161.797 113.25 166.285 +163.174 113.143 166.082 +166.755 112.973 165.526 + +86.4552 138.786 182.726 +86.6826 138.82 182.694 +88.0337 138.451 182.615 +89.1041 139.051 182.228 +90.7668 139.753 181.623 +91.568 140.136 181.318 +97.8852 142.007 177.897 + +76.4149 173.901 124.526 +73.0052 175.991 122.067 +73.7819 178.355 118.272 + +76.4149 173.901 124.526 +80.6521 172.429 126.21 +82.1857 172.136 126.748 +85.5179 171.209 128.274 + +110.468 101.446 150.166 +109.014 102.08 148.018 + +110.468 101.446 150.166 +108.398 100.169 150.271 +107.086 99.2783 150.439 +104.724 97.7544 150.579 + +183.805 83.5312 107.034 +182.672 83.9233 110.921 +181.76 84.2278 113.572 +180.878 84.5326 116.585 +180.129 84.7947 119.226 +179.648 84.9788 120.996 +179.245 85.1445 122.486 +178.704 85.2489 123.758 +177.811 84.9822 124.699 +177.024 84.7271 125.434 +176.097 84.5352 126.866 + +183.805 83.5312 107.034 +184.724 83.2719 106.16 +185.453 83.0613 105.256 + +183.805 83.5312 107.034 +183.315 83.597 104.329 +183.147 83.6126 103.086 +183.19 83.5729 101.808 +183.235 83.5298 100.405 + +85.8789 90.414 113.068 +88.1286 90.9798 112.686 +89.6339 91.5392 112.316 +90.8942 92.0501 111.967 +92.7994 92.9853 111.383 + +62.2229 140.746 166.423 +62.5428 140.75 166.295 +63.8134 140.762 165.756 +65.5329 140.774 165.02 +69.1583 140.775 163.383 +70.4663 140.718 162.331 +71.0564 140.71 161.605 +70.9685 140.637 160.562 +70.8593 140.397 158.559 + +214.075 90.4427 105.451 +213.86 91.0083 107.619 +213.646 91.4771 109.374 +212.969 92.0581 110.811 +212.249 92.6467 112.194 +211.869 92.9524 112.903 +209.612 94.7392 117.003 +208.035 95.9874 119.867 +206.526 97.1813 122.605 +205.428 98.051 124.601 +203.941 99.2284 127.302 +202.409 100.433 130.056 +200.388 102.067 133.851 + +137.098 134.09 147.622 +134.623 132.853 151.31 + +137.098 134.09 147.622 +137.85 134.9 145.148 +138.546 135.479 143.226 +139.225 136.045 140.711 +140.361 136.347 136.975 +140.855 136.477 135.356 +141.22 136.573 134.162 +141.909 136.728 131.841 +142.705 136.625 128.71 +143.103 136.566 127.024 +143.411 136.52 125.714 +143.8 136.461 124.044 +144.272 136.368 121.207 +144.838 136.232 116.982 +145.098 136.164 114.943 +145.202 136.135 114.091 +145.533 136.058 111.62 +146.238 136.047 108.485 +146.539 136.052 107.311 +146.75 136.038 106.242 +147.794 136.206 104.565 +149.71 136.551 102.057 +151.631 136.917 100.099 +152.834 137.101 97.8628 + +137.098 134.09 147.622 +140.206 132.06 152.686 +141.508 132.159 152.541 +142.919 131.961 153.077 +143.337 131.665 153.163 +145.583 128.927 152.801 +147.056 126.976 152.362 +147.975 125.733 152.035 +148.881 124.505 151.68 +150.002 122.957 151.274 +151.344 121.712 150.116 +153.14 120.126 148.511 +154.545 119.009 147.154 + +94.401 146.989 152.587 +98.2275 147.032 153.527 +100.515 147.028 154.956 + +94.401 146.989 152.587 +91.9812 146.575 153.567 +90.6046 146.36 154.346 +87.6461 146.343 154.728 +86.6685 146.277 154.882 +80.5806 146.487 155.935 +75.1578 146.144 156.294 + +93.6349 150.686 107.521 +93.5741 150.643 107.536 +92.6802 150.014 107.735 +90.3461 148.391 108.194 +87.7417 146.639 108.314 +82.5022 143.212 108.495 +78.7852 141.901 110.422 + +100.531 94.6789 33.5643 +100.353 95.0535 35.6746 +100.311 95.1391 36.1734 +100.179 95.3463 37.0777 +100.162 95.4491 38.2798 +99.7832 95.5787 39.87 +98.4802 95.8123 42.5902 + +72.8208 105.14 35.2123 +72.7628 105.807 36.1948 +72.6135 107.594 38.8184 +72.5596 109.027 40.8303 +72.5508 111.297 43.9262 +72.6056 111.86 44.388 +72.6875 112.526 45 +72.736 113.612 45.5606 +72.7807 115.338 46.39 +72.8152 116.523 47.0159 +72.8121 119.169 47.7203 + +127.503 83.8366 36.4597 +125.901 84.7885 37.7116 + +93.2669 95.8549 42.5271 +94.2488 95.8892 42.9568 +98.4802 95.8123 42.5902 + +147.851 86.5095 151.619 +147.95 89.3227 153.319 +147.881 90.539 154.9 +147.851 92.4524 156.779 +147.804 94.2277 158.692 +147.798 94.412 158.898 +147.778 95.1611 159.731 +147.757 95.9829 160.639 +147.744 96.7291 161.452 +147.728 97.8233 162.635 +147.686 99.6101 164.613 +147.6 103.59 168.988 + +73.4588 110.468 60.4054 +73.8005 111.867 60.4663 +74.2254 116.638 58.7871 +73.9801 119.509 57.1376 + +80.0347 128.548 125.692 +79.6636 129.345 125.723 +79.2256 130.962 125.236 +77.3069 131.484 124.371 + +53.1627 149.63 106.66 +54.3526 148.384 107.549 +55.3439 147.353 108.228 +56.7029 145.936 109.141 +58.0363 144.486 109.819 +60.2184 141.923 110.96 + +96.051 182.453 114.395 +95.8722 181.658 114.877 +95.5631 180.898 115.463 +95.221 179.989 116.198 +94.5418 178.171 117.661 +94.1405 177.03 118.525 +93.3338 175.4 119.843 + +201.409 161.651 87.2789 +200.194 160.251 87.0208 + +52.2455 141.411 117.977 +55.2916 141.535 115.95 +56.7823 141.5 114.945 +60.2184 141.923 110.96 + +52.2455 141.411 117.977 +51.0541 140.335 118.923 +50.5032 139.992 119.338 +50.1404 139.782 119.608 + +83.033 178.113 134.072 +83.568 176.122 133.049 +83.7573 175.436 132.675 +83.9421 174.715 132.264 +84.2232 173.744 131.678 +84.4189 173.074 131.199 +84.6744 172.327 130.77 +85.5179 171.209 128.274 + +54.6579 116.021 125.201 +55.9795 116.287 125.151 +57.1855 116.563 125.111 +59.4458 117.38 125.062 +63.2676 118.529 124.945 + +62.6789 113.824 154.732 +62.9124 115.255 153.96 +62.7628 117.635 152.398 + +103.424 139.242 164.383 +101.803 141.887 161.722 +101.136 142.794 160.754 +101.369 143.464 159.673 +100.515 147.028 154.956 + +181.919 113.747 160.026 +183.167 115.827 163.453 +183.837 116.927 164.886 +187.954 117.175 165.248 +189.649 116.67 164.845 +191.85 115.854 164.196 + +181.919 113.747 160.026 +175.277 114.133 162.987 +173.927 114.074 163.36 +170.51 114.013 164.447 +168.158 113.647 165.115 +166.755 112.973 165.526 + +181.919 113.747 160.026 +184.289 112.924 157.704 +185.314 111.936 155.535 +186.055 111.229 153.98 +186.655 110.968 153.298 +187.594 110.624 152.351 +188.453 110.213 151.365 +189.325 109.697 150.242 +189.968 109.302 149.392 +190.524 108.95 148.637 +191.124 108.562 147.808 +192.145 107.887 146.369 +192.981 107.322 145.167 +193.935 106.676 143.794 +194.407 106.355 143.111 +195.09 105.885 142.109 +195.806 105.389 141.054 +196.937 104.584 139.323 +198.614 103.35 136.622 +200.388 102.067 133.851 + +124.018 117.11 176.88 +124.776 117.435 176.679 +126.384 118.116 176.214 +127.229 118.318 175.476 +127.71 118.401 174.968 +128.481 118.313 173.777 +129.285 118.213 172.479 +130.227 116.673 167.898 + +72.8121 119.169 47.7203 +72.5342 121.663 45.6542 +72.4665 121.793 44.106 +72.3487 122.123 43.165 +72.1927 122.505 41.9108 +72.1556 122.598 41.6129 +72.0415 122.878 40.7008 +71.8382 123.378 39.0778 +71.5627 124.111 36.8786 +71.1584 125.81 33.6384 +71.0324 126.556 32.5039 + +72.8121 119.169 47.7203 +73.2291 119.406 51.4996 +73.9801 119.509 57.1376 + +134.623 132.853 151.31 +133.954 129.566 155.945 +134.209 128.131 157.348 +134.428 126.48 158.935 +135.042 124.917 160.126 +135.427 123.843 160.935 +137.462 121.764 162.517 + +134.623 132.853 151.31 +132.381 133.243 152.498 +130.198 133.269 154.174 +128.142 133.489 155.507 +125.215 134.943 155.871 +123.636 135.754 156.034 +122.364 136.328 156.274 +121.335 136.793 156.467 +120.322 137.251 156.657 +119.315 137.706 156.846 +117.81 138.387 157.133 +114.438 139.91 157.771 +113.287 140.442 158.036 +111.115 141.497 158.904 +108.582 142.76 159.536 + +138.162 138.601 9.71481 +139.196 137.043 17.2367 +140.009 135.837 23.3368 +140.225 135.518 24.9814 +140.494 135.121 27.0234 +140.704 134.811 28.6256 +140.95 134.446 30.4981 +141.365 133.834 33.6622 +141.665 133.403 36.3515 +141.873 133.115 38.5699 +141.973 132.977 39.6369 +142.103 132.797 41.0426 +142.246 132.598 42.5289 +142.504 132.277 46.0637 +142.733 132.034 49.9747 +142.825 131.937 51.5179 +142.906 131.851 52.8913 +143.052 131.702 55.165 +143.173 131.575 57.1548 +143.194 131.693 59.6412 +143.151 131.824 61.5241 +143.134 131.928 63.073 +143.083 132.098 65.6293 +142.991 132.436 70.5731 +142.816 132.695 73.3165 +142.2 132.875 75.0686 +141.329 133.133 77.5512 +139.671 133.2 79.1787 + +130.218 84.4908 44.9766 +129.854 84.658 44.9649 +125.645 86.5985 48.0148 + +125.645 86.5985 48.0148 +125.525 86.1982 45.3974 +125.6 85.9339 43.9746 +125.72 85.6376 42.4654 +125.901 84.7885 37.7116 + +99.134 98.6006 58.3369 +100.866 96.8182 55.5209 + +77.5689 162.766 66.1985 +77.6291 162.511 66.347 +77.7696 161.54 66.8938 +77.8554 160.992 67.1833 +78.0001 160.011 67.6884 +78.4147 156.996 67.9795 + +86.2866 91.5121 71.941 +87.0984 91.4126 72.2989 +89.4314 91.1494 73.3702 +92.0223 90.9428 74.8762 +95.0145 90.8691 74.3417 +96.611 90.8302 74.0764 +97.9104 90.7819 73.8512 +99.0862 90.4824 73.5335 +102.37 89.953 72.9031 + +71.6117 104.63 83.3448 +70.9731 106.201 83.0274 +70.1649 108.405 82.6446 +69.5535 110.538 82.3844 +68.9269 113.019 82.1301 +69.8552 114.587 82.7025 +71.1654 117.024 83.5028 +72.3494 118.96 84.1649 +73.4834 120.613 84.7469 +74.3676 121.51 85.1141 +75.6483 122.63 85.5455 +76.9758 123.252 85.142 +81.7039 124.026 85 + +75.5857 183.215 108.611 +75.5789 183.197 108.646 +75.5652 183.162 108.713 +75.2835 182.848 109.515 + +56.2777 165.156 116.875 +57.2439 165.052 116.564 +57.4957 165.022 116.484 +58.7704 164.867 116.073 +59.8366 164.761 115.674 +60.7432 164.905 114.922 +65.2745 163.976 113.788 + +59.7953 104.835 123.029 +60.1185 106.612 123.226 +60.5099 108.413 123.502 +61.7244 113.687 124.33 +63.2676 118.529 124.945 + +117.575 84.4393 120.476 +118.145 84.8318 120.289 +118.938 85.617 118.995 +120.903 88.3144 116.109 + +191.646 82.1407 128.141 +189.874 82.6614 129.423 +186.81 83.5814 131.57 +185.567 84.1305 132.33 +183.662 85.1007 133.383 +181.529 86.1133 134.35 +178.653 86.4597 133.523 + +67.7233 179.217 121.751 +68.5052 178.942 121.484 +69.2559 178.643 121.33 +70.3307 178.241 121.163 +73.7819 178.355 118.272 + +104.419 96.1337 153.083 +104.417 96.2148 152.916 +104.724 97.7544 150.579 + +70.6218 115.037 175.9 +70.6411 115.096 175.875 +71.0189 116.138 175.328 +71.2814 116.84 174.941 +71.6723 117.852 174.326 +73.2648 119.515 172.736 +74.0039 120.279 172.003 +74.348 120.709 171.584 +74.8063 121.81 170.495 +77.3838 122.734 169.568 + +95.606 142.97 180.448 +97.8852 142.007 177.897 + +121.984 132.135 69.8458 +123.096 132.005 71.3436 +124.699 131.96 72.8582 +125.351 131.947 73.4661 +126.282 131.932 74.335 +128.913 131.996 76.5196 +130.561 132.163 77.5723 +133.032 132.505 78.6017 +134.6 132.726 79.2376 +135.927 132.879 79.4344 +139.671 133.2 79.1787 + +63.2676 118.529 124.945 +66.8928 121.8 125.14 +68.4283 123.11 125.203 +70.0249 124.546 125.255 +70.2913 124.799 125.256 +71.8896 126.336 125.242 +73.1014 127.529 125.174 +74.0631 128.488 125.103 +75.1523 129.933 124.598 +77.3069 131.484 124.371 + +102.836 158.339 152.718 +102.383 156.439 153.586 +102.148 151.2 154.516 +100.515 147.028 154.956 + +93.3338 175.4 119.843 +96.3426 172.993 118.861 +97.6247 172.439 118.114 +98.4465 172.205 117.616 + +93.3338 175.4 119.843 +92.6589 175.112 120.445 +91.7177 174.356 121.451 +89.5162 172.455 123.98 +85.5179 171.209 128.274 + +92.7994 92.9853 111.383 +95.8883 92.7141 110.964 +97.9353 92.552 110.668 +99.1637 92.414 110.501 +100.643 92.2564 110.305 +105.863 91.6136 109.516 + +204.379 99.5227 128.948 +200.388 102.067 133.851 + +83.2766 125.401 96.3324 +80.7928 130.01 97.0484 +79.7561 131.935 98.2504 +79.5274 132.399 98.4313 +78.913 133.681 98.9454 +77.7852 136.307 100.615 + +83.2766 125.401 96.3324 +81.962 125.383 89.8166 +81.7039 124.026 85 + +60.2184 141.923 110.96 +65.7557 138.894 109.509 + +102.37 89.953 72.9031 +105.116 90.7493 73.5158 +105.86 91.0468 73.7937 +108.779 92.0873 75.342 + +78.4147 156.996 67.9795 +78.6679 155.523 70.3109 +78.8451 154.547 72.2847 +78.9555 153.887 73.1561 +79.0495 153.323 73.8664 +79.1491 152.743 74.5967 +79.3014 151.856 75.7108 +79.4575 151.311 76.3675 +79.7234 150.331 77.4993 +80.1313 148.875 79.1721 +80.3282 144.293 84.7584 + +139.671 133.2 79.1787 +141.156 133.657 81.4758 +141.584 133.79 82.145 +141.94 133.914 82.7939 +142.398 134.066 83.5873 +143.671 134.419 85.2669 +144.723 134.715 86.6897 +145.903 135.06 88.3537 +147.384 135.497 90.4895 +148.417 135.804 92.0152 +149.255 136.051 93.1952 +151.082 136.571 95.2191 +152.834 137.101 97.8628 + +78.5962 158.884 111.503 +75.8372 160.375 112.438 +73.876 160.721 113.486 +71.4088 161.302 114.376 +67.4892 163.144 113.842 +65.2745 163.976 113.788 + +78.5962 158.884 111.503 +80.1904 153.948 113.773 +80.4862 151.972 114.928 +80.7639 150.556 115.736 +80.8499 148.33 116.299 +80.3308 145.31 115.445 + +121.308 90.1466 110.362 +115.522 91.7707 111.272 +111.353 91.5936 109.642 +105.863 91.6136 109.516 + +121.308 90.1466 110.362 +128.016 88.9504 106.464 +129.03 88.6759 105.818 +130.262 88.3392 105.092 +131.722 87.8825 104.212 +136.177 85.8858 102.65 + +121.308 90.1466 110.362 +120.903 88.3144 116.109 + +200.194 160.251 87.0208 +197.122 156.859 88.0642 +195.462 155.071 88.9655 +194.69 154.269 89.4532 +193.926 153.499 89.9147 +193.239 152.832 90.3166 +192.326 151.98 90.8258 +191.207 150.939 91.4489 +190.286 150.111 91.9389 +188.286 148.416 92.9241 +186.582 147.054 93.7021 +185.27 146.095 94.2338 +183.078 145.393 94.8614 +181.254 144.844 95.3606 +180.035 144.48 95.6921 +177.285 143.664 96.4358 +175.813 143.235 96.8293 +174.181 142.764 97.2618 +171.843 142.103 97.8707 +170.148 141.629 98.3073 +165.931 140.47 99.3846 +161.92 139.38 100.143 +160.714 139.054 99.69 +159.037 138.618 99.0589 +156.994 138.113 98.5701 +155.215 137.665 97.9346 +152.834 137.101 97.8628 + +77.3069 131.484 124.371 +77.8011 136.842 119.925 +78.6694 138.726 119.642 +80.619 142.64 119.533 + +80.3308 145.31 115.445 +78.7852 141.901 110.422 + +80.3308 145.31 115.445 +80.1472 142.876 117.329 +80.619 142.64 119.533 + +178.653 86.4597 133.523 +176.858 85.7053 130.906 +175.88 84.7912 128.761 +176.097 84.5352 126.866 + +67.2101 141.299 86.6562 +73.9272 140.856 90.4568 + +137.913 86.9824 90.8748 +136.676 87.0994 93.6931 +135.142 87.0835 96.0474 +134.246 87.1896 98.4681 +136.177 85.8858 102.65 + +78.7852 141.901 110.422 +76.3985 139.181 106.35 + +75.2835 182.848 109.515 +75.1767 182.295 110.575 +74.9107 181.426 112.338 +74.5579 180.158 114.885 +73.7819 178.355 118.272 + +100.866 96.8182 55.5209 +103.523 95.5641 59.8603 +104.308 95.2298 61.3552 +104.733 95.036 62.0998 +105.013 94.9114 62.6383 +106.451 94.2613 65.4832 +107.404 93.8369 66.9428 +108.241 93.4638 68.1883 +109.118 93.0328 69.8205 +110.461 92.2893 72.2288 + +100.866 96.8182 55.5209 +100.482 96.3446 51.1849 +100.086 96.2835 49.1402 +99.7205 96.234 47.7864 +98.4802 95.8123 42.5902 + +97.8852 142.007 177.897 +100.871 142.517 175.978 +102.611 142.864 174.9 +104.725 143.29 173.588 +105.706 143.415 172.755 +106.169 143.471 172.33 +107.164 143.594 171.179 +108.816 143.77 169.608 +107.08 143.438 161.908 +108.582 142.76 159.536 + +65.7557 138.894 109.509 +68.5713 139.132 108.973 +69.9468 139.2 108.555 +76.3985 139.181 106.35 + +143.789 82.3533 103.716 +147.069 81.3156 106.068 +147.936 81.1058 106.859 +149.228 80.8158 108.041 +149.897 80.6672 108.657 +151.652 80.2673 110.152 +154.164 79.8105 111.524 +156.897 79.359 113.066 +160.592 78.9805 115.411 +163.282 78.8926 117.329 +164.072 78.9211 117.954 +167.681 79.8606 121.603 +171.169 81.5775 125.86 +172.087 82.3002 126.498 +173.057 83.0278 126.968 +176.097 84.5352 126.866 + +143.789 82.3533 103.716 +140.925 83.5917 102.805 +139.854 84.1147 102.719 +138.756 84.6463 102.675 +136.177 85.8858 102.65 + +108.779 92.0873 75.342 +110.461 92.2893 72.2288 + +69.3503 138.067 158.082 +70.8593 140.397 158.559 + +73.9272 140.856 90.4568 +78.2128 142.331 87.8051 +80.3282 144.293 84.7584 + +73.9272 140.856 90.4568 +75.3867 139.578 93.3638 +75.7 138.444 95.7412 +75.8338 138.202 96.3378 +77.7852 136.307 100.615 + +83.2234 120.801 76.5165 +82.4246 120.156 73.4506 +80.677 121.173 72.1018 +80.3677 121.269 71.673 +79.4916 121.559 70.4854 +78.3154 121.628 67.8343 +77.5388 121.724 66.1089 +76.9422 121.792 64.793 +76.4322 121.994 63.6542 +75.8873 121.971 62.4044 +75.4683 121.981 61.4311 +74.7801 122.032 59.782 +73.9801 119.509 57.1376 + +83.2234 120.801 76.5165 +82.2348 122.635 80.8777 +82.0259 122.962 81.7245 +81.7039 124.026 85 + +83.2234 120.801 76.5165 +85.9082 120.537 79.1001 +87.9279 119.848 79.4764 +90.9187 118.57 78.7805 +92.1933 118.14 78.8521 +93.1586 117.814 78.9335 + +130.227 116.673 167.898 +133.124 119.598 166.151 +134.296 120.499 164.837 +137.462 121.764 162.517 + +108.582 142.76 159.536 +105.886 144.329 157.561 +104.232 145.167 156.896 +100.515 147.028 154.956 + +77.7852 136.307 100.615 +77.4771 137.823 103.34 +76.3985 139.181 106.35 + +70.8593 140.397 158.559 +71.7459 141.746 157.883 +72.7059 143.232 157.281 +75.1578 146.144 156.294 + diff --git a/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.cpp b/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.cpp new file mode 100644 index 0000000..dbe59d5 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.cpp @@ -0,0 +1,22 @@ +#define SKELETONSEGMENTMAPPER_CPP +#include + +#include +#include + +namespace meshskeletonizationplugin +{ +using namespace sofa::defaulttype; + +void registerSkeletonSegmentMapper(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData( + "Maps a previously-read skeleton (SkeletonReader) onto liver segments (e.g. " + "Couinaud I-VIII), using a per-mesh-vertex segment label and smoothing " + "per-branch by majority vote") + .add< SkeletonSegmentMapper >()); +} + +template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonSegmentMapper; + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.h b/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.h new file mode 100644 index 0000000..c59ea3d --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.h @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace sofa; +using namespace sofa::defaulttype; + +namespace meshskeletonizationplugin +{ + +template +class SkeletonSegmentMapper : public sofa::core::DataEngine +{ +public: + SOFA_CLASS(SOFA_TEMPLATE(SkeletonSegmentMapper, DataTypes), sofa::core::DataEngine); + + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::VecCoord VecCoord; + typedef typename Coord::value_type Real; + typedef type::Vec<3, Real> Vec3; + + /// The SkeletonReader whose graph should be segmented. If left unset, the + /// first SkeletonReader found in the context is used. + sofa::core::objectmodel::SingleLink< + SkeletonSegmentMapper, + SkeletonReader, + sofa::core::objectmodel::BaseLink::FLAG_STOREPATH | sofa::core::objectmodel::BaseLink::FLAG_STRONGLINK> + l_skeletonReader; + + /// One closed mesh per liver segment (e.g. the Couinaud collision meshes), + /// in the same order as d_inSegmentNames. + sofa::core::objectmodel::MultiLink< + SkeletonSegmentMapper, + sofa::core::loader::MeshLoader, + sofa::core::objectmodel::BaseLink::FLAG_STOREPATH> + l_segmentMeshes; + + //Component parameters + // Inputs + sofa::core::objectmodel::Data> d_inSegmentNames; ///< Human-readable name per entry of l_segmentMeshes, e.g. "II", "IVa", "VIII" + sofa::core::objectmodel::DataFileName d_outSegmentReportFilename; ///< Optional CSV report: id, x, y, z, segment name + // Outputs + sofa::core::objectmodel::Data> d_outNodeSegments; ///< Segment index per skeleton node (into l_segmentMeshes/d_inSegmentNames, -1 = unknown), indexed like graph().nodes() + sofa::core::objectmodel::Data> d_outNodeSegmentNames; ///< Same as d_outNodeSegments, resolved to names ("unknown" if -1) + sofa::core::objectmodel::Data d_outSegmentCount; ///< Number of distinct segments found (excluding unknown) + + /// Direct access to the segmented graph, e.g. for another component to + /// query via getContext()->get>()->graph(). + const SkeletonGraph& graph() const { return m_graph; } + + void init() override; + void doUpdate() override; + void draw(const sofa::core::visual::VisualParams* vparams) override; + +private: + SkeletonSegmentMapper(); + virtual ~SkeletonSegmentMapper() = default; + + /// Local working copy of the linked reader's graph, augmented with + /// segment labels (SkeletonGraph is a plain value type, cheap to copy). + SkeletonGraph m_graph; +}; + +#if !defined(SKELETONSEGMENTMAPPER_CPP) +extern template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonSegmentMapper; +#endif + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.inl b/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.inl new file mode 100644 index 0000000..9f1870b --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SegmentMapping/SkeletonSegmentMapper.inl @@ -0,0 +1,273 @@ +#pragma once +#include + +// Reuses the Kernel/Polyhedron/Point typedefs already declared (at global +// scope) in MeshSkeletonization.h, so segment meshes are built the same way +// MeshSkeletonization builds its own polyhedron. +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace meshskeletonizationplugin +{ + +namespace +{ + // Builds a CGAL Polyhedron_3 from a flat vertex/triangle mesh, mirroring + // MeshSkeletonization::geometryToPolyhedronOp but as a free function so it + // can be reused here without duplicating a private nested class. + template + class MeshToPolyhedronOp : public CGAL::Modifier_base + { + public: + MeshToPolyhedronOp(const VecCoord& vertices, const SeqTriangles& triangles) + : m_vertices(vertices), m_triangles(triangles) + { + } + + void operator()(HalfedgeDS& hds) override + { + CGAL::Polyhedron_incremental_builder_3 builder(hds, true); + builder.begin_surface(m_vertices.size(), m_triangles.size()); + + for (const auto& v : m_vertices) + builder.add_vertex(Point(v[0], v[1], v[2])); + + for (const auto& tri : m_triangles) + { + builder.begin_facet(); + for (int j = 0; j < 3; ++j) + builder.add_vertex_to_facet(tri[j]); + builder.end_facet(); + } + + if (builder.check_unconnected_vertices()) + builder.remove_unconnected_vertices(); + + builder.end_surface(); + } + + private: + const VecCoord& m_vertices; + const SeqTriangles& m_triangles; + }; + + using AABBTraits = CGAL::AABB_traits>; + using AABBTree = CGAL::AABB_tree; + using PointInsideTest = CGAL::Side_of_triangle_mesh; + + /// One segment mesh, ready for point-in-mesh + closest-point queries. + struct SegmentMeshQuery + { + Polyhedron polyhedron; + std::unique_ptr tree; + std::unique_ptr insideTest; + + void build() + { + tree = std::make_unique(CGAL::faces(polyhedron).first, CGAL::faces(polyhedron).second, polyhedron); + tree->accelerate_distance_queries(); + insideTest = std::make_unique(*tree); + } + }; +} // anonymous namespace + +template +SkeletonSegmentMapper::SkeletonSegmentMapper() + : l_skeletonReader(initLink("skeletonReader", + "SkeletonReader whose graph should be segmented; if empty, the first " + "SkeletonReader found in the scene is used")) + , l_segmentMeshes(initLink("segmentMeshes", + "One closed mesh loader per liver segment (e.g. Couinaud collision meshes), " + "in the same order as segmentNames")) + , d_inSegmentNames(initData(&d_inSegmentNames, "segmentNames", + "Human-readable name per entry of segmentMeshes, e.g. 'II', 'IVa', 'VIII'")) + , d_outSegmentReportFilename(initData(&d_outSegmentReportFilename, "outSegmentReportFilename", + "Optional path to export a CSV report: id, x, y, z, segment name")) + , d_outNodeSegments(initData(&d_outNodeSegments, "nodeSegments", + "Segment index per skeleton node (-1 if unknown), indexed like the graph's nodes")) + , d_outNodeSegmentNames(initData(&d_outNodeSegmentNames, "nodeSegmentNames", + "Same as nodeSegments, resolved to names ('unknown' if -1)")) + , d_outSegmentCount(initData(&d_outSegmentCount, 0, "segmentCount", + "Number of distinct segments found (excluding -1/unknown)")) +{ + addOutput(&d_outNodeSegments); + addOutput(&d_outNodeSegmentNames); + addOutput(&d_outSegmentCount); +} + +template +void SkeletonSegmentMapper::init() +{ + if (!l_skeletonReader) + { + l_skeletonReader.set(this->getContext()->template get>()); + } + if (!l_skeletonReader) + { + msg_error() << "No SkeletonReader found. Set 'skeletonReader' to a valid " + "component path, or add one earlier in the scene."; + } + + if (l_segmentMeshes.empty()) + { + msg_error() << "No segment meshes linked: set 'segmentMeshes' to a list of mesh " + "loader paths (one per liver segment)."; + } + else if (l_segmentMeshes.size() != d_inSegmentNames.getValue().size()) + { + msg_warning() << "segmentMeshes (" << l_segmentMeshes.size() << ") and segmentNames (" + << d_inSegmentNames.getValue().size() << ") have different sizes; " + "unnamed segments will be reported by index only."; + } + + setDirtyValue(); + update(); // compute eagerly, don't wait for something to read an output Data +} + +template +void SkeletonSegmentMapper::doUpdate() +{ + if (!l_skeletonReader || l_segmentMeshes.empty()) + return; + + // Work on our own copy of the reader's graph so we don't need a + // non-const accessor on SkeletonReader just for this. + m_graph = l_skeletonReader->graph(); + + // Build one point-in-mesh query per linked segment mesh. + std::vector segmentQueries(l_segmentMeshes.size()); + for (std::size_t i = 0; i < l_segmentMeshes.size(); ++i) + { + sofa::core::loader::MeshLoader* loader = l_segmentMeshes.get(i); + if (!loader) + continue; + + MeshToPolyhedronOp< + sofa::type::vector, + sofa::type::vector> + op(loader->d_positions.getValue(), loader->d_triangles.getValue()); + + segmentQueries[i].polyhedron.delegate(op); + if (!segmentQueries[i].polyhedron.is_empty()) + segmentQueries[i].build(); + } + + // Raw per-node label: which segment mesh contains this node, or (if none + // does) whichever segment mesh's surface is closest. + const auto& nodes = m_graph.nodes(); + std::vector raw(nodes.size(), -1); + + for (const SkeletonNode& node : nodes) + { + const auto& p = node.position(); + Point query(p[0], p[1], p[2]); + + int inside = -1; + for (std::size_t i = 0; i < segmentQueries.size() && inside == -1; ++i) + { + if (segmentQueries[i].insideTest && + (*segmentQueries[i].insideTest)(query) == CGAL::ON_BOUNDED_SIDE) + { + inside = static_cast(i); + } + } + + if (inside != -1) + { + raw[node.id()] = inside; + continue; + } + + // Fallback: closest segment surface. + double bestDist2 = std::numeric_limits::max(); + int bestSeg = -1; + for (std::size_t i = 0; i < segmentQueries.size(); ++i) + { + if (!segmentQueries[i].tree) + continue; + double d2 = CGAL::to_double(segmentQueries[i].tree->squared_distance(query)); + if (d2 < bestDist2) + { + bestDist2 = d2; + bestSeg = static_cast(i); + } + } + raw[node.id()] = bestSeg; + } + + m_graph.assignSegmentLabels(raw); + + const auto& names = d_inSegmentNames.getValue(); + + sofa::helper::WriteAccessor>> outSegments(d_outNodeSegments); + sofa::helper::WriteAccessor>> outSegmentNames(d_outNodeSegmentNames); + outSegments.resize(nodes.size()); + outSegmentNames.resize(nodes.size()); + + std::set distinct; + for (const SkeletonNode& n : nodes) + { + int seg = m_graph.segmentOf(n.id()); + outSegments[n.id()] = seg; + outSegmentNames[n.id()] = (seg >= 0 && seg < static_cast(names.size())) ? names[seg] : "unknown"; + if (seg != -1) + distinct.insert(seg); + } + + d_outSegmentCount.setValue(static_cast(distinct.size())); + + if (d_outSegmentReportFilename.isSet() && !d_outSegmentReportFilename.getFullPath().empty()) + { + m_graph.exportSegmentReportCSV(d_outSegmentReportFilename.getFullPath(), names); + } +} + +template +void SkeletonSegmentMapper::draw(const sofa::core::visual::VisualParams* vparams) +{ + if (!vparams->displayFlags().getShowBehaviorModels()) + return; + + static const std::vector palette = { + sofa::type::RGBAColor(0.90f, 0.10f, 0.10f, 1.0f), + sofa::type::RGBAColor(0.10f, 0.60f, 0.90f, 1.0f), + sofa::type::RGBAColor(0.20f, 0.80f, 0.20f, 1.0f), + sofa::type::RGBAColor(0.95f, 0.75f, 0.10f, 1.0f), + sofa::type::RGBAColor(0.60f, 0.20f, 0.80f, 1.0f), + sofa::type::RGBAColor(0.90f, 0.45f, 0.10f, 1.0f), + sofa::type::RGBAColor(0.10f, 0.80f, 0.70f, 1.0f), + sofa::type::RGBAColor(0.50f, 0.50f, 0.50f, 1.0f), + }; + static const sofa::type::RGBAColor unknownColor(0.7f, 0.7f, 0.7f, 1.0f); + + std::vector points; + std::vector colors; + points.reserve(m_graph.nodes().size()); + colors.reserve(m_graph.nodes().size()); + + for (const SkeletonNode& n : m_graph.nodes()) + { + const auto& p = n.position(); + points.emplace_back(p[0], p[1], p[2]); + + int seg = m_graph.segmentOf(n.id()); + colors.push_back(seg >= 0 ? palette[seg % palette.size()] : unknownColor); + } + + vparams->drawTool()->drawPoints(points, 6.0f, colors); +} + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp index 2c650e4..f7e51be 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.cpp @@ -16,6 +16,7 @@ void SkeletonGraph::clear() m_nodes.clear(); m_adjacency.clear(); m_loopEdges.clear(); + m_nodeSegment.clear(); m_rootId = -1; } @@ -91,6 +92,93 @@ bool SkeletonGraph::loadFromFile(const std::string& filename, double mergeTolera return true; } +bool SkeletonGraph::loadFromVTK(const std::string& filename) +{ + std::ifstream in(filename); + if (!in.is_open()) + return false; + + clear(); + + // Skip the 4-line ASCII VTK header: version, title, "ASCII", "DATASET POLYDATA". + std::string discard; + for (int i = 0; i < 4; ++i) + std::getline(in, discard); + + std::string tag; + int currentBlockCount = 0; // set by POINT_DATA/CELL_DATA, used to size SCALARS reads + + while (in >> tag) + { + if (tag == "POINTS") + { + int numPoints = 0; + std::string dataType; + in >> numPoints >> dataType; + + m_nodes.clear(); + m_nodes.reserve(numPoints); + for (int i = 0; i < numPoints; ++i) + { + std::array p{}; + in >> p[0] >> p[1] >> p[2]; + m_nodes.emplace_back(i, p[0], p[1], p[2]); + } + } + else if (tag == "LINES") + { + int numLines = 0, listSize = 0; + in >> numLines >> listSize; + for (int i = 0; i < numLines; ++i) + { + int count = 0, a = 0, b = 0; + in >> count >> a >> b; + if (count == 2 && a >= 0 && b >= 0 && + a < static_cast(m_nodes.size()) && b < static_cast(m_nodes.size())) + { + // exportToVTK() writes "parentId childId" per line. + m_nodes[a].addChildId(b); + m_nodes[b].addParentId(a); + + // Also record the raw undirected connectivity - this is + // what simulateResection()'s reachability BFS walks, so + // without it a cut would never propagate to children. + connect(a, b); + } + } + } + else if (tag == "POINT_DATA" || tag == "CELL_DATA") + { + in >> currentBlockCount; + } + else if (tag == "SCALARS") + { + std::string name, dataType, lookupTag, lookupName; + in >> name >> dataType >> lookupTag >> lookupName; // " \nLOOKUP_TABLE default" + + if (name == "type" && currentBlockCount == static_cast(m_nodes.size())) + { + for (int i = 0; i < currentBlockCount; ++i) + { + int t = 0; + in >> t; + if (t == 1) + m_rootId = i; + } + } + else + { + // Not needed to rebuild the tree (depth, is_loop, ...): consume and discard. + double dummy; + for (int i = 0; i < currentBlockCount; ++i) + in >> dummy; + } + } + } + + return hasRoot(); +} + int SkeletonGraph::closestNodeId(const std::array& p) const { int best = -1; @@ -409,4 +497,204 @@ void SkeletonGraph::exportReportCSV(const std::string& filename) const << "\"" << joinIds(loopParents) << "\"\n"; } } + +// --- Liver-segment mapping --------------------------------------------------- + +void SkeletonGraph::assignSegmentLabels(const std::vector& rawNodeLabels) +{ + const int n = static_cast(m_nodes.size()); + m_nodeSegment.assign(n, -1); + + if (!hasRoot() || rawNodeLabels.empty()) + return; + + const std::vector& raw = rawNodeLabels; + + // Walk the tree from the root, splitting it into maximal branches: a + // branch runs from the root (or right after a branch point) down to the + // next branch point or leaf. Every node in a branch gets that branch's + // majority raw label, so a few mislabeled nodes near a segment boundary + // don't fragment an otherwise-clear branch. + std::vector stack; + stack.push_back(m_rootId); + + while (!stack.empty()) + { + int start = stack.back(); + stack.pop_back(); + + std::vector chain; + int cur = start; + while (true) + { + chain.push_back(cur); + const SkeletonNode* curNode = node(cur); + const auto& children = curNode->childrenIds(); + + if (children.size() == 1) + { + cur = children.front(); + continue; + } + + // Reached a leaf (0 children) or a branch point (>1 children): + // end this chain here, and start a fresh chain at each child. + for (int c : children) + stack.push_back(c); + break; + } + + std::map counts; + for (int id : chain) + if (id < static_cast(raw.size()) && raw[id] != -1) + ++counts[raw[id]]; + + int majority = -1; + int best = 0; + for (const auto& kv : counts) + { + if (kv.second > best) + { + best = kv.second; + majority = kv.first; + } + } + + for (int id : chain) + m_nodeSegment[id] = majority; + } +} + +int SkeletonGraph::segmentOf(int nodeId) const +{ + if (nodeId < 0 || nodeId >= static_cast(m_nodeSegment.size())) + return -1; + return m_nodeSegment[nodeId]; +} + +std::vector SkeletonGraph::nodesInSegment(int segment) const +{ + std::vector result; + for (const SkeletonNode& n : m_nodes) + if (segmentOf(n.id()) == segment) + result.push_back(n.id()); + return result; +} + +void SkeletonGraph::exportSegmentReportCSV(const std::string& filename) const +{ + if (!hasRoot()) + return; + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "id,x,y,z,segment\n"; + out << std::fixed << std::setprecision(6); + + for (const SkeletonNode& n : m_nodes) + { + const auto& p = n.position(); + out << n.id() << "," + << p[0] << "," << p[1] << "," << p[2] << "," + << segmentOf(n.id()) << "\n"; + } +} + +void SkeletonGraph::exportSegmentReportCSV(const std::string& filename, const std::vector& segmentNames) const +{ + if (!hasRoot()) + return; + + std::set distinctSegments; + for (const SkeletonNode& n : m_nodes) + { + int seg = segmentOf(n.id()); + if (seg != -1) + distinctSegments.insert(seg); + } + + std::ofstream out(filename, std::ofstream::out | std::ofstream::trunc); + out << "# totalNodes=" << m_nodes.size() << ",distinctSegments=" << distinctSegments.size() << "\n"; + out << "id,x,y,z,segment\n"; + out << std::fixed << std::setprecision(6); + + for (const SkeletonNode& n : m_nodes) + { + const auto& p = n.position(); + int seg = segmentOf(n.id()); + + std::string name = "unknown"; + if (seg >= 0 && seg < static_cast(segmentNames.size())) + name = segmentNames[seg]; + + out << n.id() << "," + << p[0] << "," << p[1] << "," << p[2] << "," + << name << "\n"; + } +} + +std::vector SkeletonGraph::simulateResection(const std::vector& cutNodeIds) const +{ + std::vector affected; + if (!hasRoot()) + return affected; + + std::set cutSet(cutNodeIds.begin(), cutNodeIds.end()); + + // If the root itself is cut, nothing downstream can be perfused any more. + if (cutSet.count(m_rootId)) + { + affected.reserve(m_nodes.size()); + for (const SkeletonNode& n : m_nodes) + affected.push_back(n.id()); + return affected; + } + + // Reachability BFS over the raw connectivity graph (which already + // includes any collateral/loop edges): a cut node is simply never + // pushed/expanded, which is equivalent to deleting it and all of its + // edges from the graph. Anything still reachable from the root through + // some other path (e.g. an anastomosis bypassing the cut) stays + // perfused; everything else is affected. + std::vector reachable(m_nodes.size(), false); + std::queue q; + reachable[m_rootId] = true; + q.push(m_rootId); + + while (!q.empty()) + { + int u = q.front(); + q.pop(); + + auto it = m_adjacency.find(u); + if (it == m_adjacency.end()) + continue; + + for (int v : it->second) + { + if (cutSet.count(v) || reachable[v]) + continue; + reachable[v] = true; + q.push(v); + } + } + + for (const SkeletonNode& n : m_nodes) + if (cutSet.count(n.id()) || !reachable[n.id()]) + affected.push_back(n.id()); + + return affected; +} + +std::vector SkeletonGraph::affectedSegments(const std::vector& affectedNodeIds) const +{ + std::set segments; + for (int id : affectedNodeIds) + { + int seg = segmentOf(id); + if (seg != -1) + segments.insert(seg); + } + return std::vector(segments.begin(), segments.end()); +} + } // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h index 6b0cc62..200542f 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonGraph.h @@ -24,6 +24,14 @@ class SkeletonGraph /// to populate parent/children ids on the nodes. bool loadFromFile(const std::string& filename, double mergeTolerance = 1e-6); + /// Loads a skeleton already exported as VTK POLYDATA by exportToVTK() (points + + /// "parent child" LINES + a "type" POINT_DATA scalar marking the root with value + /// 1). Unlike loadFromFile(), the tree structure (parent/children ids, root) is + /// read directly from the file instead of recomputed by buildTree(); other scalar + /// fields (depth, is_loop) are read past and ignored. Returns false if the file + /// could not be opened or no root ("type"==1) was found. + bool loadFromVTK(const std::string& filename); + /// Picks the node closest to entryPoint as root and (re)computes every /// node's parentIds/childrenIds via BFS over the raw connectivity. void buildTree(const std::array& entryPoint); @@ -51,6 +59,61 @@ class SkeletonGraph void exportToVTK(const std::string& filename) const; void clear(); + // --- Liver-segment mapping ------------------------------------------------- + + /// Assigns each node a liver-segment id (e.g. an index into a list of + /// Couinaud segments) from `rawNodeLabels`, indexed the same way as + /// nodes() (rawNodeLabels[nodeId], -1 = unknown/undetermined for that + /// node, e.g. because it fell outside every segment mesh). Typically + /// produced externally per node, e.g. via a point-in-mesh test against a + /// set of closed segment meshes (see SkeletonSegmentMapper). + /// + /// Raw per-node labels can be noisy near segment boundaries, so the tree + /// is split into maximal branches (runs of nodes between the root, + /// branch points, and leaves) and every node in a branch is set to that + /// branch's majority raw label. Requires the tree to have a root + /// (buildTree() or loadFromVTK()). Branches with no labeled node at all + /// get -1. + void assignSegmentLabels(const std::vector& rawNodeLabels); + + /// Segment id assigned to a node by the last assignSegmentLabels() call, + /// or -1 if it hasn't been run (or the node has no label). + int segmentOf(int nodeId) const; + + /// Ids of all nodes currently assigned to the given segment. + std::vector nodesInSegment(int segment) const; + + /// Writes a CSV report (id, x, y, z, segment) reflecting the last + /// assignSegmentLabels() call. + void exportSegmentReportCSV(const std::string& filename) const; + + /// Same as above, but resolves each segment id to a human-readable name + /// via `segmentNames` (segmentNames[segmentId]); ids without a matching + /// entry, and -1 (unknown), are written as "unknown". + void exportSegmentReportCSV(const std::string& filename, const std::vector& segmentNames) const; + + // --- Resection (devascularization) simulation ------------------------------- + + /// Simulates a resection (vessel transection) at each of `cutNodeIds`: + /// every cut node is fully removed from the connectivity graph (all of + /// its edges, both primary tree and any loop/anastomosis edges), then + /// reachability from the root is recomputed over what remains. This is + /// deliberately NOT the same as subtree(): a node below a cut can still + /// be reachable (and so still perfused) if a collateral/anastomosis + /// connects it back to the root through a path that avoids every cut + /// node - subtree() would incorrectly flag it as affected. + /// + /// Returns every node that can no longer reach the root (i.e. would lose + /// blood supply), plus the cut nodes themselves. If the root itself is + /// cut, every node is returned. Requires hasRoot(). + std::vector simulateResection(const std::vector& cutNodeIds) const; + + /// Convenience: the distinct liver segments touched by `affectedNodeIds` + /// (typically the result of simulateResection()) - i.e. the segments + /// that would lose blood supply. Requires assignSegmentLabels() to have + /// been called already; nodes with no segment (-1) are ignored. + std::vector affectedSegments(const std::vector& affectedNodeIds) const; + private: int findOrCreateNode(const std::array& p, double tol); int closestNodeId(const std::array& p) const; @@ -60,6 +123,10 @@ class SkeletonGraph std::map> m_adjacency; ///< raw undirected connectivity from the file std::vector> m_loopEdges; int m_rootId{ -1 }; + + /// Segment id per node (parallel to m_nodes, indexed by node id), filled by + /// assignSegmentLabels(). Empty until that has been called at least once. + std::vector m_nodeSegment; }; } // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h index 6deba3d..514e199 100644 --- a/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h +++ b/src/MeshSkeletonizationPlugin/SkeletonGraph/SkeletonNode.h @@ -38,8 +38,6 @@ class SkeletonNode bool isLeaf() const { return m_childrenIds.empty(); } bool isBranchPoint() const { return m_childrenIds.size() > 1; } - // --- Optional relation to the input (vessel) mesh this skeleton came from --- - /// Index of the closest vertex in the input mesh, -1 if not computed. int meshVertexId() const { return m_meshVertexId; } void setMeshVertexId(int vId) { m_meshVertexId = vId; } diff --git a/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.cpp b/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.cpp new file mode 100644 index 0000000..88e59be --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.cpp @@ -0,0 +1,22 @@ +#define SKELETONRESECTIONSIMULATOR_CPP +#include + +#include +#include + +namespace meshskeletonizationplugin +{ +using namespace sofa::defaulttype; + +void registerSkeletonResectionSimulator(sofa::core::ObjectFactory* factory) +{ + factory->registerObjects(sofa::core::ObjectRegistrationData( + "Simulates a vessel resection at one or more skeleton nodes and reports which " + "nodes and liver segments would lose blood supply, accounting for collateral " + "(loop/anastomosis) paths that bypass the cut") + .add< SkeletonResectionSimulator >()); +} + +template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonResectionSimulator; + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.h b/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.h new file mode 100644 index 0000000..484a811 --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.h @@ -0,0 +1,95 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace sofa; +using namespace sofa::defaulttype; + +namespace meshskeletonizationplugin +{ + +template +class SkeletonResectionSimulator : public sofa::core::DataEngine +{ +public: + SOFA_CLASS(SOFA_TEMPLATE(SkeletonResectionSimulator, DataTypes), sofa::core::DataEngine); + + typedef typename DataTypes::Coord Coord; + typedef typename DataTypes::VecCoord VecCoord; + typedef typename Coord::value_type Real; + typedef type::Vec<3, Real> Vec3; + + /// The segmented skeleton to run resection scenarios against. If left + /// unset, the first SkeletonSegmentMapper found in the context is used. + sofa::core::objectmodel::SingleLink< + SkeletonResectionSimulator, + SkeletonSegmentMapper, + sofa::core::objectmodel::BaseLink::FLAG_STOREPATH | sofa::core::objectmodel::BaseLink::FLAG_STRONGLINK> + l_segmentMapper; + + /// Optional: the actual visual object (e.g. OglModel) for each segment, + /// in the same order as the linked mapper's segmentNames. If set, their + /// "color" Data is pushed directly every draw() call - more reliable + /// than a scene-level Data link, since most visual models don't re-read + /// a linked color every frame on their own. + sofa::core::objectmodel::MultiLink< + SkeletonResectionSimulator, + sofa::core::objectmodel::BaseObject, + sofa::core::objectmodel::BaseLink::FLAG_STOREPATH> + l_segmentVisualModels; + + // Inputs + sofa::core::objectmodel::Data> d_inCutNodeIds; ///< Node id(s) where the vessel is (candidate) severed + sofa::core::objectmodel::Data d_activationDelay; ///< Seconds after simulation start before affected nodes/segments actually switch color (default 5.0); everything shows as perfused (green) until then + sofa::core::objectmodel::DataFileName d_outReportFilename; ///< Optional CSV report: id, x, y, z, segment, for affected nodes only + + // Outputs + sofa::core::objectmodel::Data> d_outAffectedNodeIds; ///< Node ids that would lose blood supply (includes the cut nodes themselves) + sofa::core::objectmodel::Data d_outAffectedNodeCount; ///< Convenience: size of d_outAffectedNodeIds + sofa::core::objectmodel::Data> d_outAffectedSegmentIds; ///< Distinct segment indices touched by the affected nodes + sofa::core::objectmodel::Data> d_outAffectedSegmentNames; ///< Same, resolved to names via the linked SkeletonSegmentMapper's segmentNames + sofa::core::objectmodel::Data> d_outSegmentColors; ///< One color per segment, same order as the linked mapper's segmentNames - green until activationDelay elapses, then red for affected segments. Link an OglModel's "color" to e.g. "@resectionSim.segmentColors[0]" per segment (index syntax support depends on SOFA version). + + void init() override; + void doUpdate() override; + void draw(const sofa::core::visual::VisualParams* vparams) override; + +private: + SkeletonResectionSimulator(); + virtual ~SkeletonResectionSimulator() = default; + + /// Recomputes m_colorsActive from the current simulation time and + /// refreshes d_outSegmentColors accordingly. Called every draw() so the + /// activationDelay threshold takes effect without needing an event + /// listener (and the Sofa.Simulation.Core dependency that would add). + void updateSegmentColors(); + + /// Local working copy of the linked mapper's (already segmented) graph. + SkeletonGraph m_graph; + + /// Whether affected nodes/segments should currently render as + /// affected (red/black) rather than perfused (green) - false until + /// d_activationDelay seconds have elapsed since simulation start. + bool m_colorsActive{ false }; + + /// Guards so diagnostic messages below are logged once, not every frame. + bool m_loggedVisualModelLinkStatus{ false }; + std::vector m_loggedMissingColorData; +}; + +#if !defined(SKELETONRESECTIONSIMULATOR_CPP) +extern template class SOFA_MESHSKELETONIZATIONPLUGIN_API SkeletonResectionSimulator; +#endif + +} // namespace meshskeletonizationplugin \ No newline at end of file diff --git a/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.inl b/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.inl new file mode 100644 index 0000000..f7ac96b --- /dev/null +++ b/src/MeshSkeletonizationPlugin/SkeletonResection/SkeletonResectionSimulator.inl @@ -0,0 +1,269 @@ +#pragma once +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace meshskeletonizationplugin +{ + +template +SkeletonResectionSimulator::SkeletonResectionSimulator() + : l_segmentMapper(initLink("segmentMapper", + "Segmented skeleton to run resection scenarios against; if empty, the first " + "SkeletonSegmentMapper found in the scene is used")) + , l_segmentVisualModels(initLink("segmentVisualModels", + "Optional: the visual object (e.g. OglModel) for each segment, same order as " + "segmentNames. Its 'color' Data is pushed directly every frame - more reliable " + "than linking a color attribute to segmentColors[i] in the scene.")) + , d_inCutNodeIds(initData(&d_inCutNodeIds, "cutNodeIds", + "Node id(s) where the vessel is (candidate) severed")) + , d_activationDelay(initData(&d_activationDelay, 5.0, "activationDelay", + "Seconds after simulation start before affected nodes/segments actually switch " + "color to red/black; everything renders as perfused (green) until then")) + , d_outReportFilename(initData(&d_outReportFilename, "outReportFilename", + "Optional path to export a CSV report (id, x, y, z, segment) of the affected nodes")) + , d_outAffectedNodeIds(initData(&d_outAffectedNodeIds, "affectedNodeIds", + "Node ids that would lose blood supply (includes the cut nodes themselves)")) + , d_outAffectedNodeCount(initData(&d_outAffectedNodeCount, 0, "affectedNodeCount", + "Convenience: size of affectedNodeIds")) + , d_outAffectedSegmentIds(initData(&d_outAffectedSegmentIds, "affectedSegmentIds", + "Distinct segment indices touched by the affected nodes")) + , d_outAffectedSegmentNames(initData(&d_outAffectedSegmentNames, "affectedSegmentNames", + "Same as affectedSegmentIds, resolved to names")) + , d_outSegmentColors(initData(&d_outSegmentColors, "segmentColors", + "One color per segment (same order as the linked mapper's segmentNames): green " + "until activationDelay elapses, then red for affected segments. Link an OglModel's " + "'color' Data to e.g. '@resectionSim.segmentColors[0]' for the first segment.")) +{ + addInput(&d_inCutNodeIds); + addOutput(&d_outAffectedNodeIds); + addOutput(&d_outAffectedNodeCount); + addOutput(&d_outAffectedSegmentIds); + addOutput(&d_outAffectedSegmentNames); + addOutput(&d_outSegmentColors); +} + +template +void SkeletonResectionSimulator::init() +{ + if (!l_segmentMapper) + { + l_segmentMapper.set(this->getContext()->template get>()); + } + if (!l_segmentMapper) + { + msg_error() << "No SkeletonSegmentMapper found. Set 'segmentMapper' to a " + "valid component path, or add one earlier in the scene."; + } + + setDirtyValue(); + update(); // computes each time without waiting for something to read an output Data +} + +template +void SkeletonResectionSimulator::doUpdate() +{ + if (!l_segmentMapper) + return; + // Working on copy of the already segmented graph so the candidate is re-run per candidate without touching the mapper + m_graph = l_segmentMapper->graph(); + + const auto& cutIds = d_inCutNodeIds.getValue(); + std::vector affected = m_graph.simulateResection(cutIds); + std::vector segments = m_graph.affectedSegments(affected); + + const auto& segmentNames = l_segmentMapper->d_inSegmentNames.getValue(); + std::vector segmentNameStrs; + segmentNameStrs.reserve(segments.size()); + for (int seg : segments) + segmentNameStrs.push_back(seg >= 0 && seg < static_cast(segmentNames.size()) + ? segmentNames[seg] : "unknown"); + + d_outAffectedNodeIds.setValue(affected); + d_outAffectedNodeCount.setValue(static_cast(affected.size())); + d_outAffectedSegmentIds.setValue(segments); + d_outAffectedSegmentNames.setValue(segmentNameStrs); + + updateSegmentColors(); // initial colors; draw() keeps these fresh every frame after this + + if (d_outReportFilename.isSet() && !d_outReportFilename.getFullPath().empty()) + { + std::ofstream out(d_outReportFilename.getFullPath(), std::ofstream::out | std::ofstream::trunc); + out << "# cutNodeIds=" << cutIds.size() + << ",affectedNodeCount=" << affected.size() + << ",affectedSegmentCount=" << segments.size() + << ",affectedSegments="; + for (std::size_t i = 0; i < segmentNameStrs.size(); ++i) + out << (i ? ";" : "") << segmentNameStrs[i]; + out << "\n"; + out << "id,x,y,z,segment\n"; + out << std::fixed << std::setprecision(6); + for (int id : affected) + { + const SkeletonNode* n = m_graph.node(id); + if (!n) + continue; + const auto& p = n->position(); + int seg = m_graph.segmentOf(id); + std::string segName = (seg >= 0 && seg < static_cast(segmentNames.size())) ? segmentNames[seg] : "unknown"; + out << id << "," << p[0] << "," << p[1] << "," << p[2] << "," << segName << "\n"; + } + } +} + +template +void SkeletonResectionSimulator::updateSegmentColors() +{ + // colors of the segments before and after (green --> red) + static const sofa::type::RGBAColor safeColor(0.20f, 0.80f, 0.20f, 1.0f); + static const sofa::type::RGBAColor affectedColor(0.90f, 0.10f, 0.10f, 1.0f); + + m_colorsActive = (this->getContext()->getTime() >= d_activationDelay.getValue()); + + if (!l_segmentMapper) + return; + + // --- Diagnostics: run once, so we can see exactly what's wrong instead of silently doing nothing. + if (!m_loggedVisualModelLinkStatus) + { + m_loggedVisualModelLinkStatus = true; + if (l_segmentVisualModels.empty()) + { + msg_warning() << "segmentVisualModels is empty: no visual objects linked, so no " + "mesh color will ever change. Check the 'segmentVisualModels' " + "attribute/paths in the scene."; + } + else + { + m_loggedMissingColorData.assign(l_segmentVisualModels.size(), false); + for (std::size_t i = 0; i < l_segmentVisualModels.size(); ++i) + { + sofa::core::objectmodel::BaseObject* obj = l_segmentVisualModels.get(i); + if (!obj) + { + msg_warning() << "segmentVisualModels[" << i << "] did not resolve to any object " + "(bad path?)."; + continue; + } + msg_info() << "segmentVisualModels[" << i << "] resolved to '" << obj->getName() + << "' (" << obj->getClassName() << ")."; + } + } + } + + const auto& segmentNames = l_segmentMapper->d_inSegmentNames.getValue(); + const auto& segments = d_outAffectedSegmentIds.getValue(); + std::set affectedSegSet(segments.begin(), segments.end()); + + sofa::helper::WriteAccessor>> colors(d_outSegmentColors); + colors.resize(segmentNames.size()); + for (std::size_t i = 0; i < segmentNames.size(); ++i) + colors[i] = (m_colorsActive && affectedSegSet.count(static_cast(i))) ? affectedColor : safeColor; + + // Push directly into each linked visual model's own "color" Data, if + // provided - this is what actually makes the mesh repaint, since a + // passive scene-level Data link to segmentColors[i] isn't guaranteed to + // be re-read every frame by the visual model itself. + for (std::size_t i = 0; i < l_segmentVisualModels.size() && i < colors.size(); ++i) + { + sofa::core::objectmodel::BaseObject* obj = l_segmentVisualModels.get(i); + if (!obj) + continue; + + // OglModel doesn't expose a plain "color" Data that is why this method was used + sofa::core::objectmodel::BaseData* materialData = obj->findData("material"); + if (!materialData) + { + if (i < m_loggedMissingColorData.size() && !m_loggedMissingColorData[i]) + { + m_loggedMissingColorData[i] = true; + std::ostringstream fields; + for (sofa::core::objectmodel::BaseData* d : obj->getDataFields()) + fields << d->getName() << " "; + msg_warning() << "'" << obj->getName() << "' (" << obj->getClassName() + << ") has no Data named 'material' either. Its actual Data fields are: " + << fields.str(); + } + continue; + } + + std::istringstream iss(materialData->getValueString()); + std::vector tokens{ std::istream_iterator(iss), std::istream_iterator() }; + + auto diffuseIt = std::find(tokens.begin(), tokens.end(), "Diffuse"); + if (diffuseIt == tokens.end() || std::distance(diffuseIt, tokens.end()) < 6) + { + if (i < m_loggedMissingColorData.size() && !m_loggedMissingColorData[i]) + { + m_loggedMissingColorData[i] = true; + msg_warning() << "Could not find a 'Diffuse r g b a' pattern in '" + << obj->getName() << "'s material string: " << materialData->getValueString(); + } + continue; + } + + const auto& c = colors[i]; + *(diffuseIt + 1) = "1"; // force useDiffuse on, so our color is actually applied + std::ostringstream rs, gs, bs, as; + rs << c[0]; gs << c[1]; bs << c[2]; as << c[3]; + *(diffuseIt + 2) = rs.str(); + *(diffuseIt + 3) = gs.str(); + *(diffuseIt + 4) = bs.str(); + *(diffuseIt + 5) = as.str(); + + std::ostringstream newStr; + for (std::size_t k = 0; k < tokens.size(); ++k) + newStr << (k ? " " : "") << tokens[k]; + materialData->read(newStr.str()); + } +} + +template +void SkeletonResectionSimulator::draw(const sofa::core::visual::VisualParams* vparams) +{ + updateSegmentColors(); // keeps segmentColors (and m_colorsActive) current every frame + + if (!vparams->displayFlags().getShowBehaviorModels()) + return; + + static const sofa::type::RGBAColor perfusedColor(0.20f, 0.80f, 0.20f, 1.0f); + static const sofa::type::RGBAColor affectedColor(0.0f, 0.0f, 0.0f, 1.0f); + static const sofa::type::RGBAColor cutColor(1.0f, 1.0f, 1.0f, 1.0f); + + const auto& affected = d_outAffectedNodeIds.getValue(); + std::set affectedSet(affected.begin(), affected.end()); + std::set cutSet(d_inCutNodeIds.getValue().begin(), d_inCutNodeIds.getValue().end()); + + std::vector points; + std::vector colors; + points.reserve(m_graph.nodes().size()); + colors.reserve(m_graph.nodes().size()); + + for (const SkeletonNode& n : m_graph.nodes()) + { + const auto& p = n.position(); + points.emplace_back(p[0], p[1], p[2]); + + if (!m_colorsActive) + colors.push_back(perfusedColor); // before activationDelay: everything shows as perfused + else if (cutSet.count(n.id())) + colors.push_back(cutColor); + else if (affectedSet.count(n.id())) + colors.push_back(affectedColor); + else + colors.push_back(perfusedColor); + } + + vparams->drawTool()->drawPoints(points, 7.0f, colors); +} + +} // namespace meshskeletonizationplugin diff --git a/src/MeshSkeletonizationPlugin/init.cpp b/src/MeshSkeletonizationPlugin/init.cpp index 6527428..4c994ef 100644 --- a/src/MeshSkeletonizationPlugin/init.cpp +++ b/src/MeshSkeletonizationPlugin/init.cpp @@ -30,6 +30,8 @@ namespace meshskeletonizationplugin extern void registerMeshSkeletonization(sofa::core::ObjectFactory* factory); //extern void registerSkeletonizationLoader(sofa::core::ObjectFactory* factory); extern void registerSkeletonReader(sofa::core::ObjectFactory* factory); +extern void registerSkeletonSegmentMapper(sofa::core::ObjectFactory* factory); +extern void registerSkeletonResectionSimulator(sofa::core::ObjectFactory* factory); //Here are just several convenient functions to help users know what the plugin contains extern "C" { @@ -82,7 +84,9 @@ void registerObjects(sofa::core::ObjectFactory* factory) { registerMeshSkeletonization(factory); // registerSkeletonizationLoader(factory); - registerSkeletonReader(factory); + registerSkeletonReader(factory); + registerSkeletonSegmentMapper(factory); + registerSkeletonResectionSimulator(factory); } } From ca12630cdc93fa8d694cb2176376d5b6fe9c1c3b Mon Sep 17 00:00:00 2001 From: Kamelia Date: Tue, 25 Aug 2026 15:42:44 +0200 Subject: [PATCH 10/12] Addition of needed scene file for trial segmentectomy --- .gitignore | 1 - TestScene.scn | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 TestScene.scn diff --git a/.gitignore b/.gitignore index 73a7d6f..5d43e36 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,5 @@ *.vtk *.obj *.sxn -*.scn *.csv diff --git a/TestScene.scn b/TestScene.scn new file mode 100644 index 0000000..d8507a8 --- /dev/null +++ b/TestScene.scn @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From a7a5b2cd094edbd489764b752dcc3098e0221665 Mon Sep 17 00:00:00 2001 From: epernod Date: Tue, 25 Aug 2026 17:31:28 +0200 Subject: [PATCH 11/12] rm data --- .../Patient_08_venoussystem_skeleton.txt | 1330 ----------------- 1 file changed, 1330 deletions(-) delete mode 100644 data/patient_08/Patient_08_venoussystem_skeleton.txt diff --git a/data/patient_08/Patient_08_venoussystem_skeleton.txt b/data/patient_08/Patient_08_venoussystem_skeleton.txt deleted file mode 100644 index e824fde..0000000 --- a/data/patient_08/Patient_08_venoussystem_skeleton.txt +++ /dev/null @@ -1,1330 +0,0 @@ -124.847 84.4897 34.42 -124.929 84.5022 34.5772 -125.643 84.5831 35.8539 -125.901 84.7885 37.7116 - -123.042 88.3776 54.5085 -123.214 88.515 55.2484 - -194.212 110.69 160.864 -193.643 111.415 161.304 -192.833 112.434 161.934 -192.446 112.91 162.239 -191.02 114.77 163.445 -191.85 115.854 164.196 - -65.8874 136.055 49.1372 -66.6845 135.002 50.0835 -66.8917 134.726 50.3257 -68.0989 133.096 51.7116 -69.0322 131.751 52.7607 -70.0813 130.187 53.8771 -70.8367 128.629 54.3381 -71.6768 126.994 55.2105 -72.1984 126.006 55.8317 -72.5729 125.076 56.1057 -73.9801 119.509 57.1376 - -78.071 158.086 59.845 -78.1325 157.866 60.8743 -78.2282 157.485 62.6068 -78.3101 157.142 64.1188 -78.3664 156.924 65.3104 -78.392 156.826 65.8751 -78.4147 156.996 67.9795 - -60.2039 155.341 71.6785 -60.3399 155.33 72.5722 -60.4304 155.324 73.1424 -60.7675 155.323 75.1102 -61.0034 155.266 77.2087 -61.0796 155.278 78.0135 -61.1706 155.428 79.4894 -61.0173 156.758 81.4062 - -137.163 85.092 74.5876 -137.006 85.1093 75.4299 -136.791 85.1271 76.6176 -136.37 85.1386 78.9678 -136.104 85.3324 82.2544 -136.513 85.7459 84.3486 -136.749 85.9748 85.5818 -136.82 86.2036 87.085 -137.913 86.9824 90.8748 - -104.1 86.5675 70.8634 -102.958 88.3178 71.4794 -102.37 89.953 72.9031 - -59.6024 138.075 81.831 -59.6619 138.109 81.8917 -60.5798 138.655 82.7245 -62.2433 139.653 84.0144 -63.8185 140.449 84.9221 -64.7391 140.795 85.3336 -67.2101 141.299 86.6562 - -125.457 106.864 158.045 -122.632 103.734 149.272 - -125.457 106.864 158.045 -126.737 109.082 159.321 -127.961 111.187 161.484 -128.532 112.153 162.541 -128.794 112.596 163.027 -129.14 113.18 163.665 -129.586 113.948 164.516 -130.03 114.817 165.447 -130.227 116.673 167.898 - -125.457 106.864 158.045 -124.617 105.028 158.788 -124.534 103.932 160.485 -124.681 103.259 161.692 -124.875 102.132 163.675 -124.889 101.083 165.303 -124.797 99.7985 167.085 -124.613 98.9346 168.069 -124.491 98.4369 168.659 - -84.9269 179.043 85.5297 -84.9876 178.452 86.3632 -85.1387 176.786 88.6976 -85.222 175.019 91.0726 -85.2864 173.549 93.0427 -85.3214 172.774 94.0817 -85.3519 172.048 95.0576 -85.4086 170.568 97.0421 -84.8833 168.875 99.1214 -84.3757 167.435 100.86 -83.7539 165.739 102.859 -82.7873 163.469 105.302 -81.7354 162.01 107.086 -81.0079 160.186 108.87 -78.5962 158.884 111.503 - -148.79 75.3299 87.1424 -148.406 75.6382 87.7389 -147.667 76.2275 88.8712 -147.3 76.5477 89.5006 -146.747 77.2283 90.9686 -146.403 77.6623 91.9134 -145.849 78.3654 93.4483 -145.587 78.7011 94.1836 -145.321 79.0457 94.943 -144.671 80.0604 97.4016 -144.557 80.7497 99.5844 -144.551 81.1474 100.942 -143.789 82.3533 103.716 - -61.0173 156.758 81.4062 -60.0179 160.838 81.2346 -59.3482 163.105 80.9458 -58.9502 164.585 80.7231 -58.9488 164.591 80.7222 -58.947 164.597 80.721 - -61.0173 156.758 81.4062 -61.5186 155.006 82.5176 -61.7994 153.031 84.8869 -63.3386 151.021 85.3607 -64.6575 149.411 85.8313 -66.0364 147.811 86.2995 -68.073 144.339 87.0143 -67.2101 141.299 86.6562 - -90.7024 140.89 85.4398 -90.4432 141.064 85.4101 -89.0715 141.99 85.2423 -88.2669 142.511 85.1326 -86.9446 143.145 84.862 -85.5599 143.709 84.6407 -82.6381 144.087 84.6342 -80.3282 144.293 84.7584 - -142.957 87.784 89.5012 -142.26 87.6998 89.5785 -140.827 87.4643 89.6202 -137.913 86.9824 90.8748 - -115.064 95.1406 94.0754 -114.321 98.0252 95.5105 - -115.064 95.1406 94.0754 -116.119 93.7546 97.1936 -116.302 93.6433 97.997 -116.924 93.3885 99.9499 -117.469 93.0765 101.913 -118.322 92.695 103.737 -118.684 92.5415 104.437 -119.342 92.1358 105.522 -121.308 90.1466 110.362 - -115.064 95.1406 94.0754 -114.826 94.7176 92.168 -114.245 94.4389 88.7568 -113.874 94.0078 86.2572 -113.015 93.611 83.2099 -112.247 93.2826 80.8076 -108.779 92.0873 75.342 - -83.0616 116.469 101.194 -83.0746 116.601 101.15 -83.1327 117.256 100.923 -83.2576 118.403 100.523 -83.4035 119.602 100.087 -83.7359 121.925 99.2861 -83.2766 125.401 96.3324 - -60.1339 110.395 99.8877 -60.0678 110.68 100.002 -59.8273 111.751 100.435 -59.5351 113.299 101.053 -59.2226 114.997 101.732 -58.9327 116.846 102.464 -59.3508 118.136 103.057 -60.5475 121.632 104.644 -61.615 124.739 106.053 -61.8904 125.528 106.403 -62.4854 127.186 107.098 -63.0756 128.838 107.795 -63.7248 130.624 108.502 -64.17 131.873 108.995 -64.5734 133.253 109.473 -64.0551 135.842 109.722 -65.7557 138.894 109.509 - -90.3733 123.382 100.082 -88.3308 124.128 99.6338 -87.6055 124.725 99.4783 -85.4958 125.715 98.3503 -83.2766 125.401 96.3324 - -105.728 86.0623 102.144 -105.763 86.9818 103.358 -106.349 88.3762 105.107 -106.883 89.5362 106.576 -105.863 91.6136 109.516 - -59.0806 172.943 102.879 -59.6145 172.107 103.97 -60.5768 170.592 105.928 -61.0244 169.905 106.777 -61.5277 169.14 107.71 -62.047 168.265 108.807 -62.5938 167.02 110.478 -65.2745 163.976 113.788 - -75.289 183.143 109.052 -75.2835 182.848 109.515 - -123.214 88.515 55.2484 -124.06 88.0184 53.2858 -124.334 87.7243 52.0909 -124.835 87.2365 50.1839 -125.645 86.5985 48.0148 - -123.214 88.515 55.2484 -121.99 89.1055 57.8561 -121.431 89.3442 58.8862 -119.522 90.1316 62.2955 -118.835 90.4081 63.4899 -117.418 90.9507 65.7539 -116.89 91.1439 66.5483 -112.438 92.2765 70.8728 -110.461 92.2893 72.2288 - -88.1816 97.2536 110.696 -89.0148 96.5852 110.893 -89.856 95.9571 110.972 -90.8048 95.2674 111.024 -92.7994 92.9853 111.383 - -151.772 79.6779 129.217 -151.394 80.3266 130.898 -150.917 81.1439 133.018 -150.324 82.2103 135.811 -149.825 83.1552 138.307 -149.436 83.9595 140.454 -148.882 85.2101 143.79 -148.467 86.28 146.761 -148.289 87.0198 148.749 -147.851 86.5095 151.619 - -49.9261 142.58 119.632 -50.2884 142.488 119.362 -51.4191 142.121 118.54 -52.2455 141.411 117.977 - -65.3679 171.39 129.221 -66.0789 171.467 128.962 -66.4468 171.508 128.829 -67.8691 171.683 128.31 -69.7787 171.918 127.627 -71.8539 172.404 126.74 -76.4149 173.901 124.526 - -105.486 162.228 145.628 -105.639 161.646 146.29 -105.717 161.328 146.653 -105.961 160.159 147.997 -106.125 159.239 149.051 -105.701 158.994 149.604 -105.232 158.731 150.218 -102.836 158.339 152.718 - -52.9788 155.622 146.398 -54.2184 155.689 147.308 - -58.595 116.628 149.578 -59.5359 117.068 150.013 -60.6451 117.579 150.541 -61.5376 117.98 150.973 -62.7628 117.635 152.398 - -51.8804 157.179 146.412 -53.4637 156.257 147.056 -54.2184 155.689 147.308 - -46.6617 140.452 147.581 -47.146 140.405 147.678 -48.5185 140.264 147.956 -50.9146 139.98 148.448 -53.1244 139.685 148.946 -55.5227 139.344 149.58 -58.2477 138.93 150.348 -60.6974 138.317 151.733 -61.881 137.993 152.521 -62.5414 137.793 152.983 -64.3833 137.64 154.341 -66.0255 137.624 155.595 -69.3503 138.067 158.082 - -147.944 82.6213 150.006 -147.867 83.5909 150.499 -147.787 84.8522 151.226 -147.851 86.5095 151.619 - -99.615 95.6746 147.363 -99.1811 92.8 143.863 -98.5766 91.8938 142.548 -98.3313 91.5686 142.074 -97.8069 90.9323 141.139 -96.6192 89.517 139.041 - -99.615 95.6746 147.363 -102.972 97.3308 149.452 -104.724 97.7544 150.579 - -99.615 95.6746 147.363 -96.1198 96.1695 147.903 -95.0086 96.1916 147.91 -93.1309 96.1242 147.756 -91.1169 95.9514 147.36 -88.2995 95.8544 146.527 -86.8508 95.7558 145.991 -85.4867 95.6793 145.513 -81.8621 95.3218 144.064 -80.0653 95.1249 143.33 -78.6254 94.9421 142.705 -78.1847 94.8804 142.515 - -90.5135 150.292 138.104 -86.8999 147.594 131.34 -85.7142 146.474 129.26 -85.0025 145.966 127.84 -83.4109 144.779 124.722 -81.5923 143.393 121.457 -80.619 142.64 119.533 - -90.5135 150.292 138.104 -90.9449 156.055 135.739 -91.046 156.754 135.604 -91.003 159.158 134.818 -90.9703 160.014 134.535 -90.508 161.847 133.739 -88.8763 164.418 132.233 -88.0501 165.851 131.555 -87.0119 167.71 130.646 -85.5179 171.209 128.274 - -90.5135 150.292 138.104 -91.7676 149.196 141.659 -92.6349 148.853 143.849 -94.066 148.192 147.703 -94.401 146.989 152.587 - -117.221 76.2543 102.398 -117.477 76.6777 103.125 -118.17 77.7991 105.035 -118.751 78.9295 106.95 -119.366 80.2807 109.132 -119.813 81.2675 110.718 -120.326 82.4553 112.487 -120.452 84.0333 114.02 -120.492 84.7095 114.356 -120.903 88.3144 116.109 - -54.2184 155.689 147.308 -57.0426 154.63 149.221 -58.5487 153.913 149.791 -59.8621 153.294 150.305 -60.9499 152.784 150.755 -61.8698 152.348 151.137 -62.8903 151.86 151.561 -64.4202 151.129 152.209 -66.049 150.344 152.905 -68.2328 149.278 153.867 -70.8738 147.886 155.079 -75.1578 146.144 156.294 - -122.632 103.734 149.272 -117.694 103.487 151.503 - -122.632 103.734 149.272 -123.145 102.933 146.461 -123.447 102.248 144.325 -123.82 101.861 142.852 -124.038 101.061 140.313 -124.281 100.052 137.138 -124.09 99.1014 134.701 -123.87 98.2222 132.421 -123.533 97.3655 130.079 -123.059 96.2007 126.885 -122.742 95.3799 124.62 -122.636 94.6555 123.085 -122.51 94.0483 121.798 -122.185 93.2856 120.15 -121.861 92.5243 118.589 -120.903 88.3144 116.109 - -118.701 106.065 155.053 -117.694 103.487 151.503 - -64.4974 164.956 157.59 -64.5156 164.946 157.598 -65.0859 164.625 157.85 -66.3986 163.876 158.422 -67.6684 162.831 158.559 -69.0688 161.62 158.644 -70.9686 159.96 158.75 -72.4147 158.653 158.796 -74.1191 157.101 158.843 -76.2692 154.908 158.734 -77.8233 153.315 158.644 -77.9301 152.355 158.274 -77.9222 151.356 157.794 -77.5416 150.202 157.441 -75.1578 146.144 156.294 - -117.694 103.487 151.503 -115.42 103.032 151.971 -113.722 102.385 151.522 -112.305 101.886 151.08 -110.468 101.446 150.166 - -201.848 162.011 83.8723 -201.124 161.121 84.8928 -200.194 160.251 87.0208 - -67.0005 130.345 158.177 -72.0285 129.975 162.498 -73.639 127.635 164.847 -74.6077 125.423 166.914 -77.3838 122.734 169.568 - -67.0005 130.345 158.177 -63.0468 129.398 156.51 -62.0203 129.257 156.478 -61.0808 129.26 156.412 -59.0677 129.253 156.27 -58.1169 129.26 156.256 -57.6527 129.276 156.318 -57.024 129.303 156.48 - -67.0005 130.345 158.177 -66.4227 127.289 156.419 -66.3024 125.243 155.531 -65.3908 121.006 153.687 -62.7628 117.635 152.398 - -67.0005 130.345 158.177 -69.3503 138.067 158.082 - -95.6139 165.986 154.885 -96.3134 165.368 154.77 -97.102 164.67 154.642 -98.8221 163.138 154.372 -99.7056 161.844 154.137 -100.648 160.434 153.897 -102.836 158.339 152.718 - -219.934 113.058 162.207 -218.951 113.721 162.473 -216.507 115.078 163.08 -213.201 115.421 163.34 -211.098 115.528 163.466 -209.969 115.582 163.532 -209.625 115.598 163.552 -208.593 115.644 163.61 -207.315 115.7 163.682 -206.195 115.747 163.743 -204.462 115.814 163.836 -203.275 115.857 163.897 -201.767 115.91 163.975 -199.614 115.981 164.081 -197.699 116.042 164.174 -195.356 116.063 164.251 -191.85 115.854 164.196 - -153.62 112.901 167.546 -157.111 113.414 167.089 - -153.62 112.901 167.546 -149.791 109.724 169.376 -149.438 108.554 169.871 -149.286 108.163 169.813 -147.6 103.59 168.988 - -153.62 112.901 167.546 -149.915 115.226 166.531 -147.437 116.318 166.089 -145.268 117.172 165.542 -142.772 118.189 164.888 -141.038 119.129 164.274 -139.629 119.958 163.805 -137.462 121.764 162.517 - -113.148 122.841 173.304 -111.953 122.8 173.804 - -113.148 122.841 173.304 -115.304 123.432 172.989 -116.774 123.932 172.879 -118.334 124.481 172.781 -119.206 124.788 172.726 -121.121 125.456 172.597 -123.168 126.268 172.627 -124.975 126.993 172.69 -125.924 127.377 172.74 - -113.148 122.841 173.304 -111.797 122.127 173.146 -109.777 121.373 173.237 -107.475 120.518 173.343 -106.354 120.102 173.396 -104.263 119.326 173.493 -100.703 118.019 173.664 -98.6779 117.373 173.819 -96.9282 117.471 173.852 -96.1139 117.51 173.868 -94.6261 117.581 173.896 -92.7821 117.672 173.929 -84.9554 118.093 174.051 -83.5101 119.082 173.103 -82.7744 119.619 172.59 -81.9479 120.223 172.012 -81.2223 120.752 171.503 -80.35 121.406 170.873 -79.2821 121.689 170.595 -77.3838 122.734 169.568 - -169.647 103.832 166.361 -167.651 106.343 166.082 -166.241 108.065 166.461 -164.779 109.874 166.659 -166.755 112.973 165.526 - -169.647 103.832 166.361 -170.795 103.121 169.698 -171.284 102.76 170.868 -172.046 102.205 172.538 -172.624 101.834 173.708 -173.386 101.603 174.246 - -169.647 103.832 166.361 -170.013 102.384 162.458 -170.805 100.589 159.464 -171.825 98.2257 155.406 -173.033 95.8115 151.423 -174.218 93.5197 147.414 -174.691 92.399 145.017 -175.121 91.4092 142.871 -175.981 89.5399 138.873 -177.245 88.2945 136.794 -178.653 86.4597 133.523 - -144.878 102.899 174.575 -145.926 102.852 172.102 -147.6 103.59 168.988 - -157.111 113.414 167.089 -155.956 112.376 164.095 -155.767 110.934 161.429 -155.805 110.262 160.268 - -157.111 113.414 167.089 -159.262 113.363 166.721 -160.313 113.329 166.517 -161.797 113.25 166.285 -163.174 113.143 166.082 -166.755 112.973 165.526 - -86.4552 138.786 182.726 -86.6826 138.82 182.694 -88.0337 138.451 182.615 -89.1041 139.051 182.228 -90.7668 139.753 181.623 -91.568 140.136 181.318 -97.8852 142.007 177.897 - -76.4149 173.901 124.526 -73.0052 175.991 122.067 -73.7819 178.355 118.272 - -76.4149 173.901 124.526 -80.6521 172.429 126.21 -82.1857 172.136 126.748 -85.5179 171.209 128.274 - -110.468 101.446 150.166 -109.014 102.08 148.018 - -110.468 101.446 150.166 -108.398 100.169 150.271 -107.086 99.2783 150.439 -104.724 97.7544 150.579 - -183.805 83.5312 107.034 -182.672 83.9233 110.921 -181.76 84.2278 113.572 -180.878 84.5326 116.585 -180.129 84.7947 119.226 -179.648 84.9788 120.996 -179.245 85.1445 122.486 -178.704 85.2489 123.758 -177.811 84.9822 124.699 -177.024 84.7271 125.434 -176.097 84.5352 126.866 - -183.805 83.5312 107.034 -184.724 83.2719 106.16 -185.453 83.0613 105.256 - -183.805 83.5312 107.034 -183.315 83.597 104.329 -183.147 83.6126 103.086 -183.19 83.5729 101.808 -183.235 83.5298 100.405 - -85.8789 90.414 113.068 -88.1286 90.9798 112.686 -89.6339 91.5392 112.316 -90.8942 92.0501 111.967 -92.7994 92.9853 111.383 - -62.2229 140.746 166.423 -62.5428 140.75 166.295 -63.8134 140.762 165.756 -65.5329 140.774 165.02 -69.1583 140.775 163.383 -70.4663 140.718 162.331 -71.0564 140.71 161.605 -70.9685 140.637 160.562 -70.8593 140.397 158.559 - -214.075 90.4427 105.451 -213.86 91.0083 107.619 -213.646 91.4771 109.374 -212.969 92.0581 110.811 -212.249 92.6467 112.194 -211.869 92.9524 112.903 -209.612 94.7392 117.003 -208.035 95.9874 119.867 -206.526 97.1813 122.605 -205.428 98.051 124.601 -203.941 99.2284 127.302 -202.409 100.433 130.056 -200.388 102.067 133.851 - -137.098 134.09 147.622 -134.623 132.853 151.31 - -137.098 134.09 147.622 -137.85 134.9 145.148 -138.546 135.479 143.226 -139.225 136.045 140.711 -140.361 136.347 136.975 -140.855 136.477 135.356 -141.22 136.573 134.162 -141.909 136.728 131.841 -142.705 136.625 128.71 -143.103 136.566 127.024 -143.411 136.52 125.714 -143.8 136.461 124.044 -144.272 136.368 121.207 -144.838 136.232 116.982 -145.098 136.164 114.943 -145.202 136.135 114.091 -145.533 136.058 111.62 -146.238 136.047 108.485 -146.539 136.052 107.311 -146.75 136.038 106.242 -147.794 136.206 104.565 -149.71 136.551 102.057 -151.631 136.917 100.099 -152.834 137.101 97.8628 - -137.098 134.09 147.622 -140.206 132.06 152.686 -141.508 132.159 152.541 -142.919 131.961 153.077 -143.337 131.665 153.163 -145.583 128.927 152.801 -147.056 126.976 152.362 -147.975 125.733 152.035 -148.881 124.505 151.68 -150.002 122.957 151.274 -151.344 121.712 150.116 -153.14 120.126 148.511 -154.545 119.009 147.154 - -94.401 146.989 152.587 -98.2275 147.032 153.527 -100.515 147.028 154.956 - -94.401 146.989 152.587 -91.9812 146.575 153.567 -90.6046 146.36 154.346 -87.6461 146.343 154.728 -86.6685 146.277 154.882 -80.5806 146.487 155.935 -75.1578 146.144 156.294 - -93.6349 150.686 107.521 -93.5741 150.643 107.536 -92.6802 150.014 107.735 -90.3461 148.391 108.194 -87.7417 146.639 108.314 -82.5022 143.212 108.495 -78.7852 141.901 110.422 - -100.531 94.6789 33.5643 -100.353 95.0535 35.6746 -100.311 95.1391 36.1734 -100.179 95.3463 37.0777 -100.162 95.4491 38.2798 -99.7832 95.5787 39.87 -98.4802 95.8123 42.5902 - -72.8208 105.14 35.2123 -72.7628 105.807 36.1948 -72.6135 107.594 38.8184 -72.5596 109.027 40.8303 -72.5508 111.297 43.9262 -72.6056 111.86 44.388 -72.6875 112.526 45 -72.736 113.612 45.5606 -72.7807 115.338 46.39 -72.8152 116.523 47.0159 -72.8121 119.169 47.7203 - -127.503 83.8366 36.4597 -125.901 84.7885 37.7116 - -93.2669 95.8549 42.5271 -94.2488 95.8892 42.9568 -98.4802 95.8123 42.5902 - -147.851 86.5095 151.619 -147.95 89.3227 153.319 -147.881 90.539 154.9 -147.851 92.4524 156.779 -147.804 94.2277 158.692 -147.798 94.412 158.898 -147.778 95.1611 159.731 -147.757 95.9829 160.639 -147.744 96.7291 161.452 -147.728 97.8233 162.635 -147.686 99.6101 164.613 -147.6 103.59 168.988 - -73.4588 110.468 60.4054 -73.8005 111.867 60.4663 -74.2254 116.638 58.7871 -73.9801 119.509 57.1376 - -80.0347 128.548 125.692 -79.6636 129.345 125.723 -79.2256 130.962 125.236 -77.3069 131.484 124.371 - -53.1627 149.63 106.66 -54.3526 148.384 107.549 -55.3439 147.353 108.228 -56.7029 145.936 109.141 -58.0363 144.486 109.819 -60.2184 141.923 110.96 - -96.051 182.453 114.395 -95.8722 181.658 114.877 -95.5631 180.898 115.463 -95.221 179.989 116.198 -94.5418 178.171 117.661 -94.1405 177.03 118.525 -93.3338 175.4 119.843 - -201.409 161.651 87.2789 -200.194 160.251 87.0208 - -52.2455 141.411 117.977 -55.2916 141.535 115.95 -56.7823 141.5 114.945 -60.2184 141.923 110.96 - -52.2455 141.411 117.977 -51.0541 140.335 118.923 -50.5032 139.992 119.338 -50.1404 139.782 119.608 - -83.033 178.113 134.072 -83.568 176.122 133.049 -83.7573 175.436 132.675 -83.9421 174.715 132.264 -84.2232 173.744 131.678 -84.4189 173.074 131.199 -84.6744 172.327 130.77 -85.5179 171.209 128.274 - -54.6579 116.021 125.201 -55.9795 116.287 125.151 -57.1855 116.563 125.111 -59.4458 117.38 125.062 -63.2676 118.529 124.945 - -62.6789 113.824 154.732 -62.9124 115.255 153.96 -62.7628 117.635 152.398 - -103.424 139.242 164.383 -101.803 141.887 161.722 -101.136 142.794 160.754 -101.369 143.464 159.673 -100.515 147.028 154.956 - -181.919 113.747 160.026 -183.167 115.827 163.453 -183.837 116.927 164.886 -187.954 117.175 165.248 -189.649 116.67 164.845 -191.85 115.854 164.196 - -181.919 113.747 160.026 -175.277 114.133 162.987 -173.927 114.074 163.36 -170.51 114.013 164.447 -168.158 113.647 165.115 -166.755 112.973 165.526 - -181.919 113.747 160.026 -184.289 112.924 157.704 -185.314 111.936 155.535 -186.055 111.229 153.98 -186.655 110.968 153.298 -187.594 110.624 152.351 -188.453 110.213 151.365 -189.325 109.697 150.242 -189.968 109.302 149.392 -190.524 108.95 148.637 -191.124 108.562 147.808 -192.145 107.887 146.369 -192.981 107.322 145.167 -193.935 106.676 143.794 -194.407 106.355 143.111 -195.09 105.885 142.109 -195.806 105.389 141.054 -196.937 104.584 139.323 -198.614 103.35 136.622 -200.388 102.067 133.851 - -124.018 117.11 176.88 -124.776 117.435 176.679 -126.384 118.116 176.214 -127.229 118.318 175.476 -127.71 118.401 174.968 -128.481 118.313 173.777 -129.285 118.213 172.479 -130.227 116.673 167.898 - -72.8121 119.169 47.7203 -72.5342 121.663 45.6542 -72.4665 121.793 44.106 -72.3487 122.123 43.165 -72.1927 122.505 41.9108 -72.1556 122.598 41.6129 -72.0415 122.878 40.7008 -71.8382 123.378 39.0778 -71.5627 124.111 36.8786 -71.1584 125.81 33.6384 -71.0324 126.556 32.5039 - -72.8121 119.169 47.7203 -73.2291 119.406 51.4996 -73.9801 119.509 57.1376 - -134.623 132.853 151.31 -133.954 129.566 155.945 -134.209 128.131 157.348 -134.428 126.48 158.935 -135.042 124.917 160.126 -135.427 123.843 160.935 -137.462 121.764 162.517 - -134.623 132.853 151.31 -132.381 133.243 152.498 -130.198 133.269 154.174 -128.142 133.489 155.507 -125.215 134.943 155.871 -123.636 135.754 156.034 -122.364 136.328 156.274 -121.335 136.793 156.467 -120.322 137.251 156.657 -119.315 137.706 156.846 -117.81 138.387 157.133 -114.438 139.91 157.771 -113.287 140.442 158.036 -111.115 141.497 158.904 -108.582 142.76 159.536 - -138.162 138.601 9.71481 -139.196 137.043 17.2367 -140.009 135.837 23.3368 -140.225 135.518 24.9814 -140.494 135.121 27.0234 -140.704 134.811 28.6256 -140.95 134.446 30.4981 -141.365 133.834 33.6622 -141.665 133.403 36.3515 -141.873 133.115 38.5699 -141.973 132.977 39.6369 -142.103 132.797 41.0426 -142.246 132.598 42.5289 -142.504 132.277 46.0637 -142.733 132.034 49.9747 -142.825 131.937 51.5179 -142.906 131.851 52.8913 -143.052 131.702 55.165 -143.173 131.575 57.1548 -143.194 131.693 59.6412 -143.151 131.824 61.5241 -143.134 131.928 63.073 -143.083 132.098 65.6293 -142.991 132.436 70.5731 -142.816 132.695 73.3165 -142.2 132.875 75.0686 -141.329 133.133 77.5512 -139.671 133.2 79.1787 - -130.218 84.4908 44.9766 -129.854 84.658 44.9649 -125.645 86.5985 48.0148 - -125.645 86.5985 48.0148 -125.525 86.1982 45.3974 -125.6 85.9339 43.9746 -125.72 85.6376 42.4654 -125.901 84.7885 37.7116 - -99.134 98.6006 58.3369 -100.866 96.8182 55.5209 - -77.5689 162.766 66.1985 -77.6291 162.511 66.347 -77.7696 161.54 66.8938 -77.8554 160.992 67.1833 -78.0001 160.011 67.6884 -78.4147 156.996 67.9795 - -86.2866 91.5121 71.941 -87.0984 91.4126 72.2989 -89.4314 91.1494 73.3702 -92.0223 90.9428 74.8762 -95.0145 90.8691 74.3417 -96.611 90.8302 74.0764 -97.9104 90.7819 73.8512 -99.0862 90.4824 73.5335 -102.37 89.953 72.9031 - -71.6117 104.63 83.3448 -70.9731 106.201 83.0274 -70.1649 108.405 82.6446 -69.5535 110.538 82.3844 -68.9269 113.019 82.1301 -69.8552 114.587 82.7025 -71.1654 117.024 83.5028 -72.3494 118.96 84.1649 -73.4834 120.613 84.7469 -74.3676 121.51 85.1141 -75.6483 122.63 85.5455 -76.9758 123.252 85.142 -81.7039 124.026 85 - -75.5857 183.215 108.611 -75.5789 183.197 108.646 -75.5652 183.162 108.713 -75.2835 182.848 109.515 - -56.2777 165.156 116.875 -57.2439 165.052 116.564 -57.4957 165.022 116.484 -58.7704 164.867 116.073 -59.8366 164.761 115.674 -60.7432 164.905 114.922 -65.2745 163.976 113.788 - -59.7953 104.835 123.029 -60.1185 106.612 123.226 -60.5099 108.413 123.502 -61.7244 113.687 124.33 -63.2676 118.529 124.945 - -117.575 84.4393 120.476 -118.145 84.8318 120.289 -118.938 85.617 118.995 -120.903 88.3144 116.109 - -191.646 82.1407 128.141 -189.874 82.6614 129.423 -186.81 83.5814 131.57 -185.567 84.1305 132.33 -183.662 85.1007 133.383 -181.529 86.1133 134.35 -178.653 86.4597 133.523 - -67.7233 179.217 121.751 -68.5052 178.942 121.484 -69.2559 178.643 121.33 -70.3307 178.241 121.163 -73.7819 178.355 118.272 - -104.419 96.1337 153.083 -104.417 96.2148 152.916 -104.724 97.7544 150.579 - -70.6218 115.037 175.9 -70.6411 115.096 175.875 -71.0189 116.138 175.328 -71.2814 116.84 174.941 -71.6723 117.852 174.326 -73.2648 119.515 172.736 -74.0039 120.279 172.003 -74.348 120.709 171.584 -74.8063 121.81 170.495 -77.3838 122.734 169.568 - -95.606 142.97 180.448 -97.8852 142.007 177.897 - -121.984 132.135 69.8458 -123.096 132.005 71.3436 -124.699 131.96 72.8582 -125.351 131.947 73.4661 -126.282 131.932 74.335 -128.913 131.996 76.5196 -130.561 132.163 77.5723 -133.032 132.505 78.6017 -134.6 132.726 79.2376 -135.927 132.879 79.4344 -139.671 133.2 79.1787 - -63.2676 118.529 124.945 -66.8928 121.8 125.14 -68.4283 123.11 125.203 -70.0249 124.546 125.255 -70.2913 124.799 125.256 -71.8896 126.336 125.242 -73.1014 127.529 125.174 -74.0631 128.488 125.103 -75.1523 129.933 124.598 -77.3069 131.484 124.371 - -102.836 158.339 152.718 -102.383 156.439 153.586 -102.148 151.2 154.516 -100.515 147.028 154.956 - -93.3338 175.4 119.843 -96.3426 172.993 118.861 -97.6247 172.439 118.114 -98.4465 172.205 117.616 - -93.3338 175.4 119.843 -92.6589 175.112 120.445 -91.7177 174.356 121.451 -89.5162 172.455 123.98 -85.5179 171.209 128.274 - -92.7994 92.9853 111.383 -95.8883 92.7141 110.964 -97.9353 92.552 110.668 -99.1637 92.414 110.501 -100.643 92.2564 110.305 -105.863 91.6136 109.516 - -204.379 99.5227 128.948 -200.388 102.067 133.851 - -83.2766 125.401 96.3324 -80.7928 130.01 97.0484 -79.7561 131.935 98.2504 -79.5274 132.399 98.4313 -78.913 133.681 98.9454 -77.7852 136.307 100.615 - -83.2766 125.401 96.3324 -81.962 125.383 89.8166 -81.7039 124.026 85 - -60.2184 141.923 110.96 -65.7557 138.894 109.509 - -102.37 89.953 72.9031 -105.116 90.7493 73.5158 -105.86 91.0468 73.7937 -108.779 92.0873 75.342 - -78.4147 156.996 67.9795 -78.6679 155.523 70.3109 -78.8451 154.547 72.2847 -78.9555 153.887 73.1561 -79.0495 153.323 73.8664 -79.1491 152.743 74.5967 -79.3014 151.856 75.7108 -79.4575 151.311 76.3675 -79.7234 150.331 77.4993 -80.1313 148.875 79.1721 -80.3282 144.293 84.7584 - -139.671 133.2 79.1787 -141.156 133.657 81.4758 -141.584 133.79 82.145 -141.94 133.914 82.7939 -142.398 134.066 83.5873 -143.671 134.419 85.2669 -144.723 134.715 86.6897 -145.903 135.06 88.3537 -147.384 135.497 90.4895 -148.417 135.804 92.0152 -149.255 136.051 93.1952 -151.082 136.571 95.2191 -152.834 137.101 97.8628 - -78.5962 158.884 111.503 -75.8372 160.375 112.438 -73.876 160.721 113.486 -71.4088 161.302 114.376 -67.4892 163.144 113.842 -65.2745 163.976 113.788 - -78.5962 158.884 111.503 -80.1904 153.948 113.773 -80.4862 151.972 114.928 -80.7639 150.556 115.736 -80.8499 148.33 116.299 -80.3308 145.31 115.445 - -121.308 90.1466 110.362 -115.522 91.7707 111.272 -111.353 91.5936 109.642 -105.863 91.6136 109.516 - -121.308 90.1466 110.362 -128.016 88.9504 106.464 -129.03 88.6759 105.818 -130.262 88.3392 105.092 -131.722 87.8825 104.212 -136.177 85.8858 102.65 - -121.308 90.1466 110.362 -120.903 88.3144 116.109 - -200.194 160.251 87.0208 -197.122 156.859 88.0642 -195.462 155.071 88.9655 -194.69 154.269 89.4532 -193.926 153.499 89.9147 -193.239 152.832 90.3166 -192.326 151.98 90.8258 -191.207 150.939 91.4489 -190.286 150.111 91.9389 -188.286 148.416 92.9241 -186.582 147.054 93.7021 -185.27 146.095 94.2338 -183.078 145.393 94.8614 -181.254 144.844 95.3606 -180.035 144.48 95.6921 -177.285 143.664 96.4358 -175.813 143.235 96.8293 -174.181 142.764 97.2618 -171.843 142.103 97.8707 -170.148 141.629 98.3073 -165.931 140.47 99.3846 -161.92 139.38 100.143 -160.714 139.054 99.69 -159.037 138.618 99.0589 -156.994 138.113 98.5701 -155.215 137.665 97.9346 -152.834 137.101 97.8628 - -77.3069 131.484 124.371 -77.8011 136.842 119.925 -78.6694 138.726 119.642 -80.619 142.64 119.533 - -80.3308 145.31 115.445 -78.7852 141.901 110.422 - -80.3308 145.31 115.445 -80.1472 142.876 117.329 -80.619 142.64 119.533 - -178.653 86.4597 133.523 -176.858 85.7053 130.906 -175.88 84.7912 128.761 -176.097 84.5352 126.866 - -67.2101 141.299 86.6562 -73.9272 140.856 90.4568 - -137.913 86.9824 90.8748 -136.676 87.0994 93.6931 -135.142 87.0835 96.0474 -134.246 87.1896 98.4681 -136.177 85.8858 102.65 - -78.7852 141.901 110.422 -76.3985 139.181 106.35 - -75.2835 182.848 109.515 -75.1767 182.295 110.575 -74.9107 181.426 112.338 -74.5579 180.158 114.885 -73.7819 178.355 118.272 - -100.866 96.8182 55.5209 -103.523 95.5641 59.8603 -104.308 95.2298 61.3552 -104.733 95.036 62.0998 -105.013 94.9114 62.6383 -106.451 94.2613 65.4832 -107.404 93.8369 66.9428 -108.241 93.4638 68.1883 -109.118 93.0328 69.8205 -110.461 92.2893 72.2288 - -100.866 96.8182 55.5209 -100.482 96.3446 51.1849 -100.086 96.2835 49.1402 -99.7205 96.234 47.7864 -98.4802 95.8123 42.5902 - -97.8852 142.007 177.897 -100.871 142.517 175.978 -102.611 142.864 174.9 -104.725 143.29 173.588 -105.706 143.415 172.755 -106.169 143.471 172.33 -107.164 143.594 171.179 -108.816 143.77 169.608 -107.08 143.438 161.908 -108.582 142.76 159.536 - -65.7557 138.894 109.509 -68.5713 139.132 108.973 -69.9468 139.2 108.555 -76.3985 139.181 106.35 - -143.789 82.3533 103.716 -147.069 81.3156 106.068 -147.936 81.1058 106.859 -149.228 80.8158 108.041 -149.897 80.6672 108.657 -151.652 80.2673 110.152 -154.164 79.8105 111.524 -156.897 79.359 113.066 -160.592 78.9805 115.411 -163.282 78.8926 117.329 -164.072 78.9211 117.954 -167.681 79.8606 121.603 -171.169 81.5775 125.86 -172.087 82.3002 126.498 -173.057 83.0278 126.968 -176.097 84.5352 126.866 - -143.789 82.3533 103.716 -140.925 83.5917 102.805 -139.854 84.1147 102.719 -138.756 84.6463 102.675 -136.177 85.8858 102.65 - -108.779 92.0873 75.342 -110.461 92.2893 72.2288 - -69.3503 138.067 158.082 -70.8593 140.397 158.559 - -73.9272 140.856 90.4568 -78.2128 142.331 87.8051 -80.3282 144.293 84.7584 - -73.9272 140.856 90.4568 -75.3867 139.578 93.3638 -75.7 138.444 95.7412 -75.8338 138.202 96.3378 -77.7852 136.307 100.615 - -83.2234 120.801 76.5165 -82.4246 120.156 73.4506 -80.677 121.173 72.1018 -80.3677 121.269 71.673 -79.4916 121.559 70.4854 -78.3154 121.628 67.8343 -77.5388 121.724 66.1089 -76.9422 121.792 64.793 -76.4322 121.994 63.6542 -75.8873 121.971 62.4044 -75.4683 121.981 61.4311 -74.7801 122.032 59.782 -73.9801 119.509 57.1376 - -83.2234 120.801 76.5165 -82.2348 122.635 80.8777 -82.0259 122.962 81.7245 -81.7039 124.026 85 - -83.2234 120.801 76.5165 -85.9082 120.537 79.1001 -87.9279 119.848 79.4764 -90.9187 118.57 78.7805 -92.1933 118.14 78.8521 -93.1586 117.814 78.9335 - -130.227 116.673 167.898 -133.124 119.598 166.151 -134.296 120.499 164.837 -137.462 121.764 162.517 - -108.582 142.76 159.536 -105.886 144.329 157.561 -104.232 145.167 156.896 -100.515 147.028 154.956 - -77.7852 136.307 100.615 -77.4771 137.823 103.34 -76.3985 139.181 106.35 - -70.8593 140.397 158.559 -71.7459 141.746 157.883 -72.7059 143.232 157.281 -75.1578 146.144 156.294 - From 48d17587b4b65dca00aa514422835fc6ceb77db5 Mon Sep 17 00:00:00 2001 From: epernod Date: Tue, 25 Aug 2026 18:01:15 +0200 Subject: [PATCH 12/12] rm absolute path with relative one --- TestScene.scn | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/TestScene.scn b/TestScene.scn index d8507a8..d077089 100644 --- a/TestScene.scn +++ b/TestScene.scn @@ -14,25 +14,28 @@ --> + + + - + + outputSkeleton="\patient_08\Patient_08_venoussystem_skeleton.txt" /> + outputVTK="./patient_08\Patient_08_venoussystem_skeleton.vtk" + outputReport="Results\Patient_08_venoussystem_report_skeleton_mapper.csv" /> @@ -40,14 +43,14 @@ segmentNames must stay in the SAME order as these loaders, since that order is what maps index 0/1/2... to "II"/"III"/"IVa"... below. --> - - - - - - - - + + + + + + + + @@ -63,15 +66,15 @@ skeletonReader="@../Mesh/reader" segmentMeshes="@segII @segIII @segIVa @segIVb @segV @segVI @segVII @segVIII" segmentNames="II III IVa IVb V VI VII VIII" - outSegmentReportFilename="C:\Projects\Sofa\dev\sofa-plugins\MeshSkeletonization\Results\Patient_08_liver_segment_report_before.csv"/> + outSegmentReportFilename="\Results\Patient_08_liver_segment_report_before.csv"/> + outReportFilename="\Results\Patient_08_resection_report_after.csv"/> \ No newline at end of file