gt:         MergeResult mergeResult = mergeEdges(edgeA, edgeB);
context: package net.sf.rails.algorithms;
  
  import java.awt.Shape;
  import java.awt.geom.Line2D;
  import java.awt.geom.Point2D;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.List;
  
  import net.sf.rails.ui.swing.hexmap.HexMap;
  
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  import org.jgrapht.Graph;
  
  
  public final class NetworkEdge implements Comparable<NetworkEdge> {
  
      private static final Logger log = LoggerFactory.getLogger(NetworkEdge.class);
  
      private final NetworkVertex source;
  
      private final NetworkVertex target;
  
      private boolean greedy;
  
      private final int distance;
  
      private final List<NetworkVertex> hiddenVertices;
      // list of vertexes that were merged into the edge
  
      private int routeCosts;
      // for the multigraph approach defines the number of routes excluded
  
      public NetworkEdge(NetworkVertex source, NetworkVertex target, boolean greedy) {
          this.source = source;
          this.target = target;
          this.greedy = greedy;
          if (greedy)
              this.distance = 1;
          else
              this.distance = 0;
          hiddenVertices = new ArrayList<NetworkVertex>();
      }
  
      public NetworkEdge(NetworkVertex source, NetworkVertex target, boolean greedy,
                  int distance, List<NetworkVertex> hiddenVertexes) {
          this.source = source;
          this.target = target;
          this.greedy = greedy;
          this.distance = distance;
          this.hiddenVertices = hiddenVertexes;
      }
  
      public NetworkVertex getSource() {
          return source;
      }
  
      public NetworkVertex getTarget() {
          return target;
      }
  
      private NetworkVertex getLowVertex() {
          if (source.compareTo(target) <= 0) {
              return source;
          } else {
              return target;
          }
      }
  
      private NetworkVertex getHighVertex() {
          if (source.compareTo(target) <= 0) {
              return target;
          } else {
              return source;
          }
      }
  
      /** returns the other vertex, if given vertex is not source/target of vertex, returns null */
      NetworkVertex getOtherVertex(NetworkVertex vertex) {
          if (this.source == vertex) {
              return target;
          } else if (this.target == vertex) {
              return source;
          }
          return null;
      }
  
      /** gets common vertex, if both source and target are common, returns source of this edge */
      NetworkVertex getCommonVertex(NetworkEdge otherEdge) {
         if (this.source == otherEdge.source || this.source == otherEdge.target) {
             return this.source;
         } else if (this.target == otherEdge.source || this.target == otherEdge.target) {
             return this.target;
         }
         return null;
      }
  
      public boolean isGreedy() {
          return greedy;
      }
  
      public void setGreedy(boolean greedy) {
         this.greedy = greedy;
      }
  
      public int getDistance() {
          return distance;
      }
  
      int getRouteCosts() {
          return routeCosts;
      }
  
      void setRouteCosts(int routeCosts) {
          this.routeCosts = routeCosts;
      }
  
      public List<NetworkVertex> getHiddenVertices() {
          return hiddenVertices;
      }
  
      /**
       * all vertices from source to target, including hidden vertices
       */
      public List<NetworkVertex> getVertexPath() {
          List<NetworkVertex> vertexPath = new ArrayList<NetworkVertex>();
          vertexPath.add(source);
          vertexPath.addAll(hiddenVertices);
          vertexPath.add(target);
          return vertexPath;
      }
  
      public String toFullInfoString() {
          StringBuilder info = new StringBuilder();
          info.append("Edge ").append(getConnection());
          info.append(", greedy = ").append(greedy);
          info.append(", distance = ").append(distance);
          info.append(", hidden vertexes = ").append(hiddenVertices);
          return info.toString();
      }
  
      public String getOrderedConnection() {
          return getLowVertex() + " -> " + getHighVertex();
      }
  
      public String getConnection() {
        return source + " -> " + target;
      }
  
      @Override
      // set to "" to faciltate visual graph
      public String toString() {
          return getConnection();
  //        if (!greedy)
  //            return "*** / " + distance;
  //        else
  //          return "" + distance;
      }
  
      /**
       * Natural order based on the ordering of the connected vertices
       */
      public int compareTo(NetworkEdge otherEdge) {
          int result = this.getLowVertex().compareTo(otherEdge.getLowVertex());
          if (result == 0) {
              result = this.getHighVertex().compareTo(otherEdge.getHighVertex());
          }
          return result;
      }
  
      /**
       * Ordering based on routecosts
       */
      public static final class CostOrder implements Comparator<NetworkEdge> {
  
          public int compare(NetworkEdge edgeA, NetworkEdge edgeB) {
              int result = Integer.compare(edgeA.getRouteCosts(), edgeB.getRouteCosts());
              if (result == 0)
                  result = edgeA.compareTo(edgeB); // otherwise use natural ordering
              return result;
          }
      }
  
  
      static class MergeResult {
          protected NetworkEdge newEdge;
          protected NetworkVertex removedVertex;
          MergeResult(NetworkEdge newEdge, NetworkVertex removedVertex) {
              this.newEdge = newEdge;
              this.removedVertex = removedVertex;
          }
      }
  
      public static MergeResult mergeEdges(NetworkEdge edgeA, NetworkEdge edgeB) {
          log.info("Merge of edge {} and edge {}", edgeA.toFullInfoString(), edgeB.toFullInfoString());
  
          NetworkVertex sourceA = edgeA.getSource();
          NetworkVertex targetA = edgeA.getTarget();
          NetworkVertex sourceB = edgeB.getSource();
          NetworkVertex targetB = edgeB.getTarget();
  
          NetworkVertex newSource, newTarget, vertex = null;
  
          boolean reverseA = false, reverseB = false;
          if (sourceA == sourceB) {
              newSource = targetA;
              newTarget = targetB;
              vertex = sourceA;
              reverseA = true;
          } else if (sourceA == targetB) {
              newSource = targetA;
              newTarget = sourceB;
              vertex = sourceA;
              reverseA = true;
              reverseB = true;
          } else if (targetA == sourceB) {
              newSource = sourceA;
              newTarget = targetB;
              vertex = targetA;
          } else if (targetA == targetB) {
              newSource = sourceA;
              newTarget = sourceB;
              vertex = targetA;
              reverseB = true;
          } else {
              return null;
          }
  
          log.info("Merge newSource = {} newTarget = {} remove vertex = {}", newSource, newTarget, vertex);
  
          // define new edge
          int distance = edgeA.getDistance() + edgeB.getDistance();
  
          // create new hiddenVertexes
          List<NetworkVertex> hiddenVertexes = new ArrayList<NetworkVertex>();
          List<NetworkVertex> hiddenA = edgeA.getHiddenVertices();
          if (reverseA) {
              hiddenA = new ArrayList<NetworkVertex>(hiddenA); // clone
              Collections.reverse(hiddenA);
          }
          List<NetworkVertex> hiddenB = edgeB.getHiddenVertices();
          if (reverseB) {
              hiddenB = new ArrayList<NetworkVertex>(hiddenB); // clone
              Collections.reverse(hiddenB);
          }
          hiddenVertexes.addAll(hiddenA);
          hiddenVertexes.add(vertex);
          hiddenVertexes.addAll(hiddenB);
          NetworkEdge newEdge =
              new NetworkEdge(newSource, newTarget, true, distance, hiddenVertexes);
          log.info("New edge = {}", newEdge.toFullInfoString());
  
          // returns newEdge
          return new MergeResult(newEdge, vertex);
      }
  
      public static boolean mergeEdgesInGraph(Graph<NetworkVertex, NetworkEdge> graph,
              NetworkEdge edgeA, NetworkEdge edgeB) {
  
          // use generic merge function
  