I have made this little function for checking if a point is inside a selection box:
def select(x1, y1, w, h):
x, y = position
x2 = x1 + w
y2 = y1 + h
if x >= x1 and y >= y1:
if x <= x2 and y <= y2:
selected = True
else:
selected = False
But it only works if w and h are larger values than x1, and y1. For example, it doesn't work if the box has a negative size. How can I include checking those cases without a prior check of if w < x1 and h < y1?
Why not using the following checks:
if x >= min(x1,x2) and x <= max(x1,x2):
if y >= min(y1,y2) and y <= max(y1,y2):
...
You can find the minimum and maximum of the two numbers, and assign them to variables in one statement, using sorted(list) and destructuring assignment. Also note the use of min <= value <= max chained comparisons:
def select(x1, y1, w, h):
x, y = position
minX, maxX = sorted([x1, x1 + w])
minY, maxY = sorted([y1, y1 + h])
if minX <= x <= maxX and minY <= y <= maxY:
selected = True
else:
selected = False
Related
I'm rather new to coding and am trying to check whether a dot drawn (in pygame)is on the last line drawn (making the sprouts game).
I have two lists, both holding coordinates of the line segments (in 30pix) just drawn, and one with last dot drawn.
current_line = []
dot_pos = []
Distance function I found online:
def dist_point_to_line(line1, line2, point):
x0 = point[0]
y0 = point[1]
x1 = line1[0]
y1 = line1[1]
x2 = line2[0]
y2 = line2[1]
px = x2-x1
py = y2-y1
norm = px*px + py*py
u = ((x0 - x1) * px + (y0 - y1) * py) / float(norm)
if u > 1:
u = 1
elif u < 0:
u = 0
x = x1 + u * px
y = y1 + u * py
dx = x - x0
dy = y - y0
dist = sqrt(dx*dx + dy*dy)
return dist
Now I want to implement the check at each segment of the line, but I'm stuck. Any advice?
This is what I thought of, though it doesn't want to work:
def distance_check():
for i in range(len(current_line)-1):
if dist_point_to_line(current_line[i], current_line[i+1], dot_pos) < 10:
return True #dot allowed to be placed
return False
If dot_pos is a list then you have to get the last element of the list (dot_pos[-1]). Note the arguments to the function dist_point_to_line are single dots, rather than a list of dots:
def distance_check():
for i in range(len(current_line)-1):
if dist_point_to_line(current_line[i], current_line[i+1], dot_pos[-1]) < 10:
return True #dot allowed to be placed
return False
I started to implement a CORDIC algorithm from zero and I don't know what I'm missing, here's what I have so far.
import math
from __future__ import division
# angles
n = 5
angles = []
for i in range (0, n):
angles.append(math.atan(1/math.pow(2,i)))
# constants
kn = []
fator = 1.0
for i in range (0, n):
fator = fator * (1 / math.pow(1 + (2**(-i))**2, (1/2)))
kn.append(fator)
# taking an initial point p = (x,y) = (1,0)
z = math.pi/2 # Angle to be calculated
x = 1
y = 0
for i in range (0, n):
if (z < 0):
x = x + y*(2**(-1*i))
y = y - x*(2**(-1*i))
z = z + angles[i]
else:
x = x - y*(2**(-1*i))
y = y + x*(2**(-1*i))
z = z - angles[i]
x = x * kn[n-1]
y = y * kn[n-1]
print x, y
When I plug z = π/2 it returns 0.00883479322917 and 0.107149125055, which makes no sense.
Any help will be great!
#edit, I made some changes and now my code has this lines instead of those ones
for i in range (0, n):
if (z < 0):
x = x0 + y0*(2**(-1*i))
y = y0 - x0*(2**(-1*i))
z = z + angles[i]
else:
x = x0 - y0*(2**(-1*i))
y = y0 + x0*(2**(-1*i))
z = z - angles[i]
x0 = x
y0 = y
x = x * kn[n-1]
y = y * kn[n-1]
Now it's working way better, I had the problem because I wasn't using temporary variables as x0 and y0, now when I plug z = pi/2 it gives me better numbers as (4.28270993661e-13, 1.0) :)
I have a travel time map, I want to get the integer points along the shortest path from source to receiver.
My present solution is that I make a runge-kutta integration from the receiver location and get a series of float points. Then I sample every 5 or some number of points and assume it a straight line between in order to use the Bresenham's line algorithm. With this approach, I will get the integer points.
However, it's not enough fast. Because I need to calculate a lot of receivers' shortest path, the sum of time will be very large.
I used line_profiler to analysis the time-consuming, which shows the major part of time is for function ruge-kutta and its calling function get_velocity
codes are below
def optimal_path_2d(gradx_interp,
grady_interp,
starting_point,
dx,
N=100):
"""
Find the optimal path from starting_point to the zero contour
of travel_time. dx is the grid spacing
Solve the equation x_t = - grad t / | grad t |
"""
def get_velocity(position):
""" return normalized velocity at pos """
x, y = position
vel = np.array([gradx_interp(y, x)[0][0], grady_interp(y, x)[0][0]])
return vel / np.linalg.norm(vel)
def runge_kutta(pos, ds):
""" Fourth order Runge Kutta point update """
k1 = ds * get_velocity(pos)
k2 = ds * get_velocity(pos - k1 / 2.0)
k3 = ds * get_velocity(pos - k2 / 2.0)
k4 = ds * get_velocity(pos - k3)
return pos - (k1 + 2 * k2 + 2 * k3 + k4) / 6.0
x = runge_kutta(starting_point, dx)
xl, yl = [], []
for i in range(N):
xl.append(x[0])
yl.append(x[1])
x = runge_kutta(x, dx)
distance = ((x[0] - xl[-1])**2 +
(x[1] - yl[-1])**2)**0.5
if distance < dx*0.9:
break
return yl, xl
def get_curve(x_curve, y_curve, num_interval):
"""Curve Algorithm based on Bresenham's Line Algorithm
Produces a list of tuples
"""
num = len(x_curve)
if num < num_interval:
print("num_interval is too large.")
ret_set = set()
x0 = x_curve[0]
y0 = y_curve[0]
for i in range(num_interval, num, num_interval):
x1 = x_curve[i]
y1 = y_curve[i]
points_on_line = get_line((x0, y0), (x1, y1))
ret_set.update(points_on_line)
x0 = x1
y0 = y1
if num % num_interval != 0:
n = int(num/num_interval)*num_interval
x0 = x_curve[n]
y0 = y_curve[n]
x1 = x_curve[-1]
y1 = y_curve[-1]
points_on_line = get_line((x0, y0), (x1, y1))
ret_set.update(points_on_line)
return list(ret_set)
def get_line(start, end):
"""modifed version of Bresenham's Line Algorithm
Produces a list of tuples from start and end
>>> points1 = get_line((0, 0), (3, 4))
>>> points2 = get_line((3, 4), (0, 0))
>>> assert(set(points1) == set(points2))
>>> print points1
[(0, 0), (1, 1), (1, 2), (2, 3), (3, 4)]
>>> print points2
[(3, 4), (2, 3), (1, 2), (1, 1), (0, 0)]
"""
# Setup initial conditions
x1, y1 = (int(x) for x in start)
x2, y2 = (int(x) for x in end)
dx = x2 - x1
dy = y2 - y1
# Determine how steep the line is
is_steep = abs(dy) > abs(dx)
# Rotate line
if is_steep:
x1, y1 = y1, x1
x2, y2 = y2, x2
# Swap start and end points if necessary and store swap state
swapped = False
if x1 > x2:
x1, x2 = x2, x1
y1, y2 = y2, y1
swapped = True
# Recalculate differentials
dx = x2 - x1
dy = y2 - y1
# Calculate error
error = int(dx / 2.0)
ystep = 1 if y1 < y2 else -1
# Iterate over bounding box generating points between start and end
y = y1
points = []
for x in range(x1, x2 + 1):
coord = (y, x) if is_steep else (x, y)
points.append(coord)
error -= abs(dy)
if error < 0:
y += ystep
error += dx
# Reverse the list if the coordinates were swapped
if swapped:
points.reverse()
return points
nx = 100
ny = 100
num_interval = 5
loc_src = (10, 10)
loc_rec = (70, 90)
coordx = np.arange(nx)
coordy = np.arange(ny)
X, Y = np.meshgrid(coordx, coords)
travel_time = (X-loc_src[0])**2/5 + (Y-loc_src[1])**2/10 # for simplicity
grad_t_y, grad_t_x = np.gradient(travel_time, dx)
if isinstance(travel_time, np.ma.MaskedArray):
grad_t_y[grad_t_y.mask] = 0.0
grad_t_y = grad_t_y.data
grad_t_x[grad_t_x.mask] = 0.0
grad_t_x = grad_t_x.data
gradx_interp = RectBivariateSpline(coordy, coordx, grad_t_x)
grady_interp = RectBivariateSpline(coordy, coordx, grad_t_y)
yl, xl = optimal_path(gradx_interp, grady_interp, loc_rec, dx)
grid_indx = get_curve(xl, yl, num_interval)
I hear that Cython will be faster, then I learn a little recently and try it. the result is only 2 faster than codes above because I'm really new to Cython. The code below is incomplete, and I just wrote it for testing.
import numpy as np
from numpy.core.umath_tests import inner1d
def func(X_interp, Y_interp):
def get_velocity(double x, double y ):
""" return normalized velocity at pos """
cdef double vel[2], norm
a = X_interp(y, x)
vel[0] = a[0][0]
b = Y_interp(y, x)
vel[1] = b[0][0]
# norm = (vel[0]**2 + vel[1]**2)**0.5
# vel[0] = vel[0]/norm
# vel[1] = vel[1]/norm
return vel
def runge_kutta(double x, double y, double ds):
""" Fourth order Runge Kutta point update """
cdef double k1[2], k2[2], k3[2], k4[2], r[2], pos[2]
pos[0] = x; pos[1] = y
k1 = get_velocity(pos[0], pos[1])
k2 = get_velocity(pos[0] - k1[0]/2.0*ds,pos[1] - k1[1]/2.0*ds)
k3 = get_velocity(pos[0] - k2[0]/2.0*ds,pos[1] - k2[1]/2.0*ds)
k4 = get_velocity(pos[0] - k3[0]/2.0*ds,pos[1] - k3[1]/2.0*ds)
cdef size_t i
for i in range(2):
r[i] = pos[i] - ds * (k1[i] + 2*k2[i] + 2*k3[i] + k4[i])/6.0
return r
for i in range(50):
runge_kutta(0, 0, 1.)
# print(runge_kutta(0, 0, 1.))
I would like to draw a large number (about 1 million) of overlapping semitransparent lines with very small alpha values.
I tried matplotlib, but apperently it is not possible to set the alpha values below a certain value (1/256) (see https://github.com/matplotlib/matplotlib/issues/2287)
Switching to OpenGL did not help, I have the same issues (see e.g. http://www.opengl.org/discussion_boards/showthread.php/170674-Alpha-Buffer-Alpha-Bits).
Is there an easy way to draw lines with very small alpha values?
You need a line accumulator, here is the code modified from scikit-image:
import cython
import numpy as np
#cython.wraparound(False)
#cython.boundscheck(False)
def acc_lines(Py_ssize_t[:, ::1] lines, int w, int h):
cdef int[:, ::] count
cdef char steep = 0
cdef Py_ssize_t sx, sy, d, i, idx, r, c, dx, dy, x, y, x2, y2
count = np.zeros((h, w), int)
for idx in range(lines.shape[0]):
steep = 0
x = lines[idx, 0]
y = lines[idx, 1]
x2 = lines[idx, 2]
y2 = lines[idx, 3]
dx = x2 - x
dy = y2 - y
if dx < 0:
dx = -dx
if dy < 0:
dy = -dy
sx = 1 if (x2 - x) > 0 else -1
sy = 1 if (y2 - y) > 0 else -1
if dy > dx:
steep = 1
x, y = y, x
dx, dy = dy, dx
sx, sy = sy, sx
d = (2 * dy) - dx
for i in range(dx):
if steep:
r = x
c = y
else:
r = y
c = x
if 0 <= r < h and 0 <= c < w:
count[r, c] += 1
while d >= 0:
y = y + sy
d = d - (2 * dx)
x = x + sx
d = d + (2 * dy)
r = y2
c = x2
if 0 <= r < h and 0 <= c < w:
count[r, c] += 1
return count.base
Here is a demo that shows how to use it:
from matplotlib.collections import LineCollection
w = h = 512
lines = np.random.randint(0, 512, size=(10000, 4))
count = acc_lines(lines, w, h)
fig, axes = pl.subplots(1, 2, figsize=(10, 5))
lc = LineCollection(lines.reshape(-1, 2, 2), alpha=0.015, color="black")
axes[0].imshow(count, cmap="gray_r")
axes[1].add_collection(lc)
axes[1].axis((0, w, h, 0))
axes[0].set_aspect("equal")
axes[1].set_aspect("equal")
here is the output, left is the image calculated by acc_lines, right is drawed by LineCollection
I have this piece of code to calculate first and second derivatives of a function at a given point
def yy(x):
return 1.0*x*x
def d1(func, x ,e):
x = x
y = func(x)
x1 = x + e
y1 = func(x1)
return 1.0*(y - y1)/(x - x1)
def d2(func ,x, e):
x = x
y = d1(func, x, e)
x1 = x + e
y1 = d1(func, x1, e)
return 1.0*(y - y1)/(x - x1)
yy is the actual function. d1 and d2 functions that calculate the 1st and 2nd derivatives. They are the ones I'm interested in optimizing. As you can see they both have almost the same code. I could basically keep writing functions like that for 3rd, 4th, etc derivatives, however I'm wondering if it is possible to write it as a single function specifying the derivative level as a parameter.
def deriv(func, order, x, e):
if order < 0: raise ValueError
if order == 0: return func(x)
y = deriv(func, order-1, x, e)
x1 = x + e
y1 = deriv(func, order-1, x1, e)
return float(y - y1)/(x - x1)
order = 1 gives the first derivative, order = 2 gives the 2nd, and so on.
Try this, where lvl is derivative level.
def d(func, x ,e, lvl):
x1 = x + e
if lvl == 1:
x = x
y = func(x)
y1 = func(x1)
return 1.0*(y - y1)/(x - x1)
else:
return 1.0*(d(func, x, e, lvl-1) - d(func, x1, e, lvl-1) )/(x-x1)