Python trig problems - python

Im using Pythonista 2 on my IPhone, and I'm trying to create a touch joystick. Its a simple concept, I touch somewhere on my screen, the joystick and the boundary snap to that position. Then, when I move my finger, the boundary stays still but the joystick inside moves, until i get to the edge of the boundary, then it follows on the circumference of the circle in between the center of the boundary and my finger. Here is the code:
def touch_moved(self, touch):
global r
r = 90
l = (touch.location-c[0],touch.location-c[1])
a = math.degrees(math.tan(l[1]/l[0]))
if (touch.location[0] - c[0])**2 + (touch.location[1] - c[1])**2 < r**2:
self.joystick.position = touch.location
else:
self.joystick.position = ((math.cos(a)*r)+c[0],(math.sin(a)*r)+c[1])`
But the joystick spazzes out on the circumference, so any help is appreciated.

You're using a as a parameter to sin and cos, but it came from a call to math.degrees(); trig functions always operate on radians, not degrees.
a is derived from the result of a call to tan, which should be a warning sign: tan uses an angle as input, not normally as an output. You probably want the inverse function here, atan. Actually, what you really want is math.atan2(), which takes the horizontal and vertical values as separate parameters. As your code is written, you will get a divide-by-zero error if the touch position is directly above or below the center point.
Your calculation of l seems wrong - shouldn't you be using indexes [0] and [1] with touch.location, like you're doing two lines later?

Related

How do I make a function to draw arcs inside a matrix?

I need to make a function/method that draws arcs inside a matrix. I would use 1s as points that shape the arc and 0s as empty spots. So the function would produce something like this matrix (only I would use 1400x700 matrix in reality):
000000000000000
000100000001000
000010000010000
000000111000000
000000000000000
I need to pass the following parameters to the function:
x: the x coordinate
y: the y coordinate
w: the width
h: the height
start: the start angle, in degrees
extent: the extent, in degrees
Now, I don't know the math on how to do it. Anyone could help me?
Hint:
A circular arc is the boundary of a domain of equation
(X - Xc)² + (Y - Yc)² ≤ R².
A starting point can be
(Xc + R, Yc).
Now from a known point, you can perform contour following, i.e. repeatedly find the next 8-neighbor that verifies the inequation.
This gives you a global idea. Handling the start and end point is a little tricky. And optimizations are possible by splitting the work in 8 octants. But this is a longer story.

How to use python to move the mouse in circles

I'm trying to write a script in python, to automatically force the movement of the mouse pointer without the user's input (it quits through the keyboard), and experimenting with PyAutoGUI, PyUserInput and ctypes, I've been figuring out ways to move the pointer with constant speed, instead of having it teleport across the screen(I need the user to be able to see the path it makes). However, I need it to be able to perform curves, and particularly, circles, and I haven't found a way to do so with the aforementioned libraries. Does anybody know of a way to code them into making the mouse describe circles across the screen at constant speed, instead of just straight lines? Thank you beforehand for any input or help you may provide.
This is my attempt at making circle at the center of the screen of radius R - also note if I don't pass parameter duration then the mouse pointer moves to the next coordinates instantly. So for a circle divided into 360 parts you can set the pace using a modulus.
import pyautogui
import math
# Radius
R = 400
# measuring screen size
(x,y) = pyautogui.size()
# locating center of the screen
(X,Y) = pyautogui.position(x/2,y/2)
# offsetting by radius
pyautogui.moveTo(X+R,Y)
for i in range(360):
# setting pace with a modulus
if i%6==0:
pyautogui.moveTo(X+R*math.cos(math.radians(i)),Y+R*math.sin(math.radians(i)))
There is a way to do this using sin, cos, and tan. (I haven't been able to test this code yet, It might not work.)
Import math
Import pyautogui
def circle(radius = 5, accuracy = 360, xpos=0, ypos=0, speed = 5):
local y
local x
local angle
angle = 360/accuracy
local CurAngle
CurAngle = 0
x = []
y = []
sped = speed/accuracy
for i in range(accuracy):
x.append(xpos + radius*math.sin(math.radians(CurAngle)))
y.append(ypos + radius*math.cos(math.radians(CurAngle)))
CurAngle += angle
for i in len(x):
pyautogui.moveTo(x[i], y[i], duration = sped)
You put this near the top of your script, and pass arguments like this:
circle(radius, accuracy, xpos, ypos, speed)
Radius controls the width of the circle
Accuracy controls how many equi-distant points the circle is to be broken up into, setting accuracy to 4 will put 4 invisible points along the circle for the mouse to travel tom which will make a square, not a circle, 5 makes a pentagon, 6 a hexagon, etc.. the bigger the radius, the bigger you will want the accuracy
Xpos controls the x position of where the circle is centered
Ypos controls the y position of where the circle is centered
Speed controls how many seconds you want it to take to draw the circle.
Hope this helps :) Would you mind elaborating what you are wanting when you say 'curves'

Changing the coordinate map in function of its coordinates (gravitational lensing)

I'm trying to compute the optical phenomenon called Gravitational Lensing. In simple words its when a massive object (or with massiva mass) its between me as an observer and a star or some clase of light source. Because its massive mass the light will bend and for us it will apparently come from another location than it real position. There is a particular case (and simpler) where we suppose the mass is spheric, so from our perspective its circular in a 2D plane (or photo).
My idea for code that was changing the coordinates of a 2D plane in function of where my source light its. In other words, if I have a spheric light source, if it is far from my massive object it will image no change, but if its close to te spheric mass it will change (in fact, if its exactly behind the massive object I as an observer will see the called Einstein Ring).
For compute that I first write a mapping of this function. I take the approximation of a = x + sin(t)/exp(x) , b = y + cos(t)/exp(y). So when the source light its far from the mass, the exponential will be approximately zero, and if it is just behind the mass the source light coordinates will be (0,0), so the imagen will return (sin(t),cos(t)) the Einstein circle I was expected to get.
I code that in this way, first I define my approximation:
def coso1(x,y):
t = arange(0,2*pi, .01);
a = x + sin(t)/exp(x)
b = y + cos(t)/exp(y)
plt.plot(a,b)
plt.show()
Then I try to plot that to see how the coordinate map is changing:
from numpy import *
from matplotlib.pyplot import *
x=linspace(-10,10,10)
y=linspace(-10,10,10)
y = y.reshape(y.size, 1)
x = x.reshape(x.size, 1)
plot(coso1(x,y))
And I get this plot.
Graphic
Notice that it looks that way because the intervale I choose to take values for the x and y coordinates. If I take place in the "frontier" case where x={-1,0,1} and y={-1,0,1} it will show how the space its been deformed (or I'm guessing thats what Im seeing).
I then have a few questions. An easy question but that I hadnt find an easy answer its if I can manipulate this transformation (rotate with the mouse to aprecciate the deformation, a controller of how x or y change). And the two hard questions: Can I plot the countour lines to see how exactly are changing the topography of my map in every level of x (suppose I let y be constant), and the other question: If this is my "new" way of how the map is acting, can I use this new coordinate map as a tool where If a project any image it will be distorted in function of this "new" map. Something analogous of how cameras works with fish lens effect.

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

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)

Rephrase spirograph code into function

I'm writing a python spirograph program, and I need some help with converting part of it into a function. The code is attempting to reproduce the result illustrated in the video I found here. One line rotates around the origin, and then another rotates off the end of that, etc.
With a little bit of research into (what I think is) trigonometry, I put together a function rotate(point, angle, center=(0, 0)). The user inputs a point to be rotated, the angle (clockwise) that it is to be rotated by, and the centerpoint for it to be rotated around.
Then, I implemented an initial test, whereby one line rotates around the other. The end of the second line draws as if it were holding a pen. The code's a little messy, but it looks like this.
x, y = 0, 0
lines = []
while 1:
point1 = rotate((0,50), x)
point2 = map(sum,zip(rotate((0, 50), y), point1))
if x == 0:
oldpoint2 = point2
else:
canvas.create_line(oldpoint2[0], oldpoint2[1], point2[0], point2[1])
lines.append( canvas.create_line(0, 0, point1[0], point1[1]) )
lines.append( canvas.create_line(point1[0], point1[1], point2[0], point2[1]) )
oldpoint2 = point2
tk.update()
x += 5
if x > 360 and y > 360:
x -= 360
canvas.delete("all")
time.sleep(1)
y += 8.8
if y > 360: y -= 360
for line in lines:
canvas.delete(line)
lines = []
Great, works perfectly. My ultimate goal is what's in the video, however. In the video, the user can input any arbitrary number of arms, then define the length and angular velocity for each arm. Mine only works with two arms. My question, ultimately, is how to put the code I posted into a function that looks like drawSpiral(arms, lenlist, velocitylist). It would take the number of arms, a list of the velocities for each arm, and a list of the length of each arm as arguments.
What I've Tried
I've already attempted this several times. Initially, I had something that didn't work at all. I got some cool shapes, but definitely not the desired output. I've worked for a few hours, and the closest I could get was this:
def drawSpiral(arms, lenlist, velocitylist):
if not arms == len(lenlist) == len(velocitylist):
raise ValueError("The lists don't match the provided number of arms")
iteration = 0
while 1:
tk.update()
iteration += 1
#Empty the list of points
pointlist = []
pointlist.append((0, 0))
#Create a list of the final rotation degrees for each point
rotations = []
for vel in velocitylist:
rotations.append(vel*iteration)
for n in range(arms):
point = tuple(map(sum,zip(rotate((0, lenlist[n]), rotations[n], pointlist[n]))))
pointlist.append(point)
for point in pointlist:
create_point(point)
for n in range(arms):
print pointlist[n], pointlist[n+1]
This is fairly close to my solution, I feel, but not quite there. Calling drawSpiral(2, [50, 75], [1, 5]) looks like it might be producing some of the right points, but not connecting the right sets. Staring at it for about an hour and trying a few things, I haven't made any progress. I've also gotten pretty confused looking at my own code. I'm stuck! The point rotating around the center is attached to a point that is just flying diagonally across the screen and back. The line attached to the center is stretching back and forth. Can someone point me in the right direction?
Results of further tests
I've set up both functions to plot points at the ends of each arm, and found some interesting results. The first arm, in both cases, is rotating at a speed of 5, and the second at a speed of -3. The loop, outside of the function, is producing the pattern:
The function, called with drawSpiral(2, [50, 50], [5, -3]), produces the result of
It seems to be stretching the top half. With both arms having a velocity of 5, the function would be expected to produce two circles, one larger than the other. However, it produces an upside-down cardioid shape, with the point connected to the center.
Now there's more evidence, can anyone who understands math more than me help me?
Your error is in
for n in range(arms):
point = tuple(map(sum,zip(rotate((0, lenlist[n]), rotations[n], pointlist[n]))))
pointlist.append(point)
Specifically,
rotate((0, lenlist[n])
replace it with
for n in range(arms):
point = tuple(map(sum,zip(rotate((pointlist[n][0], lenlist[n]), rotations[n], pointlist[n]))))
pointlist.append(point)
You go against the usual mathematical notation for polars (circular graphs) and that caused your confusion and eventual issues. As far as I can tell your function is plotting an (X,Y) point (0,length) and then finding the difference between that point and the center point (which is correctly defined as the last point you found) and rotating it around that center. The issue is that (0,length) is not 'length' away from the center. By replacing the (0,lenlist[n]) with (pointlist[n][0],lenlist[n]) makes the next point based upon the last point.
Also I would recommend editing your rotate function to be rotate(length,angle,centerpoint) which would simplify the inputs to a more traditional representation.

Categories