0

I apologize, I should know this. I have 2 points on an SVG 2d coordinate system. I need to get the degrees (0-360) and all I can return right now is 0-180 back to 0 with no negative or positive sign on the 0-180... I can find close questions but none that result in 0-360.

Here is the code in javascript:

// center point, say 200,200
var rx = that.get("rotateOriginX");     // ember code but substitute 200,200 if you want  
var ry = that.get("rotateOriginY");

// I create third point (directly up on coordinate system)
// 200, 190 - line straight up and down to angle vertex above
var p1x = rx;        
var p1y = ry - 10;   // this is negative 10 to go up because svg y axis starts in upper left

// mouse position variable, this can be 360 degrees around vertex
var p2x = d3.mouse(this.parentNode.parentNode)[0];   
var p2y = d3.mouse(this.parentNode.parentNode)[1];

// I have three points now
var p0c = Math.sqrt(Math.pow(rx-p1x, 2) + Math.pow(ry-p1y, 2));
var p1c = Math.sqrt(Math.pow(rx-p2x, 2) + Math.pow(ry-p2y, 2));
var p0p1 = Math.sqrt(Math.pow(p2x-p1x, 2) + Math.pow(p2y-p1y, 2));

// this always returns 0-180-0 but is not signed (+/-) 
// ALL I WANT IS 0-360 so I can rotate a shape to user's preference as determined by mouse
var degrees = (180 * (Math.acos((p1c*p1c+p0c*p0c-p0p1*p0p1)/(2*p1c*p0c))) / Math.PI);
Nick Licata
  • 147
  • 11

2 Answers2

1
  1. acos,asin

    • are 4-quadrant
    • but is not precise in whole range
    • and there are few other problems with them like the need of clamping ...
  2. atan(dy/dx)

    • is only 2-quadrant
    • that is because atan(dy/dx) loose the sign of original dx,dy
  3. 4-quadrant atan(dy/dx) = atan2(dy,dx) or atanxy(dx,dy)

    • it is just atan with some sign of dx,dy decision table to handle all quadrants
    • here is mine atanxy in C++

atanxy

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
0

The solution was this, although any "math guy" or gal would probably be able to simplify this some, I feel like I am over complicating it but I get what I need reliably. If you simplify it please offer some explanation.

Math.acos returns a floating point from -180 to 180 with zero facing right/east (if viewing as a compass) and 0 to -180 covering the top half of the circumference of the circle. 0 through +180 goes from the right to the left covering the bottom half circumference of the circle (180 being half of 360). That is probably normal for folks that do math once in a while (0 being to the right and counter clockwise increases the number). Since I start with 2 x/y points and I know I want 0 to face up/north I can auto-create the third point in the function and just require 2 points as arguments.

So with 3 points, one always facing up/north on the 2d plane, I get the radians from Math.acos as described above. I then get the result of Math.atan2 which gives me what appears like radians again (0-180 and 0- -180) but instead of 0 facing east/right it faces up/north and so with this additional information (as well as it being signed [+-]) I can derive which quadrant the original number was in (the unsigned 0-180) and than I just correct the degree variable by subtracting from 360 if the point was in either top or bottom left side quadrants.

Convoluted, yes, functional yes, elegant, notta. Marking as answered to not take up resources for others but a more sound explanation would be welcomed.

findBearingOfTwoPoints: function(p1, p2, forceInt){
    var degrees = 0;
    try{
        var a1 = Math.sqrt(Math.pow(p1.x - p1.x, 2) + Math.pow(p1.y - (p1.y - 10), 2));
        var a2 = Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
        var a3 = Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - (p1.y - 10), 2));

        // this is probably better to be called radians
        degrees = (180 * (Math.acos((a2 * a2 + a1 * a1 - a3 * a3)/(2 * a2 * a1))) / Math.PI);

        var angle  = 0;
        var deltaY = p2.y - p1.y;
        var deltaX = p2.x - p1.x;
        angle  = (Math.atan2(deltaY, deltaX) * (180 / Math.PI));

        if(angle < -90 || angle > 90){
            degrees = 360 - degrees;
        }

        if(forceInt===true){
            degrees = parseInt(degrees);
        }
    }
    catch(e){
        //
    }
    return degrees;
},
Nick Licata
  • 147
  • 11