internal MultiEdgeRouter(List<Edge[]> multiEdgeGeoms, InteractiveEdgeRouter interactiveEdgeRouter, IEnumerable<ICurve> nodeBoundaryCurves, BundlingSettings bundlingSettings, Func<EdgeGeometry, List<Shape>> transparentShapeSetter) {
     multiEdgeGeometries = multiEdgeGeoms.Select(l => l.Select(e => e.EdgeGeometry).ToArray()).ToList();
     
     this.interactiveEdgeRouter = interactiveEdgeRouter;
     this.bundlingSettings = bundlingSettings;
     this.transparentShapeSetter = transparentShapeSetter;
     nodeTree = RectangleNode<ICurve>.CreateRectangleNodeOnData(nodeBoundaryCurves, c => c.BoundingBox);
 }
        static void DrawEdgeWithPort(Edge edge, InteractiveEdgeRouter portRouter, double par0, double par1)
        {
            var port0 = new CurvePort(edge.Source.BoundaryCurve, par0);
            var port1 = new CurvePort(edge.Target.BoundaryCurve,par1);

            SmoothedPolyline sp;
            var spline = portRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(port0, port1, true, out sp);

            Arrowheads.TrimSplineAndCalculateArrowheads(edge.EdgeGeometry,
                                                         edge.Source.BoundaryCurve,
                                                         edge.Target.BoundaryCurve,
                                                         spline, true,
                                                         false);
        }
        static void DemoRoutingFromPortToPort(GeometryGraph graph)
        {
            var edges = graph.Edges.ToArray();
            SetCurvesToNull(edges);
            var portRouter = new InteractiveEdgeRouter(graph.Nodes.Select(n => n.BoundaryCurve), 3, 0.65*3, 0);
            portRouter.Run(); //calculates the whole visibility graph, takes a long time
            DrawEdgeWithPort(edges[0], portRouter, 0.3, 0.4);
            DrawEdgeWithPort(edges[1], portRouter, 0.7, 1.5*Math.PI);
                //I know here that my node boundary curves are ellipses so the parameters run from 0 to 2Pi
            //otherwise the curve parameter runs from curve.ParStart, to curve.ParEnd

            #if TEST
            LayoutAlgorithmSettings.ShowGraph(graph);
            #endif
        }
        private void Route()
        {
            //foreach (var edge in graph.Edges) {
            //    edge.EdgeGeometry.Curve = new LineSegment(edge.Source.Center, edge.Target.Center);
            //}
            //return;

            var edgeRouter = new InteractiveEdgeRouter(from v in AllLabels() select v.BoundaryCurve, this.locationRadius / 3, this.locationRadius/9, Math.PI/6);
            edgeRouter.Run();//it will calculate the visibility graph
            edgeRouter.GetVisibilityGraph();
            foreach (var edge in Edges()) {
                SmoothedPolyline sp;
                edge.EdgeGeometry.Curve =
                    edgeRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(new FloatingPort(edge.Source.BoundaryCurve, edge.Source.Center), new FloatingPort(null, edge.Target.Center), true, out sp);
                TrimAtSource(edge);
            }
        }
 /// <summary>
 /// prepares for edge dragging
 /// </summary>
 public void PrepareForEdgeDragging() {
     if(viewer.Graph == null)
         return;
     if(DraggingStraightLine())
         return;
     var settings = viewer.Graph.LayoutAlgorithmSettings;
     if(!RectRouting(settings.EdgeRoutingSettings.EdgeRoutingMode)) {
         if(InteractiveEdgeRouter == null) {
             var padding = settings.NodeSeparation / 3;
             var loosePadding = 0.65 * padding;
             InteractiveEdgeRouter = new InteractiveEdgeRouter(EnumerateNodeBoundaryCurves(),padding,
                                                               loosePadding,0);
         }
     }
 }
        void RouteEdgeGeometry(Edge edge, InteractiveEdgeRouter iRouter) {
            var edgeGeometry = edge.EdgeGeometry;

            var addedEdges = new List<VisibilityEdge>();
            if (!(edgeGeometry.SourcePort is HookUpAnywhereFromInsidePort))
                addedEdges.AddRange(AddVisibilityEdgesFromPort(edgeGeometry.SourcePort));
            if (!(edgeGeometry.TargetPort is HookUpAnywhereFromInsidePort))
                addedEdges.AddRange(AddVisibilityEdgesFromPort(edgeGeometry.TargetPort));
            SmoothedPolyline smoothedPolyline;
            if (!ApproximateComparer.Close(edgeGeometry.SourcePort.Location, edgeGeometry.TargetPort.Location))
                edgeGeometry.Curve = iRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(
                edgeGeometry.SourcePort, edgeGeometry.TargetPort, true, out smoothedPolyline);
            else {
                edgeGeometry.Curve = Edge.RouteSelfEdge(edgeGeometry.SourcePort.Curve, Math.Max(LoosePadding * 2, edgeGeometry.GetMaxArrowheadLength()), out smoothedPolyline);
            }
            edgeGeometry.SmoothedPolyline = smoothedPolyline;
            
            if (edgeGeometry.Curve == null)
                throw new NotImplementedException();
            
            
            foreach (var visibilityEdge in addedEdges)
                VisibilityGraph.RemoveEdge(visibilityEdge);
          
            Arrowheads.TrimSplineAndCalculateArrowheads(edgeGeometry, edgeGeometry.SourcePort.Curve,
                                                        edgeGeometry.TargetPort.Curve, edgeGeometry.Curve,
                                                        false, KeepOriginalSpline);
            if (ReplaceEdgeByRails != null)
                ReplaceEdgeByRails(edge);
            //  SetTransparency(transparentShapes, false);
        }
        InteractiveEdgeRouter CreateInteractiveEdgeRouter(IEnumerable<Shape> obstacleShapes) {
            //we need to create a set here because one loose polyline can hold several original shapes
            var loosePolys = new Set<Polyline>(obstacleShapes.Select(sh => shapesToTightLooseCouples[sh].LooseShape.BoundaryCurve as Polyline));
            var router = new InteractiveEdgeRouter {
                VisibilityGraph = visGraph,
                TightHierarchy =
                    CreateTightObstacleHierarachy(obstacleShapes),
                LooseHierarchy =
                    CreateLooseObstacleHierarachy(loosePolys),
                UseSpanner = true,
                LookForRoundedVertices = true,
                TightPadding = tightPadding,
                LoosePadding = LoosePadding,
                UseEdgeLengthMultiplier = UseEdgeLengthMultiplier,
                UsePolylineEndShortcutting = UsePolylineEndShortcutting,
                UseInnerPolylingShortcutting = UseInnerPolylingShortcutting,
                AllowedShootingStraightLines = AllowedShootingStraightLines,
                CacheCorners = CacheCornersForSmoothing,
            };

            router.AddActivePolygons(loosePolys.Select(polyline => new Polygon(polyline)));
            return router;
        }
 void RouteMultiEdges(List<Edge[]> multiEdges, InteractiveEdgeRouter interactiveEdgeRouter, Set<Shape> parents) {
     var mer = new MultiEdgeRouter(multiEdges, interactiveEdgeRouter, parents.SelectMany(p => p.Children).Select(s => s.BoundaryCurve), 
          new BundlingSettings { InkImportance = 0.00001, EdgeSeparation = MultiEdgesSeparation}, MakeTransparentShapesOfEdgeGeometryAndGetTheShapes);
     //giving more importance to ink might produce weird routings with huge detours, maybe 0 is the best value here
     mer.Run();
    
 }
        void ScaleDownLooseHierarchy(InteractiveEdgeRouter interactiveEdgeRouter, Set<Shape> obstacleShapes) {
            var loosePolys = new List<Polyline>();
            foreach (var obstacleShape in obstacleShapes) {
                var tl = shapesToTightLooseCouples[obstacleShape];
                loosePolys.Add( InteractiveObstacleCalculator.LoosePolylineWithFewCorners(tl.TightPolyline, tl.Distance / BundleRouter.SuperLoosePaddingCoefficient));
            }

            interactiveEdgeRouter.LooseHierarchy=CreateLooseObstacleHierarachy(loosePolys);
                
            interactiveEdgeRouter.ClearActivePolygons();

            interactiveEdgeRouter.AddActivePolygons(loosePolys.Select(polyline => new Polygon(polyline)));         
        }
 void RouteEdge(InteractiveEdgeRouter interactiveEdgeRouter, Edge edge) {
     var transparentShapes = MakeTransparentShapesOfEdgeGeometryAndGetTheShapes(edge.EdgeGeometry);
     ProgressStep();
     RouteEdgeGeometry(edge, interactiveEdgeRouter);
     SetTransparency(transparentShapes, false);
 }
        void RouteEdgesWithTheSamePassport(IGrouping<Set<Shape>, Edge> edgeGeometryGroup, InteractiveEdgeRouter interactiveEdgeRouter, Set<Shape> obstacleShapes) {
            List<Edge> regularEdges;
            List<Edge[]> multiEdges;

            if (RouteMultiEdgesAsBundles) {
                SplitOnRegularAndMultiedges(edgeGeometryGroup, out regularEdges, out multiEdges);
                foreach (var edge in regularEdges)
                    RouteEdge(interactiveEdgeRouter, edge);
                if (multiEdges != null) {
                    ScaleDownLooseHierarchy(interactiveEdgeRouter, obstacleShapes);
                    RouteMultiEdges(multiEdges, interactiveEdgeRouter, edgeGeometryGroup.Key);
                }
            }
            else
                foreach (var eg in edgeGeometryGroup)
                    RouteEdge(interactiveEdgeRouter, eg);
        }
 /// <summary>
 /// Executes the algorithm.
 /// </summary>
 protected override void RunInternal() {
     if (pairArray.Length > 0) {
         PositionLabelsOfFlatEdges();
         interactiveEdgeRouter = new InteractiveEdgeRouter(GetObstacles(), PaddingForEdges, PaddingForEdges/3, Math.PI/6);
         interactiveEdgeRouter.CalculateWholeTangentVisibilityGraph();
         foreach (IntEdge intEdge in IntEdges())
         {
             this.ProgressStep();
             RouteEdge(intEdge);
         }
     }
 }