private void TwoEdgedThickening(Node node, float thickness)
        {
            var newBlockNodes = GetTwoEdgedThickenedNodes(node, thickness);
            var blockNode1    = newBlockNodes[0];
            var blockNode2    = newBlockNodes[1];

            blockNode1.Edges.Add(node.Edges[0]);
            blockNode1.Edges.Add(node.Edges[1]);
            blockNode2.Edges.Add(node.Edges[0]);
            blockNode2.Edges.Add(node.Edges[1]);

            node.BlockNodes.Add(blockNode1);
            node.BlockNodes.Add(blockNode2);

            BlockNodes.Add(blockNode1);
            BlockNodes.Add(blockNode2);
        }
        /**
         * THICKENER FUNCTIONS
         */

        private void OneEdgedThickening(Node node, float thickness)
        {
            //this only work for nodes, which has only one edge
            if (node.Edges.Count != 1)
            {
                throw new ArgumentException("Parameter node doesn't have exactly one edges", nameof(node));
            }

            //Calculate
            float dirRadian;

            if (node.Edges[0].NodeA == node)
            {
                dirRadian = node.Edges[0].DirRadianFromA;
            }
            else
            {
                dirRadian = node.Edges[0].DirRadianFromB;
            }

            Vector2 leftForward = new Vector2(
                Mathf.Cos(dirRadian + 1.5f * Mathf.PI / 2) * thickness * 1f / Mathf.Sin(Mathf.PI / 4),
                Mathf.Sin(dirRadian + 1.5f * Mathf.PI / 2) * thickness * 1f / Mathf.Sin(Mathf.PI / 4));
            Vector2 rightForward = new Vector2(
                Mathf.Cos(dirRadian - 1.5f * Mathf.PI / 2) * thickness * 1f / Mathf.Sin(Mathf.PI / 4),
                Mathf.Sin(dirRadian - 1.5f * Mathf.PI / 2) * thickness * 1f / Mathf.Sin(Mathf.PI / 4));


            //Then store it
            BlockNode blockNode1 = new BlockNode(node.X + leftForward.x, node.Y + leftForward.y);
            BlockNode blockNode2 = new BlockNode(node.X + rightForward.x, node.Y + rightForward.y);

            blockNode1.Edges.Add(node.Edges[0]);
            blockNode2.Edges.Add(node.Edges[0]);

            node.BlockNodes.Add(blockNode1);
            node.BlockNodes.Add(blockNode2);

            BlockNodes.Add(blockNode1);
            BlockNodes.Add(blockNode2);
        }
        private void FourEdgedThickening(Node node, float thickness)
        {
            //this only work for nodes, which has four edges
            if (node.Edges.Count != 4)
            {
                throw new ArgumentException("Parameter node doesn't have exactly four edges", nameof(node));
            }

            bool majorWithMinor = false;

            //FIRST CALCULATE
            Edge edge1 = node.Edges[0];
            Edge edge2 = node.Edges[1];
            Edge edge3 = node.Edges[2];
            Edge edge4 = node.Edges[3];

            if (!(
                    graph.MajorEdges.Contains(edge1) &&
                    graph.MajorEdges.Contains(edge2) &&
                    graph.MajorEdges.Contains(edge3) &&
                    graph.MajorEdges.Contains(edge4)) &&
                !(
                    graph.MinorEdges.Contains(edge1) &&
                    graph.MinorEdges.Contains(edge2) &&
                    graph.MinorEdges.Contains(edge3) &&
                    graph.MinorEdges.Contains(edge4)))
            {
                majorWithMinor = true;
            }


            //radians from node
            float radian1 = edge1.NodeA == node ? edge1.DirRadianFromA : edge1.DirRadianFromB;
            float radian2 = edge2.NodeA == node ? edge2.DirRadianFromA : edge2.DirRadianFromB;
            float radian3 = edge3.NodeA == node ? edge3.DirRadianFromA : edge3.DirRadianFromB;
            float radian4 = edge4.NodeA == node ? edge4.DirRadianFromA : edge4.DirRadianFromB;

            List <float> radians = new List <float> {
                radian1, radian2, radian3, radian4
            };
            List <Edge> edges = new List <Edge> {
                edge1, edge2, edge3, edge4
            };
            List <Edge> sortedEdges = new List <Edge>();

            for (int i = radians.Count - 1; i > -1; i--)  //Get the edges sorted by their radians
            {
                float smallest = radians.Min();
                int   idx      = radians.IndexOf(smallest);
                sortedEdges.Add(edges[idx]);

                edges.RemoveAt(idx);
                radians.RemoveAt(idx);
            }

            //After sorting, we can determine the role of every edge
            Edge baseEdge1   = sortedEdges[0];
            Edge baseEdge2   = sortedEdges[2];
            Edge commonEdge1 = sortedEdges[1];
            Edge commonEdge2 = sortedEdges[3];

            float averageRadBase1Common1 = AverageRadianFromTwoEdges(baseEdge1, commonEdge1, node);
            float averageRadBase1Common2 = AverageRadianFromTwoEdges(baseEdge1, commonEdge2, node);
            float averageRadBase2Common1 = AverageRadianFromTwoEdges(baseEdge2, commonEdge1, node);
            float averageRadBase2Common2 = AverageRadianFromTwoEdges(baseEdge2, commonEdge2, node);

            if (!CorrectFourEdgedAverage(
                    averageRadBase1Common1, baseEdge1, baseEdge2, commonEdge2, node))
            {
                averageRadBase1Common1 += Mathf.PI;
            }
            if (!CorrectFourEdgedAverage(
                    averageRadBase1Common2, baseEdge1, baseEdge2, commonEdge1, node))
            {
                averageRadBase1Common2 += Mathf.PI;
            }
            if (!CorrectFourEdgedAverage(
                    averageRadBase2Common1, baseEdge2, baseEdge1, commonEdge2, node))
            {
                averageRadBase2Common1 += Mathf.PI;
            }
            if (!CorrectFourEdgedAverage(
                    averageRadBase2Common2, baseEdge2, baseEdge1, commonEdge1, node))
            {
                averageRadBase2Common2 += Mathf.PI;
            }

            //4 final vectors to use for thickening
            Vector2 vecB1C1;
            Vector2 vecB1C2;
            Vector2 vecB2C1;
            Vector2 vecB2C2;

            float radianDiffB1C1 = RadianDifferenceFromTwoEdges(baseEdge1, commonEdge1, node);
            float radianDiffB1C2 = RadianDifferenceFromTwoEdges(baseEdge1, commonEdge2, node);
            float radianDiffB2C1 = RadianDifferenceFromTwoEdges(baseEdge2, commonEdge1, node);
            float radianDiffB2C2 = RadianDifferenceFromTwoEdges(baseEdge2, commonEdge2, node);

            //If one of the crossing is a Major-Minor crossing, make the vectors in a different way:
            if ((graph.MajorEdges.Contains(baseEdge1) && graph.MinorEdges.Contains(commonEdge1)) ||
                (graph.MajorEdges.Contains(commonEdge1) && graph.MinorEdges.Contains(baseEdge1)))
            {
                vecB1C1 = MajorMinorCrossingThickening(baseEdge1, commonEdge1, node, radianDiffB1C1);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(baseEdge1) && graph.MinorEdges.Contains(commonEdge1))
                {
                    vecB1C1 = new Vector2(
                        Mathf.Cos(averageRadBase1Common1) * thickness / 2 * (1f / Mathf.Sin(radianDiffB1C1 / 2)),
                        Mathf.Sin(averageRadBase1Common1) * thickness / 2 * (1f / Mathf.Sin(radianDiffB1C1 / 2)));
                }
                else
                {
                    vecB1C1 = new Vector2(
                        Mathf.Cos(averageRadBase1Common1) * thickness * (1f / Mathf.Sin(radianDiffB1C1 / 2)),
                        Mathf.Sin(averageRadBase1Common1) * thickness * (1f / Mathf.Sin(radianDiffB1C1 / 2)));
                }
            }

            if ((graph.MajorEdges.Contains(baseEdge1) && graph.MinorEdges.Contains(commonEdge2)) ||
                (graph.MajorEdges.Contains(commonEdge2) && graph.MinorEdges.Contains(baseEdge1)))
            {
                vecB1C2 = MajorMinorCrossingThickening(baseEdge1, commonEdge2, node, radianDiffB1C2);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(baseEdge1) && graph.MinorEdges.Contains(commonEdge2))
                {
                    vecB1C2 = new Vector2(
                        Mathf.Cos(averageRadBase1Common2) * thickness / 2 * (1f / Mathf.Sin(radianDiffB1C2 / 2)),
                        Mathf.Sin(averageRadBase1Common2) * thickness / 2 * (1f / Mathf.Sin(radianDiffB1C2 / 2)));
                }
                else
                {
                    vecB1C2 = new Vector2(
                        Mathf.Cos(averageRadBase1Common2) * thickness * (1f / Mathf.Sin(radianDiffB1C2 / 2)),
                        Mathf.Sin(averageRadBase1Common2) * thickness * (1f / Mathf.Sin(radianDiffB1C2 / 2)));
                }
            }

            if ((graph.MajorEdges.Contains(baseEdge2) && graph.MinorEdges.Contains(commonEdge1)) ||
                (graph.MajorEdges.Contains(commonEdge1) && graph.MinorEdges.Contains(baseEdge2)))
            {
                vecB2C1 = MajorMinorCrossingThickening(baseEdge2, commonEdge1, node, radianDiffB2C1);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(baseEdge2) && graph.MinorEdges.Contains(commonEdge1))
                {
                    vecB2C1 = new Vector2(
                        Mathf.Cos(averageRadBase2Common1) * thickness / 2 * (1f / Mathf.Sin(radianDiffB2C1 / 2)),
                        Mathf.Sin(averageRadBase2Common1) * thickness / 2 * (1f / Mathf.Sin(radianDiffB2C1 / 2)));
                }
                else
                {
                    vecB2C1 = new Vector2(
                        Mathf.Cos(averageRadBase2Common1) * thickness * (1f / Mathf.Sin(radianDiffB2C1 / 2)),
                        Mathf.Sin(averageRadBase2Common1) * thickness * (1f / Mathf.Sin(radianDiffB2C1 / 2)));
                }
            }

            if ((graph.MajorEdges.Contains(baseEdge2) && graph.MinorEdges.Contains(commonEdge2)) ||
                (graph.MajorEdges.Contains(commonEdge2) && graph.MinorEdges.Contains(baseEdge2)))
            {
                vecB2C2 = MajorMinorCrossingThickening(baseEdge2, commonEdge2, node, radianDiffB2C2);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(baseEdge2) && graph.MinorEdges.Contains(commonEdge2))
                {
                    vecB2C2 = new Vector2(
                        Mathf.Cos(averageRadBase2Common2) * thickness / 2 * (1f / Mathf.Sin(radianDiffB2C2 / 2)),
                        Mathf.Sin(averageRadBase2Common2) * thickness / 2 * (1f / Mathf.Sin(radianDiffB2C2 / 2)));
                }
                else
                {
                    vecB2C2 = new Vector2(
                        Mathf.Cos(averageRadBase2Common2) * thickness * (1f / Mathf.Sin(radianDiffB2C2 / 2)),
                        Mathf.Sin(averageRadBase2Common2) * thickness * (1f / Mathf.Sin(radianDiffB2C2 / 2)));
                }
            }

            //THEN STORE IT
            BlockNode blockNodeB1C1 = new BlockNode(node.X + vecB1C1.x, node.Y + vecB1C1.y);
            BlockNode blockNodeB1C2 = new BlockNode(node.X + vecB1C2.x, node.Y + vecB1C2.y);
            BlockNode blockNodeB2C1 = new BlockNode(node.X + vecB2C1.x, node.Y + vecB2C1.y);
            BlockNode blockNodeB2C2 = new BlockNode(node.X + vecB2C2.x, node.Y + vecB2C2.y);

            blockNodeB1C1.Edges.Add(baseEdge1);
            blockNodeB1C1.Edges.Add(commonEdge1);
            blockNodeB1C2.Edges.Add(baseEdge1);
            blockNodeB1C2.Edges.Add(commonEdge2);
            blockNodeB2C1.Edges.Add(baseEdge2);
            blockNodeB2C1.Edges.Add(commonEdge1);
            blockNodeB2C2.Edges.Add(baseEdge2);
            blockNodeB2C2.Edges.Add(commonEdge2);

            node.BlockNodes.Add(blockNodeB1C1);
            node.BlockNodes.Add(blockNodeB1C2);
            node.BlockNodes.Add(blockNodeB2C1);
            node.BlockNodes.Add(blockNodeB2C2);

            BlockNodes.Add(blockNodeB1C1);
            BlockNodes.Add(blockNodeB1C2);
            BlockNodes.Add(blockNodeB2C1);
            BlockNodes.Add(blockNodeB2C2);
        }
        private void ThreeEdgedThickening(Node node, float thickness)
        {
            //this only work for nodes, which has three edges
            if (node.Edges.Count != 3)
            {
                throw new ArgumentException("Parameter node doesn't have exactly three edges", nameof(node));
            }

            bool majorWithMinor = false;

            //First Calculate
            Edge edge1 = node.Edges[0];
            Edge edge2 = node.Edges[1];
            Edge edge3 = node.Edges[2];

            if (!(
                    graph.MajorEdges.Contains(edge1) &&
                    graph.MajorEdges.Contains(edge2) &&
                    graph.MajorEdges.Contains(edge3)) &&
                !(
                    graph.MinorEdges.Contains(edge1) &&
                    graph.MinorEdges.Contains(edge2) &&
                    graph.MinorEdges.Contains(edge3)))
            {
                majorWithMinor = true;
            }

            float averageRad12 = AverageRadianFromTwoEdges(edge1, edge2, node);
            float averageRad13 = AverageRadianFromTwoEdges(edge1, edge3, node);
            float averageRad23 = AverageRadianFromTwoEdges(edge2, edge3, node);

            float radianDiff12 = RadianDifferenceFromTwoEdges(edge1, edge2, node);
            float radianDiff13 = RadianDifferenceFromTwoEdges(edge1, edge3, node);
            float radianDiff23 = RadianDifferenceFromTwoEdges(edge2, edge3, node);

            if (radianDiff12 > Mathf.PI / 2 && !CorrectThreeEdgedAverage(averageRad12, edge3, node))
            {
                averageRad12 += Mathf.PI;
            }

            if (radianDiff13 > Mathf.PI / 2 && !CorrectThreeEdgedAverage(averageRad13, edge2, node))
            {
                averageRad13 += Mathf.PI;
            }

            if (radianDiff23 > Mathf.PI / 2 && !CorrectThreeEdgedAverage(averageRad23, edge1, node))
            {
                averageRad23 += Mathf.PI;
            }

            Vector2 vec12;
            Vector2 vec13;
            Vector2 vec23;

            //If one of the crossing is a Major-Minor crossing, make the vectors in a different way.
            if ((graph.MajorEdges.Contains(edge1) && graph.MinorEdges.Contains(edge2)) ||
                (graph.MajorEdges.Contains(edge2) && graph.MinorEdges.Contains(edge1)))
            {
                vec12 = MajorMinorCrossingThickening(edge1, edge2, node, radianDiff12);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(edge1) && graph.MinorEdges.Contains(edge2))
                {
                    vec12 = new Vector2(
                        Mathf.Cos(averageRad12) * thickness / 2 * (1f / Mathf.Sin(radianDiff12 / 2)),
                        Mathf.Sin(averageRad12) * thickness / 2 * (1f / Mathf.Sin(radianDiff12 / 2)));
                }
                else
                {
                    vec12 = new Vector2(
                        Mathf.Cos(averageRad12) * thickness * (1f / Mathf.Sin(radianDiff12 / 2)),
                        Mathf.Sin(averageRad12) * thickness * (1f / Mathf.Sin(radianDiff12 / 2)));
                }
            }

            if ((graph.MajorEdges.Contains(edge1) && graph.MinorEdges.Contains(edge3)) ||
                (graph.MajorEdges.Contains(edge3) && graph.MinorEdges.Contains(edge1)))
            {
                vec13 = MajorMinorCrossingThickening(edge1, edge3, node, radianDiff13);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(edge1) && graph.MinorEdges.Contains(edge3))
                {
                    vec13 = new Vector2(
                        Mathf.Cos(averageRad13) * thickness / 2 * (1f / Mathf.Sin(radianDiff13 / 2)),
                        Mathf.Sin(averageRad13) * thickness / 2 * (1f / Mathf.Sin(radianDiff13 / 2)));
                }
                else
                {
                    vec13 = new Vector2(
                        Mathf.Cos(averageRad13) * thickness * (1f / Mathf.Sin(radianDiff13 / 2)),
                        Mathf.Sin(averageRad13) * thickness * (1f / Mathf.Sin(radianDiff13 / 2)));
                }
            }

            if ((graph.MajorEdges.Contains(edge2) && graph.MinorEdges.Contains(edge3)) ||
                (graph.MajorEdges.Contains(edge3) && graph.MinorEdges.Contains(edge2)))
            {
                vec23 = MajorMinorCrossingThickening(edge2, edge3, node, radianDiff23);
            }
            else
            {
                if (majorWithMinor && graph.MinorEdges.Contains(edge2) && graph.MinorEdges.Contains(edge3))
                {
                    vec23 = new Vector2(
                        Mathf.Cos(averageRad23) * thickness / 2 * (1f / Mathf.Sin(radianDiff23 / 2)),
                        Mathf.Sin(averageRad23) * thickness / 2 * (1f / Mathf.Sin(radianDiff23 / 2)));
                }
                else
                {
                    vec23 = new Vector2(
                        Mathf.Cos(averageRad23) * thickness * (1f / Mathf.Sin(radianDiff23 / 2)),
                        Mathf.Sin(averageRad23) * thickness * (1f / Mathf.Sin(radianDiff23 / 2)));
                }
            }

            //Then store it
            BlockNode blockNode12 = new BlockNode(node.X + vec12.x, node.Y + vec12.y);
            BlockNode blockNode13 = new BlockNode(node.X + vec13.x, node.Y + vec13.y);
            BlockNode blockNode23 = new BlockNode(node.X + vec23.x, node.Y + vec23.y);

            blockNode12.Edges.Add(edge1);
            blockNode12.Edges.Add(edge2);
            blockNode13.Edges.Add(edge1);
            blockNode13.Edges.Add(edge3);
            blockNode23.Edges.Add(edge2);
            blockNode23.Edges.Add(edge3);

            node.BlockNodes.Add(blockNode12);
            node.BlockNodes.Add(blockNode13);
            node.BlockNodes.Add(blockNode23);

            BlockNodes.Add(blockNode12);
            BlockNodes.Add(blockNode13);
            BlockNodes.Add(blockNode23);
        }