Get the perimeter of a list of verticies - c#

I am currently developing a level editor, and I've gotten to the point where I have collected a list of vertices that I want to use to create a Polygon collider.
I have obtained these vertices by tagging certain tiles as "colliders" and running them through an algorithm to get a list of tiles that are connected. I then created a list of vertices from the list of connected tiles and removed any duplicates.
Below is an image that will help explain. All of the dots are verticies that are currently in my list, but I want to use the ones colored red to create a polygon.

This is how I ended up solving my problem. Each vertex is a part of four different tiles (Excluding edge of map cases), so I just iterated through every vertex and counted how many neighbors are "of the same type". If the result was 4 then it meant that the vertex was somewhere in the middle of the polygon. If the result was 3 it meant the vertex was on an inner corner. 2 meant it was on an edge. 1 meant it was an outer corner.
private List<Vector2> GetPerimeterOfVerticeList(List<Vector2> vertices, TileType type)
{
int neighborCount = 0;
List<Vector2> perimeter = new List<Vector2>();
//Check the four tiles touching this vertex
foreach (Vector2 v in vertices)
{
//upper left tile
if (v.x - 1 >= 0 && v.y <= gridHeight - 1 && grid[(int)v.x - 1, (int)v.y].type == type)
{
neighborCount++;
}
//upper right
if (v.x <= gridWidth - 1 && v.y <= gridHeight - 1 && grid[(int)v.x, (int)v.y].type == type)
{
neighborCount++;
}
//bottom right
if (v.y - 1 >= 0 && v.x <= gridWidth - 1 && grid[(int)v.x, (int)v.y - 1].type == type)
{
neighborCount++;
}
//bottom left
if (v.y - 1 >= 0 && v.x - 1 >= 0 && grid[(int)v.x - 1, (int)v.y - 1].type == type)
{
neighborCount++;
}
//If we have less than 4 neighbors, it means we are on the edge. 3 is an inner corner, 2 is a side piece, 1 is an outer corner
if (neighborCount < 4)
{
perimeter.Add(v);
}
//Reset the neighbor count back to 0 for the next vertex check.
neighborCount = 0;
}
return perimeter;
}

Related

Find the selected segment in a wheel of fortune spinning wheel

in Unity I have a circle sprite that is rotating over time.
private void Update()
{
transform.Rotate(0, 0, 10 * Time.deltaTime);
}
I want to calculate n pieces from this circle. Some examples:
The amount of pieces is given by the length of an array
private void SplitCircle(Part[] parts)
{
// split the circle by the amount of parts
}
I just have to calculate it. I don't need the UI part!
Each piece would take (360 / n) degrees from the circle. When having 5 pieces the first part should have a range from 0 to 72. The second one from 73 to 144 etc.
In my scene I have a button that stops the rotation of the circle. Is it possible to calculate which part is on top when pressing the button?
Normalize the circle rotation value to between 0 and 360 (rotation % 360).
Subtract this from each number in each segment's range in turn. For each segment, find the one where the bottom of the adjusted range values are < 0 at the lower bound, and >= 0 at the upper bound. Pick that one.
If the selected segment is out, adjust the pre-normalised rotation value by 90 degrees until the outcome fits with your "up".
Also, your range should not be 0..72, 73..144 etc. What about 72.5 degrees? It should be 72..144 with the lower bound being >= and the upper bound being <.
In untested C#ish pseudocode...
var adjust = 0; /* Adjust this +/- 90 if the result comes out with the wrong result */
var spriteRotation = (getSpriteRotationDegrees() + adjust) % 360.0f;
for (var i = 0; i < parts.length; i++) {
var lowerBound = parts[i].lowerBound() - spriteRotation;
var upperBound = parts[i].upperBound() - spriteRotation;
if (lowerBound < 0 && upperBound >= 0) {
break;
}
}
var winningPart = parts[i];

Procedural texture uv error

