11 solver_.setKeepTrace(keep);
18 throw Exception(
"Solver2D.setMaxIterations: iterations must be >= 0");
21 solver_.setMaxIterations(
static_cast<unsigned>(
iterations));
28 throw Exception(
"Solver2D.setTolerance: tolerance must be >= 0");
31 solver_.setTolerance(tol);
38 solver_.setForce(force);
44 if (influence < 0.f || influence > 1.f) {
45 throw Exception(
"Solver2D.setInfluence: influence must be in [0, 1]");
47 influence_ = influence;
56 throw Exception(
"Solver2D.addTarget: boneId must be >= 0");
58 solver_.addTarget(
static_cast<unsigned>(boneId), ::ik::vec2{
x,
y}, weight);
62 return static_cast<int>(solver_.targets().size());
67 throw Exception(
"Solver2D.solve: skeleton is null");
70 std::vector<::ik::vec2> original;
71 if (influence_ < 1.f) {
72 original =
state.position_;
74 const bool reached = solver_.solve(skeleton->
native(),
state);
75 if (influence_ < 1.f) {
76 const float t = influence_;
77 for (
size_t i = 0; i <
state.position_.size(); ++i) {
78 state.position_[i] = original[i] + (
state.position_[i] - original[i]) * t;
87 throw Exception(
"Solver2D.step: skeleton is null");
90 std::vector<::ik::vec2> original;
91 if (influence_ < 1.f) {
92 original =
state.position_;
94 solver_.step(skeleton->
native(), skeleton->
state(), dt);
95 if (influence_ < 1.f) {
96 const float t = influence_;
97 for (
size_t i = 0; i <
state.position_.size(); ++i) {
98 state.position_[i] = original[i] + (
state.position_[i] - original[i]) * t;
108 options.
force = force_;
110 return solveChainImpl(skeleton, rootBoneId, tipBoneId, options);
120 f = std::min(1.f, std::max(0.f, dt));
122 f = std::min(1.f,
f * std::max(0.f, dt));
125 solveChainImpl(skeleton, rootBoneId, tipBoneId, options);
128bool Solver2D::solveChainImpl(
Skeleton2D *skeleton,
int rootBoneId,
int tipBoneId,
131 throw Exception(
"Solver2D.solveChain: skeleton is null");
133 if (rootBoneId < 0 || tipBoneId < 0) {
134 throw Exception(
"Solver2D.solveChain: bone ids must be >= 0");
137 if (rootBoneId >= count || tipBoneId >= count) {
138 throw Exception(
"Solver2D.solveChain: bone id out of range");
140 if (rootBoneId == tipBoneId) {
141 throw Exception(
"Solver2D.solveChain: root and tip must differ");
146 if (
b == rootBoneId) {
153 throw Exception(
"Solver2D.solveChain: tipBoneId is not a descendant of rootBoneId");
155 return detail::solveChain<2>(skeleton->
native(), skeleton->
state(),
156 static_cast<unsigned>(rootBoneId),
157 static_cast<unsigned>(tipBoneId), solver_.targets(), options);
JobSystemThreadPool::State * state
Script-facing 2D skeleton + pose state (ik::skeleton2d + ik::ecs2d). Bone indices are stable after ea...
::ik::skeleton2d & native()
int getParent(int boneId) const
int getMaxIterations() const
int getTargetCount() const
void setForce(float force)
bool getKeepTrace() const
void setMaxIterations(int iterations)
void step(Skeleton2D *skeleton, float dt=1.f)
void setTolerance(float tol)
void setKeepTrace(bool keep)
void setInfluence(float influence)
Overall pose blend: 0 = keep the input pose, 1 = full solve (default).
void addTarget(int boneId, float x, float y, float weight=1.f)
bool solve(Skeleton2D *skeleton)
Returns true if every target is within tolerance.
bool solveChain(Skeleton2D *skeleton, int rootBoneId, int tipBoneId)
FABRIK solve restricted to the bone chain rootBoneId..tipBoneId. The chain root stays pinned and bone...
void stepChain(Skeleton2D *skeleton, int rootBoneId, int tipBoneId, float dt=1.f)
float getTolerance() const
float getInfluence() const
Options shared by the chain-scoped FABRIK solve used by Solver2D / Solver3D. These mirror the knobs o...