How to shorten this code or make it more efficient? - optimization

I want to know if there is any more efficient/shorter way to give the same result.
The function get_action_strength(action) returns a boolean if the key is pressed,
Thanks.
var degValue = 0
if (Input.get_action_strength("move_forward")):
degValue = 0
if (Input.get_action_strength("move_right")):
degValue += -45
if (Input.get_action_strength("move_left")):
degValue += 45
elif (Input.get_action_strength("move_backward")):
degValue = 180
if (Input.get_action_strength("move_right")):
degValue -= -45
if (Input.get_action_strength("move_left")):
degValue -= 45
else:
if (Input.get_action_strength("move_right")):
degValue = -90
if (Input.get_action_strength("move_left")):
degValue = 90

The function get_action_strength(action) returns a boolean if the key is pressed
No, it doesn't. get_action_strength returns float. You can use that to your advantage.
You can do this:
var x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
Furthermore, atan2 will return 0 if the parameters are 0. That is one of the benefit of using atan2 instead of atan: You don't have to worry about a division by 0. Thus, you don't need to check if x and y are not 0, just use them.
By the way, y comes before x in atan2.
One more thing, there is a rad2deg function, if you have radians and want degrees:
var x = Input.get_action_strength("move_right") - Input.get_action_strength("move_left")
var y = Input.get_action_strength("move_forward") - Input.get_action_strength("move_backward")
var degValue = rad2deg(atan2(y, x))
If you really want, you can inline the variables, and it would be a one-liner.
Ah, sorry, I may have misunderstood. You want it to be discrete, right? You want ceil:
var x = ceil(Input.get_action_strength("move_right")) - ceil(Input.get_action_strength("move_left"))
var y = ceil(Input.get_action_strength("move_forward")) - ceil(Input.get_action_strength("move_backward"))
var degValue = rad2deg(atan2(y, x))

Second branch of if's can be changed to smth like that:
degValue += -45 * int(Input.get_action_strength("move_right")) + 45 * int(Input.get_action_strength("move_left"))
When the value is False and you convert it to int, it becomes 0, and the multiply result is 0. So only one of the values is added.
Also, if the question is tagged 'python', why are you declaring variable with 'var' keyword? =)

