private Duct createVAVConnection(Objects.Edge edge, ElementId ductType, ElementId system, IList <Objects.Node> nodes, IList <MEPCurve> curves, IList <FamilyInstance> vavs, IList <FamilyInstance> fittings)
        {
            Objects.Node n1 = nodes.Single(n => n.Id == edge.Node1);
            Objects.Node n2 = nodes.Single(n => n.Id == edge.Node2);

            Objects.Node vavNode = n1;
            if (n1.NodeType != Objects.Node.NodeTypeEnum.Vav)
            {
                vavNode = n2;
            }

            Objects.Node corrNode = n1;
            if (n1.NodeType != Objects.Node.NodeTypeEnum.Other)
            {
                corrNode = n2;
            }

            // find the nearest VAV to vavNode;

            // determine if we need to shift the connector on the corridor
            var fi = isFittingAtPoint(corrNode.Location, fittings, 0.1);

            MEPCurve toConnect = null;

            if (fi != null)
            {
                MEPController.MoveFittingAway(fi, edge.Diameter, out toConnect);
            }

            Duct d =
                MEPController.MakeDuct(_uiDoc.Document, vavNode.Location, corrNode.Location, ductType, system, edge.Diameter, 0.0);

            Connector tap = MEPController.GetNearestConnector(d, corrNode.Location);

            if (toConnect == null)
            {
                toConnect = findNearestCurve(corrNode.Location, curves, 0.05);
            }

            FamilyInstance fi2 = MEPController.MakeTakeOff(tap, toConnect);

            if (fi2 != null)
            {
                fittings.Add(fi2);
            }

            // connect to the Vav
            try
            {
                FamilyInstance fiVav = findNearest(vavs, vavNode.Location);

                Connector vavConn = MEPController.GetProperConnector(fiVav, FlowDirectionType.In, DuctSystemType.SupplyAir);
                Connector vavEnd  = MEPController.GetNearestConnector(d, vavNode.Location);

                MEPController.Connect(vavConn, vavEnd);
            }
            catch { }

            return(d);
        }
        public void DrawSolution(Objects.Solution sol, IList <Objects.Node> nodes, ElementId system, ElementId ductType)
        {
            Transaction t = null;

            if (_uiDoc.Document.IsModifiable == false)
            {
                t = new Transaction(_uiDoc.Document, "Create Ductwork");
                t.Start();
            }

            Utilities.AVFUtility.Clear(_uiDoc);


            // start with the corridor
            IList <Objects.Edge> corrEdges = sol.GetCorridorEdges(nodes);

            List <Duct>    corrDucts = new List <Duct>();
            List <Duct>    allDucts  = new List <Duct>();
            SubTransaction st        = new SubTransaction(_uiDoc.Document);

            st.Start();
            foreach (var edge in corrEdges)
            {
                Objects.Node n1 = nodes.Single(n => n.Id == edge.Node1);
                Objects.Node n2 = nodes.Single(n => n.Id == edge.Node2);

                Duct d =
                    MEPController.MakeDuct(_uiDoc.Document, n1.Location, n2.Location, ductType, system, edge.Diameter, 0.0);

                corrDucts.Add(d);
                allDucts.Add(d);
            }
            st.Commit();
            _uiDoc.Document.Regenerate();

            IList <FamilyInstance> fittings = MEPController.JoinDucts(corrDucts);

            IList <Objects.Edge> vavEdges = sol.GetVAVEdges(nodes);

            IList <MEPCurve> crvDucts = corrDucts.Cast <MEPCurve>().ToList();

            var vavInstances = GetAllVAVs();

            foreach (var edge in vavEdges)
            {
                //Objects.Node n1 = nodes.Single(n => n.Id == edge.Node1);
                //Objects.Node n2 = nodes.Single(n => n.Id == edge.Node2);

                //MEPController.MakeDuct(_uiDoc.Document, n1.Location, n2.Location, ductType, system, edge.Diameter, 0.0);

                Duct d = createVAVConnection(edge, ductType, system, nodes, crvDucts, vavInstances, fittings);
            }

            IList <Objects.Edge> shaftEdges = sol.GetShaftEdges(nodes);

            foreach (var edge in shaftEdges)
            {
                Objects.Node n1 = nodes.Single(n => n.Id == edge.Node1);
                Objects.Node n2 = nodes.Single(n => n.Id == edge.Node2);

                MEPController.MakeDuct(_uiDoc.Document, n1.Location, n2.Location, ductType, system, edge.Diameter, 0.0);
            }

            if (t != null)
            {
                t.Commit();
            }
        }
        public Objects.Network BuildNetwork(IList <Objects.Space> spaces, IList <FamilyInstance> VAVs, IList <FamilyInstance> shafts, IList <Line> corridorLines, bool biDirectional = false)
        {
            // here we want to start with a node for every VAV, linked to the appropriate space.
            // then project the VAV onto the corridor lines.
            // then build the edges...

            Objects.Network     network = new Objects.Network();
            List <Objects.Node> nodes   = new List <Objects.Node>();
            List <Objects.Edge> edges   = new List <Objects.Edge>();

            network.Edges  = edges;
            network.Nodes  = nodes;
            network.Spaces = spaces.ToList();



            _ductWorkElevation = (VAVs.First().Location as LocationPoint).Point.Z;
            corridorLines      = resetLines(corridorLines);


            // figure out the current phase.
            Phase phase = _uiDoc.Document.GetElement(_uiDoc.ActiveGraphicalView.get_Parameter(BuiltInParameter.VIEW_PHASE).AsElementId()) as Phase;

            foreach (var vav in VAVs)
            {
                XYZ       location = (vav.Location as LocationPoint).Point;
                Connector c        = MEPController.GetProperConnector(vav, FlowDirectionType.In, DuctSystemType.SupplyAir);
                if (c != null)
                {
                    location = c.Origin;
                }
                location = normalizeZ(location);

                Objects.Node n = new Objects.Node()
                {
                    Location = location, Name = "VAV-" + vav.Id.IntegerValue, NodeType = Objects.Node.NodeTypeEnum.Vav
                };


                // determine the related space.
                var relatedSpace = vav.get_Space(phase);
                if (relatedSpace != null)
                {
                    n.SpaceId = relatedSpace.UniqueId;
                }

                // while we are at it, get the connection point to the corridor
                XYZ connection = getClosest(location, corridorLines, true);

                // does this node already exist?
                Objects.Node connNode = lookupExisting(location, nodes);

                if (connNode == null)
                {
                    // make a new one.
                    connNode = new Objects.Node()
                    {
                        NodeType = Objects.Node.NodeTypeEnum.Other, Name = "Corridor", Location = connection
                    };
                    nodes.Add(connNode);
                }

                // adding this later.
                nodes.Add(n);

                // make an edge from VAV to corridor.
                Objects.Edge edge = new Objects.Edge()
                {
                    Node1 = n.Id, Node2 = connNode.Id, Distance = n.Location.DistanceTo(connNode.Location)
                };
                log("Made edge from " + n.Name + " to " + connNode.Name);
                edges.Add(edge);
            }

            // now let's do the same thing with the shaft.
            foreach (var shaft in shafts)
            {
                XYZ location = (shaft.Location as LocationPoint).Point;
                location = normalizeZ(location);

                // shaft name is based on the mark
                Parameter    mark = shaft.get_Parameter(BuiltInParameter.ALL_MODEL_MARK);
                string       name = (String.IsNullOrEmpty(mark.AsString()) ? shaft.Id.IntegerValue.ToString() : mark.AsString());
                Objects.Node n    = new Objects.Node()
                {
                    Location = location, Name = "Shaft-" + name, NodeType = Objects.Node.NodeTypeEnum.Shaft
                };


                // now we need to find where this connects to the

                //CURRENT SIMPLIFICATION: NO SHAFT WILL BE ON TOP OF A CENTERLINE.
                // COME BACK AND FIX THIS  LATER!

                XYZ connection = getClosest(location, corridorLines, true);

                Objects.Node connNode = lookupExisting(connection, nodes);
                if (connNode == null)
                {
                    // make a new node
                    connNode = new Objects.Node()
                    {
                        NodeType = Objects.Node.NodeTypeEnum.Other, Name = "Corridor-To-Shaft", Location = connection
                    };
                    nodes.Add(connNode);
                }
                // add this later.
                nodes.Add(n);

                // make an edge that connects
                Objects.Edge edge = new Objects.Edge()
                {
                    Node1 = connNode.Id, Node2 = n.Id, Distance = (connNode.Location.DistanceTo(n.Location))
                };
                log("Made edge from " + connNode.Name + " to " + n.Name);
                edges.Add(edge);
            }

            // see if we have any corridor line intersects/overlaps
            for (int i = 0; i < corridorLines.Count; i++)
            {
                for (int j = i + 1; j < corridorLines.Count; j++)
                {
                    log("Checking Corrdor Lines " + i + " vs. " + j);

                    IntersectionResultArray outInts = null;
                    var result = corridorLines[i].Intersect(corridorLines[j], out outInts);
                    log("  => result: " + result);
                    switch (result)
                    {
                    case SetComparisonResult.Overlap:
                        foreach (IntersectionResult res in outInts)
                        {
                            XYZ tmp = normalizeZ(res.XYZPoint);

                            Objects.Node n1 = lookupExisting(tmp, nodes);
                            if (n1 == null)
                            {
                                n1 = new Objects.Node()
                                {
                                    Location = res.XYZPoint, NodeType = Objects.Node.NodeTypeEnum.Other, Name = "CorridorOverlap"
                                };
                                nodes.Add(n1);
                            }
                        }
                        break;
                    }
                }
            }

            // then we need to connect the corridor nodes
            foreach (var cl in corridorLines)
            {
                // for each centerline, we want the endpoints of the centerline, and an ordered list of edges that cover it (including all of the midpoints from nodes).

                IList <Objects.Node> onLine = getNodesOnLine(cl, nodes);

                // see if we have to add the endpoints, or if they're already there.
                Objects.Node n1 = lookupExisting(cl.GetEndPoint(0), nodes);
                Objects.Node n2 = lookupExisting(cl.GetEndPoint(1), nodes);
                if (n1 == null)
                {
                    n1 = new Objects.Node()
                    {
                        Location = cl.GetEndPoint(0), NodeType = Objects.Node.NodeTypeEnum.Other, Name = "CorridorEnd"
                    };
                    onLine.Add(n1);
                    nodes.Add(n1);
                }
                if (n2 == null)
                {
                    n2 = new Objects.Node()
                    {
                        Location = cl.GetEndPoint(1), NodeType = Objects.Node.NodeTypeEnum.Other, Name = "CorridorEnd"
                    };
                    onLine.Add(n2);
                    nodes.Add(n2);
                }

                // now we want to sort these things based on the distance from n1.
                onLine = onLine.OrderBy(n => n.Location.DistanceTo(n1.Location)).ToList();

                // make edges between each thing.
                for (int i = 1; i < onLine.Count; i++)
                {
                    Objects.Edge corrEdge = new Objects.Edge()
                    {
                        Node1 = onLine[i - 1].Id, Node2 = onLine[i].Id, Distance = onLine[i - 1].Location.DistanceTo(onLine[i].Location)
                    };
                    log("Made corridor edge from " + onLine[i - 1].Name + " to " + onLine[i].Name);
                    edges.Add(corrEdge);

                    if (biDirectional)
                    {
                        Objects.Edge c2 = new Objects.Edge()
                        {
                            Node2 = onLine[i - 1].Id, Node1 = onLine[i].Id, Distance = onLine[i - 1].Location.DistanceTo(onLine[i].Location)
                        };
                        log("Made corridor edge from " + onLine[i].Name + " to " + onLine[i - 1].Name);
                        edges.Add(c2);
                    }
                }
            }



            return(network);
        }