I am trying to check if a point is inside a rotated rectangle.
I found: https://gamedev.stackexchange.com/questions/128598/collision-detection-point-hitting-a-rotating-rectangle
but it doesnt work...
this is my python code:
def collides(point_x, point_y, x_rect, y_rect, width_rect, height_rect, center_rect_x, center_rect_y, angle_rect):
radians = angle_rect / 180.0 * math.pi
angle_sin = math.sin(radians)
angle_cos = math.cos(radians)
x = ((point_x - center_rect_x) * angle_cos - (point_y - center_rect_y) * angle_sin) + center _rect_x
y = ((point_x - center_rect_x) * angle_sin + (point_y - center_rect_y) * angle_cos) + center_rect_y
return x > x_rect and x < x_rect + width_rect and y > y_rect and y < y_rect + height_rect
how can I check if a point collides a rotated rectangle?
Related
Doing the Mars Rover coding problem and am stuck at level 2. Trying to debug but I just can't see it and it wont let me progress until current level is finished.
Problem Description as follows:
Calculate the position and the direction of the rover after driving a certain distance with a certain steering angle.
Input: WheelBase, Distance, SteeringAngle (2 decimal floats)
Output: X, Y, NewDirection Angle
Example:
In: 1.00 1.00 30.00
Out: 0.24 0.96 28.65
Anybody know of any links to some walk throughs, solutions etc or more examples?
There is an image link to the coding problem at the bottom
Thanks
https://catcoder.codingcontest.org/training/1212/play
## Level 1 - calculate the turn radius ##
## level1 2 - calculate new position and angle
import math
## solution works for this data
WHEELBASE = 1.00
DISTANCE = 1.00
STEERINGANGLE = 30.00
#WHEELBASE = 1.75
#DISTANCE = 3.14
#STEERINGANGLE = -23.00
def calculateTurnRadius(wheelbase, steeringangle):
return round(wheelbase / math.sin(math.radians(steeringangle)), 2)
def calculateNewDirection(wheelbase, steeringangle, distance):
turnRadius = calculateTurnRadius(wheelbase, steeringangle)
theta = distance / turnRadius
#brings theta to within a 180 arc
while theta >= math.pi * 2:
theta -= math.pi * 2
while theta < 0:
theta += math.pi * 2
# calculate theta with basic sin and cos trig
x = turnRadius - (math.cos(theta) * turnRadius)
y = math.sin(theta) * turnRadius
x = abs(round(x, 2))
y = round(y, 2)
theta = math.degrees(theta)
theta = round(theta, 2)
return x, y, theta
print(f"Turn Radius = {calculateTurnRadius(WHEELBASE, STEERINGANGLE)}")
print(f"{calculateNewDirection(WHEELBASE, STEERINGANGLE, DISTANCE)}")
Turn Radius = 2.0
(0.24, 0.96, 28.65)
[1]: https://i.stack.imgur.com/tDY2u.jpg
I'm also stuck, but what I have so far works for the first 2 inputs:
import math
WheelBase, Distance, SteeringAngle = 1, 1, 30.00
WheelBase, Distance, SteeringAngle = 2.13, 4.30, 23.00
WheelBase = float(WheelBase)
Distance = float(Distance)
SteeringAngle = float(SteeringAngle)
TurnRadius = abs(WheelBase / math.sin(math.pi * (SteeringAngle) / 180))
NewDirection = 180 * (Distance / TurnRadius) / math.pi
chord = 2 * TurnRadius * math.sin(math.pi * NewDirection / 360)
y = TurnRadius * math.sin(math.pi * (NewDirection) / 180)
x = math.sqrt(chord ** 2 - y ** 2)
print(round(x, 2), round(y, 2), round(NewDirection, 2))
print(chord)
print(math.sqrt(x ** 2 + y ** 2))
I haven't really looked at your code, but I got the solutions from level 1 to 4. So here's my code for level 2.
import math
def turn_radius(wheel_base, steering_angle):
radius: float = wheel_base/math.sin(math.radians(steering_angle))
print (f"{radius:.2f}")
return radius
def get_position(distance, steering_angle, radius):
angle = (distance*180)/(math.pi*radius)
y = (math.sin(math.radians(angle)) * radius)
x = radius - (math.cos(math.radians(angle)) * radius)
while angle < 0:
angle = 360 + angle
if angle == 360:
angle = 0
print(f"{x:.2f} {y:.2f} {angle:.2f}")
if __name__ == "__main__":
wheel_base = 2.7
distance = 45
steering_angle = -34
if steering_angle == 0:
steering_angle = 360
radius = turn_radius(wheel_base ,steering_angle)
get_position(distance, steering_angle, radius)
I'm likely using the wrong terms but seeking some help.
I would like to generate an array of x,y values for a grid that sits within the perimeter of an ellipse shape.
There is code here: http://people.sc.fsu.edu/~jburkardt/c_src/ellipse_grid/ellipse_grid.html to accomplish this in Python.
However, for my purpose the ellipses have been rotated to a certain degree. The current equation does not account for this and need some help to account for this transformation, unsure how to change the code to do this?
I've been looking into np.meshrid function as well, so if there are better ways to do this, please say.
Many thanks.
Given an ellipse in the Euclidean plane in its most general form as quadratic curve in the form
f(x,y) = a x^2 + 2b x y + c y^2 + 2d x + 2f y + g,
one can compute the center (x0,y0) by
((cd-bf)/(b^2-ac), (af-bd)/(b^2-ac))
(see equations 19 and 20 at Ellipse on MathWorld). The length of the major axis a_m can be computed by equation 21 on the same page.
Now it suffices to find all grid points (x,y) inside the circle with center (x0,y0) and radius a_m with
sign(f(x,y)) = sign(f(x0,y0)).
To generate lattice points inside ellipse, we have to know where horizontal line intersects that ellipse.
Equation of zero-centered ellipse, rotated by angle Theta:
x = a * Cos(t) * Cos(theta) - b * Sin(t) * Sin(theta)
y = a * Cos(t) * Sin(theta) + b * Sin(t) * Cos(theta)
To simplify calculations, we can introduce pseudoangle Fi and magnitude M (constants for given ellipse)
Fi = atan2(a * Sin(theta), b * Cos(theta))
M = Sqrt((a * Sin(theta))^2 + (b * Cos(theta))^2)
so
y = M * Sin(Fi) * Cos(t) + M * Cos(Fi) * Sin(t)
y/M = Sin(Fi) * Cos(t) + Cos(Fi) * Sin(t)
y/M = Sin(Fi + t)
and solution for given horizontal line at position y are
Fi + t = ArcSin( y / M)
Fi + t = Pi - ArcSin( y / M)
t1 = ArcSin( y / M) - Fi //note two values
t2 = Pi - ArcSin( y / M) - Fi
Substitute both values of t in the first equation and get values of X for given Y, and generate one lattice point sequence
To get top and bottom coordinates, differentiate y
y' = M * Cos(Fi + t) = 0
th = Pi/2 - Fi
tl = -Pi/2 - Fi
find corresponding y's and use them as starting and ending Y-coordinates for lines.
import math
def ellipselattice(cx, cy, a, b, theta):
res = []
at = a * math.sin(theta)
bt = b * math.cos(theta)
Fi = math.atan2(at, bt)
M = math.hypot(at, bt)
ta = math.pi/2 - Fi
tb = -math.pi/2 - Fi
y0 = at * math.cos(ta) + bt *math.sin(ta)
y1 = at * math.cos(tb) + bt *math.sin(tb)
y0, y1 = math.ceil(cy + min(y0, y1)), math.floor(cy + max(y0, y1))
for y in range(y0, y1+1):
t1 = math.asin(y / M) - Fi
t2 = math.pi - math.asin(y / M) - Fi
x1 = a * math.cos(t1) * math.cos(theta) - b* math.sin(t1) * math.sin(theta)
x2 = a * math.cos(t2) * math.cos(theta) - b* math.sin(t2) * math.sin(theta)
x1, x2 = math.ceil(cx + min(x1, x2)), math.floor(cx + max(x1, x2))
line = [(x, y) for x in range(x1, x2 + 1)]
res.append(line)
return res
print(ellipselattice(0, 0, 4, 3, math.pi / 4))
I have a problem with my Torus in Opengl.
Here is my code on Python:
global numc, numt, r
twopi = 2 * math.pi
for i in range(0, numc):
for j in range(0, numt):
k = 1
while k >= 0:
s = (i + k) % numc + 0.5
t = j % numt
x = (1 + r * math.cos(s * twopi / numc)) * math.cos(t * twopi / numt)
y = (1 + r * math.cos(s * twopi / numc)) * math.sin(t * twopi / numt)
z = r * math.sin(s * twopi / numc)
Colors_torus.extend([1.0, 0.0, 0.0])
Torus.extend([x, y, z])
k -= 1
On the screen below on the right side you may observe that the circles do not converge.
Right now, I am working on something (in Python) to create an ellipse and display it on the screen (in the console). I have the ellipse creation already, but rotating the ellipse gives me problems.
Ellipse Method:
def ellipse(yc, xc, b, a, rotation=0):
yc_min_b = yc - b
# divide b to account for spacing in console
b = int(round(b / 2 + 0.01)) - 1
yc = yc_min_b + b
points = []
a2 = a*a
b2 = b*b
fa2 = 4 * a2
fb2 = 4 * b2
x = 0
y = b
sigma = 2 * b2 + a2 * (1 - 2 * b)
while b2 * x <= a2 * y:
points.append((xc + x, yc + y))
points.append((xc - x, yc + y))
points.append((xc + x, yc - y))
points.append((xc - x, yc - y))
if sigma >= 0:
sigma += fa2 * (1 - y)
y -= 1
sigma += b2 * ((4 * x) + 6)
x += 1 # INCREMENT
x = a
y = 0
sigma = 2 * a2 + b2 * (1 - 2 * a)
while a2 * y <= b2 * x:
points.append((xc + x, yc + y))
points.append((xc - x, yc + y))
points.append((xc + x, yc - y))
points.append((xc - x, yc - y))
if sigma >= 0:
sigma += fb2 * (1 - x)
x -= 1
sigma += a2 * ((4 * y) + 6)
y += 1 # INCREMENT
# now rotate points
sin = math.sin(rotation)
cos = math.cos(rotation)
rotated = []
for point in points:
x = point[0]
y = point[1]
'''
px -= xc
py -= yc
xnew = px * c - py * s
ynew = px * s + py * c
px = xnew + xc
py = ynew + yc
'''
#XRot := Round(XCenter + (X - XCenter) * CAngle - (Y - YCenter) * SAngle);
#YRot := Round(YCenter + (X - XCenter) * SAngle + (Y - YCenter) * CAngle);
x = round(xc + (x + xc) * cos - (y - yc) * sin)
y = round(yc + (x - xc) * sin + (y - yc) * cos)
rotated.append((int(x), int(y)))
points = rotated
print points
ell_matr = []
# set up empty matrix
maxx = 0
maxy = 0
for point in points:
y = point[1]
x = point[0]
if y > maxy:
maxy = y
if x > maxx:
maxx = x
for i in range(maxy + 1):
ell_matr.append([])
for j in range(maxx + 1):
ell_matr[i].append(' ')
for point in points:
y = point[1]
x = point[0]
ell_matr[y][x] = fill
return ell_matr
I would ignore the matrix part, as it is translating the points into a matrix to display on screen.
Here is the output of an ellipse without rotation.
And when I add a 45 degree rotation (converted to radians)
Is there a better way to rotate the points?
I'm trying traverse all the cells that a line goes through. I've found the Fast Voxel Traversal Algorithm that seems to fit my needs, but I'm currently finding to be inaccurate. Below is a graph with a red line and points as voxel coordinates that the algorithm gives. As you can see it is almost correct except for the (4, 7) point, as it should be (5,6). I'm not sure if i'm implementing the algorithm correctly either so I've included it in Python. So i guess my question is my implementation correct or is there a better algo to this?
Thanks
def getVoxelTraversalPts(strPt, endPt, geom):
Max_Delta = 1000000.0
#origin
x0 = geom[0]
y0 = geom[3]
(sX, sY) = (strPt[0], strPt[1])
(eX, eY) = (endPt[0], endPt[1])
dx = geom[1]
dy = geom[5]
sXIndex = ((sX - x0) / dx)
sYIndex = ((sY - y0) / dy)
eXIndex = ((eX - sXIndex) / dx) + sXIndex
eYIndex = ((eY - sYIndex) / dy) + sYIndex
deltaX = float(eXIndex - sXIndex)
deltaXSign = 1 if deltaX > 0 else -1 if deltaX < 0 else 0
stepX = deltaXSign
tDeltaX = min((deltaXSign / deltaX), Max_Delta) if deltaXSign != 0 else Max_Delta
maxX = tDeltaX * (1 - sXIndex + int(sXIndex)) if deltaXSign > 0 else tDeltaX * (sXIndex - int(sXIndex))
deltaY = float(eYIndex - sYIndex)
deltaYSign = 1 if deltaY > 0 else -1 if deltaY < 0 else 0
stepY = deltaYSign
tDeltaY = min(deltaYSign / deltaY, Max_Delta) if deltaYSign != 0 else Max_Delta
maxY = tDeltaY * (1 - sYIndex + int(sYIndex)) if deltaYSign > 0 else tDeltaY * (sYIndex - int(sYIndex))
x = sXIndex
y = sYIndex
ptsIndexes = []
pt = [round(x), round(y)]
ptsIndexes.append(pt)
prevPt = pt
while True:
if maxX < maxY:
maxX += tDeltaX
x += deltaXSign
else:
maxY += tDeltaY
y += deltaYSign
pt = [round(x), round(y)]
if pt != prevPt:
#print pt
ptsIndexes.append(pt)
prevPt = pt
if maxX > 1 and maxY > 1:
break
return (ptsIndexes)
The voxels that you are walking start at 0.0, i.e. the first voxel spans space from 0.0 to 1.0, a not from -0.5 to 0.5 as you seem to be assuming. In other words, they are the ones marked with dashed line, and not the solid one.
If you want voxels to be your way, you will have to fix initial maxX and maxY calculations.
Ain't nobody got time to read the paper you posted and figure out if you've implemented it correctly.
Here's a question, though. Is the algorithm you've used (a) actually meant to determine all the cells that a line passes through or (b) form a decent voxel approximation of a straight line between two points?
I'm more familiar with Bresenham's line algorithm which performs (b). Here's a picture of it in action:
Note that the choice of cells is "aesthetic", but omits certain cells the line passes through. Including these would make the line "uglier".
I suspect a similar thing is going on with your voxel line algorithm. However, looking at your data and the Bresenham image suggests a simple solution. Walk along the line of discovered cells, but, whenever you have to make a diagonal step, consider the two intermediate cells. You can then use a line-rectangle intersection algorithm (see here) to determine which of the candidate cells should have, but wasn't, included.
I guess just to be complete, I decided to use a different algo. the one referenced here dtb's answer on another question.
here's the implementation
def getIntersectPts(strPt, endPt, geom=[0,1,0,0,0,1]):
'''
Find intersections pts for every half cell size
** cell size has only been tested with 1
Returns cell coordinates that the line passes through
'''
x0 = geom[0]
y0 = geom[3]
(sX, sY) = (strPt[0], strPt[1])
(eX, eY) = (endPt[0], endPt[1])
xSpace = geom[1]
ySpace = geom[5]
sXIndex = ((sX - x0) / xSpace)
sYIndex = ((sY - y0) / ySpace)
eXIndex = ((eX - sXIndex) / xSpace) + sXIndex
eYIndex = ((eY - sYIndex) / ySpace) + sYIndex
dx = (eXIndex - sXIndex)
dy = (eYIndex - sYIndex)
xHeading = 1.0 if dx > 0 else -1.0 if dx < 0 else 0.0
yHeading = 1.0 if dy > 0 else -1.0 if dy < 0 else 0.0
xOffset = (1 - (math.modf(sXIndex)[0]))
yOffset = (1 - (math.modf(sYIndex)[0]))
ptsIndexes = []
x = sXIndex
y = sYIndex
pt = (x, y) #1st pt
if dx != 0:
m = (float(dy) / float(dx))
b = float(sY - sX * m )
dx = abs(int(dx))
dy = abs(int(dy))
if dx == 0:
for h in range(0, dy + 1):
pt = (x, y + (yHeading *h))
ptsIndexes.append(pt)
return ptsIndexes
#print("m {}, dx {}, dy {}, b {}, xdir {}, ydir {}".format(m, dx, dy, b, xHeading, yHeading))
#print("x {}, y {}, {} {}".format(sXIndex, sYIndex, eXIndex, eYIndex))
#snap to half a cell size so we can find intersections on cell boundaries
sXIdxSp = round(2.0 * sXIndex) / 2.0
sYIdxSp = round(2.0 * sYIndex) / 2.0
eXIdxSp = round(2.0 * eXIndex) / 2.0
eYIdxSp = round(2.0 * eYIndex) / 2.0
# ptsIndexes.append(pt)
prevPt = False
#advance half grid size
for w in range(0, dx * 4):
x = xHeading * (w / 2.0) + sXIdxSp
y = (x * m + b)
if xHeading < 0:
if x < eXIdxSp:
break
else:
if x > eXIdxSp:
break
pt = (round(x), round(y)) #snapToGrid
# print(w, x, y)
if prevPt != pt:
ptsIndexes.append(pt)
prevPt = pt
#advance half grid size
for h in range(0, dy * 4):
y = yHeading * (h / 2.0) + sYIdxSp
x = ((y - b) / m)
if yHeading < 0:
if y < eYIdxSp:
break
else:
if y > eYIdxSp:
break
pt = (round(x), round(y)) # snapToGrid
# print(h, x, y)
if prevPt != pt:
ptsIndexes.append(pt)
prevPt = pt
return set(ptsIndexes) #elminate duplicates