Line2D findClosestLineSegment(double arrowPlacementTolerance, Line2D line, Shape vertexShape) {

		if (!vertexShape.contains(line.getP2())) {
			String errorString = "line end point: " + line.getP2() +
				" is not contained in shape: " + vertexShape.getBounds2D();
			throw new IllegalArgumentException(errorString);
		}

		Line2D left = new Line2D.Double();
		Line2D right = new Line2D.Double();

		// keep chopping the line in half until it is small enough and lands just outside of the
		// vertex shape, within the provided tolerance		
		int iterations = 0; // arbitrary limit to ensure rounding errors do not loop forever
		while (lengthSquared(line) > arrowPlacementTolerance && iterations++ < 15) {
			bisect(line, left, right);
			line = vertexShape.contains(right.getP1()) ? left : right;
		}
		return line;
	}
Basic class to calculate the position of an edge arrow

@param <V> the vertex type
@param <E> the edge type
Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualEdgeArrowRenderingSupport.java