If someone has done something similar, or has some advice on how to do this correctly. Let me know.
I’ve just done something similar for PText.
The initial problem is that Processing’s shearX()
affects the translation matrix of a PShape only, and not the positions of the underlying vertices, so you can’t feasibly get the size/boundary of the new shape (at least to my knowledge).
Solution
Write a new shearX() method that does affect the PShape’s vertices, then simply find the enclosing rectangle of the new vertices.
Thankfully, it’s a fairly straightforward algorithm – for a given vertex, map it’s shear amount (x-displacement) based on it’s height from some Y position:
for (int i = 0; i < myPShape.getVertexCount(); i++) {
PVector vertex = myPShape.getVertex(i);
vertex.x += PApplet.map(vertex.y, 0, baselineY, 0, maxShearX);
myPShape.setVertex(i, vertex); // need to call setVertex() to apply change
}
Then you can use these methods to find the most extreme points of the shape:
Code...
/**
* Return value of smallest (up-most) Y coordinate from shape (may return
* negative values)
*
* @param shape
* @return
*/
private static float getMinY(PShape shape) {
float min = Float.MAX_VALUE;
if (shape.getFamily() == GROUP) {
for (PShape child : shape.getChildren()) { // search all children PShapes
for (int i = 0; i < child.getVertexCount(); i++) {
min = PApplet.min(child.getVertex(i).y, min);
}
}
} else {
for (int i = 0; i < shape.getVertexCount(); i++) { // search only parent PShape
min = PApplet.min(shape.getVertex(i).y, min);
}
}
return min;
}
/**
* Return value of greatest (down-most) Y coordinate from shape
*
* @param shape
* @return
*/
private static float getMaxY(PShape shape) {
float max = Float.NEGATIVE_INFINITY;
if (shape.getFamily() == GROUP) {
for (PShape child : shape.getChildren()) { // search all children PShapes
for (int i = 0; i < child.getVertexCount(); i++) {
max = PApplet.max(child.getVertex(i).y, max);
}
}
} else {
for (int i = 0; i < shape.getVertexCount(); i++) { // search only parent PShape
max = PApplet.max(shape.getVertex(i).y, max);
}
}
return max;
}
/**
* Return value of smallest (left-most) X coordinate from shape (may return
* negative values)
*
* @param shape
* @return
*/
private static float getMinX(PShape shape) {
float min = Float.MAX_VALUE;
if (shape.getFamily() == GROUP) {
for (PShape child : shape.getChildren()) { // search all children PShapes
for (int i = 0; i < child.getVertexCount(); i++) {
min = PApplet.min(child.getVertex(i).x, min);
}
}
} else {
for (int i = 0; i < shape.getVertexCount(); i++) { // search only parent PShape
min = PApplet.min(shape.getVertex(i).x, min);
}
}
return min;
}
/**
* Return value of greatest (right-most) X coordinate from shape
*
* @param shape
* @return
*/
private static float getMaxX(PShape shape) {
float max = Float.NEGATIVE_INFINITY;
if (shape.getFamily() == GROUP) {
for (PShape child : shape.getChildren()) { // search all children PShapes
for (int i = 0; i < child.getVertexCount(); i++) {
max = PApplet.max(child.getVertex(i).x, max);
}
}
} else {
for (int i = 0; i < shape.getVertexCount(); i++) { // search only parent PShape
max = PApplet.max(shape.getVertex(i).x, max);
}
}
return max;
}
Processing’s native rotate()
method is similar – again it affects the matrix and not the vertices of a PShape. After writing a rotate()
method that affects a PShape’s vertices, we can similarly get bounding box as the shape is rotated: