Skip to content

Commit

Permalink
Implement LandmarkPairsAssociatedWithMesh::implValidate
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkewley committed Aug 2, 2024
1 parent fc84b18 commit 5c811ba
Show file tree
Hide file tree
Showing 8 changed files with 2,262 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <OpenSimCreator/Documents/ModelWarper/IValidateable.h>
#include <OpenSimCreator/Documents/ModelWarper/IWarpDetailProvider.h>
#include <OpenSimCreator/Utils/LandmarkPair3D.h>
#include <OpenSimCreator/Utils/OpenSimHelpers.h>

#include <OpenSim/Common/Component.h>
#include <OpenSim/Simulation/Model/Geometry.h>
Expand Down Expand Up @@ -407,16 +408,81 @@ namespace osc::mow
// - the destination landmarks file is assumed to be on the filesystem "next to" the `OpenSim::Model`
// in a directory named `DestinationGeometry` at `${model_parent_directory}/DestinationGeometry/${mesh_file_name_without_extension}.landmarks.csv`;
// otherwise, a validation error is generated
// - if either landmark file is invalid in some way (invalid CSV, etc.), a validation error is generated
// - if zero landmark pairs can be associated between the two landmark files, a validation error is generated
// - else, accept those pairs as "the mesh's landmark pairs"
// - else, accept those pairs as "the mesh's landmark pairs" (even if empty)
class LandmarkPairsAssociatedWithMesh final : public PairedPointSource {
OpenSim_DECLARE_CONCRETE_OBJECT(LandmarkPairsAssociatedWithMesh, PairedPointSource)
private:
PairedPoints implGetPairedPoints(WarpCache&, const OpenSim::Model&, const OpenSim::Component&) final
{
return {}; // TODO
}

std::vector<ValidationCheckResult> implValidate(
const OpenSim::Model& sourceModel,
const OpenSim::Component& sourceComponent) const final
{
std::vector<ValidationCheckResult> rv;

const auto* sourceMesh = dynamic_cast<const OpenSim::Mesh*>(&sourceComponent);
if (not sourceMesh) {
std::stringstream ss;
ss << sourceComponent.getName() << "(type: " << sourceComponent.getConcreteClassName() << ") is not an OpenSim::Mesh. " << getName() << "(type: " << getConcreteClassName() << ") requires this";
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Error);
return rv;
}

const auto sourceMeshPath = FindGeometryFileAbsPath(sourceModel, *sourceMesh);
if (not sourceMeshPath) {
std::stringstream ss;
ss << sourceComponent.getName() << ": the absolute filesystem location of this mesh cannot be found";
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Error);
return rv;
} else {
std::stringstream ss;
ss << sourceMesh->getName() << ": was found on the filesystem at " << *sourceMeshPath;
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Ok);
}

auto sourceLandmarksPath{*sourceMeshPath};
sourceLandmarksPath.replace_extension(".landmarks.csv");
if (not std::filesystem::exists(sourceLandmarksPath)) {
std::stringstream ss;
ss << sourceMesh->getName() << ": could not find an associated .landmarks.csv file at " << sourceLandmarksPath;
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Error);
return rv;
} else {
std::stringstream ss;
ss << sourceMesh->getName() << ": has a .landmarks.csv file at " << sourceLandmarksPath;
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Ok);
}

const auto modelFilePath = TryFindInputFile(sourceModel);
if (not modelFilePath) {
std::stringstream ss;
ss << getName() << ": cannot find the supplied model file's filesystem location: this is required in order to locate the `DestinationGeometry` directory";
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Error);
return rv;
} else {
std::stringstream ss;
ss << getName() << ": the model file was found at " << *modelFilePath;
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Ok);
}

const auto destinationLandmarksPath = modelFilePath->parent_path() / "DestinationGeometry" / sourceMeshPath->filename().replace_extension(".landmarks.csv");
if (not std::filesystem::exists(destinationLandmarksPath)) {
std::stringstream ss;
ss << sourceMesh->getName() << ": cannot find a destination .landmarks.csv at " << destinationLandmarksPath;
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Error);
return rv;
}
else {
std::stringstream ss;
ss << getName() << ": found a destination .landmarks.csv file at " << destinationLandmarksPath;
rv.emplace_back(std::move(ss).str(), ValidationCheckState::Ok);
}

