Finding cycle in 2 dimensional array - c#

Hi i want to find cycles in 2 dimensional(nxm) array. i have n.m-1 filled cell in my array and i want to find cycle starting empty cell, continues in filled cells an finish in empty cell.
For example we have this array;
our first cycle is [0,0],[0,3],[2,3],[2,0]
second cycle is [0,1],[0,3],[2,3],[2,2],[3,2],[3,1]
How can i find find all cycles in this array.
Thanks.

I think I have an algorithm that will do what you need.
The first step is finding all the starting points (which is easy enough), initialise a path with the point you're at, and then attempt to follow a route either left, right, up or down from that point.
public void start() {
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
if (array[y][x] == 0) {
int pos[] = {x,y};
path = new ArrayList<int[]>();
path.add(pos);
startx = x;
starty = y;
follow(x, y, 1, 0);
follow(x, y, -1, 0);
follow(x, y, 0, 1);
follow(x, y, 0, -1);
}
}
}
}
Once you start following a route in a particular direction, if you've reached your start point again, you've found a cycle, so you can't output the path you took to get there and abandon any further search along this route.
If you find a non-empty cell, you need to add your current position to your path history, and then attempt to recursively follow another route at right angles to the direction you are on. So if you're going left or right, you now try only up or down, and vice versa.
If your route takes you past an edge without finding either your start point or a non-empty cell, you obviously can go no further.
private void follow(int x, int y, int dx, int dy) {
x += dx;
y += dy;
while (x >= 0 && x < w && y >= 0 && y < h) {
if (x == startx && y == starty) {
for (int[] pos : path) {
System.out.printf("[%d,%d] ",pos[1], pos[0]);
}
System.out.printf("\n");
break;
}
if (array[y][x] != 0) {
int pos[] = {x,y};
path.add(pos);
if (dx != 0) {
follow(x, y, 0, 1);
follow(x, y, 0, -1);
}
else {
follow(x, y, 1, 0);
follow(x, y, -1, 0);
}
path.remove(path.size()-1);
}
x += dx;
y += dy;
}
}
Here's a full working example on ideone
I've noticed a couple of issues with this algorithm that may not be ideal for you depending on your requirements.
You actually get two versions of each path - one following a clockwise route and the other obviously counter-clockwise.
Some of the paths cross over their own route. For example, something like a figure of eight pattern. I don't know whether that is something you would be accept as a valid cycle or not.

Related

why is my marching cubes algorithm so slow?

i have somewhat implemented marching cubes in unity/c# (you dont need to know unity to help me though) and i cant stop feeling like i have made a big mistake in my code because it is so slow. i am already running it on a separate thread but it just takes ages to complete. please help me optimize my code.
private void _UpdateChunk()
{
lock (this)
{
// clear the tri, vert and uv lists
ClearMeshData();
// Loop through each "cube" in the terrain.
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
for (int z = 0; z < width; z++)
{
// Create an array of floats representing each corner of a cube and get the value from our terrainMap.
float[] cube = new float[8];
float[] strengths = new float[8];
for (int i = 0; i < 8; i++)
{
Vector3Int corner = new Vector3Int(x, y, z) + gamedata.CornerTable[i];
cube[i] = terrainMap[corner.x, corner.y, corner.z].BlockType;
strengths[i] = terrainMap[corner.x, corner.y, corner.z].Strength;
}
// Pass the value into the MarchCube function.
MarchCube(new Vector3(x, y, z), cube, strengths);
}
}
}
}
}
void MarchCube(Vector3 position, float[] cube, float[] strengths)
{
// Get the configuration index of this cube.
int configIndex = GetCubeConfiguration(cube);
// If the configuration of this cube is 0 or 255 (completely inside the terrain or completely outside of it) we don't need to do anything.
if (configIndex == 0 || configIndex == 255)
return;
// Loop through the triangles. There are never more than 5 triangles to a cube and only three vertices to a triangle.
int edgeIndex = 0;
Vector3 vert1 = new Vector3();
Vector3 vert2 = new Vector3();
float vert1sample = 0;
float vert2sample = 0;
float lerp = 0;
int indice = 0;
for (int i = 0; i < 5; i++)
{
for (int p = 0; p < 3; p++)
{
// Get the current indice. We increment triangleIndex through each loop.
indice = gamedata.TriangleTable[configIndex, edgeIndex];
// If the current edgeIndex is -1, there are no more indices and we can exit the function.
if (indice == -1)
return;
// Get the vertices for the start and end of this edge.
vert1 = position + gamedata.EdgeTable[indice, 0];
vert2 = position + gamedata.EdgeTable[indice, 1];
vert1sample = strengths[gamedata.EdgeIndexTable[indice, 0]];
vert2sample = strengths[gamedata.EdgeIndexTable[indice, 1]];
// Get the midpoint of this edge.
lerp = Mathf.Abs(vert1sample) / (Mathf.Abs(vert2sample) + Mathf.Abs(vert1sample));
Vector3 vertPosition = Vector3.Lerp(vert1, vert2, lerp);
// Add to our vertices and triangles list and incremement the edgeIndex.
vertices.Add(vertPosition);
triangles.Add(vertices.Count - 1);
if (getChunkVoxel(vert1 + chunkPosition) != 0)
{
uvs.Add(new Vector2(getChunkVoxel(vert1 + chunkPosition) - 1, 0));
}
else
{
uvs.Add(new Vector2(getChunkVoxel(vert2 + chunkPosition) - 1, getChunkVoxel(vert2 + chunkPosition) - 1));
}
edgeIndex++;
}
}
}
int GetCubeConfiguration(float[] cube)
{
// Starting with a configuration of zero, loop through each point in the cube and check if it is below the terrain surface.
int configurationIndex = 0;
for (int i = 0; i < 8; i++)
{
// If it is, use bit-magic to the set the corresponding bit to 1. So if only the 3rd point in the cube was below
// the surface, the bit would look like 00100000, which represents the integer value 32.
if (cube[i] < terrainSurface)
configurationIndex |= 1 << i;
}
return configurationIndex;
}
it appears that this is the part that slows my game down, help would be appreciated
i already made it faster by changing terrainpoint from a class to a struct but it is still very slow.
One main reason it is slow is that there is a lot of allocations in the loop putting a lot of pressure on the garbadge collector. There is currently 11 allocation per "cube" in the terrain in _UpdateChunk and up to 17 in MarchCube (possibly even more if the expressions like position + gamedata.EdgeTable[indice, 0] allocates a new vector). This is not reasonable. Many allocation are not needed. For example cube and strengths can be preallocated once for all the cubes in the beginning of _UpdateChunk. You do not need to allocate the vector in the expression to compute corner: you can just compute the components separately manually (or you can possibly preallocate the vector and reset its component when needed). The same thing applies for the new Vector3(x, y, z) can can be preallocated and set in the loop. Such an algorithm is computationally intensive so you should get away any overhead like virtual method calls and allocations/GC -- only low-level arrays accesses and mathematical operations should remains.
Note that some computations can be optimized. For example GetCubeConfiguration can be modified so to be branchless. Mathf.Abs(vert1sample) can be precomputed so not to compute it twice (though the compiler may already do that). I am also wondering if the expression like vertices.Add are efficient but this is dependent of the type of container which is not provided here.

Mapping PerlinNoise to a Grid

I am trying to generate a grid across my map and add nodes depending on the perlin noise value. Depending on the value obtained from the perlin noise at a location, I will add a new Node which will be of a certain type e.g. Mountain, Water etc to represent terrian. Here I am trying to make it so that if the value is > 0.5, this mean it's only mountains and so a black coloured cubes should surround the mountain areas, However, my black cubes do not match the mountain areas from the perlin noise and I cannot seem to figure out why I am going wrong. Would appreciate any insight into how I could go about achieving this.
private void LocateWalkableCells()
{
for(int z = 0; z < Height; z++)
{
for(int x = 0; x < Width; x++)
{
noise = GetNoiseValue(x, z);
if(noise > 0.5) {
grid[x,z] = new Node(new Vector3(x, 0, z), TerrainType.Mountain, 1);
}
else {
grid[x,z] = new Node(new Vector3(x, 0, z), TerrainType.Grass, 1);
}
}
}
}
private float GetNoiseValue(int x, int z)
{
int pos = (x * Width) + z;
return Mathf.Round(terrainGenerator.noiseArray[pos] * 10) / 10;
}
// Draw gizmos to visualize colour
void OnDrawGizmos()
{
Gizmos.DrawWireCube(transform.position, new Vector3(Width, 1, Height));
if(grid != null)
{
foreach(Node n in grid)
{
if(n.TerrainType == TerrainType.Grass)
{
Gizmos.color = Color.green;
}
else if(n.TerrainType == TerrainType.Mountain)
{
Gizmos.color = Color.black;
}
Gizmos.DrawCube(n.Position, Vector3.one * (nodeDiameter - .1f));
}
}
}
noiseArray is used for the vertices of the terrain in the following code:
vertices = new Vector3[(Width + 1) * (Depth + 1)];
noiseArray = PerlinNoise();
int i = 0;
for(int z = 0; z <= Depth; z++)
{
for(int x = 0; x <= Width; x++)
{
var currentHeight = noiseArray[i];
if(currentHeight > HeightThreshold)
{
currentHeight *= HeightMultiplier;
}
vertices[i] = new Vector3(x, currentHeight, z);
i++;
}
}
Output
Result from suggested answer
Still seems to miss some mountain areas, colouring green instead of black.
It think the issue is in
var pos = (x * Width) + z;
since x is you index on the width of the grid you would probably rather want
var pos = z * Width + x;
in other words you want to
skip z rows
each row has Width elements
then from there take the xth element
assuming your terrain is laid out row-wise.
Or if it is laid out column-wise (which is rather unusual but possible)
var pos = x * Height + z;
or in other words
skip x columns
each column has Height elements
then from there take the zth element
See also Converting index of one dimensional array into two dimensional array i. e. row and column
Update
Now that you have showed the terrain generation code it needs to be
var pos = z * (Width + 1) + x;
since the terrain array has actually Width + 1 elements per row.

How to loop through every square in a rectangle?

In c#, I want to loop through every square possible in a rectangle. The square size is much smaller than the rectangle dimensions. But note that I don't mean loop through every square in a grid pattern, I mean every square at any type of location (not limited to a grid). Its like randomly picking a square at a random location, but it needs to go through all possible locations and only get each one once (no duplicates).
Does anyone know of an algorithm for this?
Thanks
Al you need to do is set an origin (say, left-top), find out the maximum side length from that location, and iterate from 1 to that value for every pixel in your image.
Class names are fictional, adapt to your own needs.
IEnumerable<Rectangle> AllSquaresIn(Rectangle rect)
{
for (int x = 0; i x < rect.Width; x++)
{
for (int y = 0; y < rect.Height; y++)
{
int maxLength = Math.Min(rect.Width - x, rect.Height - y);
for (int i = 1; i <= maxLength; i++)
{
yield return new Rectangle(x, y, x + i, y + i);
}
}
}
}
Since i is always positive, it will be impossible to have duplicate rectangles.
Since it appears from the comments that you only want the rectangles of a given size:
IEnumerable<Rectangle> AllSquaresIn(Rectangle rect, int length)
{
for (int x = 0; i x < rect.Width - length; x++)
{
for (int y = 0; y < rect.Height - length; y++)
{
yield return new Rectangle(x, y, x + length, y + length);
}
}
}

Find chest size using Kinect v2

