问题
I try to find coordinate values with the same values. And I'm going to link three coordinate values.
I am doing this to make mesh at Unity.
I first found the same coordinates by bfs method.
And there is a problem trying to connect the three adjacent coordinates.
I did the following to find out if there are any adjacent points in eight directions.
private int[,] fx = new int[8, 2] { { -1, 0 }, { -1, 0 }, { 1, 0 }, { 1, 1 },
{ -1, 0 }, { -1, 0 }, { 0, 1 }, { 0, 1 } };
private int[,] fy = new int[8, 2] { { -1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 },
{ 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, 1 } };
void CreateTriangle()
{
int index = 0;
while (SegNode.Count > 0)
{
Node curNode = SegNode.Peek();
for (int i = 0; i < 8; i++)
{
Node nextNode = new Node(curNode.x + fx[i, 0], curNode.y + fy[i, 0], curNode.color);
Node nextNode2 = new Node(curNode.x + fx[i, 1], curNode.y + fy[i, 1], curNode.color);
Debug.Log("CurNode " + curNode.x + " , " + curNode.y +
" NextNode " + nextNode.x + " , " + nextNode.y +
" NextNode2 " + nextNode2.x + " , " + nextNode2.y);
if (SegNode.Contains(nextNode) && SegNode.Contains(nextNode2))
{
newTriangles.Add(SegNode.ToArray().ToList().IndexOf(curNode) + index);
newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode) + index);
newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode2) + index);
}
}
index++;
SegNode.Dequeue();
}
}
there is clearly a point about (0,1) (1,0), but I can't find it using Queue.Contains()
Maybe Contains() don't recognize it because I used [new] to create a new object. How can I find an object?
Here is my full code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class MeshCreator : MonoBehaviour
{
// This first list contains every vertex of the mesh that we are going to render
public List<Vector3> newVertices = new List<Vector3>();
// The triangles tell Unity how to build each section of the mesh joining
// the vertices
public List<int> newTriangles = new List<int>();
// The UV list is unimportant right now but it tells Unity how the texture is
// aligned on each polygon
public List<Vector2> newUV = new List<Vector2>();
// A mesh is made up of the vertices, triangles and UVs we are going to define,
// after we make them up we'll save them as this mesh
private Mesh mesh;
// Start is called before the first frame update
private int[,] pixel = new int[15, 15] {
{ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 2, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
private bool[,] visit = new bool[15, 15];
private int[] dx = new int[4] { 0, 1, -1, 0 };
private int[] dy = new int[4] { 1, 0, 0, -1 };
public int idx = 0;
public class Node
{
public int x, y, color;
public Node(int x, int y, int color)
{
this.x = x;
this.y = y;
this.color = color;
}
}
public Queue<Node> SegNode = new Queue<Node>();
void bfs(int r, int c, int color)
{
Queue<Node> q = new Queue<Node>();
q.Enqueue(new Node(r, c, color));
while (q.Count > 0)
{
Node curNode = q.Dequeue();
SegNode.Enqueue(curNode);
for (int i = 0; i < 4; i++)
{
int tr = curNode.x + dx[i];
int tc = curNode.y + dy[i];
if (tr >= 0 && tr < 15 && tc >= 0 && tc < 15)
{
if (!visit[tr, tc] && pixel[tr, tc] == color)
{
visit[tr, tc] = true;
q.Enqueue(new Node(tr, tc, color));
newVertices.Add(new Vector3(tr, tc, 0));
}
}
}
}
}
private int[,] fx = new int[8, 2] { { -1, 0 }, { -1, 0 }, { 1, 0 }, { 1, 1 },
{ -1, 0 }, { -1, 0 }, { 0, 1 }, { 0, 1 } };
private int[,] fy = new int[8, 2] { { -1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 },
{ 0, 1 }, { 1, 1 }, { 1, 0 }, { 1, 1 } };
void CreateTriangle()
{
int index = 0;
while (SegNode.Count > 0)
{
Node curNode = SegNode.Peek();
for (int i = 0; i < 8; i++)
{
Node nextNode = new Node(curNode.x + fx[i, 0], curNode.y + fy[i, 0], curNode.color);
Node nextNode2 = new Node(curNode.x + fx[i, 1], curNode.y + fy[i, 1], curNode.color);
Debug.Log("CurNode " + curNode.x + " , " + curNode.y +
" NextNode " + nextNode.x + " , " + nextNode.y +
" NextNode2 " + nextNode2.x + " , " + nextNode2.y);
if (SegNode.Contains(nextNode) && SegNode.Contains(nextNode2))
{
newTriangles.Add(SegNode.ToArray().ToList().IndexOf(curNode) + index);
newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode) + index);
newTriangles.Add(SegNode.ToArray().ToList().IndexOf(nextNode2) + index);
}
}
index++;
SegNode.Dequeue();
}
}
void Start()
{
//int result = 0;
for (int r = 0; r < 15; r++)
{
for (int c = 0; c < 15; c++)
{
if (!visit[r, c] && pixel[r, c] != 0)
{
newVertices.Add(new Vector3(r, c, 0));
bfs(r, c, pixel[r, c]);
//result++;
}
}
}
CreateTriangle();
mesh = GetComponent<MeshFilter>().mesh;
}
}
回答1:
classes are reference types. That means your SegNode queue doesn't actually contain values but references to instances of Node.
As you said already your Contains check doesn't work like that since you are checking if the same reference to the excatly same instance of Node exists in the queue.
You could simply make your Node a value type instead by changing it from a class to a struct
public struct Node
{
public int x, y, color;
public Node(int x, int y, int color)
{
this.x = x;
this.y = y;
this.color = color;
}
}
than your check
Node nextNode = new Node(curNode.x + fx[i, 0], curNode.y + fy[i, 0], curNode.color);
Node nextNode2 = new Node(curNode.x + fx[i, 1], curNode.y + fy[i, 1], curNode.color);
Debug.Log("CurNode " + curNode.x + " , " + curNode.y +
" NextNode " + nextNode.x + " , " + nextNode.y +
" NextNode2 " + nextNode2.x + " , " + nextNode2.y);
if (SegNode.Contains(nextNode) && SegNode.Contains(nextNode2))
{
//...
}
should work.
Alternatively you can use e.g. Linq FirstOrDefault like
var nextNode = SegNode.FirstOrDefault(n => n.x == curNode.x + fx[i, 0]
&& n.y == curNode.y + fy[i, 0]);
var nextNode2 = SegNode.FirstOrDefault(n => n.x == curNode.x + fx[i, 1]
&& n.y == curNode.y + fy[i, 1]);
if(nextNode != null && nextNode2 != null)
{
// ...
}
FirstOrDefaultreturns the first match defined by the predicate e.g.n.x == curNode.x + fx[i, 0] && n.y == curNode.y + fy[i, 0]or
nullif no matches are found or the list/queue is empty
as a broader alternative you could also let your Node implement IEquatable but that's maybe a bit overkill for your usecase ;)
来源:https://stackoverflow.com/questions/55095183/to-find-objects-of-the-same-value-using-queue-contains-in-c-unity