public static <V extends VisualVertex, E extends VisualEdge<V>> 
			Rectangle getTotalGraphSizeInLayoutSpace(
												Collection<V> vertices,
												Collection<E> edges,
												Function<V, Rectangle> vertexToBounds,
											    Function<E, List<Point2D>> edgeToArticulations) {
	//@formatter:on

		Rectangle vertexBounds = getBoundsForVerticesInLayoutSpace(vertices, vertexToBounds);

		double largestX = vertexBounds.x + vertexBounds.width;
		double largestY = vertexBounds.y + vertexBounds.height;
		double smallestX = vertexBounds.x;
		double smallestY = vertexBounds.y;

		for (E e : edges) {

			List<Point2D> articulationPoints = edgeToArticulations.apply(e);
			for (Point2D point : articulationPoints) {
				double vertexX = point.getX();
				double vertexY = point.getY();

				double componentMinX = vertexX - EXTRA_LAYOUT_COLUMN_SPACING / 2;
				double componentMinY = vertexY - EXTRA_LAYOUT_ROW_SPACING / 2;
				double componentMaxX = vertexX + EXTRA_LAYOUT_COLUMN_SPACING / 2;
				double componentMaxY = vertexY + EXTRA_LAYOUT_ROW_SPACING / 2;

				smallestX = Math.min(componentMinX, smallestX);
				smallestY = Math.min(componentMinY, smallestY);
				largestX = Math.max(componentMaxX, largestX);
				largestY = Math.max(componentMaxY, largestY);
			}
		}

		int width = (int) (largestX - smallestX);
		int height = (int) (largestY - smallestY);
		return new Rectangle((int) smallestX, (int) smallestY, width, height);
	}
Transforms the given edge loop shape to graph space, which includes updating
the size and location of the loop to be relative to the vertex.

@param edgeLoopShape The shape to transform
@param vertexShape The shape of the vertex for which the edge is being created
@param x The x coordinate of the vertex
@param y The y coordinate of the vertex
@return the transformed edge loop shape
Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/GraphViewerUtils.java