internal static void Search(GridGraph graph, GridSearch search, int x, int y, float[,] weights, IComparer <GridEdge> comparer) { search.Clear(); int width = graph.Width; int height = graph.Height; search.IsVisited[x, y] = true; search.Order.Add(new Vector2i(x, y)); search.Parent[x, y] = new Vector2i(x, y); PriorityQueue <GridEdge> queue = new PriorityQueue <GridEdge>(comparer); List <GridEdge> edges = new List <GridEdge>(8); graph.GetEdges(x, y, edges, weights); if (edges.Count != 0) { foreach (GridEdge edge in edges) { queue.Push(edge); } edges.Clear(); } while (queue.Count != 0) { GridEdge edge = queue.Pop(); Vector2i v = edge.To; if (search.IsVisited[v.x, v.y]) { continue; } search.Order.Add(v); search.IsVisited[v.x, v.y] = true; search.Parent[v.x, v.y] = edge.From; if (graph.Edges[v.x, v.y] == 0) { continue; } graph.GetEdges(v.x, v.y, edges, weights); foreach (GridEdge e in edges) { if (search.IsVisited[e.To.x, e.To.y]) { continue; } queue.Push(e); } edges.Clear(); } }
public GridEdge <T, U> AddEdge(GridNode <T, U> from, GridNode <T, U> to, U data) { GridEdge <T, U> newEdge = new GridEdge <T, U>(from, to, data); from.Edges[newEdge.Direction] = newEdge; _edgeCount++; return(newEdge); }
//간선을 추가한다. public void AddEdge(GridEdge newEdge) { //목적지가 같은 Edge를 허용하지 않음. foreach (GridEdge gridEdge in edges) { if (gridEdge.EndVertexGrid == newEdge.EndVertexGrid) { throw new System.NotSupportedException(); } } edges.Add(newEdge); }
/// <summary> /// Adds the edge data to the cell at startXYZ + cornerOffsetXYZ if it exists (not out of range) /// return the cell so we can preprocess for meshing? /// </summary> public GridCell AddToCellQEF(GridEdge e, int sx, int sy, int sz, int cox, int coy, int coz) { int x = sx + cox; int y = sy + coy; int z = sz + coz; if (x >= 0 && x < subdivisions && y >= 0 && y < subdivisions && z >= 0 && z < subdivisions) { //it exists GridCell cell = cells[x, y, z]; cell.AddQEF(e.intersection, e.normal); return(cell); } else { //NOPE! Chuck Testa return(null); } }
public void JoiningEdge_NeighborNodes_Edge() { Vec2 position = new Vec2(3, 3); GridNode node = _grid[position]; IPathfindingEdge joiningEdge = node.JoiningEdge(_grid[position + Direction.N]); IPathfindingEdge edge = new GridEdge(position, Direction.N); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.W]); edge = new GridEdge(position, Direction.W); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.E]); edge = new GridEdge(new Vec2(position.x + 1, position.y), Direction.W); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.S]); edge = new GridEdge(new Vec2(position.x, position.y + 1), Direction.N); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.NW]); edge = new GridVertex(position); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.NE]); edge = new GridVertex(new Vec2(position.x + 1, position.y)); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.SW]); edge = new GridVertex(new Vec2(position.x, position.y + 1)); Assert.AreEqual(edge, joiningEdge); joiningEdge = node.JoiningEdge(_grid[position + Direction.SE]); edge = new GridVertex(new Vec2(position.x + 1, position.y + 1)); Assert.AreEqual(edge, joiningEdge); }
public virtual void Insert(Control item, Control existui, GridEdge at, int xspan, int yspan, int hexpand, HorizontalAlignment halign, int vexpand, VerticalAlignment valign) { NativeMethods.GridInsertAt(Owner.handle, item.handle, existui.handle, at, xspan, yspan, hexpand, halign, vexpand, valign); base.Insert(existui.Index, item); }
public static extern void GridInsertAt(IntPtr grid, IntPtr child, IntPtr existing, GridEdge at, int xspan, int yspan, int hexpand, HorizontalAlignment halign, int vexpand, VerticalAlignment valign);
public void IsTraversable_DoesNotContainMotility_False() { GridEdge edge = new GridEdge(1f, Motility.Land, Vec2.One, Direction.N); Assert.IsFalse(edge.IsTraversable(Motility.Burrow)); }
public void IsTraversable_ContainsMotility_True() { GridEdge edge = new GridEdge(1f, Motility.Land, Vec2.One, Direction.N); Assert.IsTrue(edge.IsTraversable(Motility.Land)); }
public void IsTraversable_UnconstrainedEdge_True() { GridEdge edge = new GridEdge(1f, Motility.Unconstrained, Vec2.One, Direction.N); Assert.IsTrue(edge.IsTraversable(Motility.Land)); }
public void Fill_SetEdge_Equals() { Vec2 vec2 = new Vec2(2, 2); PathfindingGrid grid = new PathfindingGrid(vec2); Assert.IsNull(grid[0, 0, Direction.N]); Assert.IsNull(grid[0, 0, Direction.W]); Assert.IsNull(grid[0, 0, Direction.E]); Assert.IsNull(grid[0, 0, Direction.S]); Assert.IsNull(grid[0, 1, Direction.N]); Assert.IsNull(grid[0, 1, Direction.W]); Assert.IsNull(grid[0, 1, Direction.E]); Assert.IsNull(grid[0, 1, Direction.S]); Assert.IsNull(grid[1, 0, Direction.N]); Assert.IsNull(grid[1, 0, Direction.W]); Assert.IsNull(grid[1, 0, Direction.E]); Assert.IsNull(grid[1, 0, Direction.S]); Assert.IsNull(grid[1, 1, Direction.N]); Assert.IsNull(grid[1, 1, Direction.W]); Assert.IsNull(grid[1, 1, Direction.E]); Assert.IsNull(grid[1, 1, Direction.S]); grid.Fill(position => new GridNode(Tiles.Stone, position, grid)); grid.FillEdges((position, annotation) => new GridEdge(position, annotation)); //grid.FillVertices((position) => new GridVertex(position)); Assert.IsNotNull(grid[0, 0, Direction.N]); Assert.IsNotNull(grid[0, 0, Direction.W]); Assert.IsNotNull(grid[0, 0, Direction.E]); Assert.IsNotNull(grid[0, 0, Direction.S]); Assert.IsNotNull(grid[0, 1, Direction.N]); Assert.IsNotNull(grid[0, 1, Direction.W]); Assert.IsNotNull(grid[0, 1, Direction.E]); Assert.IsNotNull(grid[0, 1, Direction.S]); Assert.IsNotNull(grid[1, 0, Direction.N]); Assert.IsNotNull(grid[1, 0, Direction.W]); Assert.IsNotNull(grid[1, 0, Direction.E]); Assert.IsNotNull(grid[1, 0, Direction.S]); Assert.IsNotNull(grid[1, 1, Direction.N]); Assert.IsNotNull(grid[1, 1, Direction.W]); Assert.IsNotNull(grid[1, 1, Direction.E]); Assert.IsNotNull(grid[1, 1, Direction.S]); Assert.AreEqual(new GridEdge(Vec2.Zero, Direction.N), grid[0, 0, Direction.N]); Assert.AreEqual(new GridEdge(Vec2.Zero, Direction.W), grid[0, 0, Direction.W]); Assert.AreEqual(new GridEdge(new Vec2(1, 0), Direction.W), grid[0, 0, Direction.E]); Assert.AreEqual(new GridEdge(new Vec2(0, 1), Direction.N), grid[0, 0, Direction.S]); Assert.AreEqual(new GridEdge(new Vec2(0, 1), Direction.N), grid[0, 1, Direction.N]); Assert.AreEqual(new GridEdge(new Vec2(0, 1), Direction.W), grid[0, 1, Direction.W]); Assert.AreEqual(new GridEdge(new Vec2(1, 1), Direction.W), grid[0, 1, Direction.E]); var expected = new GridEdge(new Vec2(0, 2), Direction.N); var actual = grid[0, 1, Direction.S]; Assert.AreEqual(new GridEdge(new Vec2(0, 2), Direction.N), grid[0, 1, Direction.S]); Assert.AreEqual(new GridEdge(new Vec2(1, 0), Direction.N), grid[1, 0, Direction.N]); Assert.AreEqual(new GridEdge(new Vec2(1, 0), Direction.W), grid[1, 0, Direction.W]); Assert.AreEqual(new GridEdge(new Vec2(2, 0), Direction.W), grid[1, 0, Direction.E]); Assert.AreEqual(new GridEdge(new Vec2(1, 1), Direction.N), grid[1, 0, Direction.S]); Assert.AreEqual(new GridEdge(new Vec2(1, 1), Direction.N), grid[1, 1, Direction.N]); Assert.AreEqual(new GridEdge(new Vec2(1, 1), Direction.W), grid[1, 1, Direction.W]); Assert.AreEqual(new GridEdge(new Vec2(2, 1), Direction.W), grid[1, 1, Direction.E]); Assert.AreEqual(new GridEdge(new Vec2(1, 2), Direction.N), grid[1, 1, Direction.S]); }
protected PathEdge MakePathEdge(GridEdge edge) { return(new PathEdge(edge.StartLoc, edge.EndLoc)); }
//caxo - corner A x offset //cbyo - corner B y offset, etc //should be faster to just use ints instead of passing in vec3's, might be negligicable, but isn't too much more compliated /// <summary> /// Checks the edge created beteween the two points xyz+ cornerAXYZoffset and xyz + cornerBXYZoffset for a sign change between the densities of the corners /// if there is a sign change the edge is added to a list and the neighbouring cells that share this edge have the edge added to their QEF solver /// </summary> public void CheckEdge(int x, int y, int z, int caxo, int cayo, int cazo, int cbxo, int cbyo, int cbzo) { GridCorner cA = corners[x + caxo, y + cayo, z + cazo]; GridCorner cB = corners[x + cbxo, y + cbyo, z + cbzo]; List <GridCell> facesTemp = new List <GridCell>(); if (cA.density * cB.density <= 0f) //different sign { GridEdge e = new GridEdge(cA.position, cB.position); int intersectionSteps = 8; if (subdivisionLevel == 1) { intersectionSteps = 16; } e.intersection = ApproximateEdgeIntersection(cA.position, cB.position, Density, intersectionSteps); e.normal = CalculateSurfaceNormal(e.intersection, Density); //e.intersection = e.normal = Vector3.zero; edges.Add(e); #region swapping and comments //need to find every cell that shares this edge so we can do QEF solve stuff per cell //get start corner indicies, sorted by smallest corner first //then find the direction we're going on (offset from start to end) //then just manually find neighbours #region swapping logic //swap so they're ordred properly //could do this in the density block only when we need to bool swap = false; if (x + caxo < x + cbxo) { //good } else if (x + caxo == x + cbxo) //same check next { if (y + cayo < y + cbyo) { //good } else if (y + cayo == y + cbyo) //same, check next { if (z + cazo < z + cbzo) { //good } else if (z + cazo == z + cbzo) { //same...all components were the same.. This should never happen } else { swap = true; } } else { swap = true; } } else { swap = true; } #endregion int sx; int sy; int sz; int dx; int dy; int dz; if (swap) { sx = x + cbxo; sy = y + cbyo; sz = z + cbzo; dx = (caxo - cbxo); dy = (cayo - cbyo); dz = (cazo - cbzo); } else { sx = x + caxo; sy = y + cayo; sz = z + cazo; dx = (cbxo - caxo); dy = (cbyo - cayo); dz = (cbzo - cazo); } #endregion //we should have six directions if (dx == 1 && dy == 0 && dz == 0) { //cells offsets [0,0,0] [0,0,-1] [0,-1,-1] [0,-1,0] //check each offset to see if it exists (and doesn't cause an out of range error) //if it exists add to the QEF and solve and stuff facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, 0, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, 0, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, -1, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, -1, 0)); } else if (dx == -1 && dy == 0 && dz == 0) { //this case will never happen, because we sort on x first so that the direction is always+. //If x *was* to be -, we would have swapped corners //but lets just fill it in anyways //cells offsets [-1,0,0] [-1,0,-1] [-1,-1,-1] [-1,-1,0] facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, 0, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, 0, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, -1, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, -1, 0)); } else if (dx == 0 && dy == 1 && dz == 0) { //cell offsets [0,0,-1] [0,0,0] [-1,0,0] [-1,0,-1] facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, 0, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, 0, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, 0, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, 0, -1)); } else if (dx == 0 && dy == -1 && dz == 0) { //cell offsets [0,-1,0] [0,-1,-1] [-1,-1,-1] [-1,-1,0] facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, -1, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, -1, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, -1, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, -1, -1)); } else if (dx == 0 && dy == 0 && dz == 1) { //cell offsets [0,0,0] [0,-1,0] [-1,-1,0] [-1,0,0] facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, 0, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, -1, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, -1, 0)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, 0, 0)); } else if (dx == 0 && dy == 0 && dz == -1) { //cell offsets [0,0,-1] [0,-1,-1] [-1,-1,-1] [-1,0,-1] facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, 0, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, 0, -1, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, -1, -1)); facesTemp.Add(AddToCellQEF(e, sx, sy, sz, -1, 0, -1)); } if (facesTemp.Count == 4) { facesTemp.Sort(); //need to sort the faces so we don't get any duplicates //and then we need to check to make sure the faces list doesn't contain this face GridCell ft0 = facesTemp[0]; //Debug.Log(ft0 == null); //Debug.Log(ft0.cellIndex == null); Vector3 index = new Vector3(ft0.cellIndex.x, ft0.cellIndex.y, ft0.cellIndex.z); List <GridFace> fl = null; if (faces.ContainsKey(index)) { fl = faces[index]; } //we need to check every element in FL to make sure we don't already have this face if (fl == null) { //cant check because this face doesn't have a spot in the list yet //so we can just add it because it doesn't exist, so this will be the first one fl = new List <GridFace>(); GridFace f = new GridFace(); f.faces.Add(facesTemp[0]); f.faces.Add(facesTemp[1]); f.faces.Add(facesTemp[2]); f.faces.Add(facesTemp[3]); fl.Add(f); faces[index] = fl; } else { if (fl.Count == 0) { //cant check. For some reason the list was created, but never added to //add because it doesn't exist yet GridFace f = new GridFace(); f.faces.Add(facesTemp[0]); f.faces.Add(facesTemp[1]); f.faces.Add(facesTemp[2]); f.faces.Add(facesTemp[3]); fl.Add(f); } else { for (int i = 0; i < fl.Count; i++) { //we can skip checking facesTemp[0].cellIndex against fl[0][0] because we know they're the same //because that's how we sort the main list anyways if (fl[i].faces[1] == facesTemp[1]) { //second cell is the same if (fl[i].faces[2] == facesTemp[2]) { //third cell is the same if (fl[i].faces[3] == facesTemp[3]) { //last cell is the same... all match, so we don't want to add this faceTemp to the real list //because it will be a duplicate } else { //diff GridFace f = new GridFace(); f.faces.Add(facesTemp[0]); f.faces.Add(facesTemp[1]); f.faces.Add(facesTemp[2]); f.faces.Add(facesTemp[3]); fl.Add(f); break; } } else { //diff GridFace f = new GridFace(); f.faces.Add(facesTemp[0]); f.faces.Add(facesTemp[1]); f.faces.Add(facesTemp[2]); f.faces.Add(facesTemp[3]); fl.Add(f); break; } } else { //diff GridFace f = new GridFace(); f.faces.Add(facesTemp[0]); f.faces.Add(facesTemp[1]); f.faces.Add(facesTemp[2]); f.faces.Add(facesTemp[3]); fl.Add(f); break; } } } } } } }
public GridCell(Vector3 center, float gridScale = 1f) { QefSolver qef = new QefSolver(); //check each corner against the density function //and generate SOMETHING at that position to see if our density function is right //we can cache the results from each corner, as we need to check every one anyways //is there a smarter way //we can have up to 4 sign changes per cell.. // 0 ---- 1 // | | // 1------0 <---- opposite for the top face = 4 total //get corner positions //take the center (int coords), convert them to world positions, then +/- on every axis this.gridScale = gridScale; worldPos = center * gridScale; //need to do corners in the same order every time //assign the corners to their density value at that corner position for (int i = 0; i < 8; i++) { float v = DualContouring1.density(worldPos + DualContouring1.cornerOffsets[i] * 0.5f * gridScale); //thresholding here to turn the density into an ID corners[i] = v >= 0 ? 1 : 0; } //check if any edges have sign changes //I guess only store the edges that are important, like the ones that have a sign change. //we need to check every corner against it's neighbour cells, so we need to know which ones are it's neighbours. //Each corner has three neighbours, for (int i = 0; i < 4; i++) //but we only want to check half of them, otherwise we have doubles? { for (int j = 0; j < 3; j++) { int neighbour = cornerNeighbours[i, j]; if (corners[i] != corners[neighbour]) //if this corner has a different density value than any of it's neighbours //we need to be able to find neighbours based on edges... //not sure how //make a naive implimentation first { GridEdge e = new GridEdge(i, neighbour, center); edges.Add(e); DualContouring1.edges.Add(e); Vector3 edgeCornerA = worldPos + DualContouring1.cornerOffsets[e.corners[0]] * 0.5f * gridScale; Vector3 edgeCornerB = worldPos + DualContouring1.cornerOffsets[e.corners[1]] * 0.5f * gridScale; //need these for meshing to find shared edges I guess e.cornersOffset[0] = DualContouring1.cornerOffsets[e.corners[0]]; e.cornersOffset[1] = DualContouring1.cornerOffsets[e.corners[1]]; //computing the intersection position and normal of this edge against the density function e.position = DualContouring1.ApproximateEdgeIntersection(edgeCornerA, edgeCornerB, DualContouring1.density); e.normal = DualContouring1.CalculateSurfaceNormal(e.position, DualContouring1.density); //from here we have to get the actual position of the vertex for this cell //we do this using the QefSolver. For every edge intersection add the position and normal qef.add(e.position, e.normal); //add the normal so we can grab it later (summed, so we have to grab normal/edges.Count normal += e.normal; Debug.Log("1"); } } } if (edges.Count != 0) { vertex = Vector3.zero; qef.solve(vertex, QEF_ERROR, QEF_SWEEPS, QEF_ERROR); Vector3 min = center + DualContouring1.cornerOffsets[0] * 0.5f * gridScale; Vector3 max = center + DualContouring1.cornerOffsets[6] * 0.5f * gridScale; if (vertex.x < min.x || vertex.x > max.x || vertex.y < min.y || vertex.y > max.y || vertex.z < min.z || vertex.z > max.z) { vertex = qef.getMassPoint(); } DualContouring1.verticies.Add(new MeshVertex(vertex, (normal / edges.Count).normalized)); vertexIndex = DualContouring1.verticies.Count - 1; if (vertex == Vector3.zero) { Debug.Log("Zero"); } Debug.Log("2"); hasVertex = true; } }