I am creating a game with procedural generated plane and uv, it works mostly fine, but there is one place where the uv seems distorted in a very confusing way.
Intro: the uv is mapped in a "Global" uv coordinates, instead of a local one, because the texture has to be aligned with adjacent planes. Each texture has a tiling of 2*2, I introduce a uv scale of 2 which means each plane "v" coordinates will be mapped in range [0, 0.5] of the texture vertically, to make sure horizontally "u" coordinates do not go out of range [0, 1]. (horizontally the noise is unpredictable to some extend).
code:
Vector2[] CalculateU(float[] leftXMap, float[] rightXMap) {
int length = leftXMap.Length;
float totalHeight = (length - 1) * 1; // distance between two vertices vertically is 1
float uvheight = totalHeight * uvScale; // uvScale is 2, purpose is to map a plane's v(vertically), into a range of [0, 0.5]..
Vector2[] UMap = new Vector2[length * 2];
for(int i = 0; i < length; i++) {
float left = leftXMap[i];
float right = rightXMap[i];
// make left and right positive.
while (left < 0) {
left += uvheight;
}
while(right < 0) {
right += uvheight;
}
float leftu = (left % uvheight) / uvheight;
float leftv = (i / (float)(length-1)) / uvScale;
float rightu = (right % uvheight) / uvheight;
float rightv = leftv; //(i / (float)length) / 2f;
UMap[i * 2] = new Vector2(leftu, leftv);
UMap[i * 2 + 1] = new Vector2(rightu, rightv);
}
}
explain:
the parameters for the function, are the noise maps for the generated plane. the noise is the x coordinates. while the y coordinates are simple value of 0, 1, 2, .... (length-1).
Distorted texture:
Zoomed in:
I managed to solved the problem, the UV map gets messed where the left noise map values are negative, and right noise map is positive values.
Since I always try to map all negative values to positive values, so left noise map, which is also be my left vertex x coordinates, will be mapped to positive values. but then it will be larger than right noise map (right vertex x coordinates). then it messed up the UV.
I solved it by not mapping at all, and suddenly realize that UV map values can be negative, I don't have to map at all!

Find vertices in equilateral triangle mesh originating from a center vertex

I'd like to ask whether there is code out there or if you can give me some help in writing some (C#, but I guess the maths is the same everywhere).
I'd like to specify a center point from which an equilateral triangle mesh is created and get the vertex points of these triangles. The center point should not be a face center, but a vertex itself.
A further input would be the size of the triangles (i.e side length) and a radius to which triangle vertices are generated.
The reason behind it is that I want to create a mesh which is centered nicely on the screen/window center with as little code as possible. I just find mesh generation code, but not a "radial outward propagation" example.
In the end, I'd like to have the subsequently farther away vertices being displaced in a logarithmic fashion, but I guess that's just an easy addition once the mesh code is there.
Can anybody help me with that? Thanks!
You need to specify two things, a radius and the direction that the first triangle points.
The radius will be the distance from the initial point to the vertices of the first triangle. All triangles will have the same radius.
The direction is some specification in radians. I will assume that 0 means pointing to the right (PI would be point to the left).
Finding the vertices of the first triangle can be done like this (pseudo-code, not language specific):
float theta = 0; // The direction, 0 means pointing to the right
float thetaInc = TWO_PI/3; // 3 because you want a triangle
for (int i = 0; i < 3; i++) {
vertX[i] = initialPointX+cos(theta)*radius;
vertY[i] = initialPointY+sin(theta)*radius;
theta += thetaInc;
}
There are many ways to find the center points of the neighboring triangles. One way would be to use the same code but initialize theta = TWO_PI/6, replace radius with foo (see math below), assign new center points of neighboring triangles in the for loop, and then use the same code with an appropriately rotated direction (theta += PI) to find the vertices of those triangles.
Distance from one triangle center to another only knowing radius:
hypotenuse = sqrt(sq(radius)+sq(radius));
halfHypotenuse = hypotenuse/2.0;
Pythagorean theorem to find distance from center of triangle to center of an edge: foo = sqrt(sq(radius)-sq(halfHypotenuse));
Final distance = foo*2.0;
Code to find the center points of the neighboring triangles:
float[] nx = new float[3];
float[] ny = new float[3];
float theta = TWO_PI/6;
float hyp = sqrt(sq(radius)+sq(radius));
float halfHyp = hyp/2.0;
float foo = sqrt((sq(radius)-sq(halfHyp)))*2.0;
for (int i = 0; i < 3; i++) {
nx[i] = initialPointX+cos(theta)*foo;
ny[i] = initialPointY+sin(theta)*foo;
theta += thetaInc;
}
Thank you very much for your answer. I will play around with your code - the propagation part will come handy for sure.
In the meantime I have played around with hexagons instead of triangles and this codes works fairly alright for the same purpose.:
//populate array from the centre hex, going outwards the desired number of hex rings
for (int i = 0; i < numberOfHexagonRings; i++)
{
for (double j = -i; j <= i; j++)
for (double k = -i; k <= i; k++)
for (double l = -i; l <= i; l++)
if ((Math.Abs(j) + Math.Abs(k) + Math.Abs(l) == i * 2) && (j + k + l == 0))
{
positionX = (int)(screenCenterX + ((double)sideLength * (l / 2 + j)));
positionY = (int)(screenCenterY + (3/2 * ((double)sideLength / Math.Sqrt(3)) * l));

Best Algorithms to determine the whether a rectangle is inside a circle

I have to draw rectangle with different fill color depending on the its intersection with a concentric circle. Picture shown will give you a better idea about the scenario,
( representation purpose only)
Currently I am checking each point status by applying Pythagoras's theorem
pseudo code:
SquareOf Point Distance from center (sqrOfDistance) = square(point X
- Circle center X) + square(point Y- Circle center Y)
compare these value with Square of radius (sqrOfInnerR)
if sqrOfDistance == sqrOfInnerR
Inline
else if sqrOfDistance > sqrOfInnerR
Out
else
In
even though the current logic works; it need to perform these check with each points (4 or 8 times) and and finally with together to determine the state. in my real world application there will be around 3,000,000 rectangles comes to the picture.
private RectState CheckTheRectangleState(Rect rect, double radius, bool firstCall = true)
{
double SquareOfRadius = Square(radius);
var _x = rect.X - ControlCenter.X;
var _y = rect.Y - ControlCenter.Y;
var squareOfDistanceToTopLeftPoint = Square(_x) + Square(_y);
var squareOfDistanceToTopRight = Square(_x + rect.Width) + Square(_y);
var squareOfDistanceToBottonLeft = Square(_x) + Square(_y + rect.Height);
var squareOfDistanceToBottonRight = Square(_x + rect.Width) + Square(_y + rect.Height);
var topLeftStatus = squareOfDistanceToTopLeftPoint == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToTopLeftPoint > SquareOfRadius ? PointStatus.Out : PointStatus.In);
var topRightStatus = squareOfDistanceToTopRight == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToTopRight > SquareOfRadius ? PointStatus.Out : PointStatus.In);
var bottonLeftStatus = squareOfDistanceToBottonLeft == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToBottonLeft > SquareOfRadius ? PointStatus.Out : PointStatus.In);
var bottonRightStatus = squareOfDistanceToBottonRight == SquareOfRadius ? PointStatus.Inline : (squareOfDistanceToBottonRight > SquareOfRadius ? PointStatus.Out : PointStatus.In);
if ((topLeftStatus == PointStatus.In || topLeftStatus == PointStatus.Inline) &&
(topRightStatus == PointStatus.In || topRightStatus == PointStatus.Inline) &&
(bottonLeftStatus == PointStatus.In || bottonLeftStatus == PointStatus.Inline) &&
(bottonRightStatus == PointStatus.In || bottonRightStatus == PointStatus.Inline))
{
return firstCall ? RectState.In : RectState.Partial;
}
else
{
if (firstCall)
CheckTheRectangleState(rect, outCircleRadius, false);
}
return RectState.Out;
}
}
where Square() is custom function to get square. Square(x){ return x*x;}
PointStatus and RectState are enum to determine the status of points.
If you are dealing with a lot of rectangles and if most of them are going to be outside the circle most of the time, one way to optimize the check in a early exit way is to first imagine a square enclosing the circle, from (-r,-r) to (r,r), where r is the radius of the circle and centre of the circle is (0,0) and check if the rectangles are within this square. This should be much faster , and the check for collision with the circle needs to happen only if this one succeeds.
edit: #hvd has added an excellent idea for an early exit positive check. If the rectangle is within the inner square, it is definitely inside the circle.
Depending on the size of your rectangle vs circle, you could also go 1 level deeper and make rectangles between the inner square and the circle. But you need to check that the points of the queried rectangles are all in any of the rectangles (+ inner square), and all of them do not need to be in the same one.
So, in the most cases, we can decide that square is a circle, and then our task can become more easier. It will look in such way
float distance = Distance(LargeCircle.center, square.center);
if (distance > LargeCircle.radius){
//two cases here, we can be outside of circle, or intersect it
} else {
//two cases again. We can be inside a circle, or intersect it
}
Hope it will help
Just comment to what #Karthik T suggests. With representing circle with rectangle you can check it with:
ignore rectangles with top bound above of top bound of circle
ignore rectangles with bottom bound lower than bottom bound of circle
ignore rectangles with left bound before left bound of circle
ignore rectangles with right bound after right bound of circle
rest is one that inside
Thus you have only 4 checks rather than 8.
After that you can split circle in quadrants and classify rectangles into cases:
If bottom-right corner is in left-upper quadrant - check only top-left corner (by distance)
If bottom-left corner is in right-upper quadrant - check only top-right corner
If top-right corner is in left-lower quadrant - check only bottom-left corner
If top-left corner is in right-lower quadrant - check only bottom-right corner
If bottom-right corner and bottom-left corner is in upper half of square - check only upper-left and upper-right corner
...
Rest (those for which each corner is in its own quadrant) check all corners by distance.
Update: Actually its much better to classify rectangles in first turn and then filter-out outside of square and then filter-out by cases.
Sample of code:
struct Vec {
public double X, Y;
public Vec Offset(Vec d) { return new Vec { X = X + d.X, Y = Y + d.Y }; }
public Vec Negate() { return new Vec { X = -X, Y = -Y }; }
public Vec OrthX() { return new Vec { X = X }; }
public Vec OrthY() { return new Vec { Y = Y }; }
}
struct Rect { public Vec TopLeft, Size; }
Vec NextVec(Random rng)
{ return new Vec { X = rng.Next(), Y = rng.Next() }; }
Rect NextRect(Random rng)
{
var topLeft = NextVec(rng);
return new Rect { TopLeft = NextVec(rng), Size = NextVec(rng) };
}
Vec Center;
double R, SqR;
private static double Square(double X) { return X*X; }
private bool Contains(Vec point)
{ return (Square(point.X - Center.X) + Square(point.Y - Center.Y)) < SqR; }
private bool Contains(Rect rect)
{
var a = rect.TopLeft;
var c = rect.TopLeft.Offset(rect.Size);
if (c.Y < Center.Y) // in upper half
{
if (c.X < Center.X) // in upper-left quadrant
{
return Contains(a);
}
else if (a.X > Center.X) // in upper-right quadrant
{
return Contains(rect.TopLeft.Offset(rect.Size.OrthX()));
}
else // spans over upper half
{
return Contains(a) &&
Contains(rect.TopLeft.Offset(rect.Size.OrthX()));
}
}
else if (a.Y > Center.Y) // in lower half
{
if (c.X < Center.X) // in lower-left quadrant
{
return Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
}
else if (a.X > Center.X) // in lower-right quadrant
{
return Contains(c);
}
else // spans over lower half
{
return Contains(c) &&
Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
}
}
else // rect spans over upper and lower halfs
{
if (c.X < Center.X) // spans over left half
{
return Contains(a) &&
Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
}
else if (a.X > Center.X) // spans over right half
{
return Contains(rect.TopLeft.Offset(rect.Size.OrthX())) &&
Contains(c);
}
else // rect spans over all quadrants
{
return Contains(a) &&
Contains(c) &&
Contains(rect.TopLeft.Offset(rect.Size.OrthX())) &&
Contains(rect.TopLeft.Offset(rect.Size.OrthY()));
}
}
}
BTW: Consider orginizing rectangles in Quadtree
Much faster if u check if 4 corners(x,y) are closer to center of sphere then lenght of radius?
example
sqrt((Xcorner - Xcenter)^2 + (Ycorner - Ycenter)^2) <= R
and break the calculation for each corner of square if any doesn't pass the condition.

Looping through the boundary of a rectangle between two points on the rectangle?

Whew, that was a big one.
Right, so I have two points, on the boundary of the rectangle and also on the two lines, which are cast from the origin. The arrangement of P1/P2 is arbitrary, for the sake of simplicity.
My question is, how can I loop through the green area (The smallest area, basically) of the rectangle?
The implementation: I want to create a field-of-vision effect in a game that I am creating. The origin is the player, who can be anywhere on the current viewport (The rectangle). The lines' directions are offset from the direction that the player is facing. I intend to trace all positions on the green area from the origin, checking for obstructions.
I would prefer a code example answer, any language, but preferably C#
I think, what you want is something like this:
All coordinates C with the following criteria are on the green line that is part of the rectangle R:
(P1.y == P2.y)
?
(
C.x >= P1.x && C.x <= P2.x
)
:
(
(C.x >= P2.x && C.x <= R.right && C.y == P2.y) ||
(C.x >= P1.x && C.x <= R.right && C.y == P1.y) ||
(C.x == R.x && C.y <= P1.y && C.y >= P2.y)
)
This assumes that P1 will be below P2 in case they are not on the same line and that P1 will be before P2 if they are on the same line.
If you want to find out which objects are in the "green area"...
Assuming you know the size of the rectangle you can calculate the vertices of the polygon you're interested in (origin, P1, P2 and the visible rectangle corners) then you can loop through your objects to find which are inside using point in polygon detection.
Randolph Franklyn's for example. Returns 1 for interior points and 0 for exterior points...
int pnpoly(int npol, float *xp, float *yp, float x, float y)
{
int i, j, c = 0;
for (i = 0, j = npol-1; i < npol; j = i++) {
if ((((yp[i] <= y) && (y < yp[j])) ||
((yp[j] <= y) && (y < yp[i]))) &&
(x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
c = !c;
}
return c;
}
I'd imagine the simplest way to do what you want(field of view) would be to first draw everything to screen, then draw black everywhere you don't want things to be seen.
So basically drawing darkness onto the no fog-of-war screen.

Categories