How can I get polar coordinates represented properly? - actionscript-3

I have the following hexagonal grid and trying to calculate the degrees to each edge hexagon from the center (light blue):
The blue highlighted hex is correct at 0 degrees and that quadrant (lower right) is correct. Here is my angle calculation method:
private static function calculateAngle(hex1:Hexagon, hex2:Hexagon):Number {
// hex1 is always passed in as the grid center or start
var diffY:Number = Math.abs(hex2.center.y) - Math.abs(hex1.center.y);
var diffX:Number = Math.abs(hex2.center.x) - Math.abs(hex1.center.x);
var radians:Number = Math.atan(diffY / diffX);
return radians * 180 / Math.PI;
}
Why are the remaining angles (text in each hexagon) incorrect?

You're really close to correct; you just need to compensate for the periodicity of atan. The standard way to do this is to use atan2, which returns a signed angle in (-pi, pi] instead of an unsigned angle in [0, pi). You can do so like this:
var radians:Number = Math.atan2(
hex2.center.y - hex1.center.y, hex2.center.x - hex1.center.x);
Note that I didn't include the call to abs in there: the signedness of those values is needed for atan2 to know which quadrant its in!
Edit: if you're looking for an angle in [0, pi], which represents the minimum angle between the center hex and the blue-highlighted hex, you can just take the absolute value of the result of atan2: return Math.abs(radians) * 180 / Math.PI; the question leaves it a little unclear as to which one you're asking for.

Related

AS3 shooting bullets to cursor from centre of character position

I'm making a top down shooter game. I've got my character moving. All I want to do next is make a bullet shoot from the center of my character to the direction my cursor is at. How would i go about doing this?
I'm really struggling to think of the code i need to make this work.
This will involve simple vector math. There are tons of resources online about this. Here's the basic gist:
1) First, calculate the angle (in radians) between your character and your target (in this case the mouse location). You can use Math.atan2() to perform this calculation.
var angle:Number = Math.atan2(mouseY - playerY, mouseX - playerX);
2) Next, use that angle to create a vector (x,y delta) which represents the direction of travel for your bullet. You use Math.cos() and Math.sin() to compute the x and y value:
var speed:Number = 5;
var vector:Point = new Point(Math.cos(angle) * speed, Math.sin(angle) * speed);
3) Now you can update the bullets position each frame by that vector:
bullet.x += vector.x;
bullet.y += vector.y;
4) And if you want to make your bullet sprite point in the direction of travel, convert that angle to degrees and set the bullet sprite's rotation:
var degrees:Number = angle * (180 / Math.PI);
bullet.rotation = degrees;
Note that for the purpose of the math here, 0 degrees is considered to be right-facing along the x-axis, not up-facing like you might naturally think of 0 degrees (at least I do). What this means is your sprites unrotated orientation should be facing right-ward.

Bezier Curve always the same length

I'm working on a game in HTML5 canvas.
I want is draw an S-shaped cubic bezier curve between two points, but I'm looking for a way to calculate the coordinates of the control points so that the curve itself is always the same length no matter how close those points are, until it reaches the point where the curve becomes a straight line.
This is solvable numerically. I assume you have a cubic bezier with 4 control points.
at each step you have the first (P0) and last (P3) points, and you want to calculate P1 and P2 such that the total length is constant.
Adding this constraint removes one degree of freedom so we have 1 left (started with 4, determined the end points (-2) and the constant length is another -1). So you need to decide about that.
The bezier curve is a polynomial defined between 0 and 1, you need to integrate on the square root of the sum of elements (2d?). for a cubic bezier, this means a sqrt of a 6 degree polynomial, which wolfram doesn't know how to solve. But if you have all your other control points known (or known up to a dependency on some other constraint) you can have a save table of precalculated values for that constraint.
Is it really necessary that the curve is a bezier curve? Fitting two circular arcs whose total length is constant is much easier. And you will always get an S-shape.
Fitting of two circular arcs:
Let D be the euclidean distance between the endpoints. Let C be the constant length that we want. I got the following expression for b (drawn in the image):
b = sqrt(D*sin(C/4)/4 - (D^2)/16)
I haven't checked if it is correct so if someone gets something different, leave a comment.
EDIT: You should consider the negative solution too that I obtain when solving the equation and check which one is correct.
b = -sqrt(D*sin(C/4)/4 - (D^2)/16)
Here's a working example in SVG that's close to correct:
http://phrogz.net/svg/constant-length-bezier.xhtml
I experimentally determined that when the endpoints are on top of one another the handles should be
desiredLength × cos(30°)
away from the handles; and (of course) when the end points are at their greatest distance the handles should be on top of one another. Plotting all ideal points looks sort of like an ellipse:
The blue line is the actual ideal equation, while the red line above is an ellipse approximating the ideal. Using the equation for the ellipse (as my example above does) allows the line to get about 9% too long in the middle.
Here's the relevant JavaScript code:
// M is the MoveTo command in SVG (the first point on the path)
// C is the CurveTo command in SVG:
// C.x is the end point of the path
// C.x1 is the first control point
// C.x2 is the second control point
function makeFixedLengthSCurve(path,length){
var dx = C.x - M.x, dy = C.y - M.y;
var len = Math.sqrt(dx*dx+dy*dy);
var angle = Math.atan2(dy,dx);
if (len >= length){
C.x = M.x + 100 * Math.cos(angle);
C.y = M.y + 100 * Math.sin(angle);
C.x1 = M.x; C.y1 = M.y;
C.x2 = C.x; C.y2 = C.y;
}else{
// Ellipse of major axis length and minor axis length*cos(30°)
var a = length, b = length*Math.cos(30*Math.PI/180);
var handleDistance = Math.sqrt( b*b * ( 1 - len*len / (a*a) ) );
C.x1 = M.x + handleDistance * Math.sin(angle);
C.y1 = M.y - handleDistance * Math.cos(angle);
C.x2 = C.x - handleDistance * Math.sin(angle);
C.y2 = C.y + handleDistance * Math.cos(angle);
}
}

