get center polygon C# [duplicate] - c#

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.

Related

How to divide objects into limited area with C#?

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.

Find the direction of one rectangle relative to other

Problem
How can i find the direction of one rectangle w.r.t to the other. The directions i am interested is up, down, left, and right. My rectangle is represented by a Cell class. I am trying to write a function in that cell class. Function accepts a parameter of Cell type the returns the direction either 1(up) 2(down) 3(left), or 4(right) of the passed cell w.r.t to the calling cell.
What i tried
I found the mid point of both the rectangles, and then compared the x, and y coordinates. But this technique is not working in all the cases. whenever i find a missing case, i have to include more and more if statements which i think is not a good programming practice. its becoming more and more error prone and difficult to understand.
While searching for the solution: maybe math.atan2() can work in my case. Maybe i can find the angle between mid points of these 2 rectangles and use the value of angle to determine the direction. But i am not sure if my thinking is correct.
Please guide me. Should i keep using my function and rectify it, or is there a better solution such as math.atan2()? A helping image for better understanding and a required solution is demonstrated below after the code.
Code
public int dirOfThisCell(Cell cell)
{
int dir = 0;
//find mid points of both cells
PointF midPointThis = this.computeAndGetMidPoint();
PointF midPointCell = cell.computeAndGetMidPoint();
//MessageBox.Show(mess);
//if x of both points is same or with little variance because of variance in sizes of cells
===>> //Comparison Starts!!
if (midPointThis.X > midPointCell.X)
{
//this cell is to the right.
if ((midPointCell.Y) == (midPointThis.Y))
{
dir = 3;
}
else if (Math.Abs(midPointCell.Y) - Math.Abs(midPointThis.Y) < 5) { dir = 3; }
else if (Math.Abs(midPointCell.Y) - Math.Abs(midPointThis.Y) > 5) {
if (midPointThis.Y > midPointCell.Y) { dir = 1; }
else if (midPointThis.Y < midPointCell.Y) dir = 2;
}
// a considerable difference
else { dir = 3; }
//some small variations in y
//else if(Math.Abs()
}
else if (midPointThis.X < midPointCell.X)
{
// this cell is to the left
if ((midPointCell.Y) == (midPointThis.Y))
{
dir = 4;
}
else if (Math.Abs(midPointCell.Y) - Math.Abs(midPointThis.Y) <= 10)
{
dir = 4;
}
}
//if this cell is below
else if (midPointThis.Y > midPointCell.Y)
{
//this cell is down than the cell
if ((midPointCell.X) == (midPointThis.X))
{
dir = 1;
}
//else if (Math.Abs(midPointCell.X) - Math.Abs(midPointThis.X) < 2) { dir = 1; }
}
else if (midPointThis.Y < midPointCell.Y)
{
if ((midPointCell.X) == (midPointThis.X))
{
dir = 2;
}
}
return dir;
}
Image
Sample Image
Sample rectangles are shown in the picture number wise. The rectangle can be of single cell or made by combining multiple numbered cells.
Sample Solution required
Direction of cell 18 w.r.t to 8 should be up(1)
Direction of cell 18 w.r.t to 10 should be up(1)
Direction of cell 14 w.r.t to 13 should be right(4)
Direction of cell 9 w.r.t to 31 should be down(1)
Direction of cell 15 w.r.t to 9 should be left(3)
I am working in c#.
Any help would be much appreciated.
Thank You
Calculating the angle of the center of a rectangle compared to the center of another does not seem to be a very good idea, because the center of those rectangles are only telling you where their center is and the solution is completely reluctant to the width, height and direction of the sides. I know that the third one is not a concern in your specific case as you can safely assume that the sides are horizontal XOR vertical, but in general terms, that could be an issue as well. To calculate the relative position of Shape1 (which is a rectangle in our particular case) compared to Shape2, you need to calculate the minimum and maximum x and y for both.
Shape1 is to the left of Shape2 <=> Shape1.maxX <= Shape2.minX
Shape1 is to the right of Shape2 <=> Shape2.minX >= Shape2.maxX
Shape1 is above Shape2 <=> Shape1.maxY <= Shape2.minY
Shape2 is below Shape2 <=> Shape2.minY >= Shape1.maxY

Rasterizing image with colored fixed-width chars

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.

Finding the point corresponding to an arc length on the ellipse iteratively

Given a distance (arc length) anticlockwise away from a known point (P_0) on an ellipse, I am trying to find the point at that distance (P_1).
Since I cannot evaluate the t corresponding to a specific arc length analytically, I am forced to iterate through each discrete point until I arrive at an answer.
My initial code is something like this:
// t_0 is the parametric t on the ellipse corresponding to P_0
Point GetPos(double distance, double t_0, double res = 5000, double epsilon = 0.1)
{
for(int i = 0; i < res; ++i)
{
// The minus is to make the point move in an clockwise direction
t = t_0 - (double)(i)/(double)res * t_0;
// Find the integral from t to t_0 to get the arc length
// If arc length is within epsilon, return the corresponding point
}
}
Unfortunately, this code may not converge if the arc length given by the t value just nicely overshoots the epsilon value. And since this is a loop that decreases t, the overshoot will not be corrected.
I was thinking of modelling this as a control problem, using something like a PID controller. However, I realised that since the set point (which is my desired arc length), and my output (which is essentially the parametric t), are referring to different variables, I do not know how to proceed.
Is there a better method of solving this kind of problem or am I missing something from my current approach?
After some thought I used a binary search method instead, since a PID controller is difficult to tune and usually does not converge fast enough for all cases of the ellipses under consideration.
double max = t_0; double min = 0; double result = 0; double mid = 0;
mid = (max - min) / 2.0;
while ((Math.Abs(distance - result) > epsilon))
{
result = // Arc Length from t_0 to mid
if (result > distance)
{
min = mid;
mid = ((max - mid) / 2.0) + min;
}
else
{
max = mid;
mid = (mid - min) / 2.0;
}
}
// Return the point at t = max
The binary search works as the search is always over an ordered range (from t_0 to 0).

Interpolating Z values when given complete and incomplete XYZ pairs

I am building a windows form application that works with PolyLineZ (ESRI Shapefile) data and rewrites outlying Z values. The minimum and maximum Z-values are defined by the user through the interface
Let's take the following as an example, let's say the minimum is 0 and the maximum is 10:
XY Z
1,1 0
1,3 1
1,5 7
1,7 11*
1,10 10
The value with the 11 would need to be interpolated as it does not fall into the range defined by the user. This is a very simplified example obviously. Some PolyLines can be missing more values.
What I've done:
I've researched linear interpolation. Looked at example youtube videos, having a hard time wrapping my head around it.
What I need:
Code examples from either any language or an "English" explanation of the theory behind linear/bilinear/trilinear interpolation so that I can implement it into my program. My math skills aren't the greatest, so I have a hard time understanding wikipedias definition of it.
I'm also assuming that linear interpolation is what I need to research,
EDIT: Currently implementing the following, stop me if I'm wrong
I'm using what I think is Pythagorean Theory type approach. I haven't made it catch exceptions yet (ie, making sure the left point is actually left, make sure the list doesn't run out of bounds, etc), that can come later
internal static double calculateDistance(XYPoints a, XYPoints b)
{
double xd = b.X - a.X;
double yd = b.Y - a.Y;
return Math.Sqrt(xd * xd + yd * yd);
}
for (var i = 0; i < polylinez.ZPoints.Count;i++)
{
if (polylinez.ZPoints[i] > maxValue || (polylinez.ZPoints[i] < minValue))
{
//polylinez.ZPoints[i] = (((1 - polylinez.XYpoints[i].X) * polylinez.ZPoints[i - 1]) + (polylinez.XYpoints[i].X * polylinez.ZPoints[i + 1]));
double prevdistance = calculateDistance(polylinez.XYpoints[i - 1], polylinez.XYpoints[i]);
double nextdistance = calculateDistance(polylinez.XYpoints[i], polylinez.XYpoints[i + 1]);
double fraction = prevdistance / nextdistance;
double diffsBetweensZ = polylinez.ZPoints[i + 1] - polylinez.ZPoints[i - 1];
Console.WriteLine(polylinez.ZPoints[i - 1] + (diffsBetweensZ * fraction));
}
}
return polylinez;
It returns 9.12 as an answer for the above example table. This sounds about right to me. I checked my distance calculator method with sample data on the internet, and it seems to be doing the trick.
First step, create a routine for calculating distances:
internal static double calculateDistance(XYPoints a, XYPoints b)
{
double xd = b.X - a.X;
double yd = b.Y - a.Y;
return Math.Sqrt(xd * xd + yd * yd);
}
I changed the variable names to something more logical (my variable names were different)
//get distance frpm previous point to point in question
double prevdistance = calculateDistance(prevXYpoint, currentXYPoint);
//get distance frpm point in question to the next point
double nextdistance = calculateDistance(currentXYPoint, nextXYPoint);
//generate a ratio
double fraction = prevdistance / (nextdistance + prevdistance);
//find out the difference between the two known points
double diffsBetweensZ = nextZpointValue - prevZpointValue;
//interpolate!
double newZvalue = (prevZpointValue + (diffsBetweensZ * fraction));
I checked this on several sets of data and it's the most accurate thing I can find... what blows my mind is that I couldn't find any existing code anywhere to do this.

Categories