basilisk-engine 0.1.14__py3-none-any.whl → 0.1.16__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of basilisk-engine might be problematic. Click here for more details.

Files changed (87) hide show
  1. basilisk/__init__.py +14 -14
  2. basilisk/audio/sound.py +27 -27
  3. basilisk/bsk_assets/cube.obj +48 -48
  4. basilisk/collisions/broad/broad_aabb.py +102 -102
  5. basilisk/collisions/broad/broad_bvh.py +137 -137
  6. basilisk/collisions/collider.py +95 -95
  7. basilisk/collisions/collider_handler.py +224 -224
  8. basilisk/collisions/narrow/contact_manifold.py +95 -95
  9. basilisk/collisions/narrow/dataclasses.py +34 -34
  10. basilisk/collisions/narrow/deprecated.py +46 -46
  11. basilisk/collisions/narrow/epa.py +91 -91
  12. basilisk/collisions/narrow/gjk.py +66 -66
  13. basilisk/collisions/narrow/graham_scan.py +24 -24
  14. basilisk/collisions/narrow/helper.py +29 -29
  15. basilisk/collisions/narrow/line_intersections.py +106 -106
  16. basilisk/collisions/narrow/sutherland_hodgman.py +75 -75
  17. basilisk/config.py +2 -2
  18. basilisk/draw/draw.py +100 -100
  19. basilisk/draw/draw_handler.py +179 -179
  20. basilisk/draw/font_renderer.py +28 -28
  21. basilisk/engine.py +206 -206
  22. basilisk/generic/abstract_bvh.py +15 -15
  23. basilisk/generic/abstract_custom.py +133 -133
  24. basilisk/generic/collisions.py +72 -72
  25. basilisk/generic/input_validation.py +66 -66
  26. basilisk/generic/math.py +6 -6
  27. basilisk/generic/matrices.py +35 -35
  28. basilisk/generic/meshes.py +72 -72
  29. basilisk/generic/quat.py +142 -142
  30. basilisk/generic/quat_methods.py +7 -7
  31. basilisk/generic/raycast_result.py +26 -26
  32. basilisk/generic/vec3.py +143 -143
  33. basilisk/input/mouse.py +61 -61
  34. basilisk/input/path.py +14 -14
  35. basilisk/mesh/cube.py +33 -33
  36. basilisk/mesh/mesh.py +230 -230
  37. basilisk/mesh/mesh_from_data.py +130 -130
  38. basilisk/mesh/model.py +271 -271
  39. basilisk/mesh/narrow_aabb.py +89 -89
  40. basilisk/mesh/narrow_bvh.py +91 -91
  41. basilisk/mesh/narrow_primative.py +23 -23
  42. basilisk/nodes/helper.py +28 -28
  43. basilisk/nodes/node.py +684 -684
  44. basilisk/nodes/node_handler.py +95 -95
  45. basilisk/particles/particle_handler.py +63 -63
  46. basilisk/particles/particle_renderer.py +87 -87
  47. basilisk/physics/impulse.py +112 -112
  48. basilisk/physics/physics_body.py +43 -43
  49. basilisk/physics/physics_engine.py +35 -35
  50. basilisk/render/batch.py +105 -105
  51. basilisk/render/camera.py +211 -211
  52. basilisk/render/chunk.py +106 -106
  53. basilisk/render/chunk_handler.py +165 -165
  54. basilisk/render/frame.py +101 -101
  55. basilisk/render/framebuffer.py +130 -130
  56. basilisk/render/image.py +87 -87
  57. basilisk/render/image_handler.py +122 -122
  58. basilisk/render/light.py +96 -96
  59. basilisk/render/light_handler.py +58 -58
  60. basilisk/render/material.py +219 -219
  61. basilisk/render/material_handler.py +135 -135
  62. basilisk/render/post_process.py +132 -132
  63. basilisk/render/shader.py +110 -110
  64. basilisk/render/shader_handler.py +80 -79
  65. basilisk/render/sky.py +120 -120
  66. basilisk/scene.py +276 -276
  67. basilisk/shaders/batch.frag +276 -276
  68. basilisk/shaders/batch.vert +115 -115
  69. basilisk/shaders/crt.frag +31 -31
  70. basilisk/shaders/draw.frag +21 -21
  71. basilisk/shaders/draw.vert +21 -21
  72. basilisk/shaders/filter.frag +22 -22
  73. basilisk/shaders/frame.frag +12 -12
  74. basilisk/shaders/frame.vert +13 -13
  75. basilisk/shaders/geometry.frag +8 -8
  76. basilisk/shaders/geometry.vert +41 -41
  77. basilisk/shaders/normal.frag +59 -59
  78. basilisk/shaders/normal.vert +96 -96
  79. basilisk/shaders/particle.frag +71 -71
  80. basilisk/shaders/particle.vert +84 -84
  81. basilisk/shaders/sky.frag +9 -9
  82. basilisk/shaders/sky.vert +13 -13
  83. {basilisk_engine-0.1.14.dist-info → basilisk_engine-0.1.16.dist-info}/METADATA +38 -45
  84. basilisk_engine-0.1.16.dist-info/RECORD +103 -0
  85. {basilisk_engine-0.1.14.dist-info → basilisk_engine-0.1.16.dist-info}/WHEEL +1 -1
  86. basilisk_engine-0.1.14.dist-info/RECORD +0 -103
  87. {basilisk_engine-0.1.14.dist-info → basilisk_engine-0.1.16.dist-info}/top_level.txt +0 -0
