Know difference between two angles with only their sine and cosine? - python

Hi recently I was writing a program with a bunch dots that the player had to avoid. The dots changed direction, but can't turn too much in a given timeframe.
I had a method of doing this but was inefficient as I had to arcsine, knowing the cosed angle and sined angle, then sine and cosine that angle. I thought of just returning the cosine and sined angle, but theres one problem. Once I received the cosine and sine, I need too know if it is too different from my current state.
With the angle this would be easy as I would just have too see the difference, here's a model program,(the code I currently have uses the angle, and isn't very helpful). I have tried graphing sine and cosine and trying to observe any patterns, none obvious showed up.
import math
def sendTargRot():
#I actually use a fairly long method to find it's current rotation, but a random.random() is a fair replacement, so in my real thing there would be no angle calculation
pretendAngle = math.pi*random.random()-math.pi
pretendCosedX = math.cos(pretendAngle)
pretendSinedX = math.sin(pretendAngle)
def changeDotAngle():
targRot = sendTargRot
#make sure targRot is not too much from current rotation
#do stuff with the angle, change dot's rotation
If you want to just give me an algorithm without code that is just as acceptable!
EDIT: I can't really change sendTargRot so it gives a proper rotation, because that would require me knowing the current angle, and really it's just moving the problem.

To get angle between two vectors you can use atan2 function
angle = Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y)
if you already have got cosines and sines (the same as coordinates on unit circle):
angle = Math.atan2(cos(a) * sin(b) - sin(a) * cos(b), cos(a) * cos(b) + sin(a) * sin(b))
This approach gives angle needed to rotate a until it coincides with b accounting for direction (in range -Pi..Pi)

Related

shortest distance between a point and a rectangle based on numpy implementation

Goal:
For a point a and a rectangle B, I would like to calculate the shortest distance between these two objects.
Motivation
Because this calculation is part of the innermost loop of multiple loops, I would like to optimize this calculation as much as possible. With my current python knowledge, making use of dedicated NumPy functions should be the way to goal(?).
Some more details:
The situation is 2D; x,y coordinates
rectangle B is defined by a certain center-of-gravity/mid-point, and width and length (And thus not by a vector of points)
the distance is thus from a to the edges of the rectangle B
My current implementation makes use of the following idea: link. Here the rectangle is divided into multiple subareas. First, it is determined inside which sub-area of B a is located. Hereafter, the calculating the shortest distance between a and B is then straightforward. However, a lot of logic checking is required to determine inside which sub-area a is located. It looks something as following,
def distance_a_to_B(a:Point):
if a in sub_area_1:
return easy_calculation_1(a)
if a in sub_area_2:
return easy_calculation_2(a)
if a in sub_area_3:
return easy_calculation_3(a)
etc
Ideally,
I would like to have an alternative/faster logic checking (Python improvement)
or
a faster mathematical algorithm
Maybe...?
One possible alternative I came up with while writing this question, is to calculate a discrete amount of n points based on Bs chaterestics. From this vector of n points I think it is quite easy use NumPy to:
calculate the shortest distance between a and each point of the n points
find the smallest value of this new vector
For a larger n, this solution would become more precise with a higher performance cost. Do you think this could be a better solution? Or do you have any suggestions for a mathematical (and no approximation) algorithm?
EDIT: added extra clarification, that the distance is towards the edges of the rectangle B
I think, this is a nice implementation of the distance function:
from math import sqrt
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
class Rectangle:
def __init__(self, center: Point, width: float, height: float):
self.center = center
self.width = width
self.height = height
def distance_to_point(self, point: Point) -> float:
""" assuming that the distance to a point inside of this rect is zero """
dx = abs(self.center.x - point.x) - (self.width * 0.5)
dy = abs(self.center.y - point.y) - (self.height * 0.5)
return sqrt((dx * (dx > 0)) ** 2 + (dy * (dy > 0)) ** 2)
I don't know, how well the Python interpreter translates this code. It is possible, to implement this approach completely branchless, which is a nice property for optimized code.
If you want to compare one point to many rectangles (1:n), you could store all rectangles in a numpy array and compare your point to all rectangles at once using numpy array functions. The same would be possible for n:1 comparison. This could greatly speed up the process!
Without knowing more about your loops I can't provide such a solution, though.

