liabru / matter-js

a 2D rigid body physics engine for the web ▲● ■
MIT License
16.85k stars 1.97k forks source link

setCentre of svg body to actual centre not centre of mass #1007

Open amcc opened 3 years ago

amcc commented 3 years ago

I'm combining paperjs and matterjs and overlaying svg shapes, its all working fine except that each library treats centres differently. Im using the body.position.x / body.position.y to move the paperjs item. I expect I need to reset the centre to the real centre rather than the centre of mass.

I'm having a bit of trouble understanding how to implement the instructions here: https://brm.io/matter-js/docs/classes/Bodies.html#method_fromVertices the issue is identifying what the input bounds might be. This is my code to create the bodies:

const svgs = document.getElementById("svgs");

const matterBodies = [];
[...svgs.children].map((svg, i) => {
  var color = colours[i];

  var vertexSets = select(svg, "path").map(function (path) {
    return Vertices.scale(Svg.pathToVertices(path, 30), 1, 1);
  });

  matterBodies[i] = Bodies.fromVertices(
    300 + i * 150,
    200 + i * 50,
    vertexSets,
    {
      render: {
        fillStyle: color,
        strokeStyle: color,
        lineWidth: 1,
      },
    },
    true
  );

  // Matter.Body.setCentre(
  //   matterBodies[i],
  //   Matter.Vector.sub(matterBodies[i].bounds.min, matterBodies[i].position),
  //   true
  // );

  Composite.add(world, matterBodies[i]);
});

The code is adapted from the demo, the svgs in this case being in the html. I've got commented out code which does reposition the body centre, but not correctly. You can see the current issue here: https://mtj-io.github.io/matter/

If you're able to let me know how to get the input bounds and correctly reposition the centre that would be great.

amcc commented 3 years ago

Got a botch fix for this right now and believe i'm starting to understand where the issue arises. Matter and PaperJS handle SVGs a little differently. When you show all the paths in PaperJS with selected = true you see that PaperJS is also drawing the bounding box of the SVG, this doesn't actually appear or get filled normally, but it is present as the first child of the Paper object. MatterJS ignores that bounding box if using the above code (its only looking at the path).

You can get the original SVG and reposition the object within the bounding box to get the two to align. This is pretty quick to do manually if you turn on wireframe mode in matter as it allows you to rapidly jog the image to the right place. The programatic solution would be to look at how the path is centred within its box in PaperJS and compare that with MatterJS. I have the positions of the first child (the bounding box) and subsequent children (paths) in PaperJS. I'm not sure how to achieve this though.

One other solution I've not yet tried is loading the path rather than entire SVG using PaperJS using the pathData: http://paperjs.org/reference/path/#path-pathData - this will make the methods fairly similar. Finally it might be worth drawing the Paper shapre from the Matter vertex data, or vis-versa. Whichever method is chosen minimising work done onFrame is key. Right now its pretty performant.

By the way if you're wondering why PaperJS - it does masking really well, plus perfectly smooth shapes and plays really well with Matter.

liabru commented 3 years ago

Sounds like you managed to get around this I hope?

It's usually the case that different libraries use different origin points. Matter.js needs to shift the vertices to be orientated around the centre of mass (a performance choice).

When I get around to this one, I hope to add something that returns the offset but hopefully the docs explain about how to find it for now.

amcc commented 3 years ago

Sorry it’s taken a while to get back to this!

we got round the issue by manually adjusting the SVGs centre and it worked great this way.

I have to admit I couldn’t quite fathom how to get the offset value from the docs. I expect it might help someone to get a code example for this, though no hurry for me now.