static IEnumerable<Edge> CreateEdgesForGroupRouting(IEnumerable<Cluster> clusters) {
            var c = GetClusterById(clusters, "c");
            var f = GetClusterById(clusters, "f");
            var a = c.Clusters.Single(s => s.UserData.Equals("a"));
            var b = c.Clusters.Single(s => s.UserData.Equals("b"));
            var d = f.Clusters.Single(s => s.UserData.Equals("d"));
            var e = f.Clusters.Single(s => s.UserData.Equals("e"));
            var h = GetClusterById(clusters, "h");
            var g = GetClusterById(clusters, "g");
            var l = GetClusterById(clusters, "l");
            var k = GetClusterById(clusters, "k");
            var ports = new Dictionary<Cluster, Set<Port>>();
            AddPortToShape(k, ports, new CurvePort(k.BoundaryCurve, 0.4*(k.BoundaryCurve.ParEnd + k.BoundaryCurve.ParStart)));
            AddPortToShape(l, ports);
            AddPortToShape(a, ports);
            AddPortToShape(b, ports);
            AddPortToShape(d, ports);
            AddPortToShape(e, ports);
            AddPortToShape(h, ports);
            AddPortToShape(g, ports);
            var hSecondPort = new CurvePort(h.BoundaryCurve, 0.1);

            ports[h].Insert(hSecondPort);
            var hFreePort = new FloatingPort(null, new Point(-129, -55));
            var kFreePort = new FloatingPort(null, new Point(137, -51));
            ports[h].Insert(hFreePort);
            ports[k].Insert(kFreePort);

            var fFreePort = new FloatingPort(null, new Point(3, 3));
            var kFreePort0 = new FloatingPort(null, new Point(106, 8));
            AddPortToShape(f,ports, fFreePort);
            AddPortToShape(k, ports, kFreePort0);

            AddPortToShape(c,ports,new CurvePort(c.BoundaryCurve, 0));
            AddPortToShape(f, ports,new FloatingPort(f.BoundaryCurve, f.BoundingBox.Center));
            var freePort0 = new FloatingPort(null, new Point(72, -1.3));

            var halfFreeEdge = new EdgeGeometry(freePort0, ports[a].First());
            var freePort1 = new FloatingPort(null, new Point(-122, 110));
            var freeEdge = new EdgeGeometry(freePort0, freePort1);
            var ab = new EdgeGeometry(ports[a].First(), ports[b].First());
            var abE = new Edge(a, b) {EdgeGeometry = ab};
            var ae = new EdgeGeometry(ports[a].First(), ports[e].First());
            var aeE = new Edge(a, e) {EdgeGeometry = ae};
            var de = new EdgeGeometry(ports[d].First(), ports[e].First());
            var deE = new Edge(d, e) {EdgeGeometry = de};
            var ad = new EdgeGeometry(ports[a].First(), ports[d].First());
            var adE = new Edge(a, d) {EdgeGeometry = ad};
            var he = new EdgeGeometry(ports[h].First(), ports[e].First());
            var heE = new Edge(h, e) {EdgeGeometry = he};
            var gd = new EdgeGeometry(ports[g].First(), ports[d].First());
            var gdE = new Edge(g, d) {EdgeGeometry = gd};
            var lg = new EdgeGeometry(ports[l].First(), ports[g].First());
            var lgE = new Edge(l, g) {EdgeGeometry = lg};
            var le = new EdgeGeometry(ports[l].First(), ports[e].First());
            var leE = new Edge(l, e) {EdgeGeometry = le};
            var ca = new EdgeGeometry(ports[c].First(), ports[a].First());
            var caE = new Edge(c, a) {EdgeGeometry = ca};
            var cd = new EdgeGeometry(ports[c].First(), ports[d].First());
            var cdE = new Edge(c, d) {EdgeGeometry = cd};
            var hl = new EdgeGeometry(hSecondPort, ports[l].First());
            var hlE = new Edge(h, l) {EdgeGeometry = hl};
            var lh = new EdgeGeometry(ports[l].First(), hSecondPort);
            var lhE = new Edge(l, h) {EdgeGeometry = lh};
            var ha = new EdgeGeometry(hSecondPort, ports[a].First());
            var haE = new Edge(h, a) {EdgeGeometry = ha};
            var hk = new EdgeGeometry(hSecondPort, ports[k].First());
            var hkE = new Edge(h, k) {EdgeGeometry = hk};

            var hk0 = new EdgeGeometry(hFreePort, kFreePort);
            var hk0E = new Edge(h, k) {EdgeGeometry = hk0};

            var fk = new EdgeGeometry(fFreePort, kFreePort0);
            var fkE = new Edge(f, k) {EdgeGeometry = fk};

            var hThirdPort = new CurvePort(h.BoundaryCurve, 0.5);
            var halfFreeInside = new EdgeGeometry(ports[b].First(), freePort1);
            //var halfFreeInside = new Edge(b, d) { EdgeGeometry = ad };

            ports[h].Insert(hThirdPort);
            var lSecondPort = new CurvePort(l.BoundaryCurve, 0);
            ports[l].Insert(lSecondPort);
            var hThirdLSecond = new EdgeGeometry(hThirdPort, lSecondPort);
            var hThirdLSecondE = new Edge(h, l) {EdgeGeometry = hThirdLSecond};
            //            return new[] {
            //                             /*halfFreeInside, freeEdge,*/ halfFreeEdge, lh
            //                         };
            return new[] {
                             lhE, abE, aeE, deE, adE, heE, gdE, lgE, leE, cdE, hlE,
                             hThirdLSecondE, caE, haE, hkE, hk0E, fkE
                         };
        }
        private void ReadPorts()
        {
            Match m;
            this.VerifyIsNextLine(RectFileStrings.BeginPorts);

            // Get to the first line for consistency with the lookahead for multiPort offsets and/or any
            // PortEntries, which will end up reading the following line.
            this.NextLine();

            for (;;)
            {
                if (!(m = ParseOrDone(RectFileStrings.ParsePort, RectFileStrings.EndPorts)).Success)
                {
                    break;
                }

                bool isMultiPort = IsString(m.Groups["type"].ToString(), RectFileStrings.Multi);
                bool isRelative = IsString(m.Groups["type"].ToString(), RectFileStrings.Relative);
                var x = double.Parse(m.Groups["X"].ToString());
                var y = double.Parse(m.Groups["Y"].ToString());
                var portId = int.Parse(m.Groups["portId"].ToString());
                var shapeId = int.Parse(m.Groups["shapeId"].ToString());
                Validate.IsFalse(idToPortMap.ContainsKey(portId), "PortId already exists");
                var location = new Point(x, y);
                Shape shape = GetShapeFromId(shapeId, isMultiPort || isRelative);
                Port port;
                if (isMultiPort)
                {
                    // 'location' was actually the active offset of the multiPort.  Recreate it and reset the
                    // closest-location and verify the active offset index is the same.  This may fail if there
                    // are two identical offsets in the offset list, in which case fix the test setup.
                    int activeOffsetIndex;
                    var offsets = ReadMultiPortOffsets(out activeOffsetIndex);
                    var multiPort = new MultiLocationFloatingPort(() => shape.BoundaryCurve, () => shape.BoundingBox.Center, offsets);
                    multiPort.SetClosestLocation(multiPort.CenterDelegate() + location);
                    Validate.AreEqual(multiPort.ActiveOffsetIndex, activeOffsetIndex, CurrentLineError("ActiveOffsetIndex is not as expected"));
                    port = multiPort;
                }
                else
                {
                    if (isRelative)
                    {
                        // The location in the ParsePort line is the offset for the relative port.
                        port = new RelativeFloatingPort(() => shape.BoundaryCurve, () => shape.BoundingBox.Center, location);
                    }
                    else
                    {
                        Validate.IsTrue(IsString(m.Groups["type"].ToString(), RectFileStrings.Floating), CurrentLineError("Unknown port type"));
                        port = new FloatingPort((null == shape) ? null : shape.BoundaryCurve, location);
                    }
                    this.NextLine();    // Since we didn't read multiPort offsets
                }
                idToPortMap.Add(portId, port);
                if (null != shape)
                {
                    if (!this.UseFreePortsForObstaclePorts)
                    {
                        shape.Ports.Insert(port);
                    }
                    else
                    {
                        FreeRelativePortToShapeMap[port] = shape;
                    }
                }
                ReadPortEntries(port);
            }
        }
 void RouteEdgeWithNoLabel(IntEdge intEdge) {
     Node sourceNode = routing.IntGraph.Nodes[intEdge.Source];
     Node targetNode = routing.IntGraph.Nodes[intEdge.Target];
     var sourcePort = new FloatingPort(sourceNode.BoundaryCurve, sourceNode.Center);
     var targetPort = new FloatingPort(targetNode.BoundaryCurve, targetNode.Center);
     var eg = intEdge.Edge.EdgeGeometry;
     SmoothedPolyline sp;
     eg.Curve = interactiveEdgeRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(sourcePort, targetPort, true, out sp);
     Arrowheads.TrimSplineAndCalculateArrowheads(eg,  intEdge.Edge.Source.BoundaryCurve,
                                                      intEdge.Edge.Target.BoundaryCurve, eg.Curve, false, 
                                                      settings.EdgeRoutingSettings.KeepOriginalSpline);
     intEdge.Edge.EdgeGeometry = eg;
 }
        void RouteEdgeWithLabel(IntEdge intEdge, Label label) {
            //we allow here for the edge to cross its own label
            Node sourceNode = routing.IntGraph.Nodes[intEdge.Source];
            Node targetNode = routing.IntGraph.Nodes[intEdge.Target];
            var sourcePort = new FloatingPort(sourceNode.BoundaryCurve, sourceNode.Center);
            var targetPort = new FloatingPort(targetNode.BoundaryCurve, targetNode.Center);
            ICurve labelObstacle = labelsToLabelObstacles[label];
            var labelPort = new FloatingPort(labelObstacle, label.Center);
            SmoothedPolyline poly0;
            interactiveEdgeRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(sourcePort, labelPort, true, out poly0);
            SmoothedPolyline poly1;
            interactiveEdgeRouter.RouteSplineFromPortToPortWhenTheWholeGraphIsReady(labelPort, targetPort, true, out poly1);
            Site site = poly1.HeadSite.Next;

            Site lastSite = poly0.LastSite;
            lastSite.Next = site;
            site.Previous = lastSite;
            var eg = intEdge.Edge.EdgeGeometry;
            eg.SetSmoothedPolylineAndCurve(poly0);
            Arrowheads.TrimSplineAndCalculateArrowheads(eg,  intEdge.Edge.Source.BoundaryCurve,
                                                             intEdge.Edge.Target.BoundaryCurve, eg.Curve, false, 
                                                             settings.EdgeRoutingSettings.KeepOriginalSpline);
        }
        //  int count;

        /// <summary>
        ///
        /// </summary>
        /// <param name="targetLocation"></param>
        /// <returns></returns>
        public EdgeGeometry RouteEdgeToLocation(Point targetLocation) {
            TargetPort = new FloatingPort((ICurve) null, targetLocation); //otherwise route edge to a port would be called
            TargetTightPolyline = null;
            TargetLoosePolyline = null;
            var edgeGeometry = new EdgeGeometry();

            var ls = new LineSegment(SourcePort.Location, targetLocation);

            if (LineCanBeAcceptedForRouting(ls)) {
                _polyline = new Polyline();
                _polyline.AddPoint(ls.Start);
                _polyline.AddPoint(ls.End);
                edgeGeometry.SmoothedPolyline = SmoothedPolyline.FromPoints(_polyline);
                edgeGeometry.Curve = edgeGeometry.SmoothedPolyline.CreateCurve();
                return edgeGeometry;
            }

            //can we do with just two line segments?
            if (SourcePort is CurvePort) {
                ls = new LineSegment(StartPointOfEdgeRouting, targetLocation);
                if (
                    IntersectionsOfLineAndRectangleNodeOverPolyline(ls, ObstacleCalculator.RootOfTightHierarchy).Count ==
                    0) {
                    _polyline = new Polyline();
                    _polyline.AddPoint(SourcePort.Location);
                    _polyline.AddPoint(ls.Start);
                    _polyline.AddPoint(ls.End);
                    //RelaxPolyline();
                    edgeGeometry.SmoothedPolyline = SmoothedPolyline.FromPoints(_polyline);
                    edgeGeometry.Curve = edgeGeometry.SmoothedPolyline.CreateCurve();
                    return edgeGeometry;
                }
            }

            ExtendVisibilityGraphToLocation(targetLocation);

            _polyline = GetShortestPolyline(SourceVisibilityVertex, TargetVisibilityVertex);

            RelaxPolyline();
            if (SourcePort is CurvePort)
                _polyline.PrependPoint(SourcePort.Location);

            edgeGeometry.SmoothedPolyline = SmoothedPolyline.FromPoints(_polyline);
            edgeGeometry.Curve = edgeGeometry.SmoothedPolyline.CreateCurve();
            return edgeGeometry;
        }
        protected FloatingPort MakeAbsoluteObstaclePort(Shape obstacle, Point location)
        {
            Validate.IsNotNull(obstacle, "Obstacle should not be null");

            // For absolute obstacle ports, we don't associate a shape if we are using freeports.
            // This gives test coverage of the case of a freeport/waypoint covered by an unrelated obstacle.
            if (this.UseFreePortsForObstaclePorts)
            {
                return new FloatingPort(null, location);
            }
            var port = new FloatingPort(obstacle.BoundaryCurve, location);
            obstacle.Ports.Insert(port);
            return port;
        }