@Override
	protected Map<FGEdge, List<Point2D>> positionEdgeArticulationsInLayoutSpace(
			VisualGraphVertexShapeTransformer<FGVertex> transformer,
			Map<FGVertex, Point2D> vertexLayoutLocations, Collection<FGEdge> edges,
			LayoutLocationMap<FGVertex, FGEdge> layoutToGridMap) throws CancelledException {

		Map<FGEdge, List<Point2D>> newEdgeArticulations = new HashMap<>();

		// Condensing Note: we have guilty knowledge that our parent class my condense the
		// vertices and edges towards the center of the graph after we calculate positions.
		// To prevent the edges from moving to far behind the vertices, we will compensate a
		// bit for that effect using this offset value.   The getEdgeOffset() method below is
		// updated for the condense factor.
		int edgeOffset = isCondensedLayout()
				? (int) (VERTEX_TO_EDGE_ARTICULATION_PADDING * (1 - getCondenseFactor()))
				: VERTEX_TO_EDGE_ARTICULATION_PADDING;
		Vertex2dFactory vertex2dFactory =
			new Vertex2dFactory(transformer, vertexLayoutLocations, layoutToGridMap, edgeOffset);

		//
		// Route our edges!
		//
		for (FGEdge e : edges) {
			monitor.checkCancelled();

			FGVertex startVertex = e.getStart();
			FGVertex endVertex = e.getEnd();

			Vertex2d start = vertex2dFactory.get(startVertex);
			Vertex2d end = vertex2dFactory.get(endVertex);
			boolean goingUp = start.rowIndex > end.rowIndex;

			if (goingUp) {
				// we paint loops going back up differently than other edges so the user can
				// visually pick out the loops much easier
				DecompilerBlock block = blockGraphRoot.getBlock(endVertex);
				DecompilerBlock loop = block.getParentLoop();

				if (loop != null) {
					List<Point2D> articulations =
						routeUpwardLoop(layoutToGridMap, vertex2dFactory, start, end, loop);
					newEdgeArticulations.put(e, articulations);
					continue;
				}
			}

			List<Point2D> articulations = new ArrayList<>();

			//
			// Basic routing:
			// -leave the bottom of the start vertex
			// -first bend at some constant offset
			// -move to right or left, to above the end vertex
			// -second bend above the end vertex at previous constant offset
			//
			// Edges start/end on the vertex center.  If we offset them to avoid
			//    overlapping, then they produce angles when only using two articulations.
			//    Thus, we create articulations that are behind the vertices to remove
			//    the angles.  This points will not be seen.
			//
			//
			// Complex routing:
			// -this mode will route edges around vertices
			//
			// One goal for complex edge routing is to prevent overlapping (simple edge routing
			// prefers overlapping to reduce lines).  To prevent overlapping we will use different
			// offset x and y values, depending upon the start and end vertex row and column
			// locations.   Specifically, for a given edge direction there will be a bias:
			// 		-Edge to the right - leave from the right; arrive to the left
			//  	-Edge to the left - leave from the left; arrive to the right
			//  	-Edge straight down - go straight down
			//
			// For each of the above offsets, there will be an amplifier based upon row/column
			// distance from start to end vertex.  This has the effect that larger vertex
			// distances will have a larger offset/spacing.
			//

			if (start.columnIndex < end.columnIndex) { // going to the right

				routeToTheRight(start, end, vertex2dFactory, articulations);
			}

			else if (start.columnIndex > end.columnIndex) { // going to the left; flow return

				// check for the up or down direction
				if (start.rowIndex < end.rowIndex) { // down
					routeToTheLeft(start, end, e, vertex2dFactory, articulations);
				}
				else {
					routeToTheRightGoingUpwards(start, end, vertex2dFactory, articulations);
				}
			}

			else {  // going down; no nesting; flow return

				routeDownward(start, end, e, vertex2dFactory, articulations);
			}

			newEdgeArticulations.put(e, articulations);
		}

		vertex2dFactory.dispose();
		return newEdgeArticulations;
	}
An amount by which edges entering a vertex from the left are offset to avoid overlapping
Ghidra/Features/FunctionGraphDecompilerExtension/src/main/java/ghidra/app/plugin/core/functiongraph/graph/layout/DecompilerNestedLayout.java