I need to find out the front measure of chest for any individual using Kinect while facing the camera. My current solution is:
When a MultiFrameSource arrives get the color (to display the body in the ui) body (to get the Joints), and bodyIndex frames.
copy the BodyIndexFrame to an byte[] _bodyData by using:
bodyIndexFrame.CopyFrameDataToArray(_bodyData);
I get the Joint objects for: spineShoulder and spineMid. I have assumed that the chest will always be between those points.
I convert both Joints to CameraSpacePoint (x,y,z) and from CameraSpacePoint to DepthSpacePoint (x,y) by using
_sensor.CoordinateMapper.MapCameraPointToDepthSpace(jointPosition);
I still keep a reference to the z value of spineShoulder.
Second assumption => Starting from spineShoulderY to spineMidY I try to find the widest point which is in the player area. in order to do so I will try to find the longest segment between spineShoulderX and the first left region found which does not belong to the player and the longest segment between spineShoulderX and first right side region found which does not belong to the player. Both x segments found must be in the same y coordinate.
/***************
* Returns the distance between 2 points
*/
private static int getDistanceToMid(int pointX, int midX)
{
if (midX > pointX)
{
return (midX - pointX);
}
else if (pointX > midX)
{
return (pointX - midX);
}
else
{
return 0;
}
}
/*********
* Loops through the bodyData array
* It will look for the longest x distance from midX to the last left x value
* which still belongs to a player in the y coordinate
*/
private static int findFarLeftX(byte[] bodyData,int depthWidth, int midX, int y)
{
int farLeftX = -1;
for (int x = midX; x >= 0; --x)
{
int depthIndex = (y * depthWidth) + x;
if (depthIndex > 0 && depthIndex < bodyData.Length)
{
byte player = bodyData[depthIndex];
if (player != 0xff){
if (farLeftX == -1 || farLeftX > x)
{
farLeftX = x;
}
} else{
return farLeftX;
}
}
}
return farLeftX;
}
/*********
* Loops through the bodyData array
* It will look for the longest x distance from midX to the last right x value
* which still belongs to a player in the y coordinate
*/
private static int findFarRightX(byte[] bodyData, int depthWidth, int midX, int y)
{
int farRightX = -1;
for (int x = midX; x < depthWidth; ++x)
{
int depthIndex = (y * depthWidth) + x;
if (depthIndex > 0 && depthIndex < bodyData.Length)
{
byte player = bodyData[depthIndex];
if (player != 0xff)
{
if (farRightX == -1 || farRightX < x)
{
farRightX = x;
} else{
return farRightX;
}
}
}
}
return farRightX;
}
private static BodyMember findElement(byte[] bodyData, int depthHeight, int depthWidth, int startX, int startY, int endY)
{
BodyMember member = new BodyMember(-1, -1, -1, -1);
int totalMaxSum = 0;
int farLeftX = -1;
int farRightX = -1;
int selectedY = -1;
for (int y = startY; y < depthHeight && y <= endY; ++y)
{
int leftX = findFarLeftX(bodyData, depthWidth, startX, y);
int rightX = findFarRightX(bodyData, depthWidth, startX, y);
if (leftX > -1 && rightX > -1)
{
int leftToMid = getDistanceToMid(leftX, startX);
int rightToMid = getDistanceToMid(rightX, startX);
int sum = leftToMid + rightToMid;
if (sum > totalMaxSum)
{
totalMaxSum = sum;
farLeftX = leftX;
farRightX = rightX;
selectedY = y;
}
}
}
member.setFarLeftX(farLeftX);
member.setFarLeftY(selectedY);
member.setFarRightX(farRightX);
member.setFarRightY(selectedY);
return member;
}
findElement will return a BodyMember object which contains farLeftX, farRightX, farLeftY and farRightY.
I create 2 DepthSpacePoint objects:
DepthSpacePoint chestX1 = new DepthSpacePoint();
chestX1.X = bodyMemberObj.getFarLeftX();
chestX1.Y = bodyMemberObj.getFarLeftY();
DepthSpacePoint chestX2 = new DepthSpacePoint();
chestX2.X = bodyMemberObj.getFarRightX();
chestX2.Y = bodyMemberObj.getFarRightY();
In order to get real world coordinates in meters these points must be converted to CameraSpacePoint object. In order to do so I will use the joint's z value that I kept a reference to back in point 4.
CameraSpacePoint chestLeft = _sensor.CoordinateMapper.MapDepthPointToCameraSpace(chestX1,spineShoulderZ);
CameraSpacePoint chestRight = _sensor.CoordinateMapper.MapDepthPointToCameraSpace(chestX1,spineShoulderZ);
Now,If my code and assumptions are right I should be able to get the correct distance in meters for the front chest.
double chestLength = (chestLeft.X > chestRight.X) ? chestLeft - chestRight : chestRight - chestLeft;
However this does not seem to be returning the correct values. I have been looking into a solution for this during weeks but I seem to be stuck.
I have worked with Kinect V2, and can say that skeleton data alone wild be insufficient to get reliable results. Even clothes has impact how Kinect interprets body parts, so you will have to combine results from other sensors data.
Additionally I suggest you to be creative about how you approach this,
for example, you could investigate some possible anatomic correlations about human body, most likely height is a proxy indicator, maybe age from face-recognition and height is another hint, etc.
Are you using using kinect One? Measurements in the old kinects are probably not accurate enough to fit your requirements.
However, from my point of view it would be also worth to do extraction of the moving object inside the frames (if there is only one person in front of the Kinect you will receive this person's contour, but to be sure you can compare its position with Kinect skeleton).
You can tell person to rise their hands for a short period of time. Than use Kinect distance to the persons skeleton and based on the size of the contour and given distance - calculate your final chest measurement just below the shoulders (position taken from the skeleton). I'm also not fully aware how accurately Kinect handles "bigger" people.
Here is described one of the methods: http://onlinelibrary.wiley.com/doi/10.1002/scj.10237/abstract You can also google many other papers with given subject (for free).
What do you think about this idea?
Cheers

Algorithm to find rectangles

I have the following code:
int width = 10;
int height = 7;
bool[,] array1 = new bool[width, height];
string values =
"1100000000" +
"1100000011" +
"0001100011" +
"0001100000" +
"0001110000" +
"0000000110" +
"0000000110";
for (int x = 0; x < width; x++)
{
for (int y = 0; y < height; y++)
{
array1[x, y] = (values[x + y * width] == '1');
}
}
im looking for a algorithm that would extract Ranges where we have a 1.
so from this data we would get rectangles
(0,0,2,2),
(8,1,2,2),
(3,2,3,3),
(7,5,2,2)
the order of the rectangles do not matter!
But i have no idea how to do this any one got any pointers?
After reading Rusty Weber answer i came up with the following:
private static List<Rectangle> GetRectangles(bool[,] array)
{
List<Rectangle> rectangles = new List<Rectangle>();
for (int x = 0; x < array.GetLength(0); x++)
{
for (int y = 0; y < array.GetLength(1); y++)
{
if (array[x, y])
{
rectangles.Add(GetRectangle(array, new Point(x, y)));
}
}
}
return rectangles;
}
static Rectangle GetRectangle(bool[,] array, Point startLocation)
{
int maxX = int.MinValue;
int minX = int.MaxValue;
int maxY = int.MinValue;
int minY = int.MaxValue;
HashSet<Point> visitedLocations = new HashSet<Point>();
Stack<Point> pointsToGo = new Stack<Point>();
Point location;
pointsToGo.Push(startLocation);
while (pointsToGo.Count > 0)
{
location = pointsToGo.Pop();
if (!location.X.IsBetween(0, array.GetLength(0) - 1))
continue;
if (!location.Y.IsBetween(0, array.GetLength(1) - 1))
continue;
if (!array[location.X, location.Y])
continue;
if (visitedLocations.Contains(location))
continue;
visitedLocations.Add(location);
pointsToGo.Push(new Point(location.X + 1, location.Y));
pointsToGo.Push(new Point(location.X, location.Y + 1));
pointsToGo.Push(new Point(location.X - 1, location.Y));
pointsToGo.Push(new Point(location.X, location.Y - 1));
}
foreach (Point location2 in visitedLocations)
{
array[location2.X, location2.Y] = false;
if (location2.X > maxX)
maxX = location2.X;
if (location2.X < minX)
minX = location2.X;
if (location2.Y > maxY)
maxY = location2.Y;
if (location2.Y < minY)
minY = location2.Y;
}
return new Rectangle(minX, minY, maxX - minX + 1, maxY - minY + 1);
}
public static bool IsBetween<T>(this T item, T start, T end)
{
return Comparer<T>.Default.Compare(item, start) >= 0
&& Comparer<T>.Default.Compare(item, end) <= 0;
}
COMMENT :: It might help me to answer your question if you have better defined coordinates. (0,0,2,2) isn't exactly Cartesian and it may need some explaining. Is this the top left corner followed by the widths?
Ok. The easiest to program way, in my opinion at least, to extract all possible rectangles from the graph is to have a recursively defined method that searches in a specific direction for the symmetric rectangle pattern. This however could end up being really slow so I hope that speed isn't a constraint for you. Looking at the style of code, I would say that this is a school assignment for either recursion or dynamic programming.
something along the lines of the following pseudocode
`
for i in width
{
for j in height
{
if(point[i,j] == 1)
{
potentials = searh_in_direction(i,j,graph,width,height,RIGHT,[[i,j]] )
listOfAllRects.append(potentials)
}
}
}
list_of_rectangle searh_in_direction(i,j,graph,width,height,direction, listofpoints )
{
nextdirection = direction.nextdirection; //Right -> down -> left-> up
//DEVELOP METHOD FOR RECURSION HERE THAT RETURNS ALL SETS OF 4 POINTS THAT
for every point in the direction of travel
if the point is the origional point and we have 4 points including the point we are looking at, we have a rectangle and we need to return
if point on direction of travel is a one travel on the next direction
posiblerects.append(searh_in_direction(i,j,graph,width,height,nextdirection , listofpoints.append(currentpoint)))
//after all points in direction have bee searched
return posiblerects.
}
`
I know that this code could be very confusing but that is the gist of what you need as a recursive element.
I will also note that I can already see several bugs in this code but I have run out of the 15 minutes that I said that I was going to spend on this post so you might have to pick them out yourself.
This gives you the same results you're looking for:
static void Main(string[] args)
{
string values =
"1100000000" +
"1100000011" +
"0001100011" +
"0001100000" +
"0001110000" +
"0000000110" +
"0000000110";
int width = 10;
int height = 7;
bool[,] array = new bool[width, height];
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
array[x, y] = (values[x + y * width] == '1');
List<Rectangle> rectangles = new List<Rectangle>();
for (int x = 0; x < width; ++x)
{
for (int y = 0; y < height; ++y)
{
if (array[x, y] && !Used(rectangles, x, y))
{
int rHeight = 1;
for (int rX = x + 1; rX < width && array[rX, y] && !Used(rectangles, rX, y); ++rX)
for (int rY = y + 1; rY < height && array[rX, rY] && !Used(rectangles, rX, rY); ++rY)
if (rY - y >= rHeight)
rHeight = rY - y + 1;
int rWidth = 1;
for (int rY = y + 1; rY < height && rY - y <= rHeight && array[x, rY] && !Used(rectangles, x, rY); ++rY)
for (int rX = x + 1; rX < width && array[rX, rY] && !Used(rectangles, rX, rY); ++rX)
if (rX - x >= rWidth)
rWidth = rX - x + 1;
rectangles.Add(new Rectangle(x, y, rWidth, rHeight));
}
}
}
foreach (Rectangle rect in rectangles)
Console.WriteLine(rect);
}
private static bool Used(IEnumerable<Rectangle> rectangles, int x, int y)
{
return rectangles.Any(r => r.Contains(x, y));
}
I made an adhoc Rectangle struct since I didn't reference System.Drawing, but you can pass a System.Drawing.Point to the System.Drawing.Rectangle.Contains() and get the same results.
Also, notice that the width of your array should actually be 10 and your indexing math was wrong. You should be multiplying y by the width, not the height.
It is not clear from the question if you really want rectangles that cover the 1's exactly, or if you want bounding volumes that can contain zeroes, but will cover all the 1's with a reasonably small number of rectangles.
Assuming you want rectangles to cover the 1's, and you don't need a perfect solution:
Make a temporary copy of the array.
Iterate over the temporary looking for 1's
When you hit a 1, begin a new rectagle that starts as 1x1, offset to that location ( e.g. covers just that 1 )
Expand that rectangle rightward so long as there is a 1 in the next cell
Expand that rectangle downards so long as the row below has 1's matching the width
of the current rectangle.
ONce you can't expand down any more, emit that recgantle, and clear all the 1's covered by that rectangle from the temporary
continue scanning for 1's starting with the cell directly after the top right corner of the current rectangle.
This will produce a decent covering - but by no means ideal. If you need a perfect covering - e.g. the guaranteed minimum number of rectangles then it is harder.

Categories

Resources