Alexandre B A Villares 2024-04-24 20:21:21 -03:00
rodzic de6ff3db8b
commit a4a75dcd7e
3 zmienionych plików z 249 dodań i 0 usunięć

Plik binarny nie jest wyświetlany.

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 73 KiB

Wyświetl plik

@ -0,0 +1,129 @@
# based on sketch_2023_10_24.py
import py5 # the main graphics & interaction framework
import pymunk as pm # the 2D physics engine
from trimesh.creation import triangulate_polygon
import shapely
from shapely.affinity import translate as shapely_translate
MINIMUM_DIST = 50 # harder to draw, but more elegant objects
space = pm.Space() # the pymunk simulation space
space.gravity = (0, 600)
current_poly = [] # (x, y) tuples while mouse dragging
def setup():
#global margin
py5.size(800, 800)
py5.color_mode(py5.HSB)
margin = 10
walls = (
((margin, py5.height - margin), (py5.width - margin, py5.height - margin)),
((margin, py5.height - margin), (margin, margin)),
((py5.width - margin, py5.height - margin), (py5.width - margin, margin)),
)
for pa, pb in walls:
wall = pm.Segment(space.static_body, pa, pb, 2)
wall.friction = 0.4
space.add(wall)
def draw():
py5.background(100)
for b in space.bodies: # draws the objects
b.draw()
if current_poly: # draws poly preview while dragging mouse
py5.fill(255, 0, 0, 100)
with py5.begin_closed_shape():
py5.vertices(current_poly)
space.step(0.01) # advance simulation
class DrawableBody(pm.Body):
def draw(self):
with py5.push():
py5.no_stroke()
py5.translate(self.position.x, self.position.y)
py5.rotate(self.angle)
a = self.position.y / 3
py5.fill((100 + self.area / 1000) % 255, 200, 200, 200)
py5.shape(self.py5shape, 0, 0)
def min_max(pts):
coords = tuple(zip(*pts))
return tuple(map(min, coords)), tuple(map(max, coords))
def add_trianglulated_body(poly: shapely.Polygon):
"""
Todo, look at shapely centroid and improve
DrawableBody class maybe to get the shapely.Poly
Maybe passe everything t the DrawableBody class?
"""
from math import isnan
vs, faces = triangulate_polygon(poly)
triangles = [(vs[a], vs[b], vs[c]) for a, b, c in faces]
cp = shapely.centroid(poly)
cx, cy = centroid = cp.x, cp.y
translated_tris = []
total_mass = total_moi = 0
for tri in triangles:
translated_tri = [(x - cx, y - cy) for x, y in tri]
mass = poly_area(translated_tri) * 0.1
total_mass += mass
moi = pm.moment_for_poly(mass, translated_tri)
if not isnan(moi):
total_moi += moi
translated_tris.append(translated_tri)
body = DrawableBody(total_mass, total_moi)
body.area = poly.area
body.py5shape = py5.convert_shape(shapely_translate(poly, -cx, -cy))
body.py5shape.disable_style()
body.position = centroid
shapes = []
for tri in translated_tris:
shp = pm.Poly(body, tri)
shp.friction = 0.4
shapes.append(shp)
#print(f'shapes: {len(shapes)}')
space.add(body, *shapes) # Note critical * operator expands .add(b, s0, s1, s2...)
def poly_area(pts):
area = 0.0
for (ax, ay), (bx, by) in zip(pts, pts[1:] + [pts[0]]):
area += ax * by
area -= bx * ay
return abs(area) / 2.0
def is_poly(obj): return isinstance(obj, pm.Poly)
def is_segment(obj): return isinstance(obj, pm.Segment)
def key_pressed():
global text_x
if py5.key == py5.DELETE:
# clear everything but the "box" walls
for obj in reversed(space.shapes):
if not is_segment(obj):
space.remove(obj)
def mouse_dragged():
# adds a tuple with the mouse coordinates if the current_poly list is empty
# or if the x, y in current_poly[-1] are far enough from the mouse
mx, my = py5.mouse_x, py5.mouse_y
if not current_poly or (py5.dist(current_poly[-1][0], current_poly[-1][1], mx, my)
>= MINIMUM_DIST):
current_poly.append((mx, my))
def mouse_released():
# creates an object if there are enough points on the list, clears list
if len(current_poly) >= 3:
add_trianglulated_body(shapely.Polygon(current_poly))
current_poly.clear()
py5.run_sketch(block=False) # starts py5, setup() and then the main loop, draw()

