载入中...
搜索中...
未找到
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
43int Skeleton2D::createBone(int parentId, float length) {
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
int y
Definition Grass.cpp:135
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
uint32_t b
int parent
Definition TreeMesh.cpp:175
Script-facing 2D skeleton + pose state (ik::skeleton2d + ik::ecs2d). Bone indices are stable after ea...
Definition Skeleton2D.h:12
float getLength(int boneId) const
void setOrientation(int boneId, float x, float y)
void setRotation(int boneId, float angle)
Local hinge angle (radians) relative to parent forward.
float totalLengthTo(int boneId) const
float getY(int boneId) const
int getChildCount(int boneId) const
bool hasConstraints(int boneId) const
int getBoneCount() const
float getX(int boneId) const
void initStraightPose(float rootX=0.f, float rootY=0.f)
float getRotation(int boneId) const
int getParent(int boneId) const
void clearConstraints(int boneId)
float getOrientationX(int boneId) const
float getOrientationY(int boneId) const
void setConstraints(int boneId, float minAngle, float maxAngle)
Joint limits for the single 2D hinge DOF.
void setLength(int boneId, float length)
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)
int getChild(int boneId, int childIndex) const
std::string id
Definition Widget.h:15