@@ -1,67 +1,67 @@
1
- import glm
2
- from .helper import get_support_point
3
- from .dataclasses import SupportPoint
4
- from ...nodes.node import Node
5
- from ...generic.math import triple_product
6
-
7
-
8
- def collide_gjk(node1: Node, node2: Node, iterations: int=20) -> tuple: # TODO figure out return data type
9
- """
10
- Determines if two convex polyhedra collide, returns the polytope if there is a collision.
11
- """
12
- # generate starting values
13
- dir_vec = node1.position.data - node2.position.data
14
- simplex = [get_support_point(node1, node2, dir_vec)]
15
- dir_vec = -simplex[0].support_point # set direction to point away from starting simplex point
16
-
17
- for _ in range(iterations):
18
- # gets support point and checks if its across the origin
19
- test_point = get_support_point(node1, node2, dir_vec)
20
- if glm.dot(test_point.support_point, dir_vec) < -1e-7: return False, simplex
21
-
22
- # add point and find new direction vector
23
- simplex.append(test_point)
24
- check, dir_vec, simplex = handle_simplex(simplex)
25
-
26
- if check: return True, simplex
27
- return False, simplex # timeout due to too many checks, usually float errors
28
-
29
- def handle_simplex(simplex: list[SupportPoint]) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
30
- """
31
- Call proper function based on number of support points
32
- """
33
- num = len(simplex) # not using match case to support Python < 3.10
34
- if num == 2: return handle_simplex_line(simplex)
35
- if num == 3: return handle_simplex_triangle(simplex)
36
- return handle_simplex_tetrahedron(simplex) # simplex must be 4 points
37
-
38
- def handle_simplex_line(simplex: list[SupportPoint]) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
39
- """
40
- Returns the perpendicular vector to the simplex line
41
- """
42
- vec_ab = simplex[1].support_point - simplex[0].support_point
43
- return False, triple_product(vec_ab, -simplex[0].support_point, vec_ab), simplex
44
-
45
- def handle_simplex_triangle(simplex: list[SupportPoint]) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
46
- """
47
- Returns the normal vector of the triangoe pointed towards the origin
48
- """
49
- dir_vec = glm.cross(simplex[1].support_point - simplex[0].support_point, simplex[2].support_point - simplex[0].support_point)
50
- return False, -dir_vec if glm.dot(dir_vec, -simplex[0].support_point) < 0 else dir_vec, simplex
51
-
52
- def handle_simplex_tetrahedron(simplex: list[SupportPoint], epsilon: float=0) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
53
- """
54
- Perform collision check and remove support point if no collision is found
55
- """
56
- vec_da = simplex[3].support_point - simplex[0].support_point
57
- vec_db = simplex[3].support_point - simplex[1].support_point
58
- vec_dc = simplex[3].support_point - simplex[2].support_point
59
- vec_do = -simplex[3].support_point
60
-
61
- vectors = [(glm.cross(vec_da, vec_db), 2), (glm.cross(vec_dc, vec_da), 1), (glm.cross(vec_db, vec_dc), 0)] # TODO determine if this is the best way to do this
62
- for normal_vec, index in vectors:
63
- dot_product = glm.dot(normal_vec, vec_do)
64
- if dot_product > epsilon:
65
- simplex.pop(index)
66
- return False, normal_vec, simplex
1
+ import glm
2
+ from .helper import get_support_point
3
+ from .dataclasses import SupportPoint
4
+ from ...nodes.node import Node
5
+ from ...generic.math import triple_product
6
+
7
+
8
+ def collide_gjk(node1: Node, node2: Node, iterations: int=20) -> tuple: # TODO figure out return data type
9
+ """
10
+ Determines if two convex polyhedra collide, returns the polytope if there is a collision.
11
+ """
12
+ # generate starting values
13
+ dir_vec = node1.position.data - node2.position.data
14
+ simplex = [get_support_point(node1, node2, dir_vec)]
15
+ dir_vec = -simplex[0].support_point # set direction to point away from starting simplex point
16
+
17
+ for _ in range(iterations):
18
+ # gets support point and checks if its across the origin
19
+ test_point = get_support_point(node1, node2, dir_vec)
20
+ if glm.dot(test_point.support_point, dir_vec) < -1e-7: return False, simplex
21
+
22
+ # add point and find new direction vector
23
+ simplex.append(test_point)
24
+ check, dir_vec, simplex = handle_simplex(simplex)
25
+
26
+ if check: return True, simplex
27
+ return False, simplex # timeout due to too many checks, usually float errors
28
+
29
+ def handle_simplex(simplex: list[SupportPoint]) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
30
+ """
31
+ Call proper function based on number of support points
32
+ """
33
+ num = len(simplex) # not using match case to support Python < 3.10
34
+ if num == 2: return handle_simplex_line(simplex)
35
+ if num == 3: return handle_simplex_triangle(simplex)
36
+ return handle_simplex_tetrahedron(simplex) # simplex must be 4 points
37
+
38
+ def handle_simplex_line(simplex: list[SupportPoint]) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
39
+ """
40
+ Returns the perpendicular vector to the simplex line
41
+ """
42
+ vec_ab = simplex[1].support_point - simplex[0].support_point
43
+ return False, triple_product(vec_ab, -simplex[0].support_point, vec_ab), simplex
44
+
45
+ def handle_simplex_triangle(simplex: list[SupportPoint]) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
46
+ """
47
+ Returns the normal vector of the triangoe pointed towards the origin
48
+ """
49
+ dir_vec = glm.cross(simplex[1].support_point - simplex[0].support_point, simplex[2].support_point - simplex[0].support_point)
50
+ return False, -dir_vec if glm.dot(dir_vec, -simplex[0].support_point) < 0 else dir_vec, simplex
51
+
52
+ def handle_simplex_tetrahedron(simplex: list[SupportPoint], epsilon: float=0) -> tuple[bool, glm.vec3, list[tuple[glm.vec3, glm.vec3, glm.vec3]]]:
53
+ """
54
+ Perform collision check and remove support point if no collision is found
55
+ """
56
+ vec_da = simplex[3].support_point - simplex[0].support_point
57
+ vec_db = simplex[3].support_point - simplex[1].support_point
58
+ vec_dc = simplex[3].support_point - simplex[2].support_point
59
+ vec_do = -simplex[3].support_point
60
+
61
+ vectors = [(glm.cross(vec_da, vec_db), 2), (glm.cross(vec_dc, vec_da), 1), (glm.cross(vec_db, vec_dc), 0)] # TODO determine if this is the best way to do this
62
+ for normal_vec, index in vectors:
63
+ dot_product = glm.dot(normal_vec, vec_do)
64
+ if dot_product > epsilon:
65
+ simplex.pop(index)
66
+ return False, normal_vec, simplex
67
67
  return True, None, simplex