AS3 Continuous value from rotation slider

I have a dial which I drag around a circle to give me a reading between 0 and 1.
Something like this:
dx = mouseX-centerX;
dy = mouseY-centerY;
rad = Math.atan2(dy,dx);
rad += offset;
Tweener.addTween(knob,{y:centerY - Math.cos(rad)*radius, time:.1, transition:"easeOutSine"});
Tweener.addTween(knob,{x:centerX + Math.sin(rad)*radius, time:.1, transition:"easeOutSine"});
knob.rotation = rad * 180 / Math.PI;
This work's great, except when the slider goes from 359 degrees to 1 degree, my value between 0 and 1 returns to zero. (Which makes sense, as the value is based on the angle of my slider)
I'm trying to find a way for the dial to move from 359 degrees to 361 and onwards basically.
In my head: I need to check if the next value of my mouse drag goes past the 360 degree point and add 360 to the total, to stop it returning to zero and continue to 361 degrees.
I just cant work out how to put this into code...
On each frame when you are rotating the knob, check the change in angular distance instead of direct angle.
Save the previous frames angle and see if the difference is positive or negative.
var rad = Math.atan2(dy, dx);
var diff = rad - oldRad;
oldRad = rad;
if( diff > Math.PI )
diff -= Math.PI * 2;
if( shortestAngle < -Math.PI )
diff += Math.PI * 2;
diff should contain a value that if it's been rotated to the right, is positive (or negative if rotated left). Simply add that to the total angle.
There might be some errors in the code (took it from an old project), but that's the gist of it :)
Hope that helps!

Vectors calculations in physics

