Skip to content

Implement manual deep copy for C3DData instead of relying on ezc3d's shallow copy constructor#277

Draft
Copilot wants to merge 9 commits intomasterfrom
copilot/add-c3d-file-loader-module
Draft

Implement manual deep copy for C3DData instead of relying on ezc3d's shallow copy constructor#277
Copilot wants to merge 9 commits intomasterfrom
copilot/add-c3d-file-loader-module

Conversation

Copy link

Copilot AI commented Mar 17, 2026

ezc3d::c3d stores Header, Parameters, and Data as shared_ptr internally, and Frame similarly stores Points, Analogs, Rotations as shared_ptr. The copy constructor only copies the pointers, so the previous deepCopy() via std::make_shared<ezc3d::c3d>(*data_) produced a shallow copy where mutations to the copy would affect the original.

Replaced with a manual recursive reconstruction:

  • Point/Analog registration — calls c3d::point(name) and c3d::analog(name) to initialize the POINT/ANALOG configuration consistently in the new object
  • Frame-level deep copy — rebuilds each frame from scratch:
    • Points: copies x, y, z, residual, cameraMask per point
    • Analogs: copies each subframe's channel data values
    • Rotations: copies all 4×4 matrix elements + reliability via Rotation::set()
  • Parameter groups — copies non-auto-managed groups (FORCE_PLATFORM, TRIAL, custom metadata) via c3d::parameter(); POINT/ANALOG groups are skipped since they're already initialized by the registration step
// Before: shallow — src and copy share the same internal data
return C3DData{std::make_shared<ezc3d::c3d>(*data_), source_};

// After: fully independent copy
auto dst = std::make_shared<ezc3d::c3d>();
for (const auto& name : src.pointNames()) { dst->point(name); }
for (const auto& name : src.channelNames()) { dst->analog(name); }
// ... rebuild each frame element by element ...
return C3DData{std::move(dst), source_};

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI changed the title [WIP] Add Inviwo module for loading C3D files Add C3D module for loading biomechanics motion capture files via ezc3d Mar 17, 2026
Copilot AI requested a review from petersteneteg March 17, 2026 15:15
Copilot AI changed the title Add C3D module for loading biomechanics motion capture files via ezc3d Hide ezc3d include from public headers using forward declaration Mar 18, 2026
Copilot AI changed the title Hide ezc3d include from public headers using forward declaration Hide ezc3d include from public C3D module headers Mar 18, 2026
Copilot AI changed the title Hide ezc3d include from public C3D module headers Change C3DToMesh frame property to MinMaxProperty for multi-frame extraction Mar 18, 2026
Copilot AI changed the title Change C3DToMesh frame property to MinMaxProperty for multi-frame extraction Add MinMaxProperty frame range and picking support to C3DToMesh Mar 18, 2026
@github-actions
Copy link

github-actions bot commented Mar 18, 2026

Cpp-Linter Report ⚠️

Some files did not pass the configured checks!

clang-format (v19.1.1) reports: 2 file(s) not formatted
  • misc/c3d/include/inviwo/c3d/processors/c3dtransformpoints.h
  • misc/c3d/src/processors/c3dtodataframe.cpp
