Hi,
I’m currently trying to create a “custom” version of the contains method, that is implemented for shapes of the type path. The main reason I’m not using the path shape is, that I would like to map a texture onto my shape, which is possible for paths, but seems quite tedious (especially if the shape needs to be rotateable and moveable). A suggestion on one of my previous posts, was that I could reuse the implementation of the contains method, and convert it to work with my shapes.
I have found the implementation of the contains method through the github here, I will paste in the code below for your convenience.
public boolean contains(float x, float y) {
if (family == PATH) {
PVector p = new PVector(x, y);
if (matrix != null) {
// apply the inverse transformation matrix to the point coordinates
PMatrix inverseCoords = matrix.get();
// TODO why is this called twice? [fry 190724]
// commit was https://github.com/processing/processing/commit/027fc7a4f8e8d0a435366eae754304eea282512a
inverseCoords.invert(); // maybe cache this?
inverseCoords.invert(); // maybe cache this?
inverseCoords.mult(new PVector(x, y), p);
}
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
boolean c = false;
for (int i = 0, j = vertexCount-1; i < vertexCount; j = i++) {
if (((vertices[i][Y] > p.y) != (vertices[j][Y] > p.y)) &&
(p.x <
(vertices[j][X]-vertices[i][X]) *
(y-vertices[i][Y]) /
(vertices[j][1]-vertices[i][Y]) +
vertices[i][X])) {
c = !c;
}
}
return c;
} else if (family == GROUP) {
// If this is a group, loop through children until we find one that
// contains the supplied coordinates. If a child does not support
// contains() throw a warning and continue.
for (int i = 0; i < childCount; i++) {
if (children[i].contains(x, y)) return true;
}
return false;
} else {
// https://github.com/processing/processing/issues/1280
throw new IllegalArgumentException("The contains() method is only implemented for paths.");
}
}
At first glance it seemed quite easy, just remove the if statement, that checked if it was a path shape, and convert the rest to work inside my code.
Heres my contains method (pA is a reference to the PApplet object):
public boolean contains(float x, float y) {
PVector p = new PVector(x, y);
boolean c = false;
for (int i = 0, j = shape.getVertexCount()-1; i < shape.getVertexCount(); j = i++) {
if (((shape.getVertex(i).y > p.y) != (shape.getVertex(j).y > p.y)) &&
(p.x <
(shape.getVertex(j).x-shape.getVertex(i).x) *
(shape.getVertex(i).y) /
(shape.getVertex(j).y-shape.getVertex(i).y) +
shape.getVertex(i).x)) {
c = !c;
}
}
return c;
}
It has worked (sort of), theres multiple quirks, where it returns true, even if the point im checking is not within the shape, which unfortunately makes it very inconsistent.
If any of you have some prior experience with creating a custom contains method, or can figure out where my attempt at copying the implemented version went wrong, please dont hesitate, any help will be highly appreciated!
Heres my shape initialization (if it can be of any help):
shape = pA.createShape();
shape.beginShape();
shape.noStroke();
shape.textureMode(PConstants.NORMAL);
shape.texture(texture);
for (int i = 0; i < vertices.length-1; i++) {
shape.vertex(origin.x + vertices[i].x, origin.y + vertices[i].y, Math.signum(vertices[i].x + Math.abs(vertices[i].x)), Math.signum(vertices[i].y + Math.abs(vertices[i].y)));
}
shape.endShape(PApplet.CLOSE);
If you need more information, feel free to ask
Best
Frinkle