Inverse Kinematics Demo

Hi,
I wanted to take a look at C++ classes so I made a small Demo where you can move a Rope around.
Nothing special just a small experiment.

My Pokitto didnt arrive yet so I have no Idea if this runs on actual Hardware it worked fine on the emulator though.

3 Likes

:open_mouth: Do you have a gif? Iā€™ll try this as soon as I get to my PC.

(EDIT: F3 on emulator records gifs.)

1

adding more elements would obviousy make it look more organic right now it has 10 segments each 8 pixels long

EDIT:
Here is another example with 30 segments
1

EDIT2:
Another quick gif where the rope segments get bigger and further apart
1

4 Likes

Cool! Is it demanding on performance? I can see this potentially being used for some nice effects.

EDIT:

Switching from float to fixed point should help to make it faster.

I would guess so. I used some floating point math to get it to look this wavy. However I didnt make an effort to optimise and I have no Idea how this runs on Hardware.
The concept is quite scalable in the sense that you can choose how many segments you want to have and how often per frame you want to calculate the positions of the segments since this is only a heuristic.
Calculating it only one time per frame seems fine but you can see the tail of the rope moving slightly for a good second after you stopped moving

Let me check how it runs on Pokitto for you.

Youā€™ve made a very nice framework, switching to fixed point shouldnā€™t really be a problem for anybody. I imagine the performance would matter if you had a lot of strings, like an octopus boss or something :stuck_out_tongue:

EDIT:

Runs very smooth even now (sorry, recorded via webcam :smile:):

3 Likes

@Xhaku Cool stuff! Btw I am looking into why the Pokitto has not arrived yet.

I have had bad luck with shipments lately, it seems 2 shipments have gotten lost last week.

1 Like

Thanks. I am having lots of fun with the simulator so itā€™s no big deal. i am starting to think that Iā€™m cursed however. my last 3 packages didnt arrive. the 1st item was destroyed in shipment. the 2nd item was sent 3 times after which i found out that the ebay seller sent it to the wrong adress (i verified that i entered the correct one) and never bothered to send a 4th time so i got kinda nervous when the pokitto didnt arrive :stuck_out_tongue:

1 Like

Hahaha! Your luck is even worse than mine.

Posting packages through ā€œpostal servicesā€ is like:

tumblr_owu0d9l9Sv1wzvt9qo2_500

2 Likes

Made it more C++11-ish:

1 Like

I barely understand some stuff you did :blush: but you definitely made the angle situation more readable. Guess im gonna have to look structs up and what ā€œthis->directionā€ does.

1 Like

Forgot to mention, I didnā€™t check if it actually compiles so there might be a mistake or two.
Iā€™ll compile later and correct any mistakes if I find any.


struct is the same thing as class, the only difference is that everything in a struct is public by default, whereas everything in a class is private by default.

I tend to only use struct if Iā€™m sure I want absolutely everything to be public, otherwise I use class and mix the accessors.

this-> just accesses the classā€™s member variables.
Using this-> is optional, so most people donā€™t bother using it, but I make sure to always use this-> because it makes it clearer that Iā€™m accessing a member variable and not a global variable, local variable or function argument

That way when you take a function out of context you donā€™t have to sit there guessing ā€œis this a global or a member variable?ā€.
You know that anything with this-> is a member variable,
and anything else is either a local variable, a function argument or a global variable,
and youā€™ll be able to see where the local variables and function arguments are defined,
so youā€™ll be able to deduce that anything else must be a global variable.

If thereā€™s anything else you donā€™t understand then Iā€™m happy to explain it.


To preempt one of the things youā€™re probably going to ask, this:

Segment(float x, float y, int direction)
	: x(x), y(y), direction(direction)
{
}

Is (roughly) the same as this:

Segment(float x, float y, int direction)
{
	this->x = x;
	this->y = y;
	this->direction = direction;
}

Which is the same as this:

Segment(float _x, float _y, int _direction)
{
	x = _x;
	y = _y;
	direction = _direction;
}

So hopefully that clears that up.