@@ -1,25 +1,25 @@
1
- import glm
2
- from math import atan2
3
- from .helper import is_ccw_turn
4
-
5
- def graham_scan(points:list[glm.vec2]) -> None:
6
- """converts list of arbitrary points into polygon sorted ccw"""
7
- # get pivot point
8
- pivot = min(points, key=lambda p: (p.y, p.x))
9
- points.remove(pivot)
10
-
11
- # sort points by polar angle and start hull
12
- points = sorted(points, key=lambda p: (get_polar_angle(pivot, p), glm.length(pivot - p)))
13
- hull = [pivot, points.pop(0)]
14
-
15
- for point in points:
16
- while len(hull) > 1 and not is_ccw_turn(hull[-2], hull[-1], point):
17
- hull.pop()
18
- hull.append(point)
19
-
20
- return hull
21
-
22
- def get_polar_angle(pivot:glm.vec2, point:glm.vec2) -> float:
23
- """gets the polar angle between two points from the horizontal"""
24
- vector = point - pivot
1
+ import glm
2
+ from math import atan2
3
+ from .helper import is_ccw_turn
4
+
5
+ def graham_scan(points:list[glm.vec2]) -> None:
6
+ """converts list of arbitrary points into polygon sorted ccw"""
7
+ # get pivot point
8
+ pivot = min(points, key=lambda p: (p.y, p.x))
9
+ points.remove(pivot)
10
+
11
+ # sort points by polar angle and start hull
12
+ points = sorted(points, key=lambda p: (get_polar_angle(pivot, p), glm.length(pivot - p)))
13
+ hull = [pivot, points.pop(0)]
14
+
15
+ for point in points:
16
+ while len(hull) > 1 and not is_ccw_turn(hull[-2], hull[-1], point):
17
+ hull.pop()
18
+ hull.append(point)
19
+
20
+ return hull
21
+
22
+ def get_polar_angle(pivot:glm.vec2, point:glm.vec2) -> float:
23
+ """gets the polar angle between two points from the horizontal"""
24
+ vector = point - pivot
25
25
  return atan2(vector.y, vector.x)
