// Path: src/main/java/de/jfschaefer/layeredgraphlayout/layout/Vector.java
// public class Vector {
//     public final double x;
//     public final double y;
// 
//     public Vector(double x, double y) {
//         this.x = x;
//         this.y = y;
//     }
// 
//     public Vector scaled(double l) {
//         return new Vector(l * x, l * y);
//     }
// 
//     public Vector add(Vector other) {
//         return new Vector(this.x + other.x, this.y + other.y);
//     }
// }
// 
// Path: src/main/java/de/jfschaefer/layeredgraphlayout/util/Pair.java
// public class Pair<A, B> {
//     public final A first;
//     public final B second;
//     public Pair(A first, B second) {
//         this.first = first;
//         this.second = second;
//     }
// }


import de.jfschaefer.layeredgraphlayout.layout.*;
import de.jfschaefer.layeredgraphlayout.layout.Vector;
import de.jfschaefer.layeredgraphlayout.util.Pair;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
import java.util.*;
                        segment.getEnd().x, segment.getEnd().y);
                curve.setFill(Color.TRANSPARENT);
                curve.setStroke(color);
                g.getChildren().add(curve);
            } else {
                Line line = new Line(segment.getStart().x, segment.getStart().y,
                        segment.getEnd().x, segment.getEnd().y);
                line.setStroke(color);
                g.getChildren().add(line);
            }
        }

        // Step 2: Arrow head
        if (layoutConfig.getArrowheads()) {
            Polygon arrowhead = new Polygon(0d, 0d, 4d, 8d, 0d, 4d, -4d, 8d);
            EdgeSegment segment = segments.get(segments.size() - 1);
            double fraction = 1d;
            Vector derivative = segment.getDerivativeAt(fraction);
            double angle = Math.atan2(derivative.y, derivative.x);
            Point position = segment.getAt(fraction);
            arrowhead.setLayoutX(position.x);
            arrowhead.setLayoutY(position.y);
            arrowhead.getTransforms().add(new Rotate(365d / (2 * Math.PI) * angle + 90, 0, 0));
            arrowhead.setFill(color);
            g.getChildren().add(arrowhead);
        }

        // Step 3: Label
        String labelString = labelMap.get(edge);
        if (labelString != null && !labelString.isEmpty()) {
// Path: src/main/java/de/jfschaefer/layeredgraphlayout/layout/Vector.java
// public class Vector {
//     public final double x;
//     public final double y;
// 
//     public Vector(double x, double y) {
//         this.x = x;
//         this.y = y;
//     }
// 
//     public Vector scaled(double l) {
//         return new Vector(l * x, l * y);
//     }
// 
//     public Vector add(Vector other) {
//         return new Vector(this.x + other.x, this.y + other.y);
//     }
// }
// 
// Path: src/main/java/de/jfschaefer/layeredgraphlayout/util/Pair.java
// public class Pair<A, B> {
//     public final A first;
//     public final B second;
//     public Pair(A first, B second) {
//         this.first = first;
//         this.second = second;
//     }
// }


// Path: src/main/java/de/jfschaefer/layeredgraphlayout/visualizationfx/SimpleGraphFXEdgeFactory.java
import de.jfschaefer.layeredgraphlayout.layout.*;
import de.jfschaefer.layeredgraphlayout.layout.Vector;
import de.jfschaefer.layeredgraphlayout.util.Pair;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.scene.transform.Rotate;
import java.util.*;

                        segment.getEnd().x, segment.getEnd().y);
                curve.setFill(Color.TRANSPARENT);
                curve.setStroke(color);
                g.getChildren().add(curve);
            } else {
                Line line = new Line(segment.getStart().x, segment.getStart().y,
                        segment.getEnd().x, segment.getEnd().y);
                line.setStroke(color);
                g.getChildren().add(line);
            }
        }

        // Step 2: Arrow head
        if (layoutConfig.getArrowheads()) {
            Polygon arrowhead = new Polygon(0d, 0d, 4d, 8d, 0d, 4d, -4d, 8d);
            EdgeSegment segment = segments.get(segments.size() - 1);
            double fraction = 1d;
            Vector derivative = segment.getDerivativeAt(fraction);
            double angle = Math.atan2(derivative.y, derivative.x);
            Point position = segment.getAt(fraction);
            arrowhead.setLayoutX(position.x);
            arrowhead.setLayoutY(position.y);
            arrowhead.getTransforms().add(new Rotate(365d / (2 * Math.PI) * angle + 90, 0, 0));
            arrowhead.setFill(color);
            g.getChildren().add(arrowhead);
        }

        // Step 3: Label
        String labelString = labelMap.get(edge);
        if (labelString != null && !labelString.isEmpty()) {
            final Pair<Point, Double> edgePosition = Util.naiveGetLabelPosition(segments);