javascript canvas intersection between two path2D

Viewed 461

I'm looking for a way to check if two path2D are intersecting but can't find a way...

Exemple :

// My circle
let circlePath = new Path2D();
circlePath.ellipse(x, y, radiusX, radiusY, 0, 0, Math.PI*2, false);

// My rectangle
let rectPath = new Path2D();
rectPath.rect(x, y, width, height);

// Intersect boolean
let intersect = circlePath.intersect(rectPath); // Does not exists

Is there a function to do that ?

I found isPointInPath(path2D, x, y) (that I use with my paths to check intersect with mouse) but can't use it between two paths.

Or maybe a way to get an array of all points in a Path2D to use isPointInPath with all points ?

Edit:

FYI, I want this for a game development, I want to be able to check collision between my entities (an entity is defined by some data and a Path2D). My entities can be squares, circles or more complex shapes.

1 Answers

There currently is nothing in the API to do this.

The Path2D interface is still just an opaque object, from which we can't even extract the path-data. I actually did start working on a future proposal to expose this path-data and add a few more methods to the Path2D object, like a getPointAtLength(), or an export to SVG path commands, which would help doing what you want, but I wouldn't hold my breath until it's part of the API, and I must admit I didn't even consider including such a path-intersect method...

However as part of this effort I did build a prototype of that API that currently exposes only a few of the expected methods: https://github.com/Kaiido/path2D-inspection/
Among these methods there is a toSVGString() that can be used with this project (that I didn't extensively test).

So we could build a Path2D#intersects() by merging both libraries. However note that at least mine (path2d-inspection) hasn't been extensively tested yet and I don't recommend using it in production just yet.
Anyway, here is a very quickly made hack as a proof-of-concept:

const circlePath = new Path2D();
circlePath.ellipse(rand(100, 20), rand(100, 20), rand(80, 10), rand(80, 10), rand(Math.PI*2), 0, Math.PI*2, false);

// My rectangle
const rectPath = new Path2D();
rectPath.rect(rand(150), rand(100), rand(200), rand(200));

// Intersect boolean
const intersect = rectPath.intersects(circlePath);
console.log("intersect:", intersect);

// List of intersection points
const intersections = rectPath.getIntersections(circlePath);
console.log(intersections);

// Render on a canvas to verify
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "green";
ctx.stroke(circlePath);
ctx.strokeStyle = "red";
ctx.stroke(rectPath);

function rand(max=1, min=0) {
  return Math.random() * (max - min) + min;
}
.as-console-wrapper { max-height: 50px !important }
<script src="https://cdn.jsdelivr.net/gh/Kaiido/path2D-inspection@master/build/path2D-inspection.min.js"></script>
<script>
// a really quick hack to grasp 'intersect' from their esm
globalThis.module = {};
</script>
<script src="https://cdn.jsdelivr.net/gh/bpmn-io/path-intersection@master/intersect.js"></script>
<script>
// part 2 of the hack to grasp 'intersect', let's make it a Path2D method :P
{
  const intersect = module.exports;
  delete globalThis.module;
  Path2D.prototype.getIntersections = function(path2) {
    return intersect(this.toSVGString(), path2.toSVGString());
  };
  Path2D.prototype.intersects = function(path2) {
    return this.getIntersections(path2).length > 0;
  };
}
</script>
<canvas></canvas>

Related