Iā€™d like to point out that itā€™s bad practice to use a leading underscore in an identifier beacause according to the standard:

Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace


If you have any questions whatsoever, feel free to ask,
either here or in a PM, whichever youā€™re more comfortable with.
(That goes for anyone else reading this too.)

1 Like

Thanks fo the explenation. The only thing i still dont get is all this Valuetype stuff in the Point struct

template<typename Type>
struct Point
{
	using ValueType = Type;

	ValueType x;
	ValueType y;
	
	Point(void) = default;
	Point(ValueType x, ValueType y)
		: x(x), y(y)
	{
	}
};

is this comparable to generics in java?

Yes, AFAIK itā€™s two names for the same thing.

1 Like

The template<typename Type> part is a template declaration.
Templates are C++'s implementation of generics, so itā€™s similar to Javaā€™s generics system.
The implementation is quite different from Javaā€™s, but the basic idea is the same - you have type arguments that allow a class or struct to work for multiple different types.

If youā€™re used to Javaā€™s generics system then you can think of them as being the same but with different syntax.
Truthfully the implementation details are _a lot differen_t and at some point that difference will become important,
but for now you can think of them as the same thing but with different syntax.

(Iā€™m happy to explain the differences, but it would probably be a very long explanation.)

Beware assuming them to be the same thing,
the implementations are vastly different and C++'s template system is far more powerful.

Edit:
Importantly, thanks to Javaā€™s Type Erasure mechanism,
when a Java object talks about T itā€™s actually using java.lang.Object with a load of casts everywhere.
In other words, List<String> is the same as List<Integer> and both are actually just List<Object> with some added runtime (i.e. performance penalty) casts.
For more info see Wikipedia.

Type erasure is a cheap and nasty approach to generics.
C# learned from this mistake and used reified generics instead.

C++ doesnā€™t have this issue because every instantiation of a template is a distinct type.
All type checking is done at compile time - thereā€™s no extra runtime cost.


using ValueType = Type creates whatā€™s called a type alias.
It means that from then on, ValueType is equivalent to Type - both identifiers represent the same type.

I could have not bothered with the type alias, and just written this:

template<typename Type>
struct Point
{
	Type x;
	Type y;
	
	Point(void) = default;
	Point(Type x, Type y)
		: x(x), y(y)
	{
	}
};

Which would have worked just as well, and for the sake of your program wouldnā€™t have made any difference.

I included the alias because it makes obtaining the type of the members easier in certain circumstances.

For example, if I was using the definition of Point<T> without using ValueType = Type;, and then did:

using IntPoint = Point<int>;

I would have no easy way of retrieving the int type.
(There are ways, which Iā€™ll demonstrate later.)

However, if I used the definition of Point<T> that includes using ValueType = Type; then I can do this:

IntPoint point = IntPoint(4, 5);
IntPoint::ValueType x = point.x;

So basically, it provides a way of accessing the type parameter when you arenā€™t the one supplying it.
This is quite common for templated types from the C++ standard library.
For example, here are the aliases that std::array defines.(Which includes value_type - the standard library prefers ā€˜snake caseā€™ for its types, I usually prefer ā€˜Pascal caseā€™ unless Iā€™m trying to make something compatible with the standard library.)


Now, if I hadnā€™t defined ValueType, there are still two ways I could have obtained the type.
Firstly:

IntPoint point = IntPoint(4, 5);
using ValueType = decltype(point.x);
ValueType x = point.x;

And secondly:

IntPoint point = IntPoint(4, 5);
auto x = point.x;

(Technically this second way only works for variables and certain specific situations.)

So, why is the using ValueType = Type; approach used despite having these other two methods?
Thereā€™s three reasons.

Firstly, because auto and decltype were both added in C++11, prior to that in C++03 and C++98 they didnā€™t exist, so the type alias approach was the only viable approach.
(In fact, using didnā€™t exist prior to C++11. Originally you had to use typedef, which has much more confusing syntax.)

Secondly, because itā€™s a better way of making the type self-documenting.
By using IntPoint::ValueType explicitly, it makes your intent more obvious - it makes it clear that the type is intended for holding values.
(Using auto everywhere can start to make the code look a bit cryptic in some cases.)

