How are PShape contours stored?

image

Take the PShape above. Clearly it must know that the vertices of the inner region are not to be joined with the other vertices of the edge and represent a region that is “cut-out” from the shape. Processing calls such regions contours.

Is there a way to get this info from a PShape? i.e. which contour group each vertex belongs to?

Now there’s a method getVertexCodes() which looked promising but the array it returns has less length than the number of vertices a shape has, so I wonder whether this refers to what I want and whether it’s possible to get this info from it.

Hi @micycle ,

The vertex codes will not match the number of vertices. For a cubic Bezier vertex, there will be 3 pairs (6 floats) in vertices per command; for a quadratic Bezier vertex 2 pairs (4 floats) in vertices per command. That’s why this happens when a shape that should be a PATH family is assigned the GEOMETRY family instead.

beginContour inserts a BREAK command into the vertex commands list, so maybe you could use that in conjunction with a vertex winding algorithm to get what you’re looking for.

(Also, beware of implementation differences between a super-class PShape and its sub-classes, for example PShapeOpenGL).

EDIT: When I wanted to convert between a PShape and my own 2D curve class, I used this routine to loop through the commands. The code does not address contours but it may offer a basic outline.

Hope that helps some, Jeremy

Thanks for your reply Jeremy.

After a bit more digging around in PShape, I found a block of code here that reveals the logic of the vertex codes (for the super class at least). Reversing it is simple:

	static int[] getContourGroups(int[] vertexCodes) {

		int group = 0;

		ArrayList<Integer> groups = new ArrayList<>(vertexCodes.length * 2);
		
		for (int vertexCode : vertexCodes) {
			switch (vertexCode) {
				case VERTEX:
					groups.add(group);
					break;

				case QUADRATIC_VERTEX:
					groups.add(group);
					groups.add(group);
					break;

				case BEZIER_VERTEX:
					groups.add(group);
					groups.add(group);
					groups.add(group);
					break;

				case CURVE_VERTEX:
					groups.add(group);
					break;

				case BREAK:
					/*
					 * Marks beginning/end of new contour, and should be proceeded by a VERTEX
					 */
					group++;
					break;
			}
		}

		final int[] vertexGroups = new int[groups.size()];
		Arrays.setAll(vertexGroups, groups::get);
		return vertexGroups;
	}

1 Like