载入中...
搜索中...
未找到
Skeleton2D.cpp
浏览该文件的文档.
1#include "ik/Skeleton2D.h"
2
3#include "common/Exception.h"
4
5namespace eve::ik {
6
8 ensureSorted();
9 ensureStateSize();
10}
11
12void Skeleton2D::ensureSorted() {
13 if (sk_.bones().empty()) {
14 sk_.topologicalSort();
15 }
16}
17
18void Skeleton2D::ensureStateSize() {
19 ensureSorted();
20 const unsigned n = static_cast<unsigned>(sk_.bones().size());
21 if (state_.size() < n) {
22 // Grow in place so existing joint poses survive createBone().
23 state_.position_.resize(n);
24 state_.orientation_.resize(n);
25 state_.scale_.resize(n);
26 state_.rotation_.resize(n);
27 }
28}
29
30::ik::bone2d *Skeleton2D::boneAt(int boneId) const {
31 if (boneId < 0) return nullptr;
32 const auto &bones = sk_.bones();
33 if (static_cast<size_t>(boneId) >= bones.size()) return nullptr;
34 return bones[static_cast<size_t>(boneId)];
35}
36
37void Skeleton2D::requireBone(int boneId) const {
38 if (!boneAt(boneId)) {
39 throw Exception("Skeleton2D: invalid bone id %d", boneId);
40 }
41}
42
44 ensureSorted();
45 requireBone(parentId);
46 if (length <= 0.f) {
47 throw Exception("Skeleton2D.createBone: length must be > 0");
48 }
49 ::ik::bone2d *parent = boneAt(parentId);
50 ::ik::bone2d *child = parent->createBone(length);
51 sk_.topologicalSort();
52 ensureStateSize();
53 return static_cast<int>(child->id);
54}
55
57 const_cast<Skeleton2D *>(this)->ensureSorted();
58 return static_cast<int>(sk_.bones().size());
59}
60
61int Skeleton2D::getParent(int boneId) const {
62 requireBone(boneId);
63 ::ik::bone2d *b = boneAt(boneId);
64 if (!b->parent) return -1;
65 return static_cast<int>(b->parent->id);
66}
67
68int Skeleton2D::getChildCount(int boneId) const {
69 requireBone(boneId);
70 return static_cast<int>(boneAt(boneId)->children.size());
71}
72
73int Skeleton2D::getChild(int boneId, int childIndex) const {
74 requireBone(boneId);
75 ::ik::bone2d *b = boneAt(boneId);
76 if (childIndex < 0 || static_cast<size_t>(childIndex) >= b->children.size()) {
77 throw Exception("Skeleton2D.getChild: childIndex out of range");
78 }
79 return static_cast<int>(b->children[static_cast<size_t>(childIndex)]->id);
80}
81
82float Skeleton2D::getLength(int boneId) const {
83 requireBone(boneId);
84 return boneAt(boneId)->length;
85}
86
87void Skeleton2D::setLength(int boneId, float length) {
88 requireBone(boneId);
89 if (boneId == 0) {
90 throw Exception("Skeleton2D.setLength: root length is always 0");
91 }
92 if (length <= 0.f) {
93 throw Exception("Skeleton2D.setLength: length must be > 0");
94 }
95 boneAt(boneId)->setLength(length);
96}
97
98void Skeleton2D::setPosition(int boneId, float x, float y) {
99 requireBone(boneId);
100 ensureStateSize();
101 boneAt(boneId)->position(state_) = {x, y};
102}
103
104float Skeleton2D::getX(int boneId) const {
105 requireBone(boneId);
106 const_cast<Skeleton2D *>(this)->ensureStateSize();
107 return boneAt(boneId)->position(state_)[0];
108}
109
110float Skeleton2D::getY(int boneId) const {
111 requireBone(boneId);
112 const_cast<Skeleton2D *>(this)->ensureStateSize();
113 return boneAt(boneId)->position(state_)[1];
114}
115
116void Skeleton2D::setOrientation(int boneId, float x, float y) {
117 requireBone(boneId);
118 ensureStateSize();
119 boneAt(boneId)->orientation(state_) = {x, y};
120}
121
122float Skeleton2D::getOrientationX(int boneId) const {
123 requireBone(boneId);
124 const_cast<Skeleton2D *>(this)->ensureStateSize();
125 return boneAt(boneId)->orientation(state_)[0];
126}
127
128float Skeleton2D::getOrientationY(int boneId) const {
129 requireBone(boneId);
130 const_cast<Skeleton2D *>(this)->ensureStateSize();
131 return boneAt(boneId)->orientation(state_)[1];
132}
133
134void Skeleton2D::setRotation(int boneId, float angle) {
135 requireBone(boneId);
136 ensureStateSize();
137 boneAt(boneId)->rotation(state_) = {angle};
138}
139
140float Skeleton2D::getRotation(int boneId) const {
141 requireBone(boneId);
142 const_cast<Skeleton2D *>(this)->ensureStateSize();
143 return boneAt(boneId)->rotation(state_)[0];
144}
145
146void Skeleton2D::setConstraints(int boneId, float minAngle, float maxAngle) {
147 requireBone(boneId);
148 if (minAngle > maxAngle) {
149 throw Exception("Skeleton2D.setConstraints: minAngle must be <= maxAngle");
150 }
151 boneAt(boneId)->setConstraints(::ik::vec<float, 1>{minAngle},
152 ::ik::vec<float, 1>{maxAngle});
153}
154
156 requireBone(boneId);
157 boneAt(boneId)->clearConstraints();
158}
159
160bool Skeleton2D::hasConstraints(int boneId) const {
161 requireBone(boneId);
162 return boneAt(boneId)->constrained;
163}
164
165void Skeleton2D::initStraightPose(float rootX, float rootY) {
166 ensureSorted();
167 ensureStateSize();
168 sk_.init_straight_pose(state_, ::ik::vec2{rootX, rootY});
169}
170
172 ensureSorted();
173 ensureStateSize();
174 sk_.bind(state_);
175}
176
178 ensureSorted();
179 ensureStateSize();
180 sk_.forward_kinematics(state_);
181}
182
184 ensureSorted();
185 ensureStateSize();
186 sk_.update_rotations(state_);
187}
188
189float Skeleton2D::totalLengthTo(int boneId) const {
190 requireBone(boneId);
191 return sk_.total_length_to(boneAt(boneId));
192}
193
194} // namespace eve::ik
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float length
Definition CaveMesh.cpp:94
std::uint64_t parentId
glm::vec3 n
Definition Grass.cpp:63
std::vector< Bone > bones
std::int32_t parent
MeleePoint3 b
Definition MeleeHit.cpp:41
float angle
EVENGINE_API_FOUNDATION public API.
Definition Exception.h:13
Script-facing 2D skeleton + pose state (ik::skeleton2d + ik::ecs2d). Bone indices are stable after ea...
Definition Skeleton2D.h:14
float getLength(int boneId) const
Rest length of the bone.
Skeleton2D()
Creates an empty 2D skeleton with a root bone.
Definition Skeleton2D.cpp:7
void setOrientation(int boneId, float x, float y)
Sets the bone forward orientation vector.
void setRotation(int boneId, float angle)
Local hinge angle (radians) relative to parent forward.
float totalLengthTo(int boneId) const
Sum of bone lengths from root to boneId inclusive.
void bind()
Binds the current pose as the rest pose.
void updateRotations()
Derives local rotations from world positions.
float getY(int boneId) const
World-space Y of the bone (or component).
int getChildCount(int boneId) const
Number of direct children of boneId.
bool hasConstraints(int boneId) const
True if the bone has joint limits.
int getBoneCount() const
Number of bones currently in the skeleton.
float getX(int boneId) const
World-space X of the bone (or component).
void forwardKinematics()
Updates world positions from local rotations.
void initStraightPose(float rootX=0.f, float rootY=0.f)
Initializes a straight chain pose from the root.
float getRotation(int boneId) const
Local hinge angle in radians.
int getParent(int boneId) const
Parent bone id, or -1 for the root.
void clearConstraints(int boneId)
Removes joint limits from the bone.
float getOrientationX(int boneId) const
Orientation vector X.
float getOrientationY(int boneId) const
Orientation vector Y.
void setConstraints(int boneId, float minAngle, float maxAngle)
Joint limits for the single 2D hinge DOF.
void setLength(int boneId, float length)
Sets the rest length of the bone.
int createBone(int parentId, float length=1.f)
Create a child bone under parentId; returns new bone id.
void setPosition(int boneId, float x, float y)
Sets the world-space bone position.
int getChild(int boneId, int childIndex) const
Child bone id at childIndex under boneId.
std::string id
Definition Widget.h:17