feat(simulation): add NavalDomain::serializeStateJson for WASM state export
Returns {"t":...,"vessels":[{"id":...,"x":...,"psi":...,"u":...,"r":...},...]}
2 tests verify JSON structure and time accumulation.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
6196f0ca0e
commit
9a16d8d0cf
3 files changed
+89
No files matched your search
@@ -87,6 +87,14 @@ public:
|
||||
/** Return Euclidean distance between two registered bodies. Asserts both ids exist. */
|
||||
double distanceBetween(int idA, int idB) const;
|
||||
|
||||
/**
|
||||
* Serialize all body states to a JSON string.
|
||||
*
|
||||
* Format: {"t":<sim_time>,"vessels":[{"id":<n>,"x":...,"y":...,"z":...,"phi":...,"theta":...,"psi":...,"u":...,"v":...,"r":...},...]}
|
||||
* Used by the WASM binding to transfer state to JavaScript.
|
||||
*/
|
||||
std::string serializeStateJson() const;
|
||||
|
||||
NavalDomain(const NavalDomain&) = delete;
|
||||
NavalDomain& operator=(const NavalDomain&) = delete;
|
||||
NavalDomain(NavalDomain&&) = delete;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ymir {
|
||||
@@ -188,4 +189,36 @@ naval::NavalContext NavalDomain::buildContext(int id, const BodyEntry& entry, do
|
||||
env_->waterDepth(), env_->tide()};
|
||||
}
|
||||
|
||||
std::string NavalDomain::serializeStateJson() const
|
||||
{
|
||||
std::ostringstream os;
|
||||
os << "{\"t\":" << sim_.time() << ",\"vessels\":[";
|
||||
|
||||
bool first = true;
|
||||
for (const auto& [id, entry] : entries_)
|
||||
{
|
||||
const BodyState s = sim_.state(id);
|
||||
const Vector6& q = s.q();
|
||||
const Vector6& qd = s.qdot();
|
||||
|
||||
if (!first) os << ',';
|
||||
first = false;
|
||||
|
||||
os << "{\"id\":" << id
|
||||
<< ",\"x\":" << q[0]
|
||||
<< ",\"y\":" << q[1]
|
||||
<< ",\"z\":" << q[2]
|
||||
<< ",\"phi\":" << q[3]
|
||||
<< ",\"theta\":" << q[4]
|
||||
<< ",\"psi\":" << q[5]
|
||||
<< ",\"u\":" << qd[0]
|
||||
<< ",\"v\":" << qd[1]
|
||||
<< ",\"r\":" << qd[5]
|
||||
<< '}';
|
||||
}
|
||||
|
||||
os << "]}";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
} // namespace ymir
|
||||
@@ -282,3 +282,51 @@ TEST_CASE("NavalDomain regression: matches NavalSimulation within 1e-8 over 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// serializeStateJson
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEST_CASE("NavalDomain: serializeStateJson produces valid JSON with expected keys", "[naval_domain]")
|
||||
{
|
||||
ymir::Environment env;
|
||||
ymir::CouplingRegistry coupling;
|
||||
ymir::NavalDomain domain;
|
||||
|
||||
ymir::Vector6 q0{}, qd0{};
|
||||
q0[0] = 5.0; q0[5] = 0.1;
|
||||
domain.addBody(0, makeBody(0, 1e6, q0, qd0));
|
||||
domain.onAddedToWorld(env, coupling);
|
||||
domain.initialize();
|
||||
domain.step(0.1);
|
||||
|
||||
const std::string json = domain.serializeStateJson();
|
||||
|
||||
REQUIRE(json.find("\"t\":") != std::string::npos);
|
||||
REQUIRE(json.find("\"vessels\":") != std::string::npos);
|
||||
REQUIRE(json.find("\"id\":0") != std::string::npos);
|
||||
REQUIRE(json.find("\"x\":") != std::string::npos);
|
||||
REQUIRE(json.find("\"psi\":") != std::string::npos);
|
||||
REQUIRE(json.find("\"u\":") != std::string::npos);
|
||||
REQUIRE(json.find("\"r\":") != std::string::npos);
|
||||
REQUIRE(json.front() == '{');
|
||||
REQUIRE(json.back() == '}');
|
||||
}
|
||||
|
||||
TEST_CASE("NavalDomain: serializeStateJson t advances with steps", "[naval_domain]")
|
||||
{
|
||||
ymir::Environment env;
|
||||
ymir::CouplingRegistry coupling;
|
||||
ymir::NavalDomain domain;
|
||||
|
||||
domain.addBody(0, makeBody(0));
|
||||
domain.onAddedToWorld(env, coupling);
|
||||
domain.initialize();
|
||||
domain.step(0.5);
|
||||
domain.step(0.5);
|
||||
|
||||
const std::string json = domain.serializeStateJson();
|
||||
const std::size_t tpos = json.find("\"t\":") + 4;
|
||||
const double t = std::stod(json.substr(tpos));
|
||||
REQUIRE(t == Approx(1.0).margin(1e-9));
|
||||
}
|
||||
Reference in new issue
Block a user