Problem with solving a program involving radians in `math` module

I found a python question and facing trouble in solving it correctly.
The question is as follows.
In this problem, you're going to use that class to calculate the net force from a list of forces.
Write a function called find_net_force. find_net_force should have one parameter: a list of instances of Force. The function should return a new instance of Force with the total net magnitude and net angle as the values for its magnitude and angle attributes.
As a reminder:
To find the magnitude of the net force, sum all the horizontal components and sum all the vertical components. The net force is the square root of the sum of the squares of the horizontal forces and the vertical forces (i.e.(total_horizontal2 + total_vertical2)0.5)
To find the angle of the net force, call atan2 with two arguments: the total vertical and total horizontal forces (in that order). Remember to round both the magnitude and direction to one decimal place. This can be done using round(magnitude, 1) and round(angle, 1).
The Force class has three methods: get_horizontal returns a single force's horizontal component. get_vertical returns a single force's vertical component. get_angle returns a single force's angle in degrees (or in radians if you call get_angle(use_degrees=False).
HINT: Don't overcomplicate this. The Force class does a lot of functions except atan2, degrees, and radians.
I tried using the following code to solve it and am getting a different result for the get_angle. I tried changing things with radians, degrees with no correct result.
from math import atan2, degrees, radians, sin, cos
class Force:
def __init__(self, magnitude, angle):
self.magnitude = magnitude
self.angle = radians(angle)
def get_horizontal(self):
return self.magnitude * cos(self.angle)
def get_vertical(self):
return self.magnitude * sin(self.angle)
def get_angle(self, use_degrees = True):
if use_degrees:
return degrees(self.angle)
else:
return self.angle
def find_net_force(force_instances):
total_horizontal = 0
total_vertical = 0
for instance in force_instances:
total_horizontal += float(instance.get_horizontal())
total_vertical += float(instance.get_vertical())
net_force = round((total_horizontal ** 2 + total_vertical ** 2) ** 0.5, 1)
net_angle = round(atan2(total_vertical, total_horizontal), 1)
total_force = Force(net_force, net_angle)
return total_force
force_1 = Force(50, 90)
force_2 = Force(75, -90)
force_3 = Force(100, 0)
forces = [force_1, force_2, force_3]
net_force = find_net_force(forces)
print(net_force.magnitude)
print(net_force.get_angle())
The expected output is:
103.1
-14.0
The actual result I got is:
103.1
-0.2
Update:
Thanks to Michael O. The class was expecting degrees and the function find_net_force was sending the angle in radians. I tried using the conversion to degrees in the find_net_force and it worked.
net_angle = round(degrees(atan2(total_vertical, total_horizontal)), 1)
Thanks to Michael O for helping out in the comments. The class was expecting degrees and the function find_net_force was sending the angle in radians.I tried using the conversion to degrees in the find_net_force and it worked.
net_angle = round(degrees(atan2(total_vertical, total_horizontal)), 1)

Monte Carlo Simulation to estimating pi using circle

