-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
166 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* rocky c++ | ||
* Copyright 2023 Pelican Mapping | ||
* MIT License | ||
*/ | ||
#pragma once | ||
#include <rocky/vsg/ECS.h> | ||
#include <rocky/vsg/Transform.h> | ||
|
||
namespace ROCKY_NAMESPACE | ||
{ | ||
/** | ||
* ECS Component applying simple motion to an object | ||
*/ | ||
struct Motion | ||
{ | ||
glm::dvec3 velocity; | ||
glm::dvec3 acceleration; | ||
}; | ||
|
||
/** | ||
* ECS System to process Motion components | ||
*/ | ||
class MotionSystem : public ECS::System | ||
{ | ||
public: | ||
MotionSystem(entt::registry& r) : ECS::System(r) { } | ||
|
||
std::vector<entt::entity> updated; | ||
|
||
//! Called periodically to update the transforms | ||
void update(Runtime& runtime) override | ||
{ | ||
updated.clear(); | ||
|
||
auto time = runtime.viewer->getFrameStamp()->time; | ||
|
||
if (last_time != ECS::time_point::min()) | ||
{ | ||
// delta seconds since last tick: | ||
double dt = 1e-9 * (double)(time - last_time).count(); | ||
|
||
// Join query all motions + transform pairs: | ||
auto view = registry.group<Motion, Transform>(); | ||
|
||
for (auto&& [entity, motion, transform] : view.each()) | ||
{ | ||
const glm::dvec3 zero{ 0.0, 0.0, 0.0 }; | ||
|
||
if (motion.velocity != zero) | ||
{ | ||
GeoPoint& pos = transform.position; | ||
double save_z = pos.z; | ||
|
||
auto pos_to_world = pos.srs.to(pos.srs.geocentricSRS()); | ||
|
||
// move the entity using a velocity vector in the local tangent plane | ||
glm::dvec3 world; | ||
pos_to_world((glm::dvec3)pos, world); | ||
auto l2w = pos.srs.ellipsoid().geocentricToLocalToWorld(world); | ||
|
||
world = l2w * (motion.velocity * dt); | ||
|
||
vsg::dvec3 coord(world.x, world.y, world.z); | ||
pos_to_world.inverse(coord, coord); | ||
|
||
pos.x = coord.x, pos.y = coord.y; | ||
pos.z = save_z; | ||
transform.dirty(); | ||
|
||
updated.emplace_back(entity); | ||
} | ||
|
||
motion.velocity += motion.acceleration * dt; | ||
}; | ||
} | ||
last_time = time; | ||
} | ||
|
||
private: | ||
//! Constructor | ||
ECS::time_point last_time = ECS::time_point::min(); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
/** | ||
* rocky c++ | ||
* Copyright 2023 Pelican Mapping | ||
* MIT License | ||
*/ | ||
#pragma once | ||
#include <rocky/vsg/GeoTransform.h> | ||
|
||
namespace ROCKY_NAMESPACE | ||
{ | ||
/** | ||
* Spatial transformation component. | ||
* Create with | ||
* auto& transform = registry.emplace<Transform>(entity); | ||
* | ||
* A Transform may be safely updated asynchronously. | ||
*/ | ||
struct Transform | ||
{ | ||
//! Georeferenced position | ||
GeoPoint position; | ||
|
||
//! Local transform matrix (for rotation and scale, e.g.) | ||
vsg::dmat4 localMatrix; | ||
|
||
//! Whether the localMatrix is relative to a local tangent plane at | ||
//! "position", versus a simple translated reference frame. | ||
bool localTangentPlane = true; | ||
|
||
//! Parent transform to apply before applying this one | ||
Transform* parent = nullptr; | ||
|
||
//! Underlying geotransform logic | ||
vsg::ref_ptr<GeoTransform> node; // todo. move this to a separate component...? | ||
|
||
Transform() | ||
{ | ||
} | ||
|
||
void setPosition(const GeoPoint& p) | ||
{ | ||
position = p; | ||
dirty(); | ||
} | ||
|
||
void dirty() | ||
{ | ||
if (!node) | ||
node = GeoTransform::create(); | ||
|
||
node->setPosition(position); | ||
node->localTangentPlane = localTangentPlane; | ||
} | ||
|
||
//! Returns true if the push succeeded (and a pop will be required) | ||
inline bool push(vsg::RecordTraversal& rt, const vsg::dmat4& m) | ||
{ | ||
if (node) | ||
{ | ||
return node->push(rt, m * localMatrix); | ||
} | ||
else if (parent) | ||
{ | ||
return parent->push(rt, m * localMatrix); | ||
} | ||
else return false; | ||
} | ||
|
||
//! Pops a transform applied if push() returned true. | ||
inline void pop(vsg::RecordTraversal& rt) | ||
{ | ||
if (node) | ||
{ | ||
node->pop(rt); | ||
} | ||
else if (parent) | ||
{ | ||
parent->pop(rt); | ||
} | ||
} | ||
}; | ||
} |