im currently working on a game and i need to divide a changeable amount of objects in to a limited area. I made a image to explain better:
(I know its a bit difficult to understand)
So i can't find a solution and couldn't figure it out myself. I tried a few ways to multiply and divide the object count with the index and the xMaximum but it didn't work as expected.
This is what i tried:
public float xMin, xMax;
private void UpdateValues()
{
for(int i = 0; i < transform.childCount; i++)
{
float value = xMin;
float maxIndex = transform.childCount;
float index = i;
value = transform.position.x + xMax / (maxIndex * index);
transform.GetChild(i).transform.position = new Vector3(transform.position.x, transform.position.y, value);
}
}
It just gave me the wrong numbers and i can't figure the right way out.
The available variables are:
xMinimum, xMaximum
objectcount
objectindex
If you want it to look exactly how you have shown it on images then it might be a little more tricky. Objects don’t fill the area always the same, so we need to add some exceptions:
if there is only 1 item, then just set it’s position to (xMin + xMax) / 2f
if item is first, and there are more than one, set its position to xMin + (squareWidth / 2f) (or something else if pivot is not in the middle)
if item is last and there are more than one, set its position to xMax - (squareWidth / 2f)
the remaining area, which is of size xMax - 2 * squareWidth need to be divided equally between all remaining objects. Compute the amount remaining objects (which will be all objects - 2 (first and last)). Divide remaining area by number of objects plus 1. Set remaining objects position in a loop, the statement inside will look something like this: value = (i+1) * remainingArea / (transform.childCount - 2 + 1)
That’s the rough list of steps that might help. In this example I assume, that xMin is 0, otherwise you will need to take that into account and for eg. Remaining area won’t be just xMax - 2 * squareWidth, but xMax - xMin - 2 * squareWidth.
Also you might find yourself being off a half a square here and there, but that should be easy to correct.
Related
I am trying to "fake 3D" in a game in WPF. Think of a road, and that the objects appear somewhere in the distant. As they get closer, they look bigger, and eventually they grow in size very fast.
I'm thinking that when the object appears, it's close to 0 in width and height. As it moves towards the player, it becomes closer to hundred percent of its true size.
I think I will need to solve this using logarithmic calculations, and there are several threads on that. What I would really want to do however, is to send in three values to a LogaritmicGrowth method:
the starting Y point
the point at which the object should appear at 100%
the y point where the object is at this very moment.
Thus, what I would like to get in return is the scaling factor for the object in question. So if it's halfway between the starting point and the ending point, then perhaps 0.3 (or so) should be returned.
I can write the method inputs and outputs myself, but need help with the calculation. Thanks!
I am not entirely sure about the use of log here. This is a simple geometry problem.
Think about a point P which is D distance in front of you, which has a height Y (from your line of observation). Your screen is d distance in front of you. The intersection point of the light from P on the screen is p, which makes a height y on screen.
Then, by considering the similar triangles, one can show that:
y = (Y/D) d
Just in case someone else is looking at this question in the future, here's the correct reply (I figured it out myself):
/// <summary>
/// Method that enlargens the kind of object sent in
/// </summary>
public void ExponentialGrowth2(string name, float startY, float endY)
{
float totalDistance = endY - startY;
float currentY = 0;
for (int i = 0; i < Bodies.Bodylist.Count; i++)
{
if (Bodies.Bodylist[i].Name.StartsWith(name)) //looks for all bodies of this type
{
currentY = Bodies.Bodylist[i].PosY;
float distance = currentY - startY + (float)Bodies.Bodylist[i].circle.Height;
float fraction = distance / totalDistance; //such as 0.8
Bodies.Bodylist[i].circle.Width = Bodies.Bodylist[i].OriginalWidth * Math.Pow(fraction, 3);
Bodies.Bodylist[i].circle.Height = Bodies.Bodylist[i].OriginalHeight * Math.Pow(fraction, 3);
}
}
}
The method could be worked on further, such as allowing randomized power-to values (say from 1.5 to 4.5). Note that the higher the exponential value, the greater the effect.
uI am making a program to turn an image into coloured 0's, the problem is that the 0's are not colouring properly. To get anything near resembling the image I have to start my for loop at 2 and increase by 3 each time. The following is my current code:
public partial class MainWindow : Window
{
public MainWindow()
{
TextSelection textRange;
TextPointer start;
TextPointer startPos;
TextPointer endPos;
System.Drawing.Color x;
int pixelX = 3;
int pixelY = 8;
InitializeComponent();
Bitmap b = new Bitmap(#"E:\Documents\Visual Studio 2015\Projects\RichTextBox Image to ASCII\RichTextBox Image to ASCII\Akarin.jpg");
for (int i = 2; i < 8000; i += 3)
{
textRange = richTextBox1.Selection;
start = richTextBox1.Document.ContentStart;
startPos = start.GetPositionAtOffset(i);
endPos = start.GetPositionAtOffset(i + 1);
textRange.Select(startPos, endPos);
x = b.GetPixel(pixelX, pixelY);
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(System.Windows.Media.Color.FromArgb(x.A, x.R, x.G, x.B)));
pixelX += 6;
if (pixelX > 1267)
{
pixelX = 3;
pixelY += 16;
}
i += 3;
textRange = richTextBox1.Selection;
start = richTextBox1.Document.ContentStart;
startPos = start.GetPositionAtOffset(i);
endPos = start.GetPositionAtOffset(i + 1);
textRange.Select(startPos, endPos);
x = b.GetPixel(pixelX, pixelY);
textRange.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(System.Windows.Media.Color.FromArgb(x.A, x.R, x.G, x.B)));
pixelX += 7;
if (pixelX > 1267)
{
pixelX = 3;
pixelY += 16;
}
}
}
}
The reason that I am putting the code in the for loop twice is because when you take the amount of 0's that fit horizontally and find out how many pixels each 0 takes up, it comes to about 6.5 because of the space between each 0.
EDIT: Something else that is also strange, if you look in the top left corner where it starts colouring the 0's, 4 in a row are properly coloured, but then the rest are coloured every other.
A few serious problems I'm seeing here. Normally when rasterizing you either loop through the source pixels or through the target pixels. You however... you loop by a fixed value of roughly 2666 ((8000 - 2) / 3). It's also a very bad idea to do things twice in a loop and even change the loop variable (i). Furthermore since you're having only one loop you have to care about both axes in one run. This is very error prone.
How about this approach?:
Your source image is 1280 × 720 square pixels
Since your zeros are not square you have to know their aspect ratio. If you know that you can calculate how many rows and columns you need. You probably don't want to match them 1:1 as this would give you a huge and stretched image.
Once you know how many rows and columns you need, do two loops, one inside the other and call the loop variables targetX and targetY
If your target image is supposed to be let's say 400 zeroes long in the x-axis, make the first loop go from 1 to 400
Inside the loop pick one pixel (color) from the source at 1280/400 * targetX. Your first target pixel would be at x position 1280/400 * 1 = 3,2 which is roughly 3 (round the number after calculating it). The second would be 1280/400 * 2 = 6 and so on. I think this is the biggest pain in your algorithm since you're trying to get around the 6,5px width. Just round it after calculating! If the first is 6,5, make it 7, the second is 13... you get the idea.
Same logic goes for Y axis, but you handle this with targetY.
This question already has answers here:
What is the fastest way to find the "visual" center of an irregularly shaped polygon?
(15 answers)
Closed 9 years ago.
what algorithm that i can use to get the center of polygon (red point)
case 1 : i try with maxX, maxY, minX, minY and i got the wrong point (black point)
case 2 : i try to get the second max and min coordinate X and Y, but i got problem with the polygon which have point less than 5
case 3 : i add if point count < 5 then use case 1 else use case 2 but i got some error for some polygon
can you tell me the right algorithm for me??
note :
explaination for 4th picture
//ma mean max, mi mean min, X1 mean first, X2 mean second
maX1 = maX2 = maY1 = maY2 = 0;
miX1 = miX2 = miY1 = miY2 = 2000;
//aCoor is array of coordinate, format = {x1,y1,x2,y2,x3,y3,x4,y4,...}
for(int i=0; i<aCoor.count(); i+=2)
{
//point is list of point
point.Add(aCoor[i],aCoor[i + 1]);
//this to get second max X
if(maX2 < aCoor[i])
{
maX2 = aCoor[i];
//this to get first max x
if(maX1 < maX2) {maX1 += maX2; maX2 = maX1 - maX2; maX1 -= maX2;}
}
//this to get second min X
if(miX2 > aCoor[i])
{
miX2 = aCoor[i];
//this to get first min x
if(miX1 > miX2) {miX1 += miX2; miX2 = miX1 - miX2; miX1 -= miX2;}
}
//this to get second max Y
if(maY2 < aCoor[i + 1])
{
maY2 = aCoor[i + 1];
//this to get first max x
if(maY1 < maY2) {maY1 += maY2; maY2 = maY1 - maY2; maY1 -= maY2;}
}
//this to get second min Y
if(miY2 > aCoor[i + 1])
{
miY2 = aCoor[i + 1];
//this to get first min x
if(miY1 > miY2) {miY1 += miY2; miY2 = miY1 - miY2; miY1 -= miY2;}
}
}
if(point.Count < 5)
{
Xcenter = (maX1 + miX1) / 2;
Ycenter = (maY1 + miY1) / 2;
}
else
{
Xcenter = (maX2 + miX2) / 2;
Ycenter = (maY2 + miY2) / 2;
}
this how far i do
What you are looking for is not the geometric center (or centroid) of the polygon, but the center of the portion of the polygon's axis of symmetry which lies inside the polygon. Let me edit one of your examples to demonstrate:
Edited example
Do you see what I mean?
I picked this example because it demonstrates another flaw in your thinking; this is two polygons, and each of them produce a point that fits the qualifications you're looking for. In your example you just arbitrarily chose one of them as the point you want. (I have seen your edited fourth example; it still has two interiors and does not change my point.)
In any case, what you're looking for is actually the solution to two problems: first, how to find an axis of symmetry for a polygon; second, finding a line segment on that axis of symmetry which also lies in the interior of the polygon. After that, finding the center of that segment is trivial.
I can't post any more links, but there's a paper by P. Highnam out of Carnegie Mellon University entitled Optimal Algorithms for Finding the Symmetries of a Planar Point Set which could help with the first problem, it's a bit involved so I won't explain it here. The second problem just boils down to testing each line segment to see if it contains a point of intersection with a line along the axis of symmetry running through the figure's centroid. Assuming your polygon only has one interior (read: is not like your fourth example), you should get two points. Average them and you have your center.
How can i calulate a valid range (RED) for my object's (BLACK) traveling direction (GREEN). The green is a Vector2 where x and y range is -1 to 1.
What I'm trying to do here is to create rocket fuel burn effekt. So what i got is
rocket speed (float)
rocket direction (Vector2 x = [-1, 1], y = [-1, 1])
I may think that rocket speed does not matter as fuel burn effect (particle) is created on position with its own speed.
A cheap and cheerful trick with 2D vectors is to transpose the x and y, then flip the sign on one of them to get the perpendicular vector (pseudo code):
Vector2 perpendicular ( -original.y, original.x ) // Or original.y, -original.x
Then you could do something like:
direction + perpendicular * rand(-0.3 , 0.3)
Update: having realised the question asks for the opposite vector (too busy looking at the picture!) I figure I had better answer that too. Multiply 'direction' by -1 to get the opposite vector. So this:
perpendicular * rand(-0.3 , 0.3) - direction
should give you a random direction vector somewhere in your range (not normalised, but close enough for these purposes). Then you can multiply that result by a random number depending on how long you want the tail.
If to expend upon OlduwanSteve's answer, you can make is such that it's somewhat physically accurate.
You want to create several vectors that will represent the expulsion (the red lines).
First define the number of vectors you want to represent the expulsion with - lets mark it n.
You want to get a set of n numbers which sum up to Vx. These numbers will be the x components of the expulsion vectors. You can do this like so (semi-pseudo code):
SumX = Vx;
for (i = 0; i < n; i++)
{
Ax[i] = -rand(0..SumX); // Ax is the array of all expulsion vectors x components
SumX -= Ax[i];
}
Now you'll want to calculate Ay (the y components of the expulsion vectors). This is quite similar to calculating the, except that SumY = 0.
Here instead of splitting up SumY among n elements, you need to decide a maximal y component. Best way I can think of to select this is to define a maximal allowed angle for the expulsion vectors and define the maximal Vy using: maxVy = minVx*tan(maxAlpha).
Now you can get Ay using this (semi-pseudo code):
SumY = maxVy*2; // The actual range is (-maxVy, maxVy), but using (0, 2*maxVy) is simpler IMO
for (i = 0; i < n; i++)
{
Ay[i] = rand(0..SumY);
SumY -= Ay[i];
}
for (i = 0; i < n; i++)
{
Ay[i] -= maxVy; // Translate the range back to (-maxVy, maxVy) from (0, 2*maxVy)
}
Now you have arrays of both the x and y components of the expulsion vectors. Iterate over both arrays and pair up elements to create the vectors (you don't have to iterate both arrays in the same order).
Notes:
• I align the axes in my calculations such that X is parallel to the objects speed vector (the green line).
• The calculation for maxVy does NOT guarantee that a vector of angle maxAlpha will be produced, it only guarantees that no vector of larger angle will be.
• The lines Ay[i] = rand(0..SumY) and Ax[i] = -rand(0..SumX) may lead to vectors with components of size 0. This may lead to annoying scenarios, I'd recommend to handle away such cases (for instance "while rand returns zero, call it again").
I need to calculate distances between every pair of points in an array and only want to do that once per pair. Is what I've come up with efficient enough or is there a better way? Here's an example, along with a visual to explain what I'm trying to obtain:
e.g., first get segments A-B, A-C, A-D; then B-C, B-D; and finally, C-D. In other words, we want A-B in our new array, but not B-A since it would be a duplication.
var pointsArray = new Point[4];
pointsArray[0] = new Point(0, 0);
pointsArray[1] = new Point(10, 0);
pointsArray[2] = new Point(10, 10);
pointsArray[3] = new Point(0, 10);
// using (n * (n-1)) / 2 to determine array size
int distArraySize = (pointsArray.Length*(pointsArray.Length - 1))/2;
var distanceArray = new double[distArraySize];
int distanceArrayIndex = 0;
// Loop through points and get distances, never using same point pair twice
for (int currentPointIndex = 0; currentPointIndex < pointsArray.Length - 1; currentPointIndex++)
{
for (int otherPointIndex = currentPointIndex + 1;
otherPointIndex < pointsArray.Length;
otherPointIndex++)
{
double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X;
double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y;
double distance = Math.Sqrt(Math.Pow(xDistance, 2) + Math.Pow(yDistance, 2));
// Add distance to distanceArray
distanceArray[distanceArrayIndex] = distance;
distanceArrayIndex++;
}
}
Since this will be used with many thousands of points, I'm thinking a precisely dimensioned array would be more efficient than using any sort of IEnumerable.
If you have n points, the set of all pairs of points contains n * (n-1) / 2 elements. That's the number of operations you are doing. The only change I would do is using Parallel.ForEach() to do the operations in parallel.
Something like this (needs debugging)
int distArraySize = (pointsArray.Length * (pointsArray.Length - 1)) / 2;
var distanceArray = new double[distArraySize];
int numPoints = pointsArray.Length;
Parallel.ForEach<int>(Enumerable.Range(0, numPoints - 2),
currentPointIndex =>
{
Parallel.ForEach<int>(Enumerable.Range(currentPointIndex + 1, numPoints - 2),
otherPointIndex =>
{
double xDistance = pointsArray[otherPointIndex].X - pointsArray[currentPointIndex].X;
double yDistance = pointsArray[otherPointIndex].Y - pointsArray[currentPointIndex].Y;
double distance = Math.Sqrt(xDistance * xDistance + yDistance * yDistance);
int distanceArrayIndex = currentPointIndex * numPoints - (currentPointIndex * (currentPointIndex + 1) / 2) + otherPointIndex - 1;
distanceArray[distanceArrayIndex] = distance;
});
});
Looks good to me, but don't you have a bug?
Each of the inner iterations will overwrite the previous one almost completely, except for its first position. Won't it?
That is, in distanceArray[otherPointIndex] otherPointIndex gets values from currentPointIndex + 1 to pointsArray.Length - 1.
In your example, this will range on [0-3] instead of [0-6].
I've had to perform operations like this in the past, and I think your immediate reaction to high number crunch operations is "there must be a faster or more efficient way to do this".
The only other even remotely workable solution I can think of would be to hash the pair and place this hash in a HashSet, then check the HashSet before doing the distance calculation. However, this will likely ultimately work out worse for performance.
You're solution is good. As j0aqu1n points out, you're probably going to have to crunch the numbers one way or another, and in this case you aren't ever performing the same calculation twice.
It will be interesting to see if there are any other solutions to this.
I think, it's a bit faster to use xDistance*xDistance instead of Math.Pow(xDistance, 2).
Apart from this, if you really always need to calculate all distances, there is not much room for improvement.
If, OTOH, you sometimes don't need to calculate all, you could calculate the distances lazily when needed.