I have a question on the algorithm below. What confused me is why x = random.random()*2 -1 and y = random.random()*2 -1 rather than just simply x = random.random() and y = random.random()? The complete code is as following:
import random
NUMBER_OF_TRIALS= 1000000
numberOfHits = 0
for i in range(NUMBER_OF_TRIALS):
x = random.random()*2 -1
y = random.random()*2 -1
if x * x + y * y <=1:
numberOfHits +=1
pi = 4* numberOfHits / NUMBER_OF_TRIALS
print("PI is", pi)
The circle in this simulation is centered at (0, 0) with a radius of 1, so
x = random.random() * 2 - 1
y = random.random() * 2 - 1
will make the range for each -1 to 1.
The interesting thing about this question is that the implementation works just as well, and gives you the same expected answer whether you use random.random() or random.random()*2-1... so the reason why the author chose to use random.random()*2-1 has nothing to do with what the program does.
The author of this code understands the algorithm as follows:
Imagine a circle inscribe in a square. Use the unit circle because it's simplest
Choose random points within the square, and see how many are also inside the circle
The circle has area pi and the square has area 4, so the proportion of points that fall in the circle will approach pi/4. Calculate the measured ratio and solve for pi.
Now, the square in which the unit circle is inscribed goes from (-1,-1) to (1,1). Since random() only gives you a number in [0,1), it needs to be multiplied by two and shifted to select a random number in [-1,1), which chooses random points within the square.
If the author had used random(), then he would be selecting point within the first quadrant only. All the quadrants look exactly the same, so the ratio of hits to misses would be the same and the program would still work just fine, but then the program would not be implementing the above-described procedure, and would be more difficult to understand.
One of the most important properties of good code is that it clearly communicates the author's intent.
random() gives you a random float between 0 and 1.
random()*2 -1 gives you a random float between -1 and +1.
The algorithm, as usually explained, is in terms of the proportion of points in the unit square that are in the unit circle being pi/4, which is obvious after a moment's thought, and the second one gives you that directly.
It doesn't take much additional thought to see that using only the upper-right quadrant of the unit square and the unit circle will still give you pi/4 (although it is possible to confuse yourself and get it wrong, as I embarrassingly did in the first version of this answer). But it's not as blindingly obvious. And that might be a good enough reason for a tutorial to not do things that way.
If you were interested in calculating pi as efficiently as possible, it would probably make more sense to just use random(), and add a comment about how you're diving both the unit square and the unit circle by the same value so the odds are still pi/4. But if you're interested in showing novice programmers how to design and implement randomized algorithms? Probably better to write it the way it's written.

Move point A to point B in a arc motion in 3D

I'm struggling to work out how I move point A to B in an arc motion in 3D. The duration of the movement doesn't matter so much. I have found a load of wikipedia pages on it but am having no luck understanding them as its been a long time since I was in college. Any code examples would be really useful for me to understand. Thank you, I would really appreciate your help. Here is an image that sort of shows what I am looking to achieve, although the image only represents the points in 2d, I am looking for a 3d solution.
Assuming your problem statement is:
Given points a and b, trace the circular path along the plane which lies tangent to the up vector:
And that you have the appropriate vector algebra libraries:
def interp(a, b, up, t):
""" 0 <= t <= 1"""
# find center and radius vector
center = (a + b) / 2
radius = a - center
# split path into upwards and downwards section
omega = math.acos(radius.dot(up)) # angle between center-a and center-top
t_top = omega / math.pi # time taken to reach the top
# redefine 0 as A, 1 as the top, and B as whatever remains linear
t = t / t_top
#slerp, with t intentionally > 1
sin = math.sin
return (
center +
sin((1 - t) * omega) / sin(omega) * radius +
sin(t * omega) / sin(omega) * up
)
it doesnt matter if its 2d or 3d .
you take the position of each dot and find the center beetwean them .
the distance beetwean the center and each dot is the radius .
after that give the object a moving direction and tell it to be always in a distance of radius from center . which a moving vector you can give it any direction you want .

Python (pygame) Sin, Cos and Tan

I noticed there was a sin, cos and tan function in Python.
So, I thought I would use these to make a way of aiming in my game, unfortunately, the word description of sin,cos,tan,asin,acos and atan are very confusing.
I know how to do all the sin, cos and tan rules from school, I just need to apply them to the code. So, here's what I need to do, I just need to know which one I must use:
I have
The Angle
The Hypotenuse
(I'm just keeping that the value of how far I want the object to travel before I blit it again)
From the angle, I want to work out either/both the opposite and adjacent.
The hypotenuse is going to be sin/asin and cos/acos. Which one? I don't know.
How to I input my numbers? Do I just do aim = cos(angle,hyp) or do I have to apply some other calculations?
The formulae are:
adjacent = hypothenuse * math.cos(angle)
opposite = hypothenuse * math.sin(angle)
where angle is in radians.
Your wording is a bit confusing... but what I understand is that you have a point in the 2D space and you want to advance it a particular distance (hypotenuse) aiming a specified angle above the horizon. If so:
newX = oldX + dist * cos(angle)
newY = oldY + dist * sin(angle)
That assumes that angle is in radians, that the Y axis is positive upwards and that the angle is 0 aiming to the right and PI/2 to the top. If these are not the case you may need to wiggle the signs a little.

Categories