Reputation: 753
I am using the c++ code below to calculate 360 points around the outside of an ellipse which I draw on a canvas. I set the size of the ellipse by selecting a left and right edge as x1, y1, x2, y2. When the ellipse is calculated with a horizontal major axis which is zero degrees the ellipse touches the left and right edge. When I calculate the ellipse with a 45 degree major axis the top and bottom of the ellipse no longer touch the left and right edges. I need to draw the ellipse at an angle so it touches the left and right boundary. To do this I need to draw the ellipse larger but I do not know how to calculate the larger size. Is there a way to calculate the larger size ellipse so the angled ellipse will touch the original left and right boundaries?
double x1=0, y1=0, x2=0, y2=0, x3=0, y3=0, phi=0;
int ZeroX=0, ZeroY=0;
int NUM_POINTS_PER_CONTOUR = 360;
int p=0;
int Major_Axis_Center_X=0, Full_Major_Axis_X=0;
int Major_Axis_Center_Y=0, Full_Major_Axis_Y=0;
int Full_Minor_Axis_X=0;
double AngleOfMajorAxis=0;
UnicodeString temp;
struct ell {
double a; //e.a is semi-major size
double b; //e.b is semi-minor size
double theta;
double x0; //major axis center X
double y0; //major axis center Y
} e;
//seed Values
x1=50; x2=250;
y1=75; y2=275;
//Vertical Line LEFT edge
Canvas->MoveTo(x1, y1);
Canvas->LineTo(x1, y2);
//Vertical Line RIGHT edge
Canvas->MoveTo(x2, y1);
Canvas->LineTo(x2, y2);
Full_Major_Axis_X = (x2 - x1);
Full_Major_Axis_Y = (y2 - y1);
Major_Axis_Center_X = (x1 + (Full_Major_Axis_X/2));
Major_Axis_Center_Y = (y2 - (Full_Major_Axis_Y/2));
Full_Minor_Axis_X = (Full_Major_Axis_X/2);
//Seed values
e.a = (Full_Major_Axis_X/2); //e.a is semi-major size
e.b = (Full_Minor_Axis_X/2); //e.b is semi-minor size
e.x0 = Major_Axis_Center_X;
e.y0 = Major_Axis_Center_Y;
AngleOfMajorAxis = 45.0;
e.theta = DegToRad(AngleOfMajorAxis);
//Calculate 360 points around edge of ellipse
for (p=0; p<NUM_POINTS_PER_CONTOUR; p++) {
phi = p*2*M_PI/(double)NUM_POINTS_PER_CONTOUR;
x1 = e.a * std::sin(phi);
y1 = e.b * std::cos(phi);
x2 = x1 * std::cos(e.theta) + y1 * std::sin(e.theta);
y2 = y1 * std::cos(e.theta) - x1 * std::sin(e.theta);
x3 = x2 + e.x0;
y3 = y2 + e.y0;
if(p==0){
Canvas->MoveTo(x3, y3);
}
Canvas->LineTo(x3, y3);
}
EDIT: Here is the best answer
I have added the two lines of code above my for loop
phiMax = atan(e.b/e.a * std::tan(e.theta)); // {1}
Coeff = e.a / (e.a * std::cos(phiMax) * std::cos(e.theta) + e.b * std::sin(phiMax) * std::sin(e.theta)); // {2}
Now I add the Coeff into the for loop
//Calculate 360 points around edge of ellipse
for (p=0; p<NUM_POINTS_PER_CONTOUR; p++) {
phi = p*2*M_PI/(double)NUM_POINTS_PER_CONTOUR;
x1 = Coeff * e.a * std::sin(phi);
y1 = Coeff * e.b * std::cos(phi);
x2 = x1 * std::cos(e.theta) + y1 * std::sin(e.theta);
y2 = y1 * std::cos(e.theta) - x1 * std::sin(e.theta);
x3 = x2 + e.x0;
y3 = y2 + e.y0;
if(p==0){
Canvas->MoveTo(x3, y3);
}
Canvas->LineTo(x3, y3);
}
The result is that the widest part of the ellipse always touches the left and right boundary. This is the simplest and closest answer. The picture below shows a 65 degree ellipse adjusted to touch the boundaries.
Upvotes: 1
Views: 936
Reputation: 80325
Ellipse centered at (0,0)
, rotated by t
(your theta
), has equation for x-coordinate
x = a * cos(phi) * cos(t) + b * sin(phi) * sin(t)
Extremal points (left and right) are reached when derivative is zero x'=0
dx/dphi = - a * sin(phi) * cos(t) + b * cos(phi) * sin(t) = 0
a * sin(phi) * cos(t) = b * cos(phi) * sin(t)
tg(phi) = b/a * tg(t)
phiMax = atan(b/a * tg(t)) {1}
Substitute this value in the first equation and find coefficient for enlargement (extremal semi-size should be equal to the semi-axis)
Coeff * (a * cos(phiMax) * cos(t) + b * sin(phiMax) * sin(t)) = a
Coeff = a / (a * cos(phiMax) * cos(t) + b * sin(phiMax) * sin(t)) {2}
Now you can implement formulas {1}
and {2}
and use this coefficient in your calculations like this:
x1 = Coeff * e.a * std::sin(phi);
y1 = Coeff * e.b * std::cos(phi);
Upvotes: 3
Reputation: 3938
If your lines are some distance d
apart, for an ellipse of eccentricity e
the length of the semi-major axis a
can be given by a = d / 2 (1 - e^2 * sin^2 (theta))
, where theta
is the angle of rotation for the ellipse.
For example, an angle of 0
gives a = d/2
, which is true by definition. In the case of an angle of pi/4
, or 45 degrees
, this translates to a = d / (2 - e^2)
.
I'm not entirely sure if this is correct, but I'll edit this post in a little while so you can check my work, if you like.
Also, in case you didn't know, the eccentricity of an ellipse can be given by e^2 = 1 - (b/a)^2
, where a
and b
are semi-major and semi-minor axis lengths, respectively. It is value between 0 and 1, for an ellipse.
EDIT: Corrected formula
Upvotes: 1
Reputation: 7925
What I think would help you is if you take a look at your first illustration you could use an origin point of (x,y) that bisects the original ellipse in both the x & y directions so that you have two lines of symmetry along the x and y axis. You will then have 4 points of interest on your original ellipse, these will be where the ellipse intersects or touches both the +x & -x axis as well as the +y & -y axis. This will give you 2 radius for this ellipse a short and a long radius. You can and will need to use these for reference and calculations; after you rotate your ellipse I imagine from its origin (center point) you will then need to use some trigonometry and vector algebra to determine the difference in length of vectors from your ellipse's edge point on the 45 degree line of rotation that intersects with your vertical line (x2y1, x2y2) to find this distance once you know the distance then using some vector calculations you should be able to figure out how much to skew this ellipse until it has an edge point that touches this vertical line. You shouldn't have to worry about your other vertical line (x1y1, x2y1) since we rotated from the origin bisector of this ellipse and that there are 2 lines of symmetry. You can do all of these calculations preprocess. Once you have the new coordinates for all of the rotated - skewed points then you can refresh your update or drawing buffer of points. I'll try to demonstrate this with a couple of images:
To find the distance of P2 - P1 should be fairly easy. You should already know the x value of your vertical line; and to find the y value of the line of rotation should be easy since you said it is a 45 degree rotation it has a slope of one which the equation for this line is y = x. This should give you P2 fairly quickly with minimal computation. To find P1 it should be almost as easy since it is once again along the line of y = x, and you know the size of the long radius of this ellipse. Then you subtract the two points to give you this distance. From there you can use this distance to know how much to skew or stretch this ellipse along the line y = x. Then recalculate all of your points and update your drawing buffer using the newly calculated points based off of your skew values. Now there are two ways to skew this; one is where the short radius doesn't change and it just gets longer and looks more stretched while the other is a proportional skew where if the long radius gets larger so does the short radius in a proportionate manner. I will leave that for you to determine how you want to skew this object.
Upvotes: 0