You are given the radius of a circle, as well as a point P in the circle( x,y), how do you write a function to return an x number of points( x,y), all on the circumference of the given circle. Also, how do you go about finding the angle between each generated point and point P.
I assume you would want the points on the circumference to be evenly distributed along the circumference. If this is the case, you can calculate the number of degrees between each point by dividing 360 by the number of points that you want.
Then, you can obtain any point's (x, y) coordinates as such:
(x, y) = (cos(angle), sin(angle))
where 'angle' the is the angle for the given point. (This is assuming you want values between -1 and 1, as is the case with a unit circle: http://en.wikipedia.org/wiki/Unit_circle) For example, if you want 4 points along the circle's circumference, you can calculate that there is exactly 360/4 = 90 degrees between consecutive points.
So let's call these points point0, point1, point2 and point3. Point0 is at an angle of 0 degrees, point1 at 90 degrees (1 * 90), point2 at 180 (2 * 90) and point3 at 270 (3 * 90). The coordinates for each point are then:
point0 = (cos(0), sin(0)) = (1, 0)
point1 = (cos(90), sin(90)) = (0, 1)
point2 = (cos(180), sin(180)) = (-1, 0)
point3 = (cos(270), sin(270)) = (0, -1)
Keep in mind that you normally start measuring angles on the right side of the horizontal axis of a circle. (On a clock: At the 3)
EDIT: Also please note that almost all trigonometric functions in programming take radian values instead of degrees. Radians can be hard to think with, however, which is why it's very useful to know how to convert radians and degrees to eachother. To convert degrees to radians, multiply the degree value by (pi/180). To convert radians to degrees, multiply the radian value by (180/pi). There is a reasoning behind this all, so if you would like to know more about this, I suggest you read up on radians. http://en.wikipedia.org/wiki/Radian
As far as the angle between these points and the point P goes; I will only give you some directions. You can calculate the x- and y-differences between the points and point P (this should be trivial for you, it consists of mere subtractions). Using these two values, you can calculate the angle between the points.

How do I know if a Lat,Lng point is contained within a circle?

Ok pretty self explanatory. I'm using google maps and I'm trying to find out if a lat,long point is within a circle of radius say x (x is chosen by the user).
Bounding box will not work for this. I have already tried using the following code:
distlatLng = new google.maps.LatLng(dist.latlng[0],dist.latlng[1]);
var latLngBounds = circle.getBounds();
if(latLngBounds.contains(distlatLng)){
dropPins(distlatLng,dist.f_addr);
}
This still results in markers being places outside the circle.
I'm guess this is some simple maths requiring the calculation of the curvature or an area but I'm not sure where to begin. Any suggestions?
Unfortunately Pythagoras is no help on a sphere. Thus Stuart Beard's answer is incorrect; longitude differences don't have a fixed ratio to metres but depend on the latitude.
The correct way is to use the formula for great circle distances. A good approximation, assuming a spherical earth, is this (in C++):
/** Find the great-circle distance in metres, assuming a spherical earth, between two lat-long points in degrees. */
inline double GreatCircleDistanceInMeters(double aLong1,double aLat1,double aLong2,double aLat2)
{
aLong1 *= KDegreesToRadiansDouble;
aLat1 *= KDegreesToRadiansDouble;
aLong2 *= KDegreesToRadiansDouble;
aLat2 *= KDegreesToRadiansDouble;
double cos_angle = sin(aLat1) * sin(aLat2) + cos(aLat1) * cos(aLat2) * cos(aLong2 - aLong1);
/*
Inaccurate trig functions can cause cos_angle to be a tiny amount
greater than 1 if the two positions are very close. That in turn causes
acos to give a domain error and return the special floating point value
-1.#IND000000000000, meaning 'indefinite'. Observed on VS2008 on 64-bit Windows.
*/
if (cos_angle >= 1)
return 0;
double angle = acos(cos_angle);
return angle * KEquatorialRadiusInMetres;
}
where
const double KPiDouble = 3.141592654;
const double KDegreesToRadiansDouble = KPiDouble / 180.0;
and
/**
A constant to convert radians to metres for the Mercator and other projections.
It is the semi-major axis (equatorial radius) used by the WGS 84 datum (see http://en.wikipedia.org/wiki/WGS84).
*/
const int32 KEquatorialRadiusInMetres = 6378137;
Use Google Maps API geometry library to calculate distance between circle's center and your marker, and then compare it with your radius.
var pointIsInsideCircle = google.maps.geometry.spherical.computeDistanceBetween(circle.getCenter(), point) <= circle.getRadius();
It's very simple. You just have to calculate distance between centre and given point and compare it to radius. You can Get Help to calculate distance between two lat lang from here
The following code works for me: my marker cannot be dragged outside the circle, instead it just hangs at its edge (in any direction) and the last valid position is preserved.
The function is the eventhandler for the markers 'drag' event.
_markerDragged : function() {
var latLng = this.marker.getPosition();
var center = this.circle.getCenter();
var radius = this.circle.getRadius();
if (this.circleBounds.contains(latLng) &&
(google.maps.geometry.spherical.computeDistanceBetween(latLng, center) <= radius)) {
this.lastMarkerPos = latLng;
this._geocodePosition(latLng);
} else {
// Prevent dragging marker outside circle
// see (comments of) http://unserkaiser.com/code/google-maps-marker-check-if-in-circle/
// see http://www.mvjantzen.com/blog/?p=3190 and source code of http://mvjantzen.com/cabi/trips4q2012.html
this.marker.setPosition(this.lastMarkerPos);
}
},
Thanks to http://unserkaiser.com/code/google-maps-marker-check-if-in-circle/
and http://www.mvjantzen.com/blog/?p=3190 .
I've been a bit silly really. Thinking about it we can use Pythagorus' theorem.
We have a maximum distance away from a point (X miles), and two latitudes and two longitudes. If we form a triangle using these then we can solve for the distance from the point.
So say we know point1 with coordinates lat1,lng1 is the center of the circle and point2 with coordinates lat2,lng2 is the point we are trying to decide is in the circle or not.
We form a right angled triangle using a point determined by point1 and point2. This, point3 would have coordinates lat1,lng2 or lat2,lng1 (it doesn't matter which). We then calculate the differences (or if you prefer) distances - latDiff = lat2-lat1 and lngDiff = lng2-lng1
we then calculate the distance from the center using Pythagorus - dist=sqrt(lngDiff^2+latDiff^2).
We have to translate everything into meters so that it works correctly with google maps so miles are multiplied by 1609 (approx) and degrees of latitude/longitude by 111000 (approx). This isn't exactly accurate but it does an adequate job.
Hope that all makes sense.