//takes edges and axis. check if edge exist, if exist add closest point to cell
        public void AddPortal(IEnumerable <EdgeAbstract> edges, Vector3 axis)
        {
            Vector2 axisV2 = new Vector2(axis.x, axis.z);
            Dictionary <Cell, Vector3> cellMountPoints = new Dictionary <Cell, Vector3>();

            foreach (var abstractEdge in edges)
            {
                CellContentData data = new CellContentData(abstractEdge);

                Vector3 intersection;
                SomeMath.ClosestToSegmentTopProjection(data.a, data.b, axisV2, true, out intersection);

                foreach (var cell in _cells)
                {
                    if (cell.Contains(data))
                    {
                        if (cellMountPoints.ContainsKey(cell))
                        {
                            if (SomeMath.SqrDistance(cellMountPoints[cell], axis) > SomeMath.SqrDistance(intersection, axis))
                            {
                                cellMountPoints[cell] = intersection;
                            }
                        }
                        else
                        {
                            cellMountPoints.Add(cell, intersection);
                        }
                    }
                }
            }

            Vector2 normalRaw;

            switch (cellMountPoints.Count)
            {
            case 0:
                return;

            case 1:
                normalRaw = ToV2((cellMountPoints.First().Value - axis)).normalized * -1;
                break;

            case 2:

                normalRaw = (
                    ToV2(cellMountPoints.First().Value - axis).normalized +
                    ToV2(cellMountPoints.Last().Value - axis).normalized).normalized * -1;
                break;

            default:
                normalRaw = Vector2.left;
                Dictionary <Cell, float> cellAngles = new Dictionary <Cell, float>();
                Cell first = cellMountPoints.First().Key;
                cellAngles.Add(first, 0f);

                Vector3 firstDirV3 = cellMountPoints.First().Value - axis;
                Vector2 firstDirV2 = ToV2(firstDirV3);

                foreach (var pair in cellMountPoints)
                {
                    if (pair.Key == first)
                    {
                        continue;
                    }

                    Vector2 curDir = new Vector2(pair.Value.x - axis.x, pair.Value.z - axis.z);
                    cellAngles.Add(pair.Key, Vector2.Angle(firstDirV2, curDir) * Mathf.Sign(SomeMath.V2Cross(firstDirV2, curDir)));
                }

                normalRaw = (
                    ToV2(cellMountPoints[cellAngles.Aggregate((l, r) => l.Value > r.Value ? l : r).Key] - axis).normalized +
                    ToV2(cellMountPoints[cellAngles.Aggregate((l, r) => l.Value < r.Value ? l : r).Key] - axis).normalized).normalized * -1;
                break;
            }

            portalBases.Add(new JumpPortalBase(cellMountPoints, axis, new Vector3(normalRaw.x, 0, normalRaw.y)));
        }
        private void DoFunnelIteration(Vector3 startV3, Vector3 endV3, List <CellContentGenericConnection> targetConnections)
        {
            List <CellContentData> gd = new List <CellContentData>();

            for (int i = 0; i < targetConnections.Count; i++)
            {
                gd.Add(targetConnections[i].cellData);
            }

            gd.Add(new CellContentData(endV3));
            gd.Add(new CellContentData(endV3));

            int     curCycleEnd = 0, curCycleStart = 0, curIterationGateCount = targetConnections.Count + 1;
            Vector2 left, right;

            for (int i = 0; i < maxIterations; i++)
            {
                if (curCycleEnd == curIterationGateCount)
                {
                    break;
                }

                Vector2 startV2 = funnelPath.lastV2;

                for (curCycleStart = curCycleEnd; curCycleStart < curIterationGateCount; curCycleStart++)
                {
                    if (gd[curCycleStart].leftV2 != startV2 & gd[curCycleStart].rightV2 != startV2)
                    {
                        break;
                    }
                }

                left  = gd[curCycleStart].leftV2;
                right = gd[curCycleStart].rightV2;
                Vector2 lowestLeftDir  = left - startV2;
                Vector2 lowestRightDir = right - startV2;
                float   lowestAngle    = Vector2.Angle(lowestLeftDir, lowestRightDir);

                #region gate iteration
                int     stuckLeft  = curCycleStart;
                int     stuckRight = curCycleStart;
                Vector3?endNode    = null;

                for (int curGate = curCycleStart; curGate < curIterationGateCount; curGate++)
                {
                    right = gd[curGate].rightV2;
                    left  = gd[curGate].leftV2;

                    Vector2 curLeftDir  = left - startV2;
                    Vector2 curRightDir = right - startV2;

                    if (SomeMath.V2Cross(lowestLeftDir, curRightDir) >= 0)
                    {
                        float currentAngle = Vector2.Angle(lowestLeftDir, curRightDir);

                        if (currentAngle < lowestAngle)
                        {
                            lowestRightDir = curRightDir;
                            lowestAngle    = currentAngle;
                            stuckRight     = curGate;
                        }
                    }
                    else
                    {
                        endNode     = gd[stuckLeft].leftV3;
                        curCycleEnd = stuckLeft;
                        break;
                    }

                    if (SomeMath.V2Cross(curLeftDir, lowestRightDir) >= 0)
                    {
                        float currentAngle = Vector2.Angle(curLeftDir, lowestRightDir);
                        if (currentAngle < lowestAngle)
                        {
                            lowestLeftDir = curLeftDir;
                            lowestAngle   = currentAngle;
                            stuckLeft     = curGate;
                        }
                    }
                    else
                    {
                        endNode     = gd[stuckRight].rightV3;
                        curCycleEnd = stuckRight;
                        break;
                    }
                }
                #endregion

                //flag to reach next point
                if (endNode.HasValue)
                {
                    if (curCycleStart != curCycleEnd) //move inside multiple cells
                    {
                        AddGate(curCycleStart, curCycleEnd, targetConnections, funnelPath.lastV3, endNode.Value);
                    }

                    funnelPath.AddMove(endNode.Value, (MoveState)(int)targetConnections[curCycleEnd].from.passability);
                }
            }

            if (curCycleEnd < gd.Count)
            {
                AddGate(curCycleEnd, targetConnections.Count, targetConnections, funnelPath.lastV3, endV3);
            }
        }
        /// <summary>
        /// return used edges,
        /// </summary>
        private void MakeCell(TriangulatorEdge target, bool aFirst, List <TriangulatorEdge>[] edgesDictionary, TriangulatorNode[] nodes, out List <int> cellNodes, out List <TriangulatorEdge> cellEdges)
        {
            cellNodes = new List <int>();
            cellEdges = new List <TriangulatorEdge>();
            cellEdges.Add(target);
            int startNode;

            if (aFirst)  //a are origin
            {
                startNode = target.a;
                cellNodes.Add(target.a);
                cellNodes.Add(target.b);
            }
            else
            {
                startNode = target.b;
                cellNodes.Add(target.b);
                cellNodes.Add(target.a);
            }

            int limit = 0;

            harhar++;

            while (true)
            {
                limit++;
                if (limit > 50)
                {
#if UNITY_EDITOR
                    if (Debuger_K.doDebug && Debuger_K.debugOnlyNavMesh == false)
                    {
                        for (int i = 0; i < cellNodes.Count - 1; i++)
                        {
                            Vector3 a1 = nodes[cellNodes[i]].positionV3 + (Vector3.up * 0.02f * i);
                            Vector3 a2 = nodes[cellNodes[i + 1]].positionV3 + (Vector3.up * 0.02f * i);

                            Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, a1, a2, Color.red);
                            //Debuger_K.AddTriangulatorDebugLabel(chunk, properties, SomeMath.MidPoint(a1, a2), i);
                        }
                    }
#endif
                    Debug.LogError("error while making cells " + harhar);
                    break;
                }

                int nodeMinus   = cellNodes[cellNodes.Count - 2];
                int nodeCurrent = cellNodes[cellNodes.Count - 1];
                int?nodePlus    = null;
                TriangulatorEdge?connectionPlus = null;

                Vector2 directionToMinus = (nodes[nodeMinus].positionV2 - nodes[nodeCurrent].positionV2).normalized;
                float   lowestAngle      = 180f;
                List <TriangulatorEdge> searchConnections = edgesDictionary[nodeCurrent];

                foreach (var connection in searchConnections)
                {
                    int potentialNodePlus = connection.GetOtherNode(nodeCurrent);

                    if (nodeMinus == potentialNodePlus)
                    {
                        continue;
                    }

                    Vector2 directionToPotentialPlus = (nodes[potentialNodePlus].positionV2 - nodes[nodeCurrent].positionV2).normalized;
                    float   cross        = SomeMath.V2Cross(directionToMinus, directionToPotentialPlus);
                    float   currentAngle = Vector2.Angle(directionToMinus, directionToPotentialPlus);

                    if (cross > 0f & currentAngle != 180)
                    {
                        continue;
                    }

                    if (currentAngle > lowestAngle)
                    {
                        continue;
                    }

                    connectionPlus = connection;
                    nodePlus       = potentialNodePlus;
                    lowestAngle    = currentAngle;
                }

                if (nodePlus == null)
                {
                    #region error
#if UNITY_EDITOR
                    if (Debuger_K.doDebug)
                    {
                        Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, nodes[cellNodes[0]].positionV3, nodes[cellNodes[0]].positionV3 + SmallV3(0.3f), Color.green);

                        for (int i = 0; i < cellNodes.Count - 1; i++)
                        {
                            Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, nodes[cellNodes[i]].positionV3 + SmallV3(0.1f), nodes[cellNodes[i + 1]].positionV3 + SmallV3(0.1f), Color.red);
                        }
                        for (int i = 0; i < cellNodes.Count - 1; i++)
                        {
                            Vector3 a1 = nodes[cellNodes[i]].positionV3 + SmallV3(0.02f * i);
                            Vector3 a2 = nodes[cellNodes[i + 1]].positionV3 + SmallV3(0.02f * i);
                            Debuger_K.AddTriangulatorDebugLine(pos.x, pos.z, properties, a1, a2, Color.red);
                        }

                        foreach (var connection in searchConnections)
                        {
                            int potentialNodePlus = connection.GetOtherNode(nodeCurrent);

                            if (nodeMinus == potentialNodePlus)
                            {
                                continue;
                            }

                            Vector2 directionToPotentialPlus = (nodes[potentialNodePlus].positionV2 - nodes[nodeCurrent].positionV2).normalized;

                            float cross = SomeMath.V2Cross(directionToMinus, directionToPotentialPlus);

                            Debuger_K.AddLabel(nodes[potentialNodePlus].positionV3, cross);
                            Debuger_K.AddLabel(nodes[nodeCurrent].positionV3, Vector2.Angle(directionToMinus, directionToPotentialPlus));
                            //Debuger_K.AddTriangulatorDebugLabel(chunk, properties, nodes[potentialNodePlus].positionV3, cross);
                            //Debuger_K.AddTriangulatorDebugLabel(chunk, properties, nodes[nodeCurrent].positionV3, Vector2.Angle(directionToMinus, directionToPotentialPlus));
                        }
                    }