Wyświetl plik

@ -0,0 +1,120 @@
# Based on sketch_2022_02_04py5.py
import py5
import pymunk
from random import randint, sample, choice
space = pymunk.Space() # create a new space for your simulation
space.gravity = (0, 900)
def setup():
py5.size(500, 500)
py5.color_mode(py5.HSB)
populate_boxes()
segments = (
((500, 0), (500, 500)),
((0, 0), (0, 500)),
)
for point_a, point_b in segments:
s = DrawableSegment(space.static_body, point_a, point_b, 1)
s.elasticity = 1
space.add(s)
def draw():
py5.background(150)
py5.no_stroke()
for self in space.shapes:
self.draw()
if py5.is_key_pressed and py5.key_code == py5.SHIFT:
add_balls()
if py5.is_mouse_pressed and py5.mouse_button == py5.RIGHT:
add_balls()
for self in reversed(space.shapes):
if self.body.position.y > py5.height + 10:
space.remove(self)
print(len(space.shapes))
space.step(1/py5.get_frame_rate()) # advance simulation step
def populate_boxes():
while len(space.shapes) < 22:
x, y = randint(0, py5.width), randint(0, py5.width)
if all(map(lambda self: self.point_query((x, y)).distance > 0,
space.shapes)):
create_box(x, y)
def add_balls():
create_ball(py5.mouse_x + randint(0, 1), py5.mouse_y)
def create_box(x, y):
body = pymunk.Body(body_type=pymunk.Body.KINEMATIC)
body.position = x, y
w, h = choice((100, 90, 80, 110)), choice((10, 5, 15))
box_poly = DrawablePoly.create_box(body, (w, h))
space.add(body, box_poly)
class DrawablePoly(pymunk.Poly):
def draw(self):
py5.push_matrix()
py5.translate(self.body.position.x, self.body.position.y)
py5.rotate(self.body.angle)
pts = self.get_vertices()
py5.begin_shape()
py5.fill((pts[0][0] * pts[0][1]) % 255, 200, 200)
for x, y in pts:
py5.vertex(x, y)
py5.end_shape(py5.CLOSE)
py5.pop_matrix()
def create_box(*args):
return pymunk.Poly.create_box(*args)
def create_ball(x, y):
body = pymunk.Body(mass=5, moment=10)
body.position = x, y
ball = DrawableCircle(body, radius=5)
ball.elasticity = 0.2
space.add(body, ball)
class DrawableCircle(pymunk.Circle):
def draw(self):
py5.fill(0) #(self.radius * 10, 255, 255)
py5.circle(self.body.position.x, self.body.position.y, self.radius * 2)
class DrawableSegment(pymunk.Segment):
def draw_seg(self):
with py5.push():
py5.stroke(255)
py5.stroke_weight(self.radius*2)
py5.line(self.a.x, self.a.y, self.b.x, self.b.y)
def mouse_dragged():
for self in space.shapes:
# if is_box(self):
info = self.point_query((py5.mouse_x, py5.mouse_y))
if info.distance < 2:
v = pymunk.Vec2d(py5.mouse_x - py5.pmouse_x,
py5.mouse_y - py5.pmouse_y)
self.body.position += v
def mouse_wheel(e):
for self in space.shapes:
if is_box(self):
info = self.point_query((py5.mouse_x, py5.mouse_y))
if info.distance < 2:
self.body.angle += py5.radians(e.getCount())
def key_pressed():
if py5.key == ' ':
for self in reversed(space.shapes):
if is_ball(self) or is_box(self):
space.remove(self)
populate_boxes()
def is_ball(self): return isinstance(self, pymunk.shapes.Circle)
def is_box(self): return isinstance(self, pymunk.shapes.Poly)
py5.run_sketch()