rendering.py 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import math
  2. import numpy as np
  3. # TODO: anti-aliased version, fill_coords_aa?
  4. def fill_coords(img, fn, color):
  5. """
  6. Fill pixels of an image with coordinates matching a filter function
  7. """
  8. for y in range(img.shape[0]):
  9. for x in range(img.shape[1]):
  10. yf = (y + 0.5) / img.shape[0]
  11. xf = (x + 0.5) / img.shape[1]
  12. if fn(xf, yf):
  13. img[y, x] = color
  14. return img
  15. def rotate_fn(fin, cx, cy, theta):
  16. def fout(x, y):
  17. x = x - cx
  18. y = y - cy
  19. x2 = cx + x * math.cos(-theta) - y * math.sin(-theta)
  20. y2 = cy + y * math.cos(-theta) + x * math.sin(-theta)
  21. return fin(x2, y2)
  22. return fout
  23. def point_in_line(x0, y0, x1, y1, r):
  24. p0 = np.array([x0, y0])
  25. p1 = np.array([x1, y1])
  26. dir = p1 - p0
  27. dist = np.linalg.norm(dir)
  28. dir = dir / dist
  29. def fn(x, y):
  30. q = np.array([x, y])
  31. pq = q - p0
  32. # Closest point on line
  33. a = np.dot(pq, dir)
  34. a = np.clip(a, 0, dist)
  35. p = p0 + a * dir
  36. dist_to_line = np.linalg.norm(q - p)
  37. return dist_to_line <= r
  38. return fn
  39. def point_in_circle(cx, cy, r):
  40. def fn(x, y):
  41. return (x-cx)*(x-cx) + (y-cy)*(y-cy) <= r * r
  42. return fn
  43. def point_in_rect(xmin, xmax, ymin, ymax):
  44. def fn(x, y):
  45. return x >= xmin and x <= xmax and y >= ymin and y <= ymax
  46. return fn
  47. def point_in_triangle(a, b, c):
  48. a = np.array(a)
  49. b = np.array(b)
  50. c = np.array(c)
  51. def fn(x, y):
  52. v0 = c - a
  53. v1 = b - a
  54. v2 = np.array((x, y)) - a
  55. # Compute dot products
  56. dot00 = np.dot(v0, v0)
  57. dot01 = np.dot(v0, v1)
  58. dot02 = np.dot(v0, v2)
  59. dot11 = np.dot(v1, v1)
  60. dot12 = np.dot(v1, v2)
  61. # Compute barycentric coordinates
  62. inv_denom = 1 / (dot00 * dot11 - dot01 * dot01)
  63. u = (dot11 * dot02 - dot01 * dot12) * inv_denom
  64. v = (dot00 * dot12 - dot01 * dot02) * inv_denom
  65. # Check if point is in triangle
  66. return (u >= 0) and (v >= 0) and (u + v) < 1
  67. return fn
  68. def highlight_img(img, color=(255, 255, 255), alpha=0.30):
  69. """
  70. Add highlighting to an image
  71. """
  72. blend_img = img + alpha * (np.array(color, dtype=np.uint8) - img)
  73. blend_img = blend_img.clip(0, 255).astype(np.uint8)
  74. img[:, :, :] = blend_img