#endif
                    #endregion
                    Debug.LogError("nodePlus == null");
                    break;
                }

                cellEdges.Add(connectionPlus.Value);

                if (nodePlus == startNode)
                {
                    break;
                }

                cellNodes.Add(nodePlus.Value);
            }
        }
        //public GraphTriangulator(GraphGenerator generator, NavMeshTemplateCreation template) {
        //    var volumes = generator.getVolumes;
        //    var nodes = generator.getNodes;

        //    //layer, hash
        //    Dictionary<int, Dictionary<int, List<NodeAbstract>>> dicNodes = new Dictionary<int, Dictionary<int, List<NodeAbstract>>>();
        //    Dictionary<int, Dictionary<int, List<EdgeAbstract>>> dicEdges = new Dictionary<int, Dictionary<int, List<EdgeAbstract>>>();
        //    Dictionary<int, Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>> dicValues = new Dictionary<int, Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>>();

        //    foreach (var volume in volumes) {
        //        dicNodes.Add(volume.id, new Dictionary<int, List<NodeAbstract>>());
        //        dicEdges.Add(volume.id, new Dictionary<int, List<EdgeAbstract>>());
        //        dicValues.Add(volume.id, new Dictionary<int, Dictionary<NodeAbstract, TriangulatorNodeData>>());

        //        //some hardcoded stuff
        //        foreach (var a in volume.containsAreas) {
        //            int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable);
        //            int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable);

        //            dicNodes[volume.id].Add(crouchHash, new List<NodeAbstract>());
        //            dicEdges[volume.id].Add(crouchHash, new List<EdgeAbstract>());
        //            dicValues[volume.id].Add(crouchHash, new Dictionary<NodeAbstract, TriangulatorNodeData>());

        //            dicNodes[volume.id].Add(walkHash, new List<NodeAbstract>());
        //            dicEdges[volume.id].Add(walkHash, new List<EdgeAbstract>());
        //            dicValues[volume.id].Add(walkHash, new Dictionary<NodeAbstract, TriangulatorNodeData>());
        //        }
        //    }

        //    foreach (var first in nodes) {
        //        foreach (var pair in first.getData) {
        //            int volume = pair.Key.x;
        //            int hash = pair.Key.y;

        //            dicNodes[volume][hash].Add(first);
        //            dicEdges[volume][hash].Add(first[volume, hash]);

        //            NodeTemp middle = first.GetNode(volume, hash);
        //            NodeTemp last = middle.GetNode(volume, hash);

        //            float cross = SomeMath.V2Cross(
        //                last.x - middle.x, last.z - middle.z,
        //                first.x - middle.x, first.z - middle.z);

        //            if (cross < 0) {
        //                Vector2 directionLast = new Vector2(last.x - middle.x, last.z - middle.z).normalized;
        //                Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized;
        //                dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1));
        //            }
        //            else
        //                dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero));
        //        }
        //    }

        //    foreach (var volume in volumes) {
        //        foreach (var a in volume.containsAreas) {
        //            int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable);
        //            data.Add(new TriangulatorDataSet(
        //                template,
        //                dicNodes[volume.id][crouchHash],
        //                dicEdges[volume.id][crouchHash],
        //                dicValues[volume.id][crouchHash],
        //                volume.id, a, Passability.Crouchable));


        //            int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable);
        //            data.Add(new TriangulatorDataSet(
        //                template,
        //                dicNodes[volume.id][walkHash],
        //                dicEdges[volume.id][walkHash],
        //                dicValues[volume.id][walkHash],
        //                volume.id, a, Passability.Walkable));
        //        }
        //    }

        //    //data.RemoveAll(x => x.nodes.Count == 0);
        //}

        public GraphTriangulator(GraphGeneratorNew generator, NavMeshTemplateCreation template)
        {
            int maxLayers = generator.volumeContainer.layersCount;

            //var volumes = generator.dataLayers;
            var nodes = generator.getNodes;

            //DataLayer[] dataLayers = generator.dataLayers;
            //int dataLayersLength = dataLayers.Length;

            profiler = template.profiler;



            //layer, hash
            Dictionary <int, List <NodeAbstract> >[] dicNodes = new Dictionary <int, List <NodeAbstract> > [maxLayers];
            Dictionary <int, List <EdgeAbstract> >[] dicEdges = new Dictionary <int, List <EdgeAbstract> > [maxLayers];
            Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >[] dicValues = new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > [maxLayers];

            for (int id = 0; id < maxLayers; id++)
            {
                dicNodes[id]  = new Dictionary <int, List <NodeAbstract> >();
                dicEdges[id]  = new Dictionary <int, List <EdgeAbstract> >();
                dicValues[id] = new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >();

                //DataLayer layer = dataLayers[id];

                //some hardcoded stuff
                //foreach (var hash in layer.allAreaHashes) {
                //    dicNodes[id].Add(hash, new List<NodeAbstract>());
                //    dicEdges[id].Add(hash, new List<EdgeAbstract>());
                //    dicValues[id].Add(hash, new Dictionary<NodeAbstract, TriangulatorNodeData>());
                //}
            }
            if (profiler != null)
            {
                profiler.AddLog("start preparing data in GraphTriangulator");
            }
            foreach (var first in nodes)
            {
                foreach (var pair in first.getData)
                {
                    int layer = pair.Key.x;
                    int hash  = pair.Key.y;

                    var curDicNodes  = dicNodes[layer];
                    var curDicEdges  = dicEdges[layer];
                    var curDicValues = dicValues[layer];


                    if (curDicNodes.ContainsKey(hash) == false)
                    {
                        curDicNodes.Add(hash, new List <NodeAbstract>());
                        curDicEdges.Add(hash, new List <EdgeAbstract>());
                        curDicValues.Add(hash, new Dictionary <NodeAbstract, TriangulatorNodeData>());
                    }

                    curDicNodes[hash].Add(first);
                    curDicEdges[hash].Add(first[layer, hash]);

                    NodeTemp middle = first.GetNode(layer, hash);
                    NodeTemp last   = middle.GetNode(layer, hash);

                    float cross = SomeMath.V2Cross(
                        last.x - middle.x, last.z - middle.z,
                        first.x - middle.x, first.z - middle.z);

                    if (cross < 0)
                    {
                        Vector2 directionLast  = new Vector2(last.x - middle.x, last.z - middle.z).normalized;
                        Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized;
                        curDicValues[hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1));
                    }
                    else
                    {
                        curDicValues[hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero));
                    }
                }
            }


            for (int id = 0; id < maxLayers; id++)
            {
                foreach (var hash in dicNodes[id].Keys)
                {
                    Area        area;
                    Passability pass;
                    template.hashData.GetAreaByHash((short)hash, out area, out pass);

                    data.Add(new TriangulatorDataSet(
                                 template,
                                 dicNodes[id][hash],
                                 dicEdges[id][hash],
                                 dicValues[id][hash],
                                 id, area, pass));
                }
            }
            if (profiler != null)
            {
                profiler.AddLog("end preparing data in GraphTriangulator");
            }
            //data.RemoveAll(x => x.nodes.Count == 0);
        }
