I have a square with center x0, y0. I wish to rotate the vertex of this square for a given angle (theta) expressed in degree and return the new rotated vertex in clockwise direction. I am using this approach to rotate a single point applied for each vertex
rotate point (px, py) around point (x0, y0) by angle theta you'll get:
p'x = cos(theta) * (px-x0) - sin(theta) * (py-y0) + x0
p'y = sin(theta) * (px-x0) + cos(theta) * (py-y0) + y0
where:
px, py = coordinate of the point
y0, x0, = centre of rotation
theta = angle of rotation
I wrote a function in Python where the parameters are: x, y (=centre of the square), side of the square, and theta_degree (angle of rotation in degree) but the returns is in anticlockwise direction
from math import cos, sin
def get_square_plot(x, y, side, theta_degree=0):
theta = theta_degree * pi/180
xa = x-side/2
ya = y+side/2
xb = x+side/2
yb = y+side/2
xc = x+side/2
yc = y-side/2
xd = x-side/2
yd = y-side/2
xa_new = cos(theta) * (xa - x) - sin(theta) * (ya - y) + x
ya_new = sin(theta) * (xa - x) - cos(theta) * (ya - y) + y
xb_new = cos(theta) * (xb - x) - sin(theta) * (yb - y) + x
yb_new = sin(theta) * (xb - x) - cos(theta) * (yb - y) + y
xc_new = cos(theta) * (xc - x) - sin(theta) * (yc - y) + x
yc_new = sin(theta) * (xc - x) - cos(theta) * (yc - y) + y
xd_new = cos(theta) * (xd - x) - sin(theta) * (yd - y) + x
yd_new = sin(theta) * (xd - x) - cos(theta) * (yd - y) + y
return [(xa_new, ya_new),(xb_new, yb_new),(xc_new, yc_new),(xd_new, yd_new)]
get_square_plot(0, 0, 10, 0)
[(-5.0, -5.0), (5.0, -5.0), (5.0, 5.0), (-5.0, 5.0)]
instead of
[(-5.0, 5.0), (5.0, 5.0), (5.0, -5.0), (-5.0, -5.0)]
It's such a simple thing -- you've got the formula wrong for all of your y-values.
It should be:
ya_new = sin(theta) * (xa - x) + cos(theta) * (ya - y) + y
addition instead of subtraction.
Don't forget about the geometry module, either. It can deal with a variety of basic shapes and handle translation, rotation, etc...
A square can be constructed with RegularPolygon. It does so by locating vertices a given radius from the center; to get a square with a given side length, divide by sqrt(2). Here is a function to rotate the diamond-orientation so sides are parallel to the axes and then rotate the desired angle, a:
>>> Square = lambda c, r, a: RegularPolygon(c, r/sqrt(2), 4, -rad(a) - pi/4)
>>> Square((0,0),10,0).vertices
[Point(5, -5), Point(5, 5), Point(-5, 5), Point(-5, -5)]
>>> [w.n(2) for w in Square((0,0),10,1).vertices]
[Point(4.9, -5.1), Point(5.1, 4.9), Point(-4.9, 5.1), Point(-5.1, -4.9)]
Note that the slight CW rotation of 1 degree (-rad(1)) puts the first vertex a little closer to the y-axis and a little lower as we expect. You can also enter a symbol for the angle:
>>> from sympy.utilities.misc import filldedent
>>> print filldedent(Square((0,0),10,a).vertices)
[Point(5*sqrt(2)*cos(pi*a/180 + pi/4), -5*sqrt(2)*sin(pi*a/180 +
pi/4)), Point(5*sqrt(2)*sin(pi*a/180 + pi/4), 5*sqrt(2)*cos(pi*a/180 +
pi/4)), Point(-5*sqrt(2)*cos(pi*a/180 + pi/4), 5*sqrt(2)*sin(pi*a/180
+ pi/4)), Point(-5*sqrt(2)*sin(pi*a/180 + pi/4),
-5*sqrt(2)*cos(pi*a/180 + pi/4))]
You can also check your point rotation formula by rotating a point -theta (for CW):
>>> var('px py theta x0 y0')
(px, py, theta, x0, y0)
>>> R = Point(px,py).rotate(-theta, Point(x0,y0))
>>> R.x
x0 + (px - x0)*cos(theta) + (py - y0)*sin(theta)
>>> R.y
y0 + (-px + x0)*sin(theta) + (py - y0)*cos(theta)
Related
I have a line with lenght of l and p1 and p2 and i want to rotate it by angle.
I was using this matrix but it doesn't work.
matrix
I have this code in python:
def rotate (point, point2, angel):
x1 = (cos(radians(angel)) * point1.x) +( sin(radians(angel)) * point1.y)
y1 = (-1 * sin(radians(angel)) * point1.x )+ (cos(radians(angel)) * point1.y)
x2 = (cos(radians(angel)) * point2.x) + (sin(radians(angel)) * point2.y)
y2 = (-1 * sin(radians(angel)) * point2.x) + (cos(radians(angel)) * point2.y)
return [[x1, y1], [x2, y2]]
You first need to specify an origin point, the rotation will be created around that point. You can adapt your code and use something like this:
def rotate(origin, point, angle):
"""
Rotate a point counterclockwise by a given angle around a given origin.
The angle should be given in radians.
"""
ox, oy = origin.x, origin.y
px, py = point.x, point.y
qx = ox + math.cos(angle) * (px - ox) - math.sin(angle) * (py - oy)
qy = oy + math.sin(angle) * (px - ox) + math.cos(angle) * (py - oy)
return Point(qx, qy)
You can then plot some point and see the results with:
x1 = Point(0, 0)
x2 = Point(5, 5)
mid_point = Point((x1.x + x2.x) / 2, (x1.y + x2.y) / 2)
plt.plot([x1.x, x2.x], [x1.y, x2.y], c='red')
x1 = rotate(mid_point, x1, math.radians(30))
x2 = rotate(mid_point, x2, math.radians(30))
plt.plot([x1.x, x2.x], [x1.y, x2.y], c='blue')
plt.show()
Where you can clearly see the rotation around the middle point between the two lines.
I am trying to rotate a triad of orthogonal axis, which origin is located on the surface of a sphere. The aim would be to rotate them in order to pass from Cartesian coordinates, to radial and transverse component of the sphere. I tried to find a python function but I haven't find anything good for my case so I built it by myself.
First I computed the three angles:
#Center of the sphere
xc = 7500
yc = 7500
zc = 8960
#File where the coordinates are located
data = pd.read_csv('file_test', header = None,delimiter =' ')
xa = np.array(data.iloc[1:,1])
ya = np.array(data.iloc[1:,2])
za = np.array(data.iloc[1:,0])
#Angles definition
theta = np.arctan2((ya-yc),(xa-xc))
phi = np.arctan2((za-zc),(xa-xc))
gamma = np.arctan2((za-zc),(ya-yc))
Then I rotate the vector x,y,z in this way:
def rotate_receivers(x, y, z, a, b, c):
x1 = x * np.cos(b) * np.cos(c) - y * (np.sin(c) * np.cos(b)) + z * (np.sin(b))
y1= x * (np.sin(a) * np.sin(b) *np.cos(c) + np.cos(a) * np.sin(c)) + y * ( - np.sin(b) * np.sin(a) * np.sin(c) + np.cos(c) * np.cos(a)) - z * (np.sin(a) * np.cos(b))
z1 = x * ( - np.cos(a) * np.sin(b) * np.cos(c) + np.sin(a) * np.sin(c)) + y * ( np.sin(b) * np.sin(c) * np.cos(a) + np.sin(a) * np.cos(c)) + z * np.cos(a) * np.cos(b)
return x1, y1, z1
Now I am expecting to rotate them in this way:
x1,y1,z1 = rotate_receivers(x[i],y[i],z[i],gamma[i],phi[i],theta[i])
Now the rotation works only for some angles and I don't understand why. It has to be something wrong maybe in the way I defined the angles but I don't understand what.
Thanks!
I wrote some code to try and implement one function that creates a triangle using the coordinates of the center of the screen and in this case it corresponds to the center of the triangle aswell, this coordinates are identified as "cx" and "cy" since the window is 800 x 600 cx = 400 and cy = 300.
with this i created a "first point" that has the same x coordinate of the center but its 100 pixels above the center, now using the center and this first point i tried to calculate where the other point should be.
here is the code:
def triangle(cx,cy):
angle = 2*math.pi/3
first_point_x = cx
first_point_y = cy + 100
vertex = [first_point_x,first_point_y]
for i in range(2):
newx = (vertex[i*2]-cx) * math.cos(angle) - (vertex[i*2+1]-cy) * math.sin(angle)
newy = (vertex[i*2+1]-cy) * math.cos(angle) + (vertex[i*2]-cx) * math.sin(angle)
vertex.append(newx)
vertex.append(newy)
return vertex
But for some reason the array gives negative values and numbers that overall dont correspond to what i wanted.
Any help whould be appreciated.
What you actually do is to compute a vector from (cx, cy) to the last point in the array and to rotate the vector by 120°. But you missed to add the vector to (cx, cy) before you append the point to the list:
newx = (vertex[i*2]-cx) * math.cos(angle) - (vertex[i*2+1]-cy) * math.sin(angle)
newy = (vertex[i*2+1]-cy) * math.cos(angle) + (vertex[i*2]-cx) * math.sin(angle)
newx = cx + (vertex[i*2]-cx) * math.cos(angle) - (vertex[i*2+1]-cy) * math.sin(angle)
newy = cy + (vertex[i*2+1]-cy) * math.cos(angle) + (vertex[i*2]-cx) * math.sin(angle)
Compute the vector from the center to the last point
vx = vertex[i*2] - cx
vy = vertex[i*2+1] - cy
Rotate the vector
rotated_vx = vx * math.cos(angle) - vy * math.sin(angle)
rotated_vy = vy * math.cos(angle) + vx * math.sin(angle)
Compute the new point
newx = cx + rotated_vx
newy = cy + rotated_vy
I have a line segments defined with a start and an end point:
A:
x1 = 10.7196405787775
y1 = 59.9050401935882
B:
x2 = 10.7109989561813
y2 = 59.9018650448204
where x defines longitude and y defines latitude.
I also have a point:
P:
x0 = 10.6542116666667
y0 = 59.429105
How do I compute the shortest distance between the line segment and the point? I know how to do this in Cartesian coordinates, but not in long/lat coordinates.
Here is an implementation of a formula off Wikipedia:
def distance(p0, p1, p2): # p3 is the point
x0, y0 = p0
x1, y1 = p1
x2, y2 = p2
nom = abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1)
denom = ((y2 - y1)**2 + (x2 - x1) ** 2) ** 0.5
result = nom / denom
return result
print distance((0, 0), (3, 4), (5, 6))
# should probably test less obvious cases
assert 1 == distance((0, 0), (1, 1), (2, 1))
# change 0.001 to whatever accuracy you demand on testing.
# Notice that it's never perfect...
assert 0.5 * (2 ** 0.5) - distance((0, 0), (1, 0), (0, 1)) < 0.001
Using the helpful Python geocoding library geopy, and the formula for the midpoint of a great circle from Chris Veness's geodesy formulae, we can find the distance between a great circle arc and a given point:
from math import sin, cos, atan2, sqrt, degrees, radians, pi
from geopy.distance import great_circle as distance
from geopy.point import Point
def midpoint(a, b):
a_lat, a_lon = radians(a.latitude), radians(a.longitude)
b_lat, b_lon = radians(b.latitude), radians(b.longitude)
delta_lon = b_lon - a_lon
B_x = cos(b_lat) * cos(delta_lon)
B_y = cos(b_lat) * sin(delta_lon)
mid_lat = atan2(
sin(a_lat) + sin(b_lat),
sqrt(((cos(a_lat) + B_x)**2 + B_y**2))
)
mid_lon = a_lon + atan2(B_y, cos(a_lat) + B_x)
# Normalise
mid_lon = (mid_lon + 3*pi) % (2*pi) - pi
return Point(latitude=degrees(mid_lat), longitude=degrees(mid_lon))
Which in this example gives:
# Example:
a = Point(latitude=59.9050401935882, longitude=10.7196405787775)
b = Point(latitude=59.9018650448204, longitude=10.7109989561813)
p = Point(latitude=59.429105, longitude=10.6542116666667)
d = distance(midpoint(a, b), p)
print d.km
# 52.8714586903
Hey trying to learn how to code and I cant figure this exercise out.
Specifically getting the precise y axis intercept points.
The formula given works for getting the x axis points but I cant figure out how to get the y axis points.
Exercise :
Input : Radius of circle and the y - intercept of the line.
Output : Circle drawn with a horizontal line across the window with the given y intercept. Mark two points of the intersection.
Print the x values of the points of intersection *Formula : x = ± √r^2 - y^2
Code::
from graphics import *
from math import *
def main():
# enter radius and the y intercept of the line
radius = eval(input("Put in radius:: "))
yinter = eval(input("Put in y intersec:: "))
#Draw window + circle + line
win = GraphWin()
win.setCoords(-10.0, -10.0, 10.0, 10.0)
circle = Circle(Point(0.0,0.0), radius)
mcircle = Circle(Point(0.0,0.0), 0.5)
circle.draw(win)
mcircle.draw(win)
line = Line(Point(-10, 0), Point(10, yinter))
line.draw(win)
#Calculate x axis points of intersept
xroot1 = sqrt(radius * radius - yinter * yinter)
xroot2 = -abs(xroot1)
print("Xroot 1 : ", xroot1)
print("Xroot 2 : ", xroot2)
x = 0
yroot1 = sqrt(radius * radius - x * x)
yroot2 = -abs(yroot1)
print("Yroot 1 : ", yroot1)
print("Yroot 2 : ", yroot2)
#mark two points of intersept in red
sc1 = Circle(Point(xroot1, yroot1), 0.3)
sc1.setFill('red')
sc2 = Circle(Point(xroot2, yroot2), 0.3)
sc2.setFill('red')
sc1.draw(win)
sc2.draw(win)
main()
Answer - With Radius of 8 and Y intersect point of 2
Yroot1 = 7.75
Yroot2 = -7.75
Xroot1 = 8.0
Xroot2 = -8.0
I just came up with a subroutine to find intersection points while solving another Zelle-graphics related SO question. There may be ways to simplify the math but I'm going the long way around:
from graphics import *
def intersection(center, radius, p1, p2):
""" find the two points where a secant intersects a circle """
dx, dy = p2.x - p1.x, p2.y - p1.y
a = dx**2 + dy**2
b = 2 * (dx * (p1.x - center.x) + dy * (p1.y - center.y))
c = (p1.x - center.x)**2 + (p1.y - center.y)**2 - radius**2
discriminant = b**2 - 4 * a * c
assert (discriminant > 0), 'Not a secant!'
t1 = (-b + discriminant**0.5) / (2 * a)
t2 = (-b - discriminant**0.5) / (2 * a)
return Point(dx * t1 + p1.x, dy * t1 + p1.y), Point(dx * t2 + p1.x, dy * t2 + p1.y)
def main(win):
center = Point(0.0, 0.0)
# Enter radius
radius = float(input("Put in radius: "))
# Draw circle and center dot
Circle(center, radius).draw(win)
Circle(center, 0.3).draw(win)
# Enter the y intercept of the line
yinter = float(input("Put in y intercept: "))
# Draw line
p1, p2 = Point(-10.0, 0.0), Point(10.0, yinter)
Line(p1, p2).draw(win)
# Mark two points of intercept in red
for i, root in enumerate(intersection(center, radius, p1, p2), start=1):
print("Root {}:".format(i), root)
dot = Circle(root, 0.3)
dot.setFill('red')
dot.draw(win)
win = GraphWin()
win.setCoords(-10.0, -10.0, 10.0, 10.0)
main(win)
win.getMouse()
OUTPUT
NOTE
You can get values input that do not produce a secant, e.g. a radius of 2 and an intercept of 8. Your code doesn't account for this -- the above will simply throw an assertion error if it occurs. But you can upgrade that to an error you can catch and fix.
For the y coordinates you can use a similar formula:
y = ± sqrt(r^2 - x^2)
and the do everything the same with marking the roots.
You should write the code like this:
x = sqrt(r ** 2 - y ** 2)
line = Line(Point(-10, 0), Point(10, yinter))
line.draw(win)
Line(Point(-10,0) is wrong, it should read:
Line(Point(-10,yinter).
Also set Xroot1 and Xroot2 = 0 or -x=0, x=0
def intersection(center, radius, p1, p2):
dx, dy = p2[0] - p1[0], p2[1] - p1[1]
a = dx**2 + dy**2
b = 2 * (dx * (p1[0]- center[0]) + dy * (p1[1] - center[1]))
c = (p1[0] - center[0])**2 + (p1[1] - center[1])**2 - radius**2
K = b**2 - 4 * a * c
return True if K>0 else False
if __name__ == "__main__":
p1 = 10,50
p2 = 100,50
center= 50,150
radius = 600
print(intersection(center, radius, p1, p2))