return rv;
}
};

// a `PairedPointSource` that uses heuristics to find the most appropriate `PairedPoints`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ namespace osc::mow

CStringView description() const { return m_Description; }
ValidationCheckState state() const { return m_State; }
bool is_error() const { return m_State == ValidationCheckState::Error; }

private:
std::string m_Description;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,19 +274,50 @@ TEST(LandmarkPairsAssociatedWithMesh, CanBeDefaultConstructed)
[[maybe_unused]] LandmarkPairsAssociatedWithMesh instance;
}

//TEST(LandmarkPairsAssociatedWithMesh, ValidateReturnsErrorIfProvidedNonMesh)
//{
// LandmarkPairsAssociatedWithMesh pairSource;
// OpenSim::Model model;
// const auto checks = pairSource.validate(model, model.getGround());
//
// ASSERT_TRUE(rgs::any_of(checks, [](const ValidationCheckResult& res) { return res.state() == ValidationCheckState::Error; }));
//}
// TODO: error if mesh has no source landmarks (but has destination landmarks)
// TODO: error if mesh has no destination landmarks (but has source landmarks)
// TODO: error if source landmarks isn't valid CSV (but destination is)
// TODO: error if destination landmarks isn't valid CSV (but source is)
// TODO: error if zero landmark pairs generated
TEST(LandmarkPairsAssociatedWithMesh, ValidateReturnsErrorIfProvidedNonMesh)
{
LandmarkPairsAssociatedWithMesh pairSource;
OpenSim::Model model;
const auto checks = pairSource.validate(model, model.getGround());

ASSERT_TRUE(rgs::any_of(checks, &ValidationCheckResult::is_error));
}

TEST(LandmarkPairsAssociatedWithMesh, ValidateReturnsErrorIfProvidedMeshWithoutSourceLandmarksButWithDestinationLandmarks)
{
// note: doesn't have a `landmarks.csv` file
const std::filesystem::path sourceMeshPath = std::filesystem::path{OSC_TESTING_RESOURCES_DIR} / "Document/ModelWarper/MissingSourceLMs/Geometry/sphere.obj";

// create a model that contains the mesh
OpenSim::Model model;
auto& mesh = AddComponent<OpenSim::Mesh>(model, sourceMeshPath.string());
mesh.connectSocket_frame(model.getGround());
FinalizeConnections(model);
InitializeModel(model);

LandmarkPairsAssociatedWithMesh pointSource;
const auto checks = pointSource.validate(model, mesh);

ASSERT_TRUE(rgs::any_of(checks, &ValidationCheckResult::is_error));
}

TEST(LandmarkPairsAssociatedWithMesh, ValidateReturnsErrorIfProvidedMeshWithSourceLandmarksButNoDestinationLandmarks)
{
// note: doesn't have a `landmarks.csv` file
std::filesystem::path sourceMeshPath = std::filesystem::path{OSC_TESTING_RESOURCES_DIR} / "Document/ModelWarper/MissingDestinationLMs/Geometry/sphere.obj";

// create a model that contains the mesh
OpenSim::Model model;
auto& mesh = AddComponent<OpenSim::Mesh>(model, sourceMeshPath.string());
mesh.connectSocket_frame(model.getGround());
FinalizeConnections(model);
InitializeModel(model);

LandmarkPairsAssociatedWithMesh pointSource;
const auto checks = pointSource.validate(model, mesh);

ASSERT_TRUE(rgs::any_of(checks, &ValidationCheckResult::is_error));
}

