It would be much better if you explained your problem in more detail, and explained your code a bit, since your function names are not in English, so it's hard for those of us who don't speak your language to navigate around your source. You could have at least provided some comments.
Anyway here you go - attached the modified project below.
This is what I did: essentially, I stretched a circular path to create an elliptical one.
I made some changes to your approach. In computer graphics, it's much better to keep the original data point as reference, untransformed (always at their original) location, and then get a new set of points on each frame by applying a transformation to the originals. So, I abandoned your 1deg-by-1deg transformation, and introduced additional set of points specifically for drawing, so that the original points don't have to change. Then I maintain an angle variable, which I update on your timer tick, by some increment (but I also keep it in the [0, 2Pi) range, once it's over 2Pi).
This is the important bit. I first calculate point - center, which effectively puts the center at the origin (0, 0), to make the calculations simpler. Then I basically use your rotation code, without the second part of the equation related to the center point. This rotates the square figure, and it's points trace a circle. (Note that you could have used matrices for this - .Net comes with a 2D transform matrix capabilities, see: Matrix class, in the System.Drawing.Drawing2D namespace).
After I rotate the point, I simply translate its Y-component by (ellipse_radius1 - ellipse_radius2) * sin(angle), which squashes (or stretches) the circular path vertically, into an ellipse. This is because when the angle is horizontal sin(0deg) = sin(180deg) = 0, and when the angle is vertical sin(90deg) = -sin(270deg) = 1.
Once that's done, I show you how to rotate the elliptical path itself: you simply need to apply the rotate transformation one more tme, but this time using the pathAngle as the current angle.
Finally, since all this was done about the origin, I translate the whole thing back to the center point (or rotation anchor point, if you will).
Code:
private PointF XoayDiemTamC(PointF p, PointF c, double a, double pathAngle)
{
PointF Q = new PointF();
// position vector = point - center; (puts the center at the origin)
Q = PointF.Subtract(p, new SizeF(c));
// don't transform if p = c
if ((-0.0001 < Q.X && Q.X < 0.0001) && (-0.0001 < Q.Y && Q.Y < 0.0001)) // Q.X == 0 && Q.Y == 0 might not work for floats
return p;
// path location (on a circle)
p.X = Q.X * (float)Math.Cos(a) - Q.Y * (float)Math.Sin(a);
p.Y = Q.X * (float)Math.Sin(a) + Q.Y * (float)Math.Cos(a);
p.Y -= (c_radius1 - c_radius2) * (float)Math.Sin(a); // scales the circle vertically to make an ellipse
// rotates the path itself
float x = p.X;
float y = p.Y;
p.X = x * (float)Math.Cos(pathAngle) - y * (float)Math.Sin(pathAngle);
p.Y = x * (float)Math.Sin(pathAngle) + y * (float)Math.Cos(pathAngle);
// translate back to center
p = PointF.Add(p, new SizeF(c));
return p;
}
I also slightly reorganized your code, added some constants, and made use of the Main_Paint handler, so as to eliminate flicker, draw the elliptical path, etc...
P.S. PointF is a struct (that is, a value type), which means that it's passed around by value (a copy is made). So when you pass one to a method, changing the properties of the parameter will not affect the original point, since it's a copy (unless the method uses the ref keyword).
Last edited by TheGreatCthulhu; August 7th, 2012 at 09:26 PM.
It would be much better if you explained your problem in more detail, and explained your code a bit, since your function names are not in English, so it's hard for those of us who don't speak your language to navigate around your source. You could have at least provided some comments.
Anyway here you go - attached the modified project below.
This is what I did: essentially, I stretched a circular path to create an elliptical one.
I made some changes to your approach. In computer graphics, it's much better to keep the original data point as reference, untransformed (always at their original) location, and then get a new set of points on each frame by applying a transformation to the originals. So, I abandoned your 1deg-by-1deg transformation, and introduced additional set of points specifically for drawing, so that the original points don't have to change. Then I maintain an angle variable, which I update on your timer tick, by some increment (but I also keep it in the [0, 2Pi) range, once it's over 2Pi).
This is the important bit. I first calculate point - center, which effectively puts the center at the origin (0, 0), to make the calculations simpler. Then I basically use your rotation code, without the second part of the equation related to the center point. This rotates the square figure, and it's points trace a circle. (Note that you could have used matrices for this - .Net comes with a 2D transform matrix capabilities, see: Matrix class, in the System.Drawing.Drawing2D namespace).
After I rotate the point, I simply translate its Y-component by (ellipse_radius1 - ellipse_radius2) * sin(angle), which squashes (or stretches) the circular path vertically, into an ellipse. This is because when the angle is horizontal sin(0deg) = sin(180deg) = 0, and when the angle is vertical sin(90deg) = -sin(270deg) = 1.
Once that's done, I show you how to rotate the elliptical path itself: you simply need to apply the rotate transformation one more tme, but this time using the pathAngle as the current angle.
Finally, since all this was done about the origin, I translate the whole thing back to the center point (or rotation anchor point, if you will).
Code:
private PointF XoayDiemTamC(PointF p, PointF c, double a, double pathAngle)
{
PointF Q = new PointF();
// position vector = point - center; (puts the center at the origin)
Q = PointF.Subtract(p, new SizeF(c));
// don't transform if p = c
if ((-0.0001 < Q.X && Q.X < 0.0001) && (-0.0001 < Q.Y && Q.Y < 0.0001)) // Q.X == 0 && Q.Y == 0 might not work for floats
return p;
// path location (on a circle)
p.X = Q.X * (float)Math.Cos(a) - Q.Y * (float)Math.Sin(a);
p.Y = Q.X * (float)Math.Sin(a) + Q.Y * (float)Math.Cos(a);
p.Y -= (c_radius1 - c_radius2) * (float)Math.Sin(a); // scales the circle vertically to make an ellipse
// rotates the path itself
float x = p.X;
float y = p.Y;
p.X = x * (float)Math.Cos(pathAngle) - y * (float)Math.Sin(pathAngle);
p.Y = x * (float)Math.Sin(pathAngle) + y * (float)Math.Cos(pathAngle);
// translate back to center
p = PointF.Add(p, new SizeF(c));
return p;
}
I also slightly reorganized your code, added some constants, and made use of the Main_Paint handler, so as to eliminate flicker, draw the elliptical path, etc...
P.S. PointF is a struct (that is, a value type), which means that it's passed around by value (a copy is made). So when you pass one to a method, changing the properties of the parameter will not affect the original point, since it's a copy (unless the method uses the ref keyword).
The first, i'm so sorry if my post wrong forum'rules, i'm sorry guy, i will learn what you say.
So, thank you, very very and gratefull, i love this forum, i will visit more, so more. Thank guy again,
BTW, I just wanted to add that to get the elliptical path itself, you don't have to use
p.Y -= (c_radius1 - c_radius2) * (float)Math.Sin(a)
you can simply multiply the Y-component with a scale factor:
p.Y = p.Y * c_radius2/c_radius1 //---(where c_radius2/c_radius1 < 1)
But this only works to get the location on the path. in your case, since you're transforming all the points, this will squash the square figure itself, as well as the circle. What you can do is to define the square separately, in so-called object-space, rotate it there by the appropriate amount, and than translate it's "pivot point" to the location on the ellipse, in world-space. Another potential problem is that the square figure orients itself as if it was still on a circular path, which is the most apparent when the eccentricity is high. You can get the normal vector to a point on an ellipse made from a vertically squashed circle by stretching the same circle, along with the appropriate radius vector by the same amount (c_radius1/c_radius2), and then normalizing the radius vector.
Once normalized, than sin(figureAngle) = normal.Y, and cos(figureAngle) = normal.X.
So if: circle:
x = cos(a);
y = sin(a);
ellipse:
x = circle.x;
y = circle.y * c_radius2/c_radius1;
Then: normal:
x = circle.x;
y = circle.y * c_radius1/c_radius2;
or:
x = circle.x * c_radius2/c_radius1;;
y = circle.y * c_radius1/c_radius2 * c_radius2/c_radius1;
BTW, I just wanted to add that to get the elliptical path itself, you don't have to use
p.Y -= (c_radius1 - c_radius2) * (float)Math.Sin(a)
you can simply multiply the Y-component with a scale factor:
p.Y = p.Y * c_radius2/c_radius1 //---(where c_radius2/c_radius1 < 1)
But this only works to get the location on the path. in your case, since you're transforming all the points, this will squash the square figure itself, as well as the circle. What you can do is to define the square separately, in so-called object-space, rotate it there by the appropriate amount, and than translate it's "pivot point" to the location on the ellipse, in world-space. Another potential problem is that the square figure orients itself as if it was still on a circular path, which is the most apparent when the eccentricity is high. You can get the normal vector to a point on an ellipse made from a vertically squashed circle by stretching the same circle, along with the appropriate radius vector by the same amount (c_radius1/c_radius2), and then normalizing the radius vector.
Once normalized, than sin(figureAngle) = normal.Y, and cos(figureAngle) = normal.X.
So if: circle:
x = cos(a);
y = sin(a);
ellipse:
x = circle.x;
y = circle.y * c_radius2/c_radius1;
Then: normal:
x = circle.x;
y = circle.y * c_radius1/c_radius2;
or:
x = circle.x * c_radius2/c_radius1;;
y = circle.y * c_radius1/c_radius2 * c_radius2/c_radius1;