24 Replies Latest reply on Mar 24, 2011 6:01 AM by Andrei1

Math trouble ! Help !

I try to calculate all the points on a curve.

The curve decided by the width(X on the picture) and height(Y on the picture) properties of a movieclip.

The distance between each green point on curve is the same.

• 1. Re: Math trouble ! Help !

It depends...

1. Is curve a part of circle or bezier?

2. If circle - how are you dealing with radius. Is height always aligned with vertical radius when height less than width and vs.?

• 2. Re: Math trouble ! Help !

Actually the X,Y on the picture is the width and height of an application.

For easily achieve this math, the X is always bigger than Y.

And the bezier is part of the ellipse or a circle. The number of the green points is random.

• 3. Re: Math trouble ! Help !

Bezier curve has nothing to do with line of circle or ellipse.

How  do you draw the curve code-wise?

• 4. Re: Math trouble ! Help !

I think this might be really difficult. The permimeter of an ellipse is really difficult to calculate -- it involves the sum of infinitely many terms. (http://www.numericana.com/answer/ellipse.htm) And it seems that if you are trying to space points at equal distances along the permiter then some type of measurement of the perimeter is needed. You do mean for the "a" in your drawing to mean the distance along the curve, not the straight distance between those points, right?

An approximation for the perimeter is Math.PI*(3*(a+b)-Math.SQRT((3*a+b)*(a+3*b))). In this case a is the major axis and b is the minor (x and y in your drawing since you've stated that x is always larger than y.

Other than that I'm not sure what the next steps might be.

• 5. Re: Math trouble ! Help !

Here is some code I use to draw ellipses. By manipulating the step you can create an "ellipse" shapped polygone with points at regular angles. Unfortunately the distance won't be the same, but maybe it will give you some ideas....

drawEllipse(this,500,400,250,150,0,2*Math.PI/16);

function drawEllipse(clip:MovieClip, h:Number,k:Number,a:Number,b:Number,rot:Number,step:Number){

// h,k = center offset

// a,b = major/minor axis

rot = (rot != null) ? rot : 0;

var cos:Number=Math.cos(rot);

var sin:Number=Math.sin(rot);

clip.clear();

clip.lineStyle(1,0xff0000);

clip.moveTo(h-a*cos,k-a*sin)

for(var t=-3.14;t<=3.14;t+=step){

var cosT:Number=Math.cos(t);

var sinT:Number=Math.sin(t);

clip.lineTo(h+a*cosT*cos-b*sinT*sin,k+b*sinT*cos+a*cosT*sin);

}

clip.lineTo(h-a*cos,k-a*sin)

}

• 6. Re: Math trouble ! Help !

Of course that is AS2 code and I just noticed this is the AS3 forum. But I think you can get the gist of it.

• 7. Re: Math trouble ! Help !

Thanks a lot for the code. Actually I want to create a layout as my picture.

I think the point is they have the same distance along the curve.

So may ∫[a-b] SQRT(1+y’)dx. I not sure is this correct.

• 8. Re: Math trouble ! Help !

Okay. So changed this to AS3. To see it work create a small dot movieclip and set it to export with the name of Dot. Then run this code. It will space the dots evenly around the perimeter. It isn't elegant, but it works pretty well. I'll leave taking it from a full ellipse to a quarter for you.

drawEllipse(this,500,400,250,150,0,2 * Math.PI / 100);

function drawEllipse(clip:MovieClip, h:Number, k:Number, a:Number, b:Number, rot:Number, step:Number) {

// h,k = center offset

// a,b = major/minor axis

var g:Graphics = clip.graphics;

var p:Number=Math.PI*(3*(a+b)-Math.sqrt((3*a+b)*(a+3*b)));

var l:Number = 0;

var seg:Number=p/20;

var cos:Number = Math.cos(rot);

var sin:Number = Math.sin(rot);

var dx:Number = h - a * cos;

var dy:Number = k - a * sin;

var dx1:Number = dx;

var dy1:Number = dy;

var temp:MovieClip=new Dot();

temp.x=dx;

temp.y=dy;

g.clear();

g.lineStyle(1,0xff0000);

g.moveTo(dx,dy);

for (var t = -3.14; t <= 3.14; t += step) {

var cosT:Number = Math.cos(t);

var sinT:Number = Math.sin(t);

dx = h + a * cosT * cos - b * sinT * sin;

dy = k + b * sinT * cos + a * cosT * sin;

g.lineTo(dx,dy);

l+=Math.sqrt((dx-dx1)*(dx-dx1)+(dy-dy1)*(dy-dy1));

dx1 = dx;

dy1 = dy;

if(l>=seg){

temp=new Dot();

temp.x=dx;

temp.y=dy;

l-=seg;

}

}

dx = h - a * cos;

dy = k - a * sin;

l+=Math.sqrt((dx-dx1)*(dx-dx1)+(dy-dy1)*(dy-dy1));

g.lineTo(h - a * cos,k - a * sin);

}

• 9. Re: Math trouble ! Help !

Thanks a lot Rothrock. It worked for me.

The curve show on the right-bottom corner in the application.

How can I use this function to calucate the dots like in the picture I had pose in the previous one.

The size is 1024px by 768px.

I mean what the arguments meaing?

• 10. Re: Math trouble ! Help !

h is the x value of the center of the ellipse and k is the y value. So if your stage is 1024 by 768 and you want the center of your ellipse to be in the lower right corner you would pass 1024 and 768 for those values.

a and b are the major and minor axes of the ellipse so again you should pass 1024 by 768.

rot will rotate the ellipse, but for this purpose you will want zero.

step should really probably be called stepAngle or something like that. It is the angle in radians that each step around the ellipse will go.

Finally seg measures how far around the whole perimeter you want the points. In the example I gave it a twentieth.

Also in the for loop it is giving the angle in radians, so you will want to change that to different ranges of pi.

Play around with it. You'll get it.

• 11. Re: Math trouble ! Help !

Rothrock you must be a math teacher.

Thanks !!  Thanks !!  Thanks !!

• 12. Re: Math trouble ! Help !

Hi Rothrock,

I try to put 100 dots on the curve.

```drawEllipse(this, 1024,768, 1024,768, 0, 2*Math.PI/90/100);
```

This result is I only get 2 dots. Is that correct ?

• 13. Re: Math trouble ! Help !

Nope.

drawEllipse(this,1024,768,1024,768,0,2*Math.PI/200);

Should probably be fine. To change the number of dots look for the seg definition inside the function

var seg:Number=p/100;

• 14. Re: Math trouble ! Help !

I think the problem is still there like the picture showed.

In the picture may be only a quarter of a circle.

So if I want to put 100 dots on it. I should pass 400 to the function ?

drawEllipse(this, 1024,768, 1024,768, 0, 2*Math.PI/400);

• 15. Re: Math trouble ! Help !

Hi Rothrock,

I find another formular calculate the circumference of an elliipse.

May be it can help to improve the exactness.

I have readed your code times, but I still can't understand the relation

between circumference and the dots position on the ellispe.

• 16. Re: Math trouble ! Help !

Yeah we are faking it a bit. But given the constraints of Flash (15 digit numbers and only drawing pixels) I think we don't need a better forumula than the Ramanujan approximation that I'm using here.

What we are actually doing is drawing a irregular polygon of whatever number you divide the 2pi by in the function call. So drawEllipse(this, 1024,768, 1024,768, 0, 2*Math.PI/400); makes a 400 sided polygon. Each little straight line measures out the same angle -- which in a circle would also be the same length -- but in an ellipse each of those little lines is a bit different in length. Try playing with different values of that number just to see what it does. Don't worry about the dots for a moment. Make it a number like 10 or 20 and you will see the straight lines. At a certain point the ellipse will start to look smooth and for simple drawing you wouldn't normally need to go any higher than that. But because of our added requirement of measuring the length we will need to go higher -- I'll explain more in a bit.

Then what we do inside the function is use the Ramanujan approximation (a very close approximation for practical purposes) to figure out what the actual perimeter of the given ellipse SHOULD be:

var p:Number=Math.PI*(3*(a+b)-Math.sqrt((3*a+b)*(a+3*b)));

Then I make a variable called seg (for segment length or something like that) and that is going to be the fraction of how far around the perimeter I want to go before I put a dot. So something like this:

var seg:Number=p/20;

Means every 20th of the distance (not angle, because we are dividing the perimeter not the 2pi angle around the ellipse) we will measure off a segment.

Then inside the loop I'm adding up the little lengths of all the straight lines and when that value goes over the segment distance we drop down a dot and subtract the segment distance from the total.

And this is where your trouble is coming in.

When I slapped this together I didn't know that you were going to want to put 400 dots around a whole ellipse. And if the number of dots is close to the number of sides of your polygon you will get errors. So if you divide 2pi by 400 and then you have 400 dots (I'm thinking of the whole ellipse here) the errors will be quite high and noticeable. You'll notice in my example I divided by 100 for the number of sides and 20 for the dots.

You can see the amount of inacuracy that is accumulating on each little segment by finding that condtional and after the last line adding a trace statement:

l-=seg;

trace([seg,l]);

That will show you how much each segment should be and how much over that segment went. As long as the second number is much smaller than the first you won't notice the errors.

So if you plan to have 400 dots you should probably divide the 2pi by 2000 or even higher. Of course 100 dots in one quadrant seems like an awful lot to me....

Also you might want to play with the values in the for loop. Since you are only interested in the left quadrant the following will save some computing and plotting time:

for (var t = -Math.PI; t <= -Math.PI/2; t += step)

Of course then you will probably not want to have that final line bit outside the loop that closes it up.

• 17. Re: Math trouble ! Help !

I think dealing with ellipse or bezier in this context is too cumbersome and pretty imprecise.

Code below accomplished drawing interface you want and positions point at equal intervals along the curve.Just make this class a document class.

```package
{
import flash.display.Graphics;
import flash.display.Sprite;
import flash.geom.Matrix;

public class ObjectCurve extends Sprite
{
private var container:Sprite;
// container width
private var w:Number = 500;
// container height
private var h:Number = 400;
// reusable Graphics reference
private var g:Graphics;

public function ObjectCurve()
{
init();
}

private function init():void
{
// make container
container = new Sprite();
g = container.graphics;
with (g) {
beginFill(0xEBEBEB);
drawRect(0, 0, w, h);
endFill();
}
container.x = container.y = 50;
/**
* diagonal is base of right triangle that is made of
* IMPORTANT! Center of cricle is positined at x = width of container
* radius is most important value to calculate fro this functionality
* it depends on, again, container dimensions
*/
// length of container diagonal
var diagonal:Number = Math.sqrt(w * w + h * h);
// angle of container diagonal
var diagonalAngle:Number = Math.atan2(h, -w);
// radius of the circle which will be used for calculating anlges.
var radius:Number = diagonal * .5 / Math.sin(diagonalAngle);
// angle between left buttom corner of container and center of circle
var angle:Number = Math.atan2(h - radius, -w);
var radAngle:Number = -(angle - ( -90 * Math.PI / 180));
// length of arc that will be drawn
// radian increment for each roation
var rotationIncrement:Number = radAngle * 4 / arcLength;
var matrix:Matrix = new Matrix();
matrix.createGradientBox(w, h, -45 * Math.PI / 180);
var colors:Array = [0x000000, 0x4646FF];
var alphas:Array = [1, 1];
var ratios:Array = [0x00, 0xFF];
// draw arc
g = container.graphics;
g.lineStyle(2, 0xFFFF00);
g.moveTo(0, h);
while (angle < -90 * Math.PI / 180) {
angle += rotationIncrement;
}
// finish to top right corner
g.lineTo(w, 0);
// continue drawing to make borders
g.lineTo(w, h);
g.lineTo(0, h);
// place points at equal intervals
// number of points
var numPoints:int = 10;
// number of segments based on number of points
// return angle to its original value
angle = Math.atan2(h - radius, -w);
var point:Sprite = drawPoint();
// place first point at the beginning of arc
point.x = w + radius * Math.cos(angle);
// create and place other points
for (var i:int = 0; i < numPoints; i++) {
angle += rotationIncrement;
point = drawPoint();
point.x = w + radius * Math.cos(angle);

}

}

private function drawPoint():Sprite {
var s:Sprite = new Sprite();
s.graphics.beginFill(0x00FF00);
s.graphics.drawCircle(0, 0, 5);
return s;
}

}

}
```
• 18. Re: Math trouble ! Help !

Hi Andrei1,

Your code works very well. I think it is above comprehension. I use the image show the details.

Hope you can't give some help to me to understand the codes

• 19. Re: Math trouble ! Help !

It is the opposite angle (adjacent to the right side) that is used to calculate radius.

You should try work it out backward on a conceptual level. The concept is that in order to find the radius that encompasses any rectangle's right bottom triangle (and as you see the code works with any rectangle as long as width is greater or equals to height) one needs to picture rectangle placed in a circle so that right-top corner coincides with the top of the circle and circle goes through left-bottom corner.

This way radius will coincide with the right rectangle side and is perpendicular (-90 degrees in Flash space). So, the center of the circle is somewhere in this perpendicular.

When you draw that you will see that two radiuses form right triangle with the base represented by diagonal and median that originates from the circle center is perpendicular to diagonal. Formula to calculate the radius is:

½ diagonal x sin(angle between diagonal and radius).

Once radius is found – the rest falls into place easier.

What else is unclear?.
• 20. Re: Math trouble ! Help !

Hmmm that is an interesting approach. Personally I think I would stick with my version for a couple of reasons.

Andrei1's code sin't actually drawing a quandrant of an actual ellipse. Maybe that isn't actually important for the look you are going for....

Also Andrei's solution  also seems to be very specifically tailored to the quandrant that you are currently using and that the x axis be larger than the y axis. The code I've given is more general (hence the extra complexity) and can handle partial or full ellipses and also rotate them should that be necessary in the future.

I've mashed the two different approaches into one file so you can compare the shapes. My code makes the red line and Andrei1's makes the blue line.

var container:Sprite;

var w:Number=1024;

var h:Number=768;

var g:Graphics;

var numPoints:Number=25;

init();

drawEllipse(this,1024,768,1024,768,0,2 * Math.PI / 5000);

function drawEllipse(clip:MovieClip, h:Number, k:Number, a:Number, b:Number, rot:Number, step:Number) {

g=clip.graphics;

var p:Number=Math.PI*(3*(a+b)-Math.sqrt((3*a+b)*(a+3*b)));

var l:Number=0;

var seg:Number=p/(numPoints*4);

var cos:Number=Math.cos(rot);

var sin:Number=Math.sin(rot);

var dx:Number=h-a*cos;

var dy:Number=k-a*sin;

var dx1:Number=dx;

var dy1:Number=dy;

var temp:Sprite=drawPoint();

temp.x=dx;

temp.y=dy;

g.clear();

g.lineStyle(4,0xff0000);

g.moveTo(dx,dy);

var startTime:Number=getTimer();

for (var t = -Math.PI; t <= -Math.PI/2; t += step) {

var cosT:Number=Math.cos(t);

var sinT:Number=Math.sin(t);

dx=h+a*cosT*cos-b*sinT*sin;

dy=k+b*sinT*cos+a*cosT*sin;

g.lineTo(dx,dy);

l+=Math.sqrt((dx-dx1)*(dx-dx1)+(dy-dy1)*(dy-dy1));

dx1=dx;

dy1=dy;

if (l>=seg) {

temp=drawPoint();

temp.x=dx;

temp.y=dy;

l-=seg;

}

}

dx=h-a*cos;

dy=k-a*sin;

l+=Math.sqrt((dx-dx1)*(dx-dx1)+(dy-dy1)*(dy-dy1));

}

function init():void {

container = new Sprite();

g=container.graphics;

var diagonal:Number=Math.sqrt(w*w+h*h);

var diagonalAngle:Number=Math.atan2(h,- w);

var radAngle:Number = -(angle - ( -90 * Math.PI / 180));

g.lineStyle(2, 0x0000ff);

g.moveTo(0, h);

while (angle < -90 * Math.PI / 180) {

angle += rotationIncrement;

}

var point:Sprite=drawPoint();

for (var i:int = 0; i < numPoints; i++) {

angle+=rotationIncrement;

point=drawPoint();

}

}

function drawPoint():Sprite {

var s:Sprite = new Sprite();

s.graphics.beginFill(0x00FF00);

s.graphics.drawCircle(0, 0, 4);

return s;

}

• 21. Re: Math trouble ! Help !

Rothrock,

Of course there is always a more abstract solution. In this case, I guess, it depends on how one views ellipse vs. circle vs. curves. It is acceptable to look at circle as a subset of ellipse and vice versa.

I think your solution is more flexible and it also accomplishes something that dealing with correct circle cannot – smoothness the line starts in the left bottom corner. I like  the ability to curve the line in a more dynamic way.

“Andrei1's code sin't actually drawing a quandrant of an actual ellipse.”

Can you explain what advantages does drawing quadrants of actual ellipse present?

“Also Andrei's solution  also seems to be very specifically tailored to the quandrant that you are currently using and that the x axis be larger than the y axis.”

This is not totally correct. Actually code can be easily scaled up to accommodate use cases when height is greater than width (or even rotated rectangles). The only difference is circle center position relative to the rectangle object occupies. In this sense this solution is quite universal. I just did not want to complicate things given original requirements.

“The code I've given is more general (hence the extra complexity) and can handle partial or full ellipses and also rotate them should that be necessary in the future.”

My code handles partial circle and, again, can be used should rotation is required.
• 22. Re: Math trouble ! Help !

There is no benefit to using an ellipse instead of a circle -- it just looked from the original drawing like an ellipse. So if that was the desired shape (for whatever reason) then you wouldn't be getting it.

My code isn't that much more complicated than yours and by the time you add in the bits to scale up your solution then I think it might be just as complex.

As always there are many different ways to approach a problem.

• 23. Re: Math trouble ! Help !

Hi Andrei1,

Sorry may be I'm bored to you. Because english is not my mother language.

But I really want to understand the code the conceptual very much.

I confuzed about  "This way radius will coincide with the right rectangle side and is perpendicular (-90 degrees in Flash space). So, the center of the circle is somewhere in this perpendicular.I think the height of the rectangle is the radius of the circle. Why not the

the center of the circle is the right-top point of the rectangle. And in the next section

"When you draw that you will see that two radiuses form right triangle with the base represented by diagonal and median that originates from the circle center is perpendicular to diagonal. Formula to calculate the radius is: ½ diagonal x sin(angle between diagonal and radius)."

Why there is an another radius ?  The other radius for the inscribed circle of the right trangle ? May be you can't understand what I mean, so

I use image to illustrate what idea in my mind.

• 24. Re: Math trouble ! Help !

This image is what you need to keep in mind:

" I think the height of the rectangle is the radius of the circle."

No, as image illustrates - it is not. Radius is even bigger than width. Only in case of square radius will have the same value as width and height.

"Why there is an another radius ?"

There is no another radius. As far as value is concerned - there is only one radius per circle (and we are dealing with a single circle).