clang-tidy (v19.1.1) reports: 37 concern(s)
  • misc/c3d/include/inviwo/c3d/c3dmodule.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/c3dmodule.h:36:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DModule' is non-const and globally accessible, consider making it const

       36 | class IVW_MODULE_C3D_API C3DModule : public InviwoModule {
          |                          ^
  • misc/c3d/include/inviwo/c3d/datastructures/c3ddata.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/datastructures/c3ddatatraits.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/io/c3dreader.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/io/c3dreader.h:46:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DReader' is non-const and globally accessible, consider making it const

       46 | class IVW_MODULE_C3D_API C3DReader : public DataReaderType<ezc3d::c3d> {
          |                          ^
  • misc/c3d/include/inviwo/c3d/ports/c3dport.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/processors/c3daveragedpositions.h:32:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       32 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/processors/c3daveragedpositions.h:45:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DAveragedPositions' is non-const and globally accessible, consider making it const

       45 | class IVW_MODULE_C3D_API C3DAveragedPositions : public Processor {
          |                          ^
  • misc/c3d/include/inviwo/c3d/processors/c3dsource.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/processors/c3dsource.h:39:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DSource' is non-const and globally accessible, consider making it const

       39 | class IVW_MODULE_C3D_API C3DSource : public DataSource<ezc3d::c3d, C3DDataOutport> {
          |                          ^
  • misc/c3d/include/inviwo/c3d/processors/c3dtodataframe.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/processors/c3dtodataframe.h:49:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DToDataFrame' is non-const and globally accessible, consider making it const

       49 | class IVW_MODULE_C3D_API C3DToDataFrame : public Processor {
          |                          ^
  • misc/c3d/include/inviwo/c3d/processors/c3dtomesh.h:31:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       31 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/processors/c3dtomesh.h:59:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DToMesh' is non-const and globally accessible, consider making it const

       59 | class IVW_MODULE_C3D_API C3DToMesh : public Processor {
          |                          ^
  • misc/c3d/include/inviwo/c3d/processors/c3dtransformpoints.h:32:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmoduledefine.h' file not found

       32 | #include <inviwo/c3d/c3dmoduledefine.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/include/inviwo/c3d/processors/c3dtransformpoints.h:50:26: warning: [cppcoreguidelines-avoid-non-const-global-variables]

    variable 'C3DTransformPoints' is non-const and globally accessible, consider making it const

       50 | class IVW_MODULE_C3D_API C3DTransformPoints : public Processor {
          |                          ^
  • misc/c3d/src/c3dmodule.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/c3dmodule.h' file not found

       30 | #include <inviwo/c3d/c3dmodule.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/datastructures/c3ddata.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/datastructures/c3ddata.h' file not found

       30 | #include <inviwo/c3d/datastructures/c3ddata.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/datastructures/c3ddata.cpp:39:35: warning: [misc-use-internal-linkage]

    function 'copyPoints' can be made static or moved into an anonymous namespace to enforce internal linkage

       39 | ezc3d::DataNS::Points3dNS::Points copyPoints(const ezc3d::DataNS::Frame& srcFrame) {
          |                                   ^         
          |                                             static 
  • misc/c3d/src/datastructures/c3ddata.cpp:51:35: warning: [misc-use-internal-linkage]

    function 'copyAnalogs' can be made static or moved into an anonymous namespace to enforce internal linkage

       51 | ezc3d::DataNS::AnalogsNS::Analogs copyAnalogs(const ezc3d::DataNS::Frame& srcFrame) {
          |                                   ^          
          |                                              static 
  • misc/c3d/src/datastructures/c3ddata.cpp:66:38: warning: [misc-use-internal-linkage]

    function 'copyRotations' can be made static or moved into an anonymous namespace to enforce internal linkage

       66 | ezc3d::DataNS::RotationNS::Rotations copyRotations(const ezc3d::DataNS::Frame& srcFrame) {
          |                                      ^            
          |                                                   static 
  • misc/c3d/src/datastructures/c3ddata.cpp:84:6: warning: [misc-use-internal-linkage]

    function 'copyAnalogs' can be made static or moved into an anonymous namespace to enforce internal linkage

       84 | void copyAnalogs(const ezc3d::DataNS::Frame& srcFrame, ezc3d::DataNS::Frame& dstFrame) {
          |      ^
          | static 
  • misc/c3d/src/datastructures/c3ddata.cpp:91:6: warning: [misc-use-internal-linkage]

    function 'copyRotations' can be made static or moved into an anonymous namespace to enforce internal linkage

       91 | void copyRotations(const ezc3d::DataNS::Frame& srcFrame, ezc3d::DataNS::Frame& dstFrame) {
          |      ^
          | static 
  • misc/c3d/src/datastructures/c3ddata.cpp:98:6: warning: [misc-use-internal-linkage]

    function 'copyPoints' can be made static or moved into an anonymous namespace to enforce internal linkage

       98 | void copyPoints(const ezc3d::DataNS::Frame& srcFrame, ezc3d::DataNS::Frame& dstFrame) {
          |      ^
          | static 
  • misc/c3d/src/datastructures/c3ddata.cpp:105:29: warning: [misc-use-internal-linkage]

    function 'copy' can be made static or moved into an anonymous namespace to enforce internal linkage

      105 | std::shared_ptr<ezc3d::c3d> copy(const ezc3d::c3d& src) {
          |                             ^   
          |                                 static 
  • misc/c3d/src/datastructures/c3ddatatraits.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/datastructures/c3ddatatraits.h' file not found

       30 | #include <inviwo/c3d/datastructures/c3ddatatraits.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/io/c3dreader.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/io/c3dreader.h' file not found

       30 | #include <inviwo/c3d/io/c3dreader.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/ports/c3dport.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/ports/c3dport.h' file not found

       30 | #include <inviwo/c3d/ports/c3dport.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/processors/c3daveragedpositions.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/processors/c3daveragedpositions.h' file not found

       30 | #include <inviwo/c3d/processors/c3daveragedpositions.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/processors/c3dsource.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/processors/c3dsource.h' file not found

       30 | #include <inviwo/c3d/processors/c3dsource.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/processors/c3dtodataframe.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/processors/c3dtodataframe.h' file not found

       30 | #include <inviwo/c3d/processors/c3dtodataframe.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/processors/c3dtomesh.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/processors/c3dtomesh.h' file not found

       30 | #include <inviwo/c3d/processors/c3dtomesh.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/processors/c3dtransformpoints.cpp:30:10: error: [clang-diagnostic-error]

    'inviwo/c3d/processors/c3dtransformpoints.h' file not found

       30 | #include <inviwo/c3d/processors/c3dtransformpoints.h>
          |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  • misc/c3d/src/processors/c3dtransformpoints.cpp:77:7: warning: [misc-use-internal-linkage]

    function 'basisEstimation' can be made static or moved into an anonymous namespace to enforce internal linkage

       77 | dmat4 basisEstimation(dvec3 a, dvec3 b, dvec3 c, dvec3 d) {
          |       ^              
          |                      static 
  • misc/c3d/src/processors/c3dtransformpoints.cpp:77:23: warning: [bugprone-easily-swappable-parameters]

    4 adjacent parameters of 'basisEstimation' of similar type ('int') are easily swapped by mistake

       77 | dmat4 basisEstimation(dvec3 a, dvec3 b, dvec3 c, dvec3 d) {
          |                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    /home/runner/work/modules/modules/inviwo/misc/c3d/src/processors/c3dtransformpoints.cpp:77:29: note: the first parameter in the range is 'a'
       77 | dmat4 basisEstimation(dvec3 a, dvec3 b, dvec3 c, dvec3 d) {
          |                             ^
    /home/runner/work/modules/modules/inviwo/misc/c3d/src/processors/c3dtransformpoints.cpp:77:56: note: the last parameter in the range is 'd'
       77 | dmat4 basisEstimation(dvec3 a, dvec3 b, dvec3 c, dvec3 d) {
          |                                                        ^
  • misc/c3d/src/processors/c3dtransformpoints.cpp:85:7: warning: [misc-use-internal-linkage]

    function 'toGLM' can be made static or moved into an anonymous namespace to enforce internal linkage

       85 | dvec3 toGLM(const ezc3d::DataNS::Points3dNS::Point& p) { return dvec3{p.x(), p.y(), p.z()}; }
          |       ^    
          |            static 

Have any feedback or feature suggestions? Share it here.

Copilot AI and others added 5 commits March 19, 2026 11:20
Co-authored-by: petersteneteg <3638222+petersteneteg@users.noreply.github.com>
Replace #include <ezc3d/ezc3d.h> in c3ddata.h with a forward
declaration of ezc3d::c3d, following the DICOM module pattern.
Move DataTraits info() implementation to c3ddatatraits.cpp to
keep the external library confined to .cpp files only.

Co-authored-by: petersteneteg <3638222+petersteneteg@users.noreply.github.com>
…rame extraction

Co-authored-by: petersteneteg <3638222+petersteneteg@users.noreply.github.com>
Co-authored-by: petersteneteg <3638222+petersteneteg@users.noreply.github.com>
Copilot AI changed the title Add MinMaxProperty frame range and picking support to C3DToMesh Add picking support and deep copy to C3D module Mar 21, 2026
…py()

Co-authored-by: petersteneteg <3638222+petersteneteg@users.noreply.github.com>
Agent-Logs-Url: https://github.com/inviwo/modules/sessions/bf174c8c-18ac-496c-ba0d-bf3876b29763
Copilot AI changed the title Add picking support and deep copy to C3D module Implement manual deep copy for C3DData instead of relying on ezc3d's shallow copy constructor Mar 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants