Skip to content

Commit

Permalink
paly is OK
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Liu committed Jun 4, 2024
1 parent 089db02 commit f21cca3
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 152 deletions.
2 changes: 1 addition & 1 deletion conf/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ TITLE: Space View
cells_side: 24
animate_time: 6 #second
normalize: true
ball_pos: [0,0.8] # normalize coordinate, [1,1] correspond to the top right corner of the screen
ball_pos: [0,0.98] # normalize coordinate, [1,1] correspond to the top right corner of the screen
problem: 04_pendulum #01_fall,02_diffuse,03_fishing,04_pendulum
2 changes: 1 addition & 1 deletion conf/problems/01_fall.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ V: 9.8-k*Y
X: ["time",0,60] #name,min,max
Y: ["speed",40,60]
args:
k: ["drag coefficient",0.2,0,10] #name,value,min,max
k: ["drag coefficient",0.2,0,1] #name,value,min,max
1 change: 1 addition & 0 deletions conf/problems/03_fishing.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
desc: aquaculture and fishing
trajectory: Y
U: 1
V: k1*Y-k2*(Y**2)-k3
X: ["time",0,1] #name,min,max
Expand Down
1 change: 1 addition & 0 deletions conf/problems/04_pendulum.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
desc: pendulum
trajectory: X
U: Y*1
V: -k1*sin(X)-k2*Y
X: ["angular",0,10] #name,min,max
Expand Down
77 changes: 40 additions & 37 deletions field/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,70 +4,73 @@

from .utils import load_config,get_config
from .ui import UI
from .views import Tip,Grid
from .views import Tip,Grid,History,Viewport,Point,Size

class App(Window):
def __init__(self):
self.reset()

self._case_idx=0
self._demo_names=load_config()
cfg=get_config(self._demo_names[0])
w,h=cfg['WIDTH'],cfg['HEIGHT']
super().__init__(w,h , cfg['TITLE'], resizable=False)
self.set_vsync(False)
clock.schedule_interval(self.update, 1/cfg['FPS'])

# def select_space(self):
# name=self.demo_names[self._case_idx]
# self.space,self.views=self.cfg['make_views'](name)
# self.reset()
self.reset()




def on_draw(self):
self.clear()
#name=self.demo_names[self._case_idx]
for v in self.views:
for v in self._views:
v.render()
self._UI.render()

def on_key_press(self, symbol, modifiers):
super().on_key_press(symbol, modifiers)
flag=False
if symbol==key.LEFT or symbol==key.UP :
self._case_idx+=len(self.demo_names)-1
self._case_idx+=len(self._demo_names)-1
flag=True
elif symbol==key.RIGHT or symbol==key.DOWN:
self._case_idx+=1
self._case_idx%= len(self.demo_names)
#self.select_space()
flag=True
if flag:
self._case_idx%= len(self._demo_names)
self.reset()

def on_mouse_press(self,x, y, button, modifiers):
if button & mouse.RIGHT:
print('mouse press')
#self.views[0].on_click(x,y)
self._views[0].on_click(x,y)

def ui_callback(self,name):
#print(name)
self.cfg=get_config(name)
self._UI = UI(self,self.ui_callback, self.demo_names,self.cfg, name, "Set Parameters")
# self._case_idx=self.demo_names.index(name)
# self.select_space()


def reset(self):
self.demo_names=load_config()
cfg=get_config(self.demo_names[0])
self.cfg=cfg
w,h=cfg['WIDTH'],cfg['HEIGHT']
super().__init__(w,h , cfg['TITLE'], resizable=False)
self.set_vsync(False)
clock.schedule_interval(self.update, 1/cfg['FPS'])
self._case_idx=0
self.reload=False
cfg=get_config(self._demo_names[self._case_idx])
self._cfg=cfg
space=Space(cfg)
self.views=[Tip(space),Grid(space)]
self._space=space
self._views=[Grid(space),Tip(space)]
trajectory=cfg.get('trajectory',False)
if trajectory:
w,h=cfg['WIDTH'],cfg['HEIGHT']
self._views.append(History(space,viewPort=Viewport(Point(w/2,0),Size(w/2,h/2))))


self._UI = UI(self,self.ui_callback, self.demo_names,cfg,self.demo_names[0], "Set Parameters")
self._UI = UI(self, cfg,'Setup')


def update(self, dt):
# for v in self.views:
# v.update()

