@Override
	public void drawSimpleEdge(RenderContext<V, E> rc, Layout<V, E> layout, E e) {

		GraphicsDecorator gDecorator = rc.getGraphicsContext();
		Graphics2D graphicsCopy = (Graphics2D) gDecorator.create();
		GraphicsDecorator g = new GraphicsDecorator(graphicsCopy);

		double alpha = e.getAlpha();
		if (alpha < 1D) {
			g.setComposite(
				AlphaComposite.getInstance(AlphaComposite.SrcOver.getRule(), (float) alpha));
		}

		Graph<V, E> graph = layout.getGraph();
		Pair<V> endpoints = graph.getEndpoints(e);
		V v1 = endpoints.getFirst();
		V v2 = endpoints.getSecond();
		float scalex = (float) g.getTransform().getScaleX();
		float scaley = (float) g.getTransform().getScaleY();

		boolean isInHoveredPath = isInHoveredVertexPath(e);
		boolean isInFocusedPath = isInFocusedVertexPath(e);
		boolean isSelected = isSelected(e);
		boolean isEmphasized = isEmphasiszed(e);

		Color drawColor = getDrawColor(graph, e);
		Color focusedColor = getFocusedColor(graph, e);
		Color selectedColor = getSelectedColor(graph, e);
		Color hoveredColor = getHoveredColor(graph, e);

		// this can be changed if clients wish to set a separate color for the hovered state
		Color selectedAccentColor = hoveredColor;

		float scale = Math.min(scalex, scaley);

		Point2D p1 = layout.apply(v1);
		Point2D p2 = layout.apply(v2);
		MultiLayerTransformer multiLayerTransformer = rc.getMultiLayerTransformer();
		p1 = multiLayerTransformer.transform(Layer.LAYOUT, p1);
		p2 = multiLayerTransformer.transform(Layer.LAYOUT, p2);
		float x1 = (float) p1.getX();
		float y1 = (float) p1.getY();
		float x2 = (float) p2.getX();
		float y2 = (float) p2.getY();

		boolean isLoop = v1.equals(v2);
		Rectangle deviceRectangle = null;
		JComponent vv = rc.getScreenDevice();
		if (vv != null) {
			Dimension d = vv.getSize();
			deviceRectangle = new Rectangle(0, 0, d.width, d.height);
		}

		Shape vs1 = getCompactShape(rc, layout, v1);
		Shape edgeShape = getEdgeShape(rc, graph, e, x1, y1, x2, y2, isLoop, vs1);

		MutableTransformer vt = multiLayerTransformer.getTransformer(Layer.VIEW);
		if (vt instanceof LensTransformer) {
			vt = ((LensTransformer) vt).getDelegate();
		}

		Context<Graph<V, E>, E> context = Context.<Graph<V, E>, E> getInstance(graph, e);
		boolean edgeHit = vt.transform(edgeShape).intersects(deviceRectangle);
		if (!edgeHit) {
			return;
		}

		Paint oldPaint = g.getPaint();

		// get Paints for filling and drawing
		// (filling is done first so that drawing and label use the same Paint)		
		BasicStroke hoverStroke = getHoveredPathStroke(e, scale);
		BasicStroke focusedStroke = getFocusedPathStroke(e, scale);
		BasicStroke selectedStroke = getSelectedStroke(e, scale);
		BasicStroke selectedAccentStroke = getSelectedAccentStroke(e, scale);
		BasicStroke empahsisStroke = getEmphasisStroke(e, scale);

		// basic shape
		g.setPaint(drawColor);
		g.draw(edgeShape);

		if (isEmphasized) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(drawColor);
			g.setStroke(empahsisStroke);
			g.draw(edgeShape);
			g.setStroke(saveStroke);
		}

		if (isInHoveredPath) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(hoveredColor);
			g.setStroke(hoverStroke);
			g.draw(edgeShape);
			g.setStroke(saveStroke);
		}

		if (isInFocusedPath) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(focusedColor);
			g.setStroke(focusedStroke);
			g.draw(edgeShape);
			g.setStroke(saveStroke);
		}

		if (isSelected) {
			Stroke saveStroke = g.getStroke();

			g.setPaint(selectedAccentColor);
			g.setStroke(selectedAccentStroke);
			g.draw(edgeShape);

			g.setPaint(selectedColor);
			g.setStroke(selectedStroke);
			g.draw(edgeShape);
			g.setStroke(saveStroke);
		}

		// debug - draw a box around the edge
		//Rectangle shapeBounds = edgeShape.getBounds();
		//g.setPaint(Palette.ORANGE);
		//g.draw(shapeBounds);

		// can add this feature as needed to speed up painting 
		//if (scale < .3) {
		//	return;
		//}

		//
		// Arrow Head
		//
		Predicate<Context<Graph<V, E>, E>> predicate = rc.getEdgeArrowPredicate();
		boolean drawArrow = predicate.apply(context);
		if (!drawArrow) {
			g.setPaint(oldPaint);
			return;
		}

		Stroke arrowStroke = rc.getEdgeArrowStrokeTransformer().apply(e);
		Stroke oldArrowStroke = g.getStroke();
		if (arrowStroke != null) {
			g.setStroke(arrowStroke);
		}

		Shape vs2 = getVertexShapeForArrow(rc, layout, v2);	// end vertex

		boolean arrowHit = vt.transform(vs2).intersects(deviceRectangle);
		if (!arrowHit) {
			g.setPaint(oldPaint);
			return;
		}

		AffineTransform at = arrowRenderingSupport.createArrowTransform(rc, edgeShape, vs2);
		if (at == null || at.isIdentity()) {
			g.setPaint(oldPaint);
			g.setStroke(oldArrowStroke);
			return;
		}

		Paint arrowDrawPaint = drawColor;
		Paint arrowFillPaint = arrowDrawPaint;
		Shape arrow = rc.getEdgeArrowTransformer().apply(context);
		arrow = scaleArrowForBetterVisibility(rc, arrow);
		arrow = at.createTransformedShape(arrow);

		// basic arrow shape
		g.setPaint(arrowFillPaint);
		g.fill(arrow);
		g.setPaint(arrowDrawPaint);
		g.draw(arrow);

		if (isEmphasized) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(arrowDrawPaint);
			g.setStroke(empahsisStroke);
			g.fill(arrow);
			g.draw(arrow);
			g.setStroke(saveStroke);
		}

		if (isInHoveredPath) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(hoveredColor);
			g.setStroke(hoverStroke);
			g.fill(arrow);
			g.draw(arrow);
			g.setStroke(saveStroke);
		}

		if (isInFocusedPath) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(focusedColor);
			g.setStroke(focusedStroke);
			g.draw(edgeShape);
			g.setStroke(saveStroke);
		}

		if (isSelected) {
			Stroke saveStroke = g.getStroke();
			g.setPaint(selectedColor);
			g.setStroke(selectedStroke);
			g.fill(arrow);
			g.draw(arrow);
			g.setStroke(saveStroke);
		}

		g.setStroke(oldArrowStroke);
		g.setPaint(oldPaint);
	}
Returns the current color to use when the edge is in the hovered path.
@param g the graph
@param e the edge 
@return the color
Ghidra/Framework/Graph/src/main/java/ghidra/graph/viewer/edge/VisualEdgeRenderer.java