John R
John R

Reputation: 3036

JavaScript and Trigonometry/Oval

I have been using this this oval function (that I found at Wikipedia http://en.wikipedia.org/wiki/Ellipse) for plotting points in a layout. I have been laying things out with two to five points plotted around an oval without any problem. The function has a parameter called 'steps'; the 'steps' parameter sets the quantity of points to plot around the oval.

Here's the main problem: If 'steps' (the number of points to plot) is equal to the numbers 7, 11, 13 or 14, it breaks. It's been a few years since I took trigonometry, so basically I am stuck.

Second minor issue: I had the code printing out all points, but when I copied/pasted and removed extraneous code to post here, it only prints out the last plotting point (not sure why).

<html>
<head>
<script type="text/javascript">
    var elipticalLayout=new Array();
    for (i=0; i <36; i++){
        elipticalLayout[i]=new Array(2);
    }

    /*
    * This functions returns an array containing the specified 
    *    number of 'steps' (points) to draw an ellipse.
    *
    * @param x {double} X coordinate
    * @param y {double} Y coordinate
    * @param a {double} Semimajor axis
    * @param b {double} Semiminor axis
    * @param angle {double} Angle of the ellipse
    *
    * Attribution: This function is from http://en.wikipedia.org/wiki/Ellipse
    */
    function calculateEllipticalLayout(x, y, a, b, angle, steps) {

      var points = [];

      // Angle is given by Degree Value
      var beta = -angle * (Math.PI / 180); //(Math.PI/180) converts Degree Value into Radians
      var sinbeta = Math.sin(beta);
      var cosbeta = Math.cos(beta);

      for (var i = 0; i < 360; i += 360 / steps) //{
        var alpha = i * (Math.PI / 180) ;
        var sinalpha = Math.sin(alpha);
        var cosalpha = Math.cos(alpha);

        var X = x + (a * cosalpha * cosbeta - b * sinalpha * sinbeta);
        var Y = y + (a * cosalpha * sinbeta + b * sinalpha * cosbeta);
        elipticalLayout[i/(360/steps)][0]=X;
        elipticalLayout[i/(360/steps)][1]=Y;
    }

    </script>
</head>
<body>
    <script type="text/javascript">

        calculateEllipticalLayout(300, 300, 245, 125,  15,    15);

        for (i=0; i<elipticalLayout.length; i++){
            document.write(i + ", " + elipticalLayout[i][0] + ", " + elipticalLayout[i][1] + "<br>");
        }
    </script>

</body>
</html>

Upvotes: 1

Views: 872

Answers (2)

RobG
RobG

Reputation: 147523

I would declare elipticalLayout within the function and return it. Below is how I'd write the function.

Note that there is no such thing as a "double" or even integer in javascript, a variable's type is defined by its value. Numbers are just numbers, they can be primitives or Number objects (almost never required).

If you are using the returned values to plot positions in pixels, you likely want to round them to integers first. I've used a simple truncation method to convert them to integers.

var elipticalLayout = [];

/*
* This functions returns an array containing the specified 
*    number of 'steps' (points) to draw an ellipse.
*
* @param x     - X coordinate
* @param y     - Y coordinate
* @param a     - Semimajor axis
* @param b     - Semiminor axis
* @param angle - Angle of the ellipse
*
* Attribution: This function is from http://en.wikipedia.org/wiki/Ellipse
*/
function calculateEllipticalLayout(x, y, a, b, angle, steps) {

  var points = [];
  var step = 360 / steps;
  var k = Math.PI/180;    // Convert deg to rad
  var cos = Math.cos;
  var sin = Math.sin;
  var i = 0;

  // Convert angle to radians
  var beta = -angle * k;
  var sinbeta = sin(beta);
  var cosbeta = cos(beta);

  while (i < 360) {

    var alpha = i * k;
    var sinalpha = sin(alpha);
    var cosalpha = cos(alpha);

    var X = x + (a * cosalpha * cosbeta - b * sinalpha * sinbeta);
    var Y = y + (a * cosalpha * sinbeta + b * sinalpha * cosbeta);

    // Truncate numbers to integer and put into array
    elipticalLayout.push([X|0, Y|0]);

    // Keep X,Y as floats
    // elipticalLayout.push([X, Y]);

    i += step;
  }
}

Upvotes: 1

c-smile
c-smile

Reputation: 27470

You fill only steps number of elements in elipticalLayout. But trying to output 36 of them.

This elipticalLayout[i/(360/steps)][0]=X; is wrong as will lead to "holes" in the sequence due to float to int rounding.

You should have something like this:

var n = 0;
for(...)
   elipticalLayout[n][0]=X;
   elipticalLayout[n][1]=Y;
   ++n;

Upvotes: 0

Related Questions