//This function checks the orientation of a BlockNode compared to and edge private int Orientation(Edge baseEdge, BlockNode testNode) { //Orientation can be calculated with the cross product of two Vectors made from the 3 Nodes float val = (baseEdge.NodeA.Y - testNode.Y) * (baseEdge.NodeB.X - testNode.X) - (baseEdge.NodeA.X - testNode.X) * (baseEdge.NodeB.Y - testNode.Y); if (val > 0.00001f) { return(1); //clockwise } if (val < -0.00001f) { return(-1); //anticlockwise } else { Debug.Log("BlockNode Collinear to it's Edge"); return(0); //collinear, shouldn't really happen with BlockNodes that uses this edge } }
/** * 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); }
public bool Equals(BlockNode otherNode) { return(Math.Abs(X - otherNode.X) < 0.0001f && Math.Abs(Y - otherNode.Y) < 0.0001f); }
/** * BLOCK FORMING */ //Recursive function, which forms a new Block from a starting BlockNode. Returns true if forming finished. Returns false if forming failed. private bool FormBlock(BlockNode node, Edge edgeToSearch, Block blockToBuild, int iteration) { if (blockToBuild.Nodes.Contains(node)) { return(true); //We got around } if (node.Block != null) { return(false); //Node already has a Block } if (iteration > 100) { return(false); //Recursive function iteration is too high } blockToBuild.Nodes.Add(node); //First add current node to the Block node.Block = blockToBuild; Node nextNode = edgeToSearch.NodeA.BlockNodes.Contains(node) ? edgeToSearch.NodeB : edgeToSearch.NodeA; //Special case: One edged node if (node.Edges.Count == 1) { Node currentNode = edgeToSearch.NodeA.BlockNodes.Contains(node) ? edgeToSearch.NodeA : edgeToSearch.NodeB; BlockNode otherBlockNode = currentNode.BlockNodes[0] == node ? currentNode.BlockNodes[1] : currentNode.BlockNodes[0]; if (!blockToBuild.Nodes.Contains(otherBlockNode)) { if (FormBlock(otherBlockNode, edgeToSearch, blockToBuild, iteration + 1)) //If it's the first blockNode, go for 2nd node, if it's the second, operate normally { return(true); } else { return(false); } } } //Check which is the next blockNode BlockNode nextBlockNode = null; int currentBlockOrientationToEdge = Orientation(edgeToSearch, node); foreach (BlockNode blockNode in nextNode.BlockNodes) { if (blockNode.Edges.Contains(edgeToSearch)) { if (Orientation(edgeToSearch, blockNode) == currentBlockOrientationToEdge) { nextBlockNode = blockNode; } } } if (nextBlockNode == null) //Next BlockNode not found, forming failed { return(false); } Edge nextEdgeToSearch; if (nextBlockNode.Edges.Count == 1) //Special case: One edged node { nextEdgeToSearch = edgeToSearch; } else { nextEdgeToSearch = nextBlockNode.Edges[0] == edgeToSearch ? nextBlockNode.Edges[1] : nextBlockNode.Edges[0]; } //Recursive call to the next node if (FormBlock(nextBlockNode, nextEdgeToSearch, blockToBuild, iteration + 1)) { return(true); } else { return(false); } }
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); }