Chain/loop export & moving fixtures

General discussion about the R.U.B.E editor
Post Reply
Elsch
Posts: 2
Joined: Mon Jul 15, 2013 8:27 pm

Chain/loop export & moving fixtures

Post by Elsch »

Hey there,

I have been playing around with R.U.B.E. for about a week now and really like it so far, even though the UI is a bit counterintuitive (or to put it charitably quite different from any similar tool I tried) sometimes.

There are two things however, which I'd deem "fix worthy":

The first one is the way (closed) loop/chain shapes are exported. If I export a line shape it looks like this:

Code: Select all

"chain" : 
{
	"vertices" : 
	{
		"x" : [
			-0.50,
			-0.8454920053482056,
			-1.404510021209717,
			-1.404510021209717,
			-0.8454909920692444,
		],
		"y" : [
			0.0,
			0.4755280017852783,
			0.2938930094242096,
			-0.2938930094242096,
			-0.4755280017852783,
		]
}
Exactly waht you would expect. If change the same shape to a loop however, it looks like this:

Code: Select all

"chain" : 
{
	"hasNextVertex" : true,
	"hasPrevVertex" : true,
	"nextVertex" : 
	{
		"x" : -0.8454920053482056,
		"y" : 0.4755280017852783
	},
	"prevVertex" : 
	{
		"x" : -0.8454909920692444,
		"y" : -0.4755280017852783
	},
	"vertices" : 
	{
		"x" : [
			-0.50,
			-0.8454920053482056,
			-1.404510021209717,
			-1.404510021209717,
			-0.8454909920692444,
			-0.50
		],
		"y" : [
			0.0,
			0.4755280017852783,
			0.2938930094242096,
			-0.2938930094242096,
			-0.4755280017852783,
			0.0
		]
}
I see several issues with this:
  • hasNextVertex, hasPrevVertex is superfluous, since I could just query for the existance of the nextVertex, prevVertex objects
  • nextVertex, prevVertex also seems superfluous, since these points are implicitly given via the vertices array
  • The same is true for the last vertice of the vertices array, which is not even needed in box2d, since the ChainShape.createChain(...) and ChainShape.createLoop(...) methods expect exactly the same vertices array (without the replicated last vertice)
Is there any special reason, why this is done instead of just exporting the same vertices in both cases and just adding an isClosed : true key/value pair to the loop? At the moment loops seem just harder to parse, because I need to strip away the last vertice and a lot of information, which is already there.

My second "issue" is with the placement of fixtures. It would be nice if the position of a fixture could be set via the properties dialog directly (as is possible for bodies). Either globally or relative to its body. Alternatively I'd like to enter the coordinates directly, when translating fixtures (the same way you can do it for the cursor). This is not really a problem, since I wrote my own moveToCursor script, but I still think it's odd, that this is not possible via the UI.
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Chain/loop export & moving fixtures

Post by iforce2d »

The prevVertex/nextVertex information says whether the chain has ghost vertices at the ends, and those ghost vertices are not necessarily one of the vertices of the chain itself (otherwise they could just be stored as an index). You can find some more info about ghost vertices here: http://www.iforce2d.net/b2dtut/ghost-vertices

The hasPrevVertex/hasNextVertex information is indeed superfluous when existence of prevVertex/nextVertex can be presumed to have the same meaning. In the original C++ b2ChainShape class the prevVertex/nextVertex members are always there, so it's necessary to also have booleans to say whether they should actually be used or not. The goal of the b2dJson format was to faithfully preserve as much as possible of the state of a Box2D world, and perhaps saving these in the JSON was a little overzealous. At this point in time, backwards compatibility is the only reason to keep them.

However since they were there, most loaders have been written to depend on them, for example the C++ loader uses chainshape.CreateChain() and then explicitly sets the prevVertex/nextVertex information, instead of using CreateLoop(). (See source.)

For a scene exported from RUBE and loaded by your own loader, you are quite right that all of the above is superfluous, because RUBE does not create chains with external ghost vertices, and you have no backward compatibility concerns. In that case you could exclude them from the exported file entirely, by unchecking those properties in the scene settings dialog (Scene -> Scene settings -> Export options):
(You'll need to expand the 'body' and 'fixture' nodes of the tree to see these.)
Selection_031.png
Selection_031.png (10.63 KiB) Viewed 9143 times
But if you want to use CreateLoop() you will have to leave at least one of them to check for existence, so you can tell whether it should be a closed loop or not.

As to why the loop version repeats the last vertex of the list again, this also seems to have occurred due to overzealous replication of the internal state of the Box2D world (as you can see in line 44 of b2ChainShape, Box2D stores the first and last vertex twice). Now that you mention it this seems quite hard to follow for people writing their own loader from scratch, and it's not really appropriate for a file format to have redundancy like that. Perhaps this can be removed in future, with the introduction of a version number added to the file that loaders can check to know whether to expect the old or new method.

Sorry for the unclear stuff... what language are you writing your loader for? Even if a straight-up port of the C++ version is difficult you might still find it useful to refer to sometimes. I was a bit puzzled myself as to why the last vertex was repeated, until I checked back in the source.

==============
Part 2 :)
Fixtures can include polygons, lines, circles, fat-lines, or any combination thereof, and in future also splines as well. As such they do not have any inherent position, and moving a fixture really amounts to moving all of the vertices of that fixture. But there are a few ways you can come up with something that you could call a position:
- average of all vertices
- center of mass
- center of bounding box
RUBE uses the second of these as the 'selection center', and the next update will include the ability to move the selection center to the cursor using (S,C) similar to the existing (C,S) to move the cursor to the selection center. This will be available for all item types. For fixtures, it will move all vertices of selected fixtures so that the overall selection center moves to the cursor. I'm guessing that's what your script does?
Elsch
Posts: 2
Joined: Mon Jul 15, 2013 8:27 pm

Re: Chain/loop export & moving fixtures

Post by Elsch »

Hi,
Thank you for the detailed and elaborate reply. Mainly I was just wondering, if i would get into trouble if I did it like you proposed here:
iforce2d wrote:For a scene exported from RUBE and loaded by your own loader, you are quite right that all of the above is superfluous, [..] But if you want to use CreateLoop() you will have to leave at least one of them to check for existence, so you can tell whether it should be a closed loop or not.
...since I already found the export options and did exactly that in my parser. :lol:

Regarding my background: Im one of the devs of Farseer Physics Engine for XNA. Though I am mainly responsible for the samples and some boolean polygon operations stuff. I switched over to LibGDX a while ago, since XNA is kinda dead and I wanted to take a shot at some Android programming. Since they have such a sleek JSON Parser and I use a lot of custom properties to attach the box2d stuff to my entity system, I decided to roll my own importer.
iforce2d wrote:You can find some more info about ghost vertices here: http://www.iforce2d.net/b2dtut/ghost-vertices
I probably have sent that link to a dozen people on the Farseer discussion board over the past few years... we reference your blog a lot there. ;)

After playing around with edge and line shapes a bit more yesterday, I still would have expected a slightly different behaviour:
My understanding was, that next and prev vertices are stored per edge. Setting these ghost-vertices to anything else than the endpoints of adjacent edges, if there are any, doesn't make much sense IMHO and defeats the purpose why ghost-vertices where introduced in the first place.
Therefore wouldn't it make much sense to set the ghost-vertices on edge chaines and edge loops automatically? ...since it never hurts right :?:
Editing the prev and next vertices by hand, should only be possible if I select the line-shape option in R.U.B.E. In that case I would assume they correspond to the outermost edge's ghost-vertices respectively, since all the "internal" ones can be derived automatically.
Of course that would probably wreck backwards compatibility completely... so I guess it is more of a feature request for future versions :roll:
iforce2d wrote:Part 2 :) [..] RUBE uses the second of these as the 'selection center', and the next update will include the ability to move the selection center to the cursor using (S,C) similar to the existing (C,S) to move the cursor to the selection center. This will be available for all item types. For fixtures, it will move all vertices of selected fixtures so that the overall selection center moves to the cursor. I'm guessing that's what your script does?
I have three scripts for move selected vertice, center of mass, or center of aabb to the cursor. So your proposed solution looks exactly like what I was missing! Great! :mrgreen:
iforce2d
Site Admin
Posts: 861
Joined: Sat Dec 22, 2012 7:20 pm

Re: Chain/loop export & moving fixtures

Post by iforce2d »

Yes, prevVertex and nextVertex are stored per edge, for every 'child' edge that a chain/loop is made from. And yes, for most interior vertices it doesn't make sense to have these set to anything other than the endpoints of adjacent vertices. I say 'most' because there are situations where you might not want to have ghost vertices even for interior vertices of a chain. And yes, in almost all cases the ghost vertices at the end of the chain will not be used. There are cases where you might want to use them though, like this:
ghostVertex.png
ghostVertex.png (4.88 KiB) Viewed 9128 times
... to stop the dynamic body moving to the right from catching on the first edge of the chain. There are of course other workarounds, like making the ghost vertex a normal vertex and positioning it a bit lower underground. The ghost vertex method has the potential advantage that no collision callbacks will be generated for the chain fixture until the dynamic body has actually touched the main part of the chain. Anyway, as a format to preserve all of these possibilities, the b2dJson ended up storing perhaps more than is necessary for what most people are using it for today.
Post Reply