@@ -1,30 +1,30 @@
1
- import glm
2
- from ...nodes.node import Node
3
- from .dataclasses import SupportPoint
4
-
5
- def get_support_point(node1: Node, node2: Node, dir_vec: glm.vec3) -> SupportPoint:
6
- """
7
- Outputs the best support point to be added to the polytop based on the direction vector.
8
- """
9
- vertex1, index1 = get_furthest_point(node1, dir_vec)
10
- vertex2, index2 = get_furthest_point(node2, -dir_vec)
11
- return SupportPoint(vertex1 - vertex2, index1, vertex1, index2, vertex2)
12
-
13
- def get_furthest_point(node: Node, dir_vec: glm.vec3) -> glm.vec3:
14
- """
15
- Determines the furthest point in a given direction
16
- """
17
- # determine furthest point by using untransformed mesh
18
- node_dir_vec = node.rotation.data * dir_vec # rotate the world space vector to node space
19
- index = node.collider.mesh.get_best_dot(node_dir_vec)
20
- vertex = node.collider.mesh.points[index]
21
- vertex = node.model_matrix * glm.vec4(vertex, 1.0)
22
-
23
- # transform point to world space
24
- return glm.vec3(vertex), index
25
-
26
- def is_ccw_turn(a:glm.vec2, b:glm.vec2, c:glm.vec2) -> bool:
27
- """
28
- Determines if the series of points results in a left hand turn
29
- """
1
+ import glm
2
+ from ...nodes.node import Node
3
+ from .dataclasses import SupportPoint
4
+
5
+ def get_support_point(node1: Node, node2: Node, dir_vec: glm.vec3) -> SupportPoint:
6
+ """
7
+ Outputs the best support point to be added to the polytop based on the direction vector.
8
+ """
9
+ vertex1, index1 = get_furthest_point(node1, dir_vec)
10
+ vertex2, index2 = get_furthest_point(node2, -dir_vec)
11
+ return SupportPoint(vertex1 - vertex2, index1, vertex1, index2, vertex2)
12
+
13
+ def get_furthest_point(node: Node, dir_vec: glm.vec3) -> glm.vec3:
14
+ """
15
+ Determines the furthest point in a given direction
16
+ """
17
+ # determine furthest point by using untransformed mesh
18
+ node_dir_vec = node.rotation.data * dir_vec # rotate the world space vector to node space
19
+ index = node.collider.mesh.get_best_dot(node_dir_vec)
20
+ vertex = node.collider.mesh.points[index]
21
+ vertex = node.model_matrix * glm.vec4(vertex, 1.0)
22
+
23
+ # transform point to world space
24
+ return glm.vec3(vertex), index
25
+
26
+ def is_ccw_turn(a:glm.vec2, b:glm.vec2, c:glm.vec2) -> bool:
27
+ """
28
+ Determines if the series of points results in a left hand turn
29
+ """
30
30
  return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) > 0 # TODO check formula