for key,_ in self.cfg.args.items():
if self.reload:
self.reset()
return
self._space.update()
for key,_ in self._cfg.args.items():
if self._UI.settings.get_changed(key):
print(self._UI.settings.get_value(key))
#self.reset()
self._cfg.args[key][1]=self._UI.settings.get_value(key)
self.reload=True
#print(self._UI.settings.get_value(key))



48 changes: 41 additions & 7 deletions field/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,37 @@
import numpy as np
from sympy import symbols, sympify, lambdify
from scipy.interpolate import interp2d
from queue import deque

class MaxSizeQueue:
def __init__(self, max_size=100):
self.queue = deque(maxlen=max_size)
self._max_size=max_size

@property
def max_size(self):
return self._max_size

def push(self, item):
self.queue.append(item)

def get_data(self):
return list(self.queue)

class Space():
STEP_K=0.2
def __init__(
self,
cfg
):
self.ball_pos=[0,0]
self.cfg=cfg
N=cfg.cells_side
self.trajectory:MaxSizeQueue=MaxSizeQueue(500)
self.reset()

def reset(self):

cfg=self.cfg
N=cfg.cells_side
x1,x2=cfg.X[1:3]
Expand Down Expand Up @@ -51,16 +71,30 @@ def reset(self):
self.x_limit=(min(xs), max(xs))
self.y_limit=(min(ys), max(ys))

def move(self,x,y)->Tuple[int,int]:
#ball_x,ball_y=self.ball_pos
u = self.u_interp(x, y)
v = self.v_interp(x, y)
dis=np.sqrt(u**2+v**2)
x += u/(dis+1e-10) * self.steps[0]
y += v/(dis+1e-10) * self.steps[1]
def clip(self,x,y)->Tuple[int,int]:
x = np.clip(x, *self.x_limit)
y = np.clip(y, *self.y_limit)
return x,y
def get_direction(self,x,y):
u = self.u_interp(x, y)
v = self.v_interp(x, y)
dis=np.sqrt(u**2+v**2)
dx = u/(dis+1e-10)
dy = v/(dis+1e-10)
return dx,dy

def next_pos(self,x,y,scale=0.5):
k= self.steps[0]*scale,self.steps[1]*scale
dx,dy=self.get_direction(x,y)
pos = self.clip(x+dx*k[0],y+dy*k[1])
return pos