You can use vectors and compute the angle from its components:
motion_vec_x = 0
motion_vec_y = 0
if (Input.get_action_strength("move_forward")):
motion_vec_y = 1
if (Input.get_action_strength("move_backward")):
motion_vec_y = -1
if (Input.get_action_strength("move_left")):
motion_vec_x = -1
if (Input.get_action_strength("move_right")):
motion_vec_x = 1
degValue = None
if abs(motion_vec_x) > 0 or abs(motion_vec_y) > 0:
degValue = np.arctan2(motion_vec_x, motion_vec_y) / np.pi * 180
print(degValue
This will yield (depending on the arctan2 implementation) 0° for up, negative degrees for a vector tilted to the left and positive values for the vector tilted to the right. Pointing straight down is going to be 180°. You will easily be able to convert this to any angle values you need and deem fit.

Related

Check if two lines are intersecting? (if so, not where so)

I saw this asked but I couldn't understand the answers!
I got 4 vector2s, P1 & P2 for line 1, P3 & P4 for line 2.
Code for intersection position works, but how do I check if that intersection is happening?
More specifically, I want to check what side of a polygon an imaginary line is passing through/colliding with
...
...Had something like it working in an old test-script, however I made no annotations and I can't adapt it. I don't know if there's anything here that could be used but thought I'd share:
if rotation_angle > PI/2 && rotation_angle < 3*PI/2:
if rad_overflow(($Position2D.position-position).angle()-PI/2) < rad_overflow(rotation_angle-PI/2) or rad_overflow(($Position2D.position-position).angle()-PI/2) > rad_overflow(rotation_angle+PI/2):
actives.x = 1
else:
actives.x = 0
if rad_overflow(($Position2D2.position-position).angle()-PI/2) < rad_overflow(rotation_angle-PI/2) or rad_overflow(($Position2D2.position-position).angle()-PI/2) > rad_overflow(rotation_angle+PI/2):
actives.y = 1
else:
actives.y = 0
else:
if rad_overflow(($Position2D.position-position).angle()-PI/2) < rad_overflow(rotation_angle-PI/2) && rad_overflow(($Position2D.position-position).angle()-PI/2) > rad_overflow(rotation_angle+PI/2):
actives.x = 1
else:
actives.x = 0
if rad_overflow(($Position2D2.position-position).angle()-PI/2) < rad_overflow(rotation_angle-PI/2) && rad_overflow(($Position2D2.position-position).angle()-PI/2) > rad_overflow(rotation_angle+PI/2):
actives.y = 1
else:
actives.y = 0
var point1 = $Position2D.position
var point2 = $Position2D2.position
var limit3 = Vector2(0,1).rotated(rotation_angle+PI/2)
var limit4 = Vector2(0,1).rotated(rotation_angle-PI/2)
var det = (point1.x - point2.x)*(limit3.y - limit4.y) - (point1.y - point2.y)*(limit3.x - limit4.x)
var new_position = Vector2(
((point1.x*point2.y - point1.y*point2.x) * (limit3.x-limit4.x) - (point1.x-point2.x) * (limit3.x*limit4.y - limit3.y*limit4.x))/det,
((point1.x*point2.y - point1.y*point2.x) * (limit3.y-limit4.y) - (point1.y-point2.y) * (limit3.x*limit4.y - limit3.y*limit4.x))/det)
if actives.x != actives.y:
print("hit")
else:
print("miss")
You ask:
I got 4 vector2s, P1 & P2 for line 1, P3 & P4 for line 2. Code for intersection position works, but how do I check if that intersection is happening?
If you are using Godot, you can use the Geometry class for this, in particular the line_intersects_line_2d method. I quote from the documentation:
Variant line_intersects_line_2d ( Vector2 from_a, Vector2 dir_a, Vector2 from_b, Vector2 dir_b )
Checks if the two lines (from_a, dir_a) and (from_b, dir_b) intersect. If yes, return the point of intersection as Vector2. If no intersection takes place, returns null.
Note: The lines are specified using direction vectors, not end points.
So that gives you both if they intersect (if it returns null they don't intersect) and where (if it does not return null it returns a Vector2 with the position of the intersection).

Why is the result of trigonometric function calculation different?

I calculated three methods of the following with Numpy.
Avoiding the circle periodicity, I given the range is 0 to +180.
The calculation results of the three methods should match.
However, all calculation results are different.
Why is this?
degAry = []
sumDeg = 0
cosRad = 0
sinRad = 0
LEN = 300
RAD2DEG = 180.0 / PI # 57.2957795
for i in range(LEN):
deg = random.uniform(0,180)
rad = np.deg2rad(deg)
degAry.append(deg)
sumDeg += deg
cosRad += np.cos(rad)
sinRad += np.sin(rad)
print(np.arctan2( sinRad/LEN, cosRad/LEN ) * RAD2DEG) # 88.39325364335279
print(np.sum(degAry)/LEN) # 88.75448888951954
print(sumDeg/LEN) # 88.75448888951951
What makes you think that the mean angle and the angle of the mean vector should be the same? This is correct only for n = 1,2, for n = 3 degAry = [0, 90, 90] is easily verified to be a counter example: mean of the angles is 60 with tan = sqrt(3), mean vector is (1/3 2/3) corresponding to tan = 2.
EDIT
Mean of circular quantities
suggesting that the sin, cos approach is best.
Refactoring your code to use numpy exclusively. The two methods are different, however, the first two using RAD2DEG or the np.degrees yield the same results. The latter which used the sum of degrees divided by sample size differs.
It doesn't appear to be a summation issue (N=3000, sum in normal order, ascending then descending). They yield the same results
np.sum(deg) # 134364.25172174018
np.sum(np.sort(deg)) # 134364.25172174018
np.sum(np.sort(deg)[::-1]) # 134364.25172174018
I didn't carry it out with the summation for the cos and sin in radian form. I will leave that for others.
PI = np.pi
sumDeg = 0.
cosRad = 0.
sinRad = 0.
N = 30
RAD2DEG = 180.0 / PI # 57.2957795
deg = np.random.uniform(0, 90.0, N)
rad = np.deg2rad(deg)
sumDeg = np.sum(deg)
cosRad = np.sum(np.cos(rad))
sinRad = np.sum(np.sin(rad))
print(np.arctan2(sinRad/N, cosRad/N) * RAD2DEG)
print(np.degrees(np.arctan2(sinRad/N, cosRad/N)))
print(sumDeg/N)
Results for
> N = 1
> 22.746571717879792
> 22.746571717879792
> 22.746571717879792
>
> N= 30
> 48.99636699165551
> 48.99636699165551
> 49.000295118106884
>
> N = 300
> 44.39333460088003
> 44.39333460088003
> 44.44513528547155
>
> N = 3000
> 44.984167020219175
> 44.984167020219175
> 44.97574462726241

How to explain the strange results for while loop with floating point in swift

I have tested while loop below and don’t understand the result.
var x: Float = 0.0
var counter = 0
while x < 1.41
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) // 1.5
How is it possible to have the result x = 1.5 for the used while condition where x < 14.1 ? How to explain this result?
Update:
and one more. Why the results are different for Double and Float ?
var x: Double = -0.5
var counter = 0
while x < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 16
print (x)//1.1
var x: Float = -0.5
var counter = 0
while x < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
Update 2
and another one. Why there is no difference for < and <= conditions. Does it mean that usage of <= has no sense for floating point ?
var x: Double = 0.0
var counter = 0
while x < 1.5
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) //1.5
var x: Double = 0.0
var counter = 0
while x <= 1.5
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x) //1.5
What else would you expect? The loop is executed 15 times. On the 14th time, x is 1.4 and so you add another 0.1, making it 1.5.
If you expect the loop to terminate at 1.4, you should increment x before checking the while condition, not after that.
If you expect the loop to terminate on 1.41, your increment is wrong and you should do
x += 0.01
instead, making it 141 iterations.
As for the second question, I am aware that Float should not be used for monetary calculations and such due to its lack of precision. However, I trusted Double so far, and the while loop in run 15 actually claims the Double value to be less than 1.0 while it is reported to be 1.0. We have got a precision problem here, as we can see if we substract x from 1.0:
print(1.0-x)
which returns: 1.11022302462516e-16
At the same time, Float seems to be unprecise in the other direction. In the last run, it is a little bigger than 0.9 (0.9 + 5.96046e-08), making it bigger than 10 in the following run.
The reason why Double and Float are wrong in different directions is just a matter of how the values are stored, and the result will be different depending on the number. For example, with 2.0 both actual values are bigger: Double by 4.440892..e-16 and Float by 2.38419e-07. For 3.0 Double is bigger by 1.33226e-15 and Float smaller by 7.1525e-07.
The same problems occur using x.isLess(than: 1.0), but this method is the basis for the < operator as of https://developer.apple.com/reference/swift/floatingpoint/1849403-isless
isLessThanOrEqualTo(1.0), on the other hand, seems to work reliably as expected.
This answer is pretty much a question itself by now, so I'm curious if anyone has an in-depth explanation of this...
Update
The more I think about it, the less of a Swift problem it is. Basically, you have that problem in all floating point calculations, because they are never precise. Both Float and Double are not precise, Double is just twice as accurate. However, this means that comparisons like == are useless with floating point values unless they are both rounded. Therefore, good advice in loops like those of yours with a known precision (in your case one decimal) would be to round to that precision before doing any kind of comparison. For example, this would fix the loop:
var x: Double = -0.5
var counter = 0
while (round(x * 1000) / 1000) < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0
var x: Float = -0.5
var counter = 0
while (round(x * 1000) / 1000) < 1.0
{
x += 0.1
counter += 1
}
print (counter) // 15
print (x)//1.0