@@ -1,107 +1,107 @@
1
- import glm
2
- from .helper import is_ccw_turn
3
-
4
- # intersectionn algorithms for lines
5
- def line_line_intersect(points1:list[glm.vec2], points2:list[glm.vec2]) -> list[glm.vec2]:
6
- """gets the intersection of 2 2d lines. if the lines are parallel, returns the second line"""
7
- # orders points from smallest x to greatest x
8
- points1 = sorted(points1, key=lambda p: (p.x, p.y))
9
- points2 = sorted(points2, key=lambda p: (p.x, p.y))
10
- vec1, vec2 = points1[1] - points1[0], points2[1] - points2[0]
11
-
12
- # if vectors have the same slope return the smallest line
13
- if have_same_slope(vec1, vec2): return sorted(points1 + points2, key=lambda p: (p.x, p.y))[1:3]
14
-
15
- # line - line intersection
16
- det = vec1.x * vec2.y - vec1.y * vec2.x
17
- if det == 0: return []
18
- t = (points2[0].x - points1[0].x) * vec2.y - (points2[0].y - points1[0].y) * vec2.x
19
- t /= det
20
- return [points1[0] + t * vec1]
21
-
22
- def have_same_slope(vec1:glm.vec2, vec2:glm.vec2, epsilon:float=1e-5) -> bool:
23
- """determines if two vectors moving in the positive x direction have the same slope"""
24
- return abs(vec1.y * vec2.x - vec2.y * vec1.x) < epsilon
25
-
26
- def line_poly_intersect(line:list[glm.vec2], polygon:list[glm.vec2]) -> list[glm.vec2]: #TODO Reseach into faster algorithm < O(2n)
27
- """computes which parts of the line clip with the polygon"""
28
- # calculate the center of the polygon
29
- assert len(polygon) > 2, 'polygon is does not contain engough points'
30
- center = glm.vec2(0,0)
31
- for point in polygon: center += point
32
- center /= len(polygon)
33
- orig_line = line[:]
34
- # determine which points are in or out of the polygon
35
- exterior_points = []
36
- for i in range(len(polygon)): # nearest even number below n
37
- for line_point in line[:]:
38
- if not is_ccw_turn(polygon[i], polygon[(i + 1) % len(polygon)], line_point): # if point is on the outside
39
- exterior_points.append((polygon[i], polygon[(i + 1) % len(polygon)], line_point)) # polypoint1, polypoint2, linepoint
40
- line.remove(line_point) # removes line point if it is confirmed to be outside
41
-
42
- # determine what to with line based on number of points found outside
43
- if len(exterior_points) == 0:
44
- return line
45
- if len(exterior_points) == 1:
46
- return line_line_intersect(line + [exterior_points[0][2]], exterior_points[0][0:2]) + [line[0]] # [intersecting point, exterior point]
47
- if len(exterior_points) == 2: # line must intersect with two edges
48
- points = []
49
- for i in range(len(polygon)):
50
- intersection = line_line_intersect(orig_line, [polygon[i], polygon[(i + 1) % len(polygon)]])
51
- if len(intersection) > 0: points += intersection
52
- if len(points) > 1: break # exit if two intersections have been found
53
- else: return [] # fallback if 0 or one intersections found
54
- return points
55
-
56
- def closest_two_lines(p1: glm.vec3, q1: glm.vec3, p2: glm.vec3, q2: glm.vec3, epsilon: float=1e-7) -> tuple[glm.vec3, glm.vec3]:
57
- """
58
- Determines the closest point on each line segment to the other line segment.
59
- """
60
- # create direction vector
61
- d1 = q1 - p1
62
- d2 = q2 - p2
63
- r = p1 - p2
64
-
65
- # get lengths of line segments
66
- a = glm.dot(d1, d1)
67
- e = glm.dot(d2, d2)
68
- f = glm.dot(d2, r)
69
-
70
- # check if either or both line segment degenerate into points
71
- if a <= epsilon and e <= epsilon:
72
- # both segments degenerate
73
- return p1, p2
74
-
75
- if a <= epsilon:
76
- s = 0
77
- t = glm.clamp(f / e, 0, 1)
78
- else:
79
- c = glm.dot(d1, r)
80
- if e <= epsilon:
81
- # the second line degenerates to a point
82
- t = 0
83
- s = glm.clamp(-c / a, 0, 1)
84
- else:
85
- # if neither of them degenerate to a point
86
- b = glm.dot(d1, d2)
87
- denom = a * e - b ** 2 # this will always be non-negative
88
-
89
- # if segments are not parallel, compute closest point from l1 to l2
90
- s = glm.clamp((b * f - c * e) / denom, 0, 1) if denom else 0
91
-
92
- # compute closest point from l2 on s1(s)
93
- t = (b * s + f) / e
94
-
95
- # if t is not in [0, 1], clamp and recompute s
96
- if t < 0:
97
- t = 0
98
- s = glm.clamp(-c / a, 0, 1)
99
- elif t > 1:
100
- t = 1
101
- s = glm.clamp((b - c) / a, 0, 1)
102
-
103
- c1 = p1 + d1 * s
104
- c2 = p2 + d2 * t
105
- return c1, c2
106
-
1
+ import glm
2
+ from .helper import is_ccw_turn
3
+
4
+ # intersectionn algorithms for lines
5
+ def line_line_intersect(points1:list[glm.vec2], points2:list[glm.vec2]) -> list[glm.vec2]:
6
+ """gets the intersection of 2 2d lines. if the lines are parallel, returns the second line"""
7
+ # orders points from smallest x to greatest x
8
+ points1 = sorted(points1, key=lambda p: (p.x, p.y))
9
+ points2 = sorted(points2, key=lambda p: (p.x, p.y))
10
+ vec1, vec2 = points1[1] - points1[0], points2[1] - points2[0]
11
+
12
+ # if vectors have the same slope return the smallest line
13
+ if have_same_slope(vec1, vec2): return sorted(points1 + points2, key=lambda p: (p.x, p.y))[1:3]
14
+
15
+ # line - line intersection
16
+ det = vec1.x * vec2.y - vec1.y * vec2.x
17
+ if det == 0: return []
18
+ t = (points2[0].x - points1[0].x) * vec2.y - (points2[0].y - points1[0].y) * vec2.x
19
+ t /= det
20
+ return [points1[0] + t * vec1]
21
+
22
+ def have_same_slope(vec1:glm.vec2, vec2:glm.vec2, epsilon:float=1e-5) -> bool:
23
+ """determines if two vectors moving in the positive x direction have the same slope"""
24
+ return abs(vec1.y * vec2.x - vec2.y * vec1.x) < epsilon
25
+
26
+ def line_poly_intersect(line:list[glm.vec2], polygon:list[glm.vec2]) -> list[glm.vec2]: #TODO Reseach into faster algorithm < O(2n)
27
+ """computes which parts of the line clip with the polygon"""
28
+ # calculate the center of the polygon
29
+ assert len(polygon) > 2, 'polygon is does not contain engough points'
30
+ center = glm.vec2(0,0)
31
+ for point in polygon: center += point
32
+ center /= len(polygon)
33
+ orig_line = line[:]
34
+ # determine which points are in or out of the polygon
35
+ exterior_points = []
36
+ for i in range(len(polygon)): # nearest even number below n
37
+ for line_point in line[:]:
38
+ if not is_ccw_turn(polygon[i], polygon[(i + 1) % len(polygon)], line_point): # if point is on the outside
39
+ exterior_points.append((polygon[i], polygon[(i + 1) % len(polygon)], line_point)) # polypoint1, polypoint2, linepoint
40
+ line.remove(line_point) # removes line point if it is confirmed to be outside
41
+
42
+ # determine what to with line based on number of points found outside
43
+ if len(exterior_points) == 0:
44
+ return line
45
+ if len(exterior_points) == 1:
46
+ return line_line_intersect(line + [exterior_points[0][2]], exterior_points[0][0:2]) + [line[0]] # [intersecting point, exterior point]
47
+ if len(exterior_points) == 2: # line must intersect with two edges
48
+ points = []
49
+ for i in range(len(polygon)):
50
+ intersection = line_line_intersect(orig_line, [polygon[i], polygon[(i + 1) % len(polygon)]])
51
+ if len(intersection) > 0: points += intersection
52
+ if len(points) > 1: break # exit if two intersections have been found
53
+ else: return [] # fallback if 0 or one intersections found
54
+ return points
55
+
56
+ def closest_two_lines(p1: glm.vec3, q1: glm.vec3, p2: glm.vec3, q2: glm.vec3, epsilon: float=1e-7) -> tuple[glm.vec3, glm.vec3]:
57
+ """
58
+ Determines the closest point on each line segment to the other line segment.
59
+ """
60
+ # create direction vector
61
+ d1 = q1 - p1
62
+ d2 = q2 - p2
63
+ r = p1 - p2
64
+
65
+ # get lengths of line segments
66
+ a = glm.dot(d1, d1)
67
+ e = glm.dot(d2, d2)
68
+ f = glm.dot(d2, r)
69
+
70
+ # check if either or both line segment degenerate into points
71
+ if a <= epsilon and e <= epsilon:
72
+ # both segments degenerate
73
+ return p1, p2
74
+
75
+ if a <= epsilon:
76
+ s = 0
77
+ t = glm.clamp(f / e, 0, 1)
78
+ else:
79
+ c = glm.dot(d1, r)
80
+ if e <= epsilon:
81
+ # the second line degenerates to a point
82
+ t = 0
83
+ s = glm.clamp(-c / a, 0, 1)
84
+ else:
85
+ # if neither of them degenerate to a point
86
+ b = glm.dot(d1, d2)
87
+ denom = a * e - b ** 2 # this will always be non-negative
88
+
89
+ # if segments are not parallel, compute closest point from l1 to l2
90
+ s = glm.clamp((b * f - c * e) / denom, 0, 1) if denom else 0
91
+
92
+ # compute closest point from l2 on s1(s)
93
+ t = (b * s + f) / e
94
+
95
+ # if t is not in [0, 1], clamp and recompute s
96
+ if t < 0:
97
+ t = 0
98
+ s = glm.clamp(-c / a, 0, 1)
99
+ elif t > 1:
100
+ t = 1
101
+ s = glm.clamp((b - c) / a, 0, 1)
102
+
103
+ c1 = p1 + d1 * s
104
+ c2 = p2 + d2 * t
105
+ return c1, c2
106
+
107
107
 
@@ -1,76 +1,76 @@
1
- import glm
2
- from .helper import is_ccw_turn
3
- from .line_intersections import line_line_intersect
4
-
5
- def sutherland_hodgman(subject:list[glm.vec2], clip:list[glm.vec2]) -> list[glm.vec2]:
6
- """determines the clipped polygon vertices from ccw oriented polygons"""
7
- output_poly = subject
8
-
9
- for i in range(len(clip)):
10
- input_poly = output_poly
11
- output_poly = []
12
-
13
- edge_start, edge_end = clip[i], clip[(i + 1) % len(clip)]
14
- for j in range(len(input_poly)):
15
- prev_point, curr_point = input_poly[j - 1], input_poly[j]
16
-
17
- if is_ccw_turn(curr_point, edge_start, edge_end):
18
- if not is_ccw_turn(prev_point, edge_start, edge_end):
19
- output_poly += line_line_intersect([edge_end, edge_start], [prev_point, curr_point])
20
- output_poly.append(curr_point)
21
- elif is_ccw_turn(prev_point, edge_start, edge_end):
22
- output_poly += line_line_intersect([edge_end, edge_start], [prev_point, curr_point])
23
-
24
- return output_poly
25
-
26
- # def get_intersect(one: glm.vec2, two: glm.vec2, thr: glm.vec2, fou: glm.vec2) -> glm.vec2:
27
- # """
28
- # Gets the intersection point between two lines
29
- # """
30
- # deno = (one.x - two.x) * (thr.y - fou.y) - (one.y - two.y) * (thr.x - fou.x)
31
- # if deno == 0: # TODO determine if this happens
32
- # print('sutherland-hodgman line intersection had zero denominator')
33
- # return None
34
- # x_num = (one.x * two.y - one.y * two.x) * (thr.x - fou.x) - (one.x - two.x) * (thr.x * fou.y - thr.y * fou.x)
35
- # y_num = (one.x * two.y - one.y * two.x) * (thr.y - fou.y) - (one.y - two.y) * (thr.x * fou.y - thr.y * fou.x)
36
- # return glm.vec2(x_num / deno, y_num / deno)
37
-
38
- # def clip(poly: list[glm.vec2], one: glm.vec2, two: glm.vec2) -> list[glm.vec2]:
39
- # """
40
- # Clip all edges of polygon with one of the clipping edges
41
- # """
42
- # num_points = len(poly)
43
- # new_points = []
44
-
45
- # for i in range(num_points):
46
- # k = (i + 1) % num_points
47
- # veci = poly[i]
48
- # veck = poly[k]
49
-
50
- # posi = (two.x - one.x) * (veci.y - one.y) - (two.y - one.y) * (veci.x - one.x)
51
- # posk = (two.x - one.x) * (veck.y - one.y) - (two.y - one.y) * (veck.x - one.x)
52
-
53
- # if posi < 0 and posk < 0: new_points.append(veck)
54
- # elif posi >= 0 and posk < 0:
55
-
56
- # new_points.append(get_intersect(one, two, veci, veck))
57
- # new_points.append(veck)
58
-
59
- # elif posi < 0 and posk >= 0:
60
-
61
- # new_points.append(get_intersect(one, two, veci, veck))
62
-
63
- # return new_points
64
-
65
- # def sutherland_hodgman(subj_poly:list[glm.vec2], clip_poly:list[glm.vec2]) -> list[glm.vec2]:
66
- # """
67
- # Determines the clipped polygon vertices from ccw oriented polygons.
68
- # """
69
- # num_clip = len(clip_poly)
70
-
71
- # for i in range(num_clip):
72
- # k = (i + 1) % num_clip
73
-
74
- # subj_poly = clip(subj_poly, clip_poly[i], clip_poly[k])
75
-
1
+ import glm
2
+ from .helper import is_ccw_turn
3
+ from .line_intersections import line_line_intersect
4
+
5
+ def sutherland_hodgman(subject:list[glm.vec2], clip:list[glm.vec2]) -> list[glm.vec2]:
6
+ """determines the clipped polygon vertices from ccw oriented polygons"""
7
+ output_poly = subject
8
+
9
+ for i in range(len(clip)):
10
+ input_poly = output_poly
11
+ output_poly = []
12
+
13
+ edge_start, edge_end = clip[i], clip[(i + 1) % len(clip)]
14
+ for j in range(len(input_poly)):
15
+ prev_point, curr_point = input_poly[j - 1], input_poly[j]
16
+
17
+ if is_ccw_turn(curr_point, edge_start, edge_end):
18
+ if not is_ccw_turn(prev_point, edge_start, edge_end):
19
+ output_poly += line_line_intersect([edge_end, edge_start], [prev_point, curr_point])
20
+ output_poly.append(curr_point)
21
+ elif is_ccw_turn(prev_point, edge_start, edge_end):
22
+ output_poly += line_line_intersect([edge_end, edge_start], [prev_point, curr_point])
23
+
24
+ return output_poly
25
+
26
+ # def get_intersect(one: glm.vec2, two: glm.vec2, thr: glm.vec2, fou: glm.vec2) -> glm.vec2:
27
+ # """
28
+ # Gets the intersection point between two lines
29
+ # """
30
+ # deno = (one.x - two.x) * (thr.y - fou.y) - (one.y - two.y) * (thr.x - fou.x)
31
+ # if deno == 0: # TODO determine if this happens
32
+ # print('sutherland-hodgman line intersection had zero denominator')
33
+ # return None
34
+ # x_num = (one.x * two.y - one.y * two.x) * (thr.x - fou.x) - (one.x - two.x) * (thr.x * fou.y - thr.y * fou.x)
35
+ # y_num = (one.x * two.y - one.y * two.x) * (thr.y - fou.y) - (one.y - two.y) * (thr.x * fou.y - thr.y * fou.x)
36
+ # return glm.vec2(x_num / deno, y_num / deno)
37
+
38
+ # def clip(poly: list[glm.vec2], one: glm.vec2, two: glm.vec2) -> list[glm.vec2]:
39
+ # """
40
+ # Clip all edges of polygon with one of the clipping edges
41
+ # """
42
+ # num_points = len(poly)
43
+ # new_points = []
44
+
45
+ # for i in range(num_points):
46
+ # k = (i + 1) % num_points
47
+ # veci = poly[i]
48
+ # veck = poly[k]
49
+
50
+ # posi = (two.x - one.x) * (veci.y - one.y) - (two.y - one.y) * (veci.x - one.x)
51
+ # posk = (two.x - one.x) * (veck.y - one.y) - (two.y - one.y) * (veck.x - one.x)
52
+
53
+ # if posi < 0 and posk < 0: new_points.append(veck)
54
+ # elif posi >= 0 and posk < 0:
55
+
56
+ # new_points.append(get_intersect(one, two, veci, veck))
57
+ # new_points.append(veck)
58
+
59
+ # elif posi < 0 and posk >= 0:
60
+
61
+ # new_points.append(get_intersect(one, two, veci, veck))
62
+
63
+ # return new_points
64
+
65
+ # def sutherland_hodgman(subj_poly:list[glm.vec2], clip_poly:list[glm.vec2]) -> list[glm.vec2]:
66
+ # """
67
+ # Determines the clipped polygon vertices from ccw oriented polygons.
68
+ # """
69
+ # num_clip = len(clip_poly)
70
+
71
+ # for i in range(num_clip):
72
+ # k = (i + 1) % num_clip
73
+
74
+ # subj_poly = clip(subj_poly, clip_poly[i], clip_poly[k])
75
+
76
76
  # return subj_poly
basilisk/config.py CHANGED
@@ -1,3 +1,3 @@
1
- class Config():
2
- def __init__(self) -> None:
1
+ class Config():
2
+ def __init__(self) -> None:
3
3
  ...