def update(self):
x,y=self.ball_pos
pos = self.next_pos(x,y,self.STEP_K)
self.trajectory.push(pos)
self.ball_pos[0]=pos[0]
self.ball_pos[1]=pos[1]
'''
def _update1(self,step):#step is dx
CS=self._space.constraint
Expand Down
26 changes: 3 additions & 23 deletions field/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,40 +90,20 @@ def get_changed(self, name: str):

class UI:
def __init__(
self, window, cb, demo_names:List[str], cfg:any,name: str = "Config", text: str = "Set pendulum parameters"
self, window, cfg:any,name: str = "Config"
):
imgui.create_context()
self.cfg=cfg
self.impl = create_renderer(window)
self.settings: UISettings = UISettings(cfg)
self.name = name
self.text = text
self.demo_names=demo_names
self.callback=cb
N=len(demo_names)
self.flags=[False]*N
self.set_flag(name)

def set_flag(self,name:str):
for i,demo in enumerate(self.demo_names):
if (name==demo):
self.flags[i]=True
break



def render(self):#,names:List[str]=['C1','C2'],cb=None
imgui.new_frame()
imgui.begin(self.name)
imgui.text(self.text)
for idx,na in enumerate(self.demo_names):
if imgui.radio_button(na, self.flags[idx]):
if self.callback!=None:
imgui.end()
imgui.end_frame()
#imgui.render()
self.callback(na)
return
if idx<len(self.flags)-1:
imgui.same_line()


for index, setting in enumerate(self.settings):
Expand Down
3 changes: 2 additions & 1 deletion field/utils/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ def load_config()->List[str]:
rt.append(p.stem)
#print(OmegaConf.to_yaml(cfg))
return rt
@lru_cache(maxsize=10)

@lru_cache(maxsize=50)
def get_config(pname:str='01_fall')->DictConfig:
if len(cache_cfg)<2:
load_config()
Expand Down
4 changes: 3 additions & 1 deletion field/views/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from .tip import Tip
from .grid import Grid
from .grid import Grid
from .history import History
from .view import Viewport,Point,Size
92 changes: 31 additions & 61 deletions field/views/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,27 @@
from math import pi,atan2,tan,exp,inf
from .view import View
class Grid(View):
N_COLORS:int = 8
#N_COLORS:int = 8


# def set_data(self,state:State,x:float,y:float):
# idx_x=self.sp._x_index
# idx_y=self.sp._y_index
# data=list(state)
# data[idx_x]=x
# data[idx_y]=y
# state.set_data(*data)
def on_click(self,sx,sy):
if sx<self._ox or sy<self._oy or sx>self._ox+self.w or sy>self._oy+self.h:
return
x,y=self.get_space_pos(sx,sy)
self._space.ball_pos=[x,y]

def render(self):
x,y=self._space.ball_pos
x,y=self.get_screen_pos(x,y)
self._ball.position=[x,y]
super().render()


def reset(self):
self._colors=linear_gradient('#0000FF','#FF4500',self.N_COLORS)
#self._colors=linear_gradient('#0000FF','#FF4500',self.N_COLORS)
w,h=self._viewport.size
self._body=shapes.Circle(w/2,h/2,6,color=(255, 255, 0),batch=self._batch)
x,y=self._space.ball_pos
x,y=self.get_screen_pos(x,y)
self._ball=shapes.Circle(x,y,6,color=(255, 255, 0),batch=self._batch)
self._lines=[]
N=self.cfg.cells_side
dx=(self._space.x_limit[1]-self._space.x_limit[0])/N
Expand All @@ -31,60 +36,25 @@ def reset(self):
for j in range(N):
x=self._space.x_limit[0]+j*dx
y=self._space.y_limit[0]+i*dy
x1,y1=self._space.move(x,y)
x1,y1=self._space.next_pos(x,y,1.2)
self.add_line_segment(x,y,x1,y1)


def add_line_segment(self,x,y,x1,y1): #sp:(row,col,slop)
def add_line_segment(self,x,y,x1,y1):
x,y=self.get_screen_pos(x,y)
x1,y1=self.get_screen_pos(x1,y1)
line=shapes.Line(x,y,x1,y1,color=(50, 45, 30),batch=self._batch)

# rect=shapes.Rectangle(sx, sy,self.cells_side ,2,color=(50, 45, 30),batch=self._batch)
# rect.anchor_position=(rect.width/2,rect.height/2)
# #c=shapes.Circle(sx, sy,1,color=(5, 245, 13),batch=self._batch)
# c=shapes.Rectangle(sx, sy,self.cells_side/2 ,2,color=(255, 245, 235),batch=self._batch)
# c.anchor_position=(0,0)
# ang=atan2(sp[2],sp[3])

# self.rotate(ang, rect,True)
# self.rotate(ang, c,False)
self._lines.append(line)

# def on_click(self,sx,sy):
# x,y=self.get_space_pos(sx,sy)
# data=list(self.sp.state)
# data[self.sp._x_index]=x
# data[self.sp._y_index]=y
# self.sp.state.set_data(*data)


# def update(self):
# self.sp.update()
# px=self.sp.state.value(self.x_axis.name)
# py=self.sp.state.value(self.y_axis.name)
# x,y=self.get_pos(px,py)
# self._body.position=(x,y)

# def rotate(self,ang:float, shape:shapes.Rectangle,auto_color=False):
# d=round(ang*180.0/pi)
# d= (d+360)%360
# shape.rotation=0-d
# if not auto_color:
# return
# slop=tan(ang)
# try:
# result = exp(-slop)
# except OverflowError:
# result = inf
# k=1.0/(1.0+result)
# n =round(k*(self.N_COLORS-1))
# shape.color=self._colors[n]

# def get_pos_by_indexs(self,row:int,col:int):
# px=self.x_axis.value_at(col)
# py=self.y_axis.value_at(row)
# return (px,py)
x2,y2=self.get_screen_pos(x1,y1)
k=0.618
x1=x*(1-k)+x2*k
y1=y*(1-k)+y2*k
line1=shapes.Line(x,y,x1,y1,color=(223, 223, 223),batch=self._batch)
line2=shapes.Line(x1,y1,x2,y2,color=(250, 50, 34),batch=self._batch)

self._lines.append((line1,line2))








Expand Down
Loading

0 comments on commit f21cca3

Please sign in to comment.