Beispiel #5
0
        public void MakeConnections(NavMeshTemplateRecast template)
        {
            if (nodes.Length == 0)
            {
                return;
            }

            List <int>      nextIterationNodes = new List <int>();
            List <T2Helper> helpers            = new List <T2Helper>();

            //GenerateEdgeMap(10, template);
            CreateAngleVisibilityField();

            for (int curNodeIndex = 0; curNodeIndex < _nodes.Length; curNodeIndex++)
            {
                if (data[curNodeIndex].cross >= 0)
                {
                    continue;
                }

                var curVisible = visibilityField[curNodeIndex];

                for (int i = 0; i < curVisible.Length; i++)
                {
                    if (IsVisible(curNodeIndex, curVisible[i]))
                    {
                        AddEdge(curNodeIndex, curVisible[i], 0);
                        goto NEXT;
                    }
                }

                nextIterationNodes.Add(curNodeIndex);
                NEXT : { continue; }
            }

            foreach (var nodeIndex in nextIterationNodes)
            {
                Vector2 nodePos    = _nodes[nodeIndex].positionV2;
                Vector2 normal     = _data[nodeIndex].normal;
                float   validAngle = 180f - (_data[nodeIndex].angle * 0.5f);

                helpers.Clear();
                foreach (var targetNode in Array.FindAll(_nodes, x => Vector2.Angle(normal, x.positionV2 - nodePos) < validAngle))
                {
                    if (nodeIndex == targetNode.id)
                    {
                        continue;
                    }

                    Vector2 targetNodeDirection = (targetNode.positionV2 - nodePos).normalized;
                    helpers.Add(new T2Helper(targetNode.id, Vector2.Angle(normal, targetNodeDirection) * Mathf.Sign(SomeMath.V2Cross(normal, targetNodeDirection))));
                }

                helpers.Sort((x, y) => { return((int)Mathf.Sign(Math.Abs(x.angle) - Math.Abs(y.angle))); });

                //get first visible node on left
                for (int i = 0; i < helpers.Count; i++)
                {
                    if (helpers[i].angle < 0 && IsVisible(nodeIndex, helpers[i].node))
                    {
                        AddEdge(nodeIndex, helpers[i].node, 0);
                        break;
                    }
                }

                //get first visible node on right
                for (int i = 0; i < helpers.Count; i++)
                {
                    if (helpers[i].angle > 0 && IsVisible(nodeIndex, helpers[i].node))
                    {
                        AddEdge(nodeIndex, helpers[i].node, 0);
                        break;
                    }
                }
            }
        }
        XZPosInt pos;//for debug

        public GraphTriangulator(GraphGenerator generator, NavMeshTemplateRecast template)
        {
            var volumes = generator.getVolumes;
            var nodes   = generator.getNodes;

            //layer, hash
            Dictionary <int, Dictionary <int, List <NodeAbstract> > > dicNodes = new Dictionary <int, Dictionary <int, List <NodeAbstract> > >();
            Dictionary <int, Dictionary <int, List <EdgeAbstract> > > dicEdges = new Dictionary <int, Dictionary <int, List <EdgeAbstract> > >();
            Dictionary <int, Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > > dicValues = new Dictionary <int, Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> > >();

            foreach (var volume in volumes)
            {
                dicNodes.Add(volume.id, new Dictionary <int, List <NodeAbstract> >());
                dicEdges.Add(volume.id, new Dictionary <int, List <EdgeAbstract> >());
                dicValues.Add(volume.id, new Dictionary <int, Dictionary <NodeAbstract, TriangulatorNodeData> >());

                //some hardcoded stuff
                foreach (var a in volume.containsAreas)
                {
                    int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable);
                    int walkHash   = PathFinder.GetAreaHash(a, Passability.Walkable);

                    dicNodes[volume.id].Add(crouchHash, new List <NodeAbstract>());
                    dicEdges[volume.id].Add(crouchHash, new List <EdgeAbstract>());
                    dicValues[volume.id].Add(crouchHash, new Dictionary <NodeAbstract, TriangulatorNodeData>());

                    dicNodes[volume.id].Add(walkHash, new List <NodeAbstract>());
                    dicEdges[volume.id].Add(walkHash, new List <EdgeAbstract>());
                    dicValues[volume.id].Add(walkHash, new Dictionary <NodeAbstract, TriangulatorNodeData>());
                }
            }

            foreach (var first in nodes)
            {
                foreach (var pair in first.getData)
                {
                    int volume = pair.Key.x;
                    int hash   = pair.Key.y;

                    dicNodes[volume][hash].Add(first);
                    dicEdges[volume][hash].Add(first[volume, hash]);

                    NodeTemp middle = first.GetNode(volume, hash);
                    NodeTemp last   = middle.GetNode(volume, hash);

                    float cross = SomeMath.V2Cross(
                        last.x - middle.x, last.z - middle.z,
                        first.x - middle.x, first.z - middle.z);

                    if (cross < 0)
                    {
                        Vector2 directionLast  = new Vector2(last.x - middle.x, last.z - middle.z).normalized;
                        Vector2 directionFirst = new Vector2(first.x - middle.x, first.z - middle.z).normalized;
                        dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, Vector2.Angle(directionLast, directionFirst), (directionLast + directionFirst).normalized * -1));
                    }
                    else
                    {
                        dicValues[volume][hash].Add(middle, new TriangulatorNodeData(cross, 0, Vector2.zero));
                    }
                }
            }

            foreach (var volume in volumes)
            {
                foreach (var a in volume.containsAreas)
                {
                    int crouchHash = PathFinder.GetAreaHash(a, Passability.Crouchable);
                    data.Add(new TriangulatorDataSet(
                                 template,
                                 dicNodes[volume.id][crouchHash],
                                 dicEdges[volume.id][crouchHash],
                                 dicValues[volume.id][crouchHash],
                                 volume.id, a, Passability.Crouchable));


                    int walkHash = PathFinder.GetAreaHash(a, Passability.Walkable);
                    data.Add(new TriangulatorDataSet(
                                 template,
                                 dicNodes[volume.id][walkHash],
                                 dicEdges[volume.id][walkHash],
                                 dicValues[volume.id][walkHash],
                                 volume.id, a, Passability.Walkable));
                }
            }

            //data.RemoveAll(x => x.nodes.Count == 0);
        }