TEST(ModelWarperConfiguration, CanDefaultConstruct)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name,x,y,z
destination_0,-0.061925,1.000000,-0.102330
destination_1,0.061730,1.000000,0.544677
destination_2,0.300334,0.819465,0.940260
destination_3,0.216009,0.202049,0.957034
destination_4,0.630927,0.587238,0.758009
destination_5,0.811265,0.881088,0.551223
destination_6,0.805500,0.356062,0.559851
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# OpenSim Creator v0.5.5 (build CUSTOM_XoNLT)
# created: 2023-12-07 10:12:48
v 0 1 0
v 1 1 0
v 0.92388 1 0.382683
v 0.707107 1 0.707107
v 0.382683 1 0.92388
v -4.37114e-08 1 1
v -0.382684 1 0.92388
v -0.707107 1 0.707107
v -0.92388 1 0.382683
v -1 1 -8.74228e-08
v -0.92388 1 -0.382683
v -0.707107 1 -0.707107
v -0.382683 1 -0.92388
v 1.19249e-08 1 -1
v 0.382684 1 -0.923879
v 0.707107 1 -0.707107
v 0.92388 1 -0.382683
v 0 -1 0
v 1 -1 0
v 0.92388 -1 0.382683
v 0.707107 -1 0.707107
v 0.382683 -1 0.92388
v -4.37114e-08 -1 1
v -0.382684 -1 0.92388
v -0.707107 -1 0.707107
v -0.92388 -1 0.382683
v -1 -1 -8.74228e-08
v -0.92388 -1 -0.382683
v -0.707107 -1 -0.707107
v -0.382683 -1 -0.92388
v 1.19249e-08 -1 -1
v 0.382684 -1 -0.923879
v 0.707107 -1 -0.707107
v 0.92388 -1 -0.382683
v 1 1 0
v 1 -1 0
v 0.92388 1 0.382683
v 0.92388 -1 0.382683
v 0.707107 1 0.707107
v 0.707107 -1 0.707107
v 0.382683 1 0.92388
v 0.382683 -1 0.92388
v -4.37114e-08 1 1
v -4.37114e-08 -1 1
v -0.382684 1 0.92388
v -0.382684 -1 0.92388
v -0.707107 1 0.707107
v -0.707107 -1 0.707107
v -0.92388 1 0.382683
v -0.92388 -1 0.382683
v -1 1 -8.74228e-08
v -1 -1 -8.74228e-08
v -0.92388 1 -0.382683
v -0.92388 -1 -0.382683
v -0.707107 1 -0.707107
v -0.707107 -1 -0.707107
v -0.382683 1 -0.92388
v -0.382683 -1 -0.92388
v 1.19249e-08 1 -1
v 1.19249e-08 -1 -1
v 0.382684 1 -0.923879
v 0.382684 -1 -0.923879
v 0.707107 1 -0.707107
v 0.707107 -1 -0.707107
v 0.92388 1 -0.382683
v 0.92388 -1 -0.382683
f 1 3 2
f 1 4 3
f 1 5 4
f 1 6 5
f 1 7 6
f 1 8 7
f 1 9 8
f 1 10 9
f 1 11 10
f 1 12 11
f 1 13 12
f 1 14 13
f 1 15 14
f 1 16 15
f 1 17 16
f 1 2 17
f 18 19 20
f 18 20 21
f 18 21 22
f 18 22 23
f 18 23 24
f 18 24 25
f 18 25 26
f 18 26 27
f 18 27 28
f 18 28 29
f 18 29 30
f 18 30 31
f 18 31 32
f 18 32 33
f 18 33 34
f 18 34 19
f 35 37 36
f 37 38 36
f 37 39 38
f 39 40 38
f 39 41 40
f 41 42 40
f 41 43 42
f 43 44 42
f 43 45 44
f 45 46 44
f 45 47 46
f 47 48 46
f 47 49 48
f 49 50 48
f 49 51 50
f 51 52 50
f 51 53 52
f 53 54 52
f 53 55 54
f 55 56 54
f 55 57 56
f 57 58 56
f 57 59 58
f 59 60 58
f 59 61 60
f 61 62 60
f 61 63 62
f 63 64 62
f 63 65 64
f 65 66 64
f 65 35 66
f 35 36 66
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name,x,y,z
source_0,0.034324,0.991844,0.074744
source_1,0.051161,0.916342,0.386610
source_2,0.044954,0.733889,0.665531
source_3,0.027493,0.403194,0.907448
source_4,0.656791,0.394051,0.637303
source_5,0.473525,0.711161,0.511863
source_6,0.291520,0.525221,0.789704
Loading

0 comments on commit 5c811ba

Please sign in to comment.