And thirdly, sometimes itā€™s just easier to work with than the alternatives.

2 Likes

Read dangerous :smiley:

1 Like

Templates is very time consuming, but sooooo worth it when it finally manage to compile

How exactly are they dangerous?

I canā€™t think of anything dangerous that they can achieve that isnā€™t already possible in non-templated code (like messing around with void *s, or doing type-punning - both of which creep into the nasal demon realm).

Time consuming to learn or time consuming to make?
In my experience they usually take the same amount of time as a specialised class,
unless youā€™re doing something especially difficult (e.g. fixed points, SI units).

They can take some time to truly understand, but theyā€™re well worth knowing.
I think many people misconstrue normal template usage as being like meta-template programming,
when really it isnā€™t.
Most of the time, itā€™s no more difficult than the Point struct that I introduced to this kinematics demo.

Meta-template programming isnā€™t something people are going to need often (especially with C++11ā€™s introduction of constexpr, which allows many former meta-template classes to be replaced with functions).

Really though, with the exception of a few rare cases,
meta-template programming typically isnā€™t much different to using higher-order functions.
If you can sit through LYAH from chapter 1 through to chapter 6 then meta-template programming should be a doddle in 80% of cases.

Factorial Example

Factorial as a function:

constepxr std::uintmax_t factorial(std::uintmax_t n)
{
	return (n > 0) ? 1 : (n * factorial(n - 1));
}

Factorial as a meta-template:

template<std::uintmax_t n>
struct factorial
{
	static constexpr std::uintmax_t value = (n * factorial<n - 1>::value);
};

template<>
struct factorial<0>
{
	static constexpr std::uintmax_t value = 1;
};

The syntax is different, but the concepts are the same:
Pattern-matching, Recursion and piecewise functions.

(And arguably recurrance relations, but thatā€™s just a fancy term for a recursive function that generates a sequence.)

To make! Usually itā€™s simpler to use - thought it can be a pain in the ass because of the diagnostics messages.

Well, Iā€™m not an expert C++ programmer either; just talking from my limited experience, and Iā€™m certainly not a genius programmer either; and I feel like my focus capacity has been downed for

I rely more and more on template, and theyā€™re definitely an indispensable tool for me.
Still, I maintain that, for me, thinking in ā€œtemplateā€ -especially when conceiving them- is harder than template-less code.

Also, Iā€™m not talking about basic stuff like std::max and Points, etc! Iā€™m skilled enough to tackle them as easily. However, for the more complex stuff I do struggle much more with template-based solutions (funny thing is that Iā€™m also much more satisfied when achieving something hahaha) than with non-template-based ones, with my everyday adventures in C++.

There are some reasons for this:

  • I donā€™t craft each day -sometimes weeks- new template class/function that requires advanced concepts such as SFINAE.
  • Thinking in templates is about thinking the problems under sometimes very different angles, frequently a plain 180Ā° haha
  • Diagnostics messages donā€™t help much. Iā€™m really sorry, but most of the time theyā€™re just misleading, plenty of way too much information and very hard to read. However they DO improve them, and I feel like itā€™s getting better and better every year.

I love template programming because itā€™s so rewarding when it works. Compile-time checks are just awesome, and itā€™s like seeing a puzzle making itself haha

1 Like

More power is always more dangerous, all Iā€™m saying :slight_smile: Itā€™s a double edged sword.

More power implies for example a bigger probability of misuse, compiler bugs, confusion, ā€¦ means more work, complexity, fewer things we can assume about the system, ā€¦

Iā€™ve once listened to an interview with CMake devs and they said they specifically didnā€™t want to use an existing general purpose language and rather made their own computationally limited language because if they used e.g. Python, people would start abusing it and messing things up. Theyā€™d have to think about all the possible imaginable things users could potentially do. So I think itā€™s important to also think about not making a tool more powerful than it needs to be.

I guess I just wanted to point out this general principle, nothing personel against templates. You know, Iā€™m always the antithesis :smile: