Lets say I have my first Point struct:
Point start = new Point(1, 9);
and my second:
Point end = new Point(4, 9);
I want to get all the points between the start and end. So for example I would want 2,9 and 3,9 in an array. Does .NET have something built in for this?
This is what I ended up doing. As #Cody Gray mentioned in his comment, there are infinite points on a line. So you need to specify how many points you are looking to retrieve.
My Line class:
public class Line {
public Point p1, p2;
public Line(Point p1, Point p2) {
this.p1 = p1;
this.p2 = p2;
}
public Point[] getPoints(int quantity) {
var points = new Point[quantity];
int ydiff = p2.Y - p1.Y, xdiff = p2.X - p1.X;
double slope = (double)(p2.Y - p1.Y) / (p2.X - p1.X);
double x, y;
--quantity;
for (double i = 0; i < quantity; i++) {
y = slope == 0 ? 0 : ydiff * (i / quantity);
x = slope == 0 ? xdiff * (i / quantity) : y / slope;
points[(int)i] = new Point((int)Math.Round(x) + p1.X, (int)Math.Round(y) + p1.Y);
}
points[quantity] = p2;
return points;
}
}
Usage:
var line = new Line(new Point(10, 15), new Point(297, 316));
var points = line.getPoints(20);
That will return a Point array of 20 Points evenly spaced between the two endpoints (inclusive). Hope that helps!
There are no build in functions for this, since there are no points between points. Mathematicaly there is a line between two points. In terms of Computer-Graphics, lines could be antialiased and so beeing not rounded to full Integer numbers.
If you are looking for a fast method of creating all integral numbers inbetween, I guess Bresenhams-Line-Algorithm would be your choice. But this is not build into .NET, you have to code it by yourself (or take Matthew Watson's implementation):
http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
There are even fasther algorithms for doing it, but I would go for Bresenham.
I know it's been quite a long time since you first asked this question but I was looking for something similar recently and found this wiki (https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm), which contained pseudo code.
So I've implemented a function with the pseudo code to perform this calculation and add the points to a List.
public List<Point> GetPoints(Point p1, Point p2)
{
List<Point> points = new List<Point>();
// no slope (vertical line)
if (p1.X == p2.X)
{
for (double y = p1.Y; y <= p2.Y; y++)
{
Point p = new Point(p1.X, y);
points.Add(p);
}
}
else
{
// swap p1 and p2 if p2.X < p1.X
if (p2.X < p1.X)
{
Point temp = p1;
p1 = p2;
p2 = temp;
}
double deltaX = p2.X - p1.X;
double deltaY = p2.Y - p1.Y;
double error = -1.0f;
double deltaErr = Math.Abs(deltaY / deltaX);
double y = p1.Y;
for (double x = p1.X; x <= p2.X; x++)
{
Point p = new Point(x, y);
points.Add(p);
Debug.WriteLine("Added Point: " + p.X.ToString() + "," + p.Y.ToString());
error += deltaErr;
Debug.WriteLine("Error is now: " + error.ToString());
while (error >= 0.0f)
{
Debug.WriteLine(" Moving Y to " + y.ToString());
y++;
points.Add(new Point(x, y));
error -= 1.0f;
}
}
if (points.Last() != p2)
{
int index = points.IndexOf(p2);
points.RemoveRange(index + 1, points.Count - index - 1);
}
}
return points;
}
You can get between points using below code. User just need to define that how many points to get between two points. Here I defined as 10 points.
PointF pStart = new PointF(10, 10);
PointF pEnd = new PointF(100, 100);
PointF[] betPoints = new PointF[10];
for (int i = 1; i <= 10; i++)
{
betPoints[i].X = (Math.Abs(pStart.X - pEnd.X) / 10) * i + pEnd.X;
betPoints[i].Y = (Math.Abs(pStart.Y - pEnd.Y) / 10) * i + pEnd.Y;
}
Related
I have the below algorithm which generates a number of points along the circumference of a circle for collision events in my program. (This works perfectly as far as I can tell).
bool Collision_True = false;
for (int Angle = 0; Angle <= 359; Angle += 5)
{
int X = (CentreX + (Radius * Math.Cos(Angle));
int Y = (CentreY + (Radius * Math.Sin(Angle));
Point point = new Point(X, Y);
if (Collision_True == false)
{
Collision_True = Player_Collisions(point);
}
}
return Collision_True;
However I want to change this so it only generates points on the bottom third of the circle, I tried changing the values in the for loop as follows:
for (int Angle = 120; Angle <= 240; Angle += 5)
{
...
}
But the points generated are still around the complete circumference of the circle instead of just the bottom third.
Any ideas? Thanks.
You need to convert to radians
for (int angleDegrees = 120; angleDegrees <= 240; angleDegrees += 5)
{
double angleRadians = angleDegrees / 180 * Math.PI;
int X = (CentreX + (Radius * Math.Cos(angleRadians));
int Y = (CentreY + (Radius * Math.Sin(angleRadians));
...
Here is problem which i have:
I load image in C#. On that image I have to insert 2 points: point A and point B by clicking mouse on random possitions.
Point A have it cords (Xa, Ya) which is read from program and I need to manually insert its GPS coords (LatitudeA and LongtudeA) for it.
Point B have it own cords (Xb, Yb) which is also read from program and I need to manually insert its GPS coords (LatitudeB and LongtudeB) for it.
So main problem is next: on every next click on screen I have to know GPS cords for that point. Also for that point C i have (Xc, Yc).
Here is my ComputeLatitudeAndLogitude method, but it seems it doesnt works perfectly. I need this on street level size.
Example:
A (487, 361, 45.252464, 19.850337)
B (1167, 397, 45.252026, 19.853990)
C (810, 513, ??? , ???); results should be C(810, 513, 45.251592 , 19.852075)
PLEASE feel free to contact me so we can fix problem, mymailis hladnopivo1990#gmail.com
public void ComputeLatitudeAndLogitud (Wpf_Maps.Point point)
{
int diffX = pointA.X - pointB.X;
int diffY = pointA.Y - pointB.Y;
double diffLatitude = pointA.Latitude - pointB.Latitude;
double diffLongitude = pointA.Longitude - pointB.Longitude;
double latitudePerPixel = Math.Abs(diffLatitude / diffX);
double longitudePerPixel = Math.Abs(diffLongitude / diffY);
int diffXforA = pointA.X - point.X;
int diffYforA = pointA.Y - point.Y;
int diffXforB = pointB.X - point.X;
int diffYforB = pointB.Y - point.Y;
double newLatitudeFromA = pointA.Latitude + (diffXforA * latitudePerPixel);
double newLatitudeFromB = pointB.Latitude + (diffXforB * latitudePerPixel);
double newLongitudeFromA = pointA.Longitude + (diffYforA * longitudePerPixel);
double newLongitudeFromB = pointB.Longitude + (diffYforB * longitudePerPixel);
point.Latitude = (newLatitudeFromA + newLatitudeFromB) / 2;
point.Longitude = (newLongitudeFromA + newLongitudeFromB) / 2;
}
Depending on the distance you need to cover, linear extrapolation will not work too good; the earth is not plain, and latitude distances vary with longitude.
One approximation would be a sphere on which you calculate the Great-circle distance.
(GPS) coordinates are usually recorded relative to a (non-sphere) model of the earth, the WGS-84 ellipsoid being the most common today. So for maximum accuracy, you'll have to calculate distances based on the corresponding reference model.
Additionally, if the reference model of the image is different from that of the GPS coordinates you may need more than two reference points to determine the exact mapping.
I presume pointA and pointB are at opposite corners of the map, A being bottom left (or top left?)... meaning every point C is up and right of the point A.
Try this simplification:
public void ComputeLatitudeAndLogitud (Wpf_Maps.Point point)
{
int diffX = pointA.X - pointB.X;
int diffY = pointA.Y - pointB.Y;
double diffLatitude = pointA.Latitude - pointB.Latitude;
double diffLongitude = pointA.Longitude - pointB.Longitude;
double latitudePerPixel = Math.Abs(diffLatitude / diffX);
double longitudePerPixel = Math.Abs(diffLongitude / diffY);
int diffXforC = point.X - pointA.X;
int diffYforC = point.Y - pointA.Y;
point.Latitude = pointA.Latitude + (diffXforC * latitudePerPixel);
point.Longitude = pointA.Longitude + (diffYforC * longitudePerPixel);
}
Here's my full code. I've got three tests cases there. The first is where pointC is somewhere random, in the second, pointC matches pointA, and in the third, pointC matches pointB.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
ComputeLatitudeAndLongitude(new MyPoint(0, 0, 10, 10), new MyPoint(100, 100, 40, 40), new MyPoint(20, 40));
ComputeLatitudeAndLongitude(new MyPoint(0, 0, 10, 10), new MyPoint(100, 100, 40, 40), new MyPoint(0, 0));
ComputeLatitudeAndLongitude(new MyPoint(0, 0, 10, 10), new MyPoint(100, 100, 40, 40), new MyPoint(100, 100));
}
public void ComputeLatitudeAndLongitude(MyPoint pointA, MyPoint pointB, MyPoint pointC)
{
int diffX = pointA.X - pointB.X;
int diffY = pointA.Y - pointB.Y;
double diffLatitude = pointA.Latitude - pointB.Latitude;
double diffLongitude = pointA.Longitude - pointB.Longitude;
double latitudePerPixel = Math.Abs(diffLatitude / diffX);
double longitudePerPixel = Math.Abs(diffLongitude / diffY);
int diffXforC = pointC.X - pointA.X;
int diffYforC = pointC.Y - pointA.Y;
pointC.Latitude = pointA.Latitude + (diffXforC * latitudePerPixel);
pointC.Longitude = pointA.Longitude + (diffYforC * longitudePerPixel);
LogResults(String.Format("pointA X:{0} Y:{1} Lat:{2} Long:{3}", pointA.X, pointA.Y, pointA.Latitude, pointA.Longitude), true);
LogResults(String.Format("pointB X:{0} Y:{1} Lat:{2} Long:{3}", pointB.X, pointB.Y, pointB.Latitude, pointB.Longitude), true);
LogResults(String.Format("pointC X:{0} Y:{1} Lat:{2} Long:{3}", pointC.X, pointC.Y, pointC.Latitude, pointC.Longitude), true);
LogResults(String.Empty, true);
}
public void LogResults(string message, bool insertNewline)
{
txtResults.Text += message + (insertNewline ? Environment.NewLine : String.Empty);
}
}
public class MyPoint
{
public int X;
public int Y;
public double Latitude = 0;
public double Longitude = 0;
public MyPoint(int x, int y)
{
X = x;
Y = y;
}
public MyPoint(int x, int y, double latitude, double longitude) : this(x, y)
{
Latitude = latitude;
Longitude = longitude;
}
}
Results:
pointA X:0 Y:0 Lat:10 Long:10
pointB X:100 Y:100 Lat:40 Long:40
pointC X:20 Y:40 Lat:16 Long:22 // C.X is 20% of the way from A.X to B.X, so C.Lat is 20% of the way from A.Lat to B.Lat, Y/Long are 40%
pointA X:0 Y:0 Lat:10 Long:10
pointB X:100 Y:100 Lat:40 Long:40
pointC X:0 Y:0 Lat:10 Long:10 // C.X = A.X and C.Y = A.Y, therefore C.Lat and C.Long = A.Lat and A.Long
pointA X:0 Y:0 Lat:10 Long:10
pointB X:100 Y:100 Lat:40 Long:40
pointC X:100 Y:100 Lat:40 Long:40 // C.X = B.X and C.Y = B.Y, therefore C.Lat and C.Long = B.Lat and B.Long
It cant be done with code above i wrote. Constant EARTH_RADIUS MUST me implemented in function for calculation, if we want to get high precision (6 digits at least: n,mmmmmm). Next code will scale proper lat/lon per pixel, so calculated point C will match referent points A and B when we put that (X,Y) cords which points A and B have.
public void ComputeLatitudeAndLogitude(Wpf_Maps.Point point){
double diffLatAB = pointB.Latitude - pointA.Latitude;
double diffLonAB = pointB.Longitude - pointA.Longitude;
int diffXAB = pointB.X - pointA.X;
int diffYAB = pointB.Y - pointA.Y;
int diffXAC = point.X - pointA.X;
int diffYAC = point.Y - pointA.Y;
point.Latitude = diffLatAB / diffXAB * diffXAC + pointA.Latitude;
point.Longitude = diffLonAB / diffYAB * diffYAC + pointA.Longitude;
}
I have stored numerical data in lists with its coordinates (xValues, yValues), and if I want to compare (add, subtract, divide...) that set of data to another I have to be aware of that I can't compare if the xValues don't match (because there is nothing to compare with). So I need to interpolate linearly between the "missing" xValues, that actually exist in the other set and generate new points. Please check this picture:
The cyan squares on the red line represent the stored points (xValues2), and (generally) they won't match the other's set xValues (xValues1). The two squares on the green line are examples of the desired generated points. With them I can work with this two graphs without problem.
For linear interpolation It's pretty straightforward: If I have two points (x0,y0) and (x1,y1) and I want to add a new point between them given a "x2":
y2=y0+(x2-x0)*(y1-y0)/(x1-x0)
To make this work I think I have to implement something like this:
Create new lists (xValuesNew, yValuesNew).
Make a union between xValues1 and xValues2 (xValuesNew).
Check what are the differences between the original xValues1 and the xValuesNew.
For each new value found generate the "y" using the formula written above.
Put that 4 steps in a method and use it again but now with the set2.
I've been on this all day, trying to find an easy solution, maybe using Linq or lambda expressions but I'm not used to work with them and my lack of knowledge on that topics ishuge. Note that this operation will be made pretty often so I have to make it not too heavy. I've thought that it will be a good idea to generate a new list instead inserting points in the middle of the original for that reason.
Please if someone could guide me a little bit or tell me if there is a math library actually doing this would be great. Thank you.
EDIT: Sorry if I haven't explained me properly.
Here I have an example (done in Excel):
Note that I can't directly add together Series1 and Series2 (+) or any other operation because the X spacing in them is different. So what I want is to generate a new point in the Series1 when is needed.
For that I would like to simple use a linear interpolation. Say that I have P1(0,40) and P2(0,60) in series1, but in series2 I have a point (1,10). I need to generate a point P3 between P1 and P2 with (1,50) coordinates.
I was trying to do this with SkipWhile and comparing the next X value of both series, if XValue of series1 is lower, then add that XValue and corresponding YValue in the newSeries. Else use the XValue2 for generating an Y and add it to the newSeries. Here is one of my attempts (doesn't work):
List<double> series1X = new List<double> { 0, 2, 4, 6, 8 };
List<double> series1Y = new List<double> { 120, 100, 110, 105, 70 };
List<double> series2X = new List<double> { 0, 1, 7, 8,9 };
List<double> newSeries1X = new List<double>();
List<double> newSeries1Y = new List<double>();
double lastX1 = series1X[series1X.Count()-1];
int i = 0;
while (next1X <= lastX1)
{
next2X = series2X.SkipWhile(p => p <= next1X).First();
Console.WriteLine(next2X.ToString());
if (next1X <= next2X)
{
newSeries1X.Add(series1X[i]);
newSeries1Y.Add(series1Y[i]);
}
if (next2X < next1X)
{
while (next2X < next1X)
{
newSeries1X.Add(next2X);
newY = series1Y[i] + (next2X - series1X[i]) * (series1Y[i + 1] - series1Y[i]) / (series1X[i + 1] - series1X[i]);
newSeries1Y.Add(newY);
next2X = series2X.SkipWhile(p => p <= next2X).First();
}
}
next1X = series1X.SkipWhile(p => p <= next2X).First();
Console.WriteLine(next1X.ToString());
i++;
}
It would be AWESOME to do this with your Zip method. But I have no idea how to write that condition in the predicate.
First off, I'd probably use an appropriate 'point' class that contains both the x and y coordinates instead of two separate lists for each coordinate. Then you can use the Zip method to quickly iterate through them:
IEnumerable<PointF> points0 = ...
IEnumerable<PointF> points0 = ...
float x2 = ...
IEnumerable<PointF> newPoints = point0.Zip(points1,
(p0, p1) => new PointF(p0.X, p0.Y + (x2-p0.X) * (p1.Y-p0.Y) / (p1.X-p0.X)));
This makes it easy to calculate a new set of points from your input data. If you just care about a single y-value, you can still do this with your current data, it will just look weird:
IEnumerable<double> y2values =
xValues1.Zip(yValues1, (x, y) => new { x, y }).Zip(
xValues2.Zip(yValues2, (x, y) => new { x, y }),
(p0, p1) => p0.y + (x2-p0.x) * (p1.y-p0.y) / (p1.x-p0.x));
I appologize if in the process of coding this answer I somehow mangled your math.
Update
Now that I have a better grasp on what you're trying to do, I don't think any Linq method will work out quite right. Here what I've come up with using indexes:
List<double> series1X = new List<double> { 0, 2, 4, 6, 8 };
List<double> series1Y = new List<double> { 120, 100, 110, 105, 70 };
List<double> series2X = new List<double> { 0, 1, 7, 8, 9 };
// in the worst case there are n + m new points
List<double> newSeries1X = new List<double>(series1X.Count + series2X.Count);
List<double> newSeries1Y = new List<double>(series1X.Count + series2X.Count);
int i = 0, j = 0;
for ( ; i < series1X.Count && j < series2X.Count; )
{
if (series1X[i] <= series2X[j])
{
newSeries1X.Add(series1X[i]);
newSeries1Y.Add(series1Y[i]);
if (series1X[i] == series2X[j])
{
j++;
}
i++;
}
else
{
int k = (i == 0) ? i : i - 1;
// interpolate
double y0 = series1Y[k];
double y1 = series1Y[k + 1];
double x0 = series1X[k];
double x1 = series1X[k + 1];
double y = y0 + (y1 - y0) * (series2X[j] - x0) / (x1 - x0);
newSeries1X.Add(series2X[j]);
newSeries1Y.Add(y);
j++;
}
}
for ( ; i < series1X.Count; i++)
{
newSeries1X.Add(series1X[i]);
newSeries1Y.Add(series1Y[i]);
}
for ( ; j < series2X.Count; j++)
{
// interpolate
double y0 = series1Y[i - 2];
double y1 = series1Y[i - 1];
double x0 = series1X[i - 2];
double x1 = series1X[i - 1];
double y = y0 + (y1 - y0) * (series2X[j] - x0) / (x1 - x0);
newSeries1X.Add(series2X[j]);
newSeries1Y.Add(y);
}
Output is
newSeries1X = { 0, 1, 2, 4, 6, 7, 8, 0 }
newSeries1Y = { 120, 110, 100, 110, 105, 87.5, 70, 52.5 }
This solution handles cases where the first series2X[0] < series1X[0] and when series2X[n] > series1X[m] by linearly 'projecting' the data outward from the first / last pair of points.
Here's another solution using enumerators (mostly), but it's not nearly as elegant as I'd hoped it would be. It could probably be improved a bit:
bool hasS1 = true, hasS2 = true, preinterp = true;
double x0 = 0, y0 = 0, x1 = 0, y1 = 0, x = 0, y = 0;
using(var s1xEnumerator = series1X.GetEnumerator())
using(var s1yEnumerator = series1Y.GetEnumerator())
using(var s2xEnumerator = series2X.GetEnumerator())
{
hasS1 = s1xEnumerator.MoveNext();
hasS2 = s2xEnumerator.MoveNext();
s1yEnumerator.MoveNext();
while(hasS1 && hasS2)
{
x1 = s1xEnumerator.Current;
y1 = s1yEnumerator.Current;
x = s2xEnumerator.Current;
if (x1 <= x)
{
newSeries1X.Add(x1);
newSeries1Y.Add(y1);
hasS1 = s1xEnumerator.MoveNext();
s1yEnumerator.MoveNext();
preinterp = false;
if (hasS1)
{
x0 = x1;
y0 = y1;
}
if (x1 == x)
{
hasS2 = s2xEnumerator.MoveNext();
}
}
else
{
// we have to look ahead to get the next interval to interpolate before x0
if (preinterp)
{
x0 = x1;
y0 = y1;
x1 = series1X[1]; // can't peek with enumerator
y1 = series1Y[1];
preinterp = false;
}
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
newSeries1X.Add(x);
newSeries1Y.Add(y);
hasS2 = s2xEnumerator.MoveNext();
}
}
while(hasS1)
{
newSeries1X.Add(s1xEnumerator.Current);
newSeries1Y.Add(s1yEnumerator.Current);
hasS1 = s1xEnumerator.MoveNext();
s1yEnumerator.MoveNext();
}
while(hasS2)
{
x = s2xEnumerator.Current;
y = y0 + (y1 - y0) * (x - x0) / (x1 - x0);
newSeries1X.Add(x);
newSeries1Y.Add(y);
hasS2 = s2xEnumerator.MoveNext();
}
}
For working with two series with different spacing I first need to generate points in the first set, then in the second (with the same method) and finally sum point to point.
Here is the code for that method:
using OxyPlot.Series;
using OxyPlot;
namespace Algorithm1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<DataPoint> S1 = new List<DataPoint> ();
List<DataPoint> S2 = new List<DataPoint>();
List<DataPoint> NS1 = new List<DataPoint>();
S1.Add(new DataPoint(4, 10));
S1.Add(new DataPoint(6, 20));
S1.Add(new DataPoint(8, 15));
S1.Add(new DataPoint(9, 70));
S1.Add(new DataPoint(10, 5));
S2.Add(new DataPoint(1, 0));
S2.Add(new DataPoint(2, 0));
S2.Add(new DataPoint(3, 0));
S2.Add(new DataPoint(6, 0));
S2.Add(new DataPoint(7, 0));
S2.Add(new DataPoint(8.1, 0));
S2.Add(new DataPoint(8.2, 0));
S2.Add(new DataPoint(8.3, 0));
S2.Add(new DataPoint(8.4, 0));
S2.Add(new DataPoint(9, 0));
S2.Add(new DataPoint(9.75, 0));
S2.Add(new DataPoint(11, 0));
S2.Add(new DataPoint(12, 0));
S2.Add(new DataPoint(16, 0));
NS1 = GetMiddlePoints(S1, S2);
foreach (DataPoint pointin NS1)
{
MessageBox.Show( point.X.ToString()+" : "+ point.Y.ToString());
}
}
#region GetMiddlePoints
private List<DataPoint> GetMiddlePoints(List<DataPoint> S1, List<DataPoint> S2)
{
List<DataPoint> NS1 = new List<DataPoint>();
int i = 0;
int j = S2.TakeWhile(p => p.X < S1[0].X).Count();
int PointsInS1 = S1.Count;
int PointsInS2 = S2.Count;
DataPoint newPoint = new DataPoint();
while (i < PointsInS1 )
{
if (j < PointsInS2 )
{
if (S1[i].X < S2[j].X)
{
newPoint = S1[i];
NS1.Add(newPoint );
i++;
}
else if (S1[i].X == S2[j].X)
{
newPoint = S1[i];
NS1.Add(newPoint );
i++;
j++;
}
else if (S1[i].X > S2[j].X)
{
newPoint .X = S2[j].X;
newPoint .Y = S1[i-1].Y + (S2[j].X - S1[i-1].X) * (S1[i].Y - S1[i-1].Y) / (S1[i].X - S1[i-1].X);
NS1.Add(newPoint );
j++;
}
}
if (j == PointsInS2 )
{
newPoint = S1[i];
NS1.Add(newPoint );
i++;
}
}
return NS1;
}
#endregion
}
}
Imagagine I have a polygon like the following:
I am looking for a C# algorithm with whom I can find a point (could be the middlepoint or also a random point) inside any polygon.
For finding the center of mass I used the following algorithm:
private Point3d GetPolyLineCentroid(DBObject pObject, double pImageWidth, double pImageHeight)
{
Point2d[] pointArray = GetPointArrayOfRoomPolygon(pObject);
double centroidX = 0.0;
double centroidY = 0.0;
double signedArea = 0.0;
double x0 = 0.0; // Current vertex X
double y0 = 0.0; // Current vertex Y
double x1 = 0.0; // Next vertex X
double y1 = 0.0; // Next vertex Y
double a = 0.0; // Partial signed area
int i = 0;
for (i = 0; i < pointArray.Length - 1; ++i)
{
x0 = pointArray[i].X;
y0 = pointArray[i].Y;
x1 = pointArray[i + 1].X;
y1 = pointArray[i + 1].Y;
a = x0 * y1 - x1 * y0;
signedArea += a;
centroidX += (x0 + x1) * a;
centroidY += (y0 + y1) * a;
}
x0 = pointArray[i].X;
y0 = pointArray[i].Y;
x1 = pointArray[0].X;
y1 = pointArray[0].Y;
a = x0 * y1 - x1 * y0;
signedArea += a;
centroidX += (x0 + x1) * a;
centroidY += (y0 + y1) * a;
signedArea *= 0.5;
centroidX /= (6.0 * signedArea);
centroidY /= (6.0 * signedArea);
Point3d centroid = new Point3d(centroidX, centroidY, 0);
return centroid;
}
This works good with polygones like this:
But if my polygon has the form of a C or something like that this algorithmn does not work because the center off mass is outside the polygon.
Does anyone has an idea how to get always points inside any polygon?
You can use polygon triangulation to break your polygon apart into triangles.
One such algorithm is demonstrated using c# in this CodeProject article.
Once you have triangles, finding arbitrary points that lie within the triangle is easy. Any barycentric coordinate with a sum of 1.0 multiplied by the vertices of the triangle will give you a point inside the triangle.
The center can be derived using the barycentric coordinate [0.333333, 0.333333, 0.333333] :
float centerX = A.x * 0.333333 + B.x * 0.333333 + C.x * 0.3333333;
float centerY = A.y * 0.333333 + B.y * 0.333333 + C.y * 0.3333333;
or more simply:
float centerX = (A.x + B.x + C.x) / 3f;
float centerY = (A.y + B.y + C.y) / 3f;
Use This:
private Point getCentroid(pointArray)
{
double centroidX = 0.0;
double centroidY = 0.0;
for (int i = 0; i < pointArray.Length; i++)
{
centroidX += pointArray[i].X;
centroidY += pointArray[i].Y;`
}
centroidX /= pointArray.Length;
centroidY /= pointArray.Length;
return(new Point(centroidX ,centroidY));
}
this code is just to find Center of Mass of Polygon. To check whether a point is inside or outside polygon check this link http://bbs.dartmouth.edu/~fangq/MATH/download/source/Determining%20if%20a%20point%20lies%20on%20the%20interior%20of%20a%20polygon.htm
I posted a previous question about generating a bezier curve based on only the start and end points, and I was able thanks to the answers in that create a bezier curve using the information I have.
This is the code that allows me to draw the types of curve that I want on a form.
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
Random rnd = new Random();
Point startp = new Point(rnd.Next(0, this.Width), rnd.Next(0, this.Height));
Point endp = new Point(rnd.Next(0, this.Width), rnd.Next(0, this.Height));
int xMod = 0;
int yMod = 0;
if (startp.X > endp.X) {
xMod = -1;
} else {
xMod = 1;
}
if (startp.Y > endp.Y) {
yMod = 1;
} else {
yMod = -1;
}
Point control1p = new Point(endp.X + (rnd.Next(20, 50) * xMod), endp.Y + (rnd.Next(20, 50) * yMod));
Point control2p = new Point(endp.X + (rnd.Next(5, 20) * xMod), endp.Y + (rnd.Next(5, 20) * yMod));
Point[] pts = {
startp,
control1p,
control2p,
endp
};
Pen dashed_pen = new Pen(Color.Black, 0);
dashed_pen.DashStyle = Drawing2D.DashStyle.Dash;
for (int i = 0; i <= 2; i++) {
e.Graphics.DrawLine(dashed_pen, pts(i), pts(i + 1));
}
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality;
Pen bez_pen = new Pen(Color.Black, 3);
e.Graphics.DrawBezier(bez_pen, pts(0), pts(1), pts(2), pts(3))
}
Is there a way, or can someone help me with returning all the points that form the curve? I'd like for each point of a curve calculated from those points to be returned in an array of points, but I'm having no luck figuring it out, and haven't been able to find a similar solution on stackoverflow or google in general.
Thanks.
What you want to do is to convert a Bezier Curve (Cubic from the looks of it) into a Polyline
Use the Equation on this page...Value of t should be between 0 to 1...Calculate all values of Bx(t) and By(t) by using the equation for values of t in increments of "0, 0.01, 0.02....1" (Convert them to integers of course) The smaller your increments, the more accurate your points will be.
Here's a C Sample of the DeCasteljau Algorithm (almost the same procedure, but its a bit optimized i believe) :)
Perfect algorithm for creating smooth Bezier curve with optimal number of points is described by Maxim Shemanarev on Anti-Grain Geometry page: Adaptive Subdivision of Bezier Curves.
It may help if you use a lerp or float t derivatives in-between the draw bezier. I've found it helps with accuracy; considering the number of float calcs .
I know this is an old post, but, having found none of the current answers all that satisfying, hopefully others will get some use out of the following:
using System.Collections.Generic;
using System.Drawing;
public List<Point> CubicBezierToPoints(Point P0, Point P1, Point P2, Point P3, double step = 0.01)
{
var pointList = new List<Point>();
for (var t = 0.00; t <= 1; t += step)
{
var x = Math.Pow(1 - t, 3) * P0.X + 3 * Math.Pow(1 - t, 2) * t * P1.X +
3 * (1 - t) * Math.Pow(t, 2) * P2.X + Math.Pow(t, 3) * P3.X;
var y = Math.Pow(1 - t, 3) * P0.Y + 3 * Math.Pow(1 - t, 2) * t * P1.Y +
3 * (1 - t) * Math.Pow(t, 2) * P2.Y + Math.Pow(t, 3) * P3.Y;
pointList.Add(new Point((int)x,(int)y));
}
return pointList;
}