Square root Iteration using x1 = (x0 - a / x0) / 2

Here is what I have so far:
Public static double Sqrt (double a){
double xOld = a / 2;
double xNew = 0;
while (Math.abs(xOld - xNew) >= 0.0001 {
xNew = (xOld + a / xOld) / 2;
xNew = xOld;
}
}
I need to use the algorithm x1 = (x0 - a / x0) / 2 to find the approximate square root of a number. a is the original number and x0 starts at the value a / 2. When I run this code I get 12.5 (which is a / 2). What i need help on is what xNew value to initialize and the last line to the while loop. Thanks for any help
TRY THIS ON FOR SIZE:
Public static double Sqrt(double a) throws IllegalArgumentException {
if (a < 0.0) throw new IllegalArgumentException();
double aSqrt = a / 2.0;
while (Math.abs(a - aSqrt*aSqrt) >= 0.0001) { // I'd use a smaller tolerance
double aSqrtPrev = aSqrt;
aSqrt = (aSqrtPrev + a / aSqrtPrev) / 2.0;
}
return aSqrt ;
}
Probably what you want is xOld = xNew at the end of your loop, as the way it is set up now, you immediately overwrite the value of xNew that you just calculated.
But the above is not enough. With xNew and xOld equal at the end of the loop, you guarantee that the while loop will exit on the next pass, given the test condition. Try using a different condition for the while loop, such as Math.abs(a - xNew*xNew) >= 0.0001 or similar.
Another way to do it would be to keep your test condition as-is, but then you would have to swap the order of the two statements in the while loop, still do the assignment xOld = xNew.

Working with circle radials. Subtraction and addition

I'm working with magnetic headings and I am struggling a little bit with the math around it.
Let's say I have a heading of 270 degrees, and I turn clockwise 110 degrees. I want the new heading, 020 degrees, as an output and not 380 degrees. Is the best way to do something like this:
if (x > 360) { x = x - 360; }
or can I use calculations with M_PI to make it more correct?
Thanks for any replies!
An angle of x degree is equal to any angle X which satisfies X = x [360] that's modular arithmetic note that x can be less then -360 or greater then 720, so in that case, adding or subtracting 360 won't give you the result you're expecting. If you want a pure calculation method by adding or subtracting, you can use this piece of code:
if (x >= 360){
while( x >= 360)
x -= 360;
}
}else if (x < 0){
while( x < 0)
x += 360;
}
}
Or, more easily, in Objective-C, the operator that gives the value of X satisfying the equation below and being in the interval of [0;360[,is the % operator. You can use it that way:
X = x % 360
Although, your angles may not be int types. Than that operator won't work because it takes int as arguments. In this case, you can use the fmod or fmodf functions. The syntax you would use would then be :
X = fmodf(x,360)
this could be best way..
x = x % 360;