Compare commits

..

14 Commits

Author SHA1 Message Date
f33d7bbec8 使用 UV 包管理器 2025-04-30 23:40:28 +08:00
bf400ca9c2 Update 2025-04-13 16:30:45 +08:00
24c1a94f36 "锚定点" 功能更新 2025-04-12 22:27:30 +08:00
fd67663868 Add basic components support 2025-04-08 23:14:29 +08:00
27d7ffe4bf Incomplete improvement (Anchor object) 2025-04-06 23:26:26 +08:00
89c8b34550 clean pycache 2025-04-06 10:41:53 +08:00
fdf2e1a3ff 更新 "注册为观察者(事件驱动)" 功能 2025-04-05 19:29:23 +08:00
a7b0373425 README Update 2025-04-05 15:46:18 +08:00
890543e3c1 minor VGL improvements 2025-04-05 14:21:31 +08:00
bce75a1727 major improvements 2025-04-04 22:19:27 +08:00
551ed9a4ce changes 2025-04-04 16:06:26 +08:00
28986de6ea m.i. 2025-03-24 00:12:39 +08:00
da3da80b17 minor improv. 2025-03-23 00:06:07 +08:00
84372e6dd8 minor improvements 2025-03-23 00:05:53 +08:00
57 changed files with 676 additions and 820 deletions

View File

@@ -12,7 +12,7 @@ venv.bak/
*.egg-info/
dist/
build/
.tmp
# IDEs and editors
.vscode/
.idea/

View File

@@ -1,2 +1,27 @@
# AiraPulsar 飞行控制系统
AiraPulsar (空中脉冲星, 简称 APSR) 是一套基于 WebSocket 的三点架构的轻量级网络飞行控制系统
AiraPulsar 是一套适用于固定翼无人机/航模的轻量级通用网络飞行控制系统
(待)支持功能:
- 影像实时回传/录制
- HUD 支持
- 多驾驶员/操作员链接支持 & 同步
- 鼠标/键盘飞行姿态控制
- 计算机辅助姿态修正 & 改出
- 自动辅助降落控制
- 物理断链情况下的自降落/修正/重新连接
- 飞行数据/机载设备监控
- 机体状态图像式监控
- 垂直载荷投放计算 (持续计算打击点)
特色:
- 通用机载计算机部署
- 模块化设计
- 数据中转服务器
目录说明:
- comet: 飞行器侧载端
- pulsar: 控制器客户端
- moon: 数据中转服务器端
- vgl: 矢量图形层 (库)
- testfield: 开发中组件
- auxiliary: 辅助程序

View File

@@ -1,52 +0,0 @@
import pygame
def selector():
pygame.init()
try:
width = int(input("Frame Width: "))
height = int(input("Frame Height: "))
except:
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("UI Design Auxiliary Tool")
selecting = False
start_pos = None
end_pos = None
running = True
screen.fill((0,0,0))
while running:
screen.fill((0,0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # 左键
selecting = True
start_pos = event.pos
elif event.type == pygame.MOUSEMOTION:
if selecting:
end_pos = event.pos
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
selecting = False
if start_pos and end_pos:
rect = pygame.Rect(
start_pos,
(end_pos[0] - start_pos[0], end_pos[1] - start_pos[1]),
)
if selecting and start_pos and end_pos:
rect = pygame.Rect(
start_pos, (end_pos[0] - start_pos[0], end_pos[1] - start_pos[1])
)
pygame.draw.rect(screen, (255, 0, 0), rect, 2) # 绘制选区矩形
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()

View File

@@ -1,28 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>图形参数生成器</title>
</head>
<body>
<h1>图形参数生成器</h1>
<label for="shape">图形类型:</label>
<select id="shape">
<option value="rect">矩形</option>
<option value="line">线条</option>
<option value="circle">圆形</option>
<option value="ellipse">椭圆</option>
<option value="polygon">多边形</option>
<option value="arc">弧形</option>
<option value="point"></option>
<option value="lines">线段</option>
</select><br><br>
<div id="params"></div><br>
<button id="generate">生成图形参数</button><br><br>
<div id="result"></div>
<script src="script.js"></script>
</body>
</html>

View File

@@ -1,152 +0,0 @@
function generateShapeDict(shape, params) {
if (shape === 'rect') {
return {
method: 'rect',
pos: params.pos || [0, 0],
size: params.size || [1, 1],
color: params.color || [255, 255, 255],
width: params.width || 0
};
} else if (shape === 'line') {
return {
method: 'line',
start_pos: params.start_pos || [0, 0],
end_pos: params.end_pos || [1, 1],
color: params.color || [255, 255, 255]
};
} else if (shape === 'circle') {
return {
method: 'circle',
center: params.center || [0, 0],
radius: params.radius || 1,
color: params.color || [255, 255, 255]
};
} else if (shape === 'ellipse') {
return {
method: 'ellipse',
pos: params.pos || [0, 0],
size: params.size || [1, 1],
color: params.color || [255, 255, 255]
};
} else if (shape === 'polygon') {
return {
method: 'polygon',
pointlist: params.pointlist || [],
color: params.color || [255, 255, 255]
};
} else if (shape === 'arc') {
return {
method: 'arc',
pos: params.pos || [0, 0],
size: params.size || [1, 1],
color: params.color || [255, 255, 255],
start_angle: params.start_angle || 0,
stop_angle: params.stop_angle || 3.14
};
} else if (shape === 'point') {
return {
method: 'point',
pos: params.pos || [0, 0],
color: params.color || [255, 255, 255]
};
} else if (shape === 'lines') {
return {
method: 'lines',
pointlist: params.pointlist || [],
color: params.color || [255, 255, 255]
};
} else {
throw new Error("Unsupported shape type");
}
}
document.addEventListener('DOMContentLoaded', function() {
const shapeSelect = document.getElementById('shape');
const paramsDiv = document.getElementById('params');
const generateButton = document.getElementById('generate');
const resultDiv = document.getElementById('result');
function createInput(label, id, type = 'text') {
const input = document.createElement('input');
input.type = type;
input.id = id;
const labelElement = document.createElement('label');
labelElement.textContent = label + ': ';
labelElement.setAttribute('for', id);
paramsDiv.appendChild(labelElement);
paramsDiv.appendChild(input);
paramsDiv.appendChild(document.createElement('br'));
return input;
}
function updateParamsInputs() {
paramsDiv.innerHTML = '';
const shape = shapeSelect.value;
if (shape === 'rect') {
createInput('矩形位置 (x y)', 'pos');
createInput('矩形大小 (width height)', 'size');
createInput('矩形颜色 (R G B)', 'color');
createInput('矩形边框宽度', 'width', 'number');
} else if (shape === 'line') {
createInput('起始位置 (x y)', 'start_pos');
createInput('结束位置 (x y)', 'end_pos');
createInput('线条颜色 (R G B)', 'color');
} else if (shape === 'circle') {
createInput('圆心位置 (x y)', 'center');
createInput('圆的半径', 'radius', 'number');
createInput('圆的颜色 (R G B)', 'color');
} else if (shape === 'ellipse') {
createInput('椭圆位置 (x y)', 'pos');
createInput('椭圆大小 (width height)', 'size');
createInput('椭圆颜色 (R G B)', 'color');
} else if (shape === 'polygon') {
createInput('多边形的点 (x1 y1 x2 y2 ...)', 'pointlist');
createInput('多边形颜色 (R G B)', 'color');
} else if (shape === 'arc') {
createInput('弧的位置 (x y)', 'pos');
createInput('弧的大小 (width height)', 'size');
createInput('弧的颜色 (R G B)', 'color');
createInput('弧的起始角度 (弧度制)', 'start_angle', 'number');
createInput('弧的结束角度 (弧度制)', 'stop_angle', 'number');
} else if (shape === 'point') {
createInput('点的位置 (x y)', 'pos');
createInput('点的颜色 (R G B)', 'color');
} else if (shape === 'lines') {
createInput('线段的点 (x1 y1 x2 y2 ...)', 'pointlist');
createInput('线段颜色 (R G B)', 'color');
}
}
shapeSelect.addEventListener('change', updateParamsInputs);
updateParamsInputs();
generateButton.addEventListener('click', function() {
const shape = shapeSelect.value;
const params = {};
const inputs = paramsDiv.querySelectorAll('input');
inputs.forEach(input => {
if (input.id === 'pointlist') {
const points = input.value.split(' ').map(Number);
params.pointlist = [];
for (let i = 0; i < points.length; i += 2) {
params.pointlist.push([points[i], points[i + 1]]);
}
} else if (input.id === 'pos' || input.id === 'size' || input.id === 'start_pos' || input.id === 'end_pos' || input.id === 'center' || input.id === 'color') {
params[input.id] = input.value.split(' ').map(Number);
} else if (input.type === 'number') {
params[input.id] = parseFloat(input.value);
} else {
params[input.id] = input.value;
}
});
try {
const shapeDict = generateShapeDict(shape, params);
resultDiv.innerHTML = '<pre>' + JSON.stringify(shapeDict, null, 2) + '</pre>';
} catch (error) {
resultDiv.innerHTML = '<p>错误: ' + error.message + '</p>';
}
});
});

1
comet/.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

View File

@@ -1,213 +0,0 @@
2025-03-07T08:56:35.501146+0800 - INFO - 初始化代理对象
2025-03-07T08:56:35.501324+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T08:56:35.501414+0800 - INFO - 代理对象代号: comet
2025-03-07T08:57:13.903527+0800 - INFO - 初始化代理对象
2025-03-07T08:57:13.903678+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T08:57:13.903742+0800 - INFO - 代理对象代号: comet
2025-03-07T08:58:55.379859+0800 - INFO - 初始化代理对象
2025-03-07T08:58:55.380016+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T08:58:55.380084+0800 - INFO - 代理对象代号: comet
2025-03-07T08:59:05.381232+0800 - INFO - 初始化代理对象
2025-03-07T08:59:05.381387+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T08:59:05.381444+0800 - INFO - 代理对象代号: comet
2025-03-07T08:59:52.906831+0800 - INFO - 初始化代理对象
2025-03-07T08:59:52.906996+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T08:59:52.907060+0800 - INFO - 代理对象代号: comet
2025-03-07T09:00:41.008959+0800 - INFO - 初始化代理对象
2025-03-07T09:00:41.008959+0800 - INFO - 初始化代理对象
2025-03-07T09:00:41.009179+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:00:41.009179+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:00:41.009279+0800 - INFO - 代理对象代号: comet
2025-03-07T09:00:41.009279+0800 - INFO - 代理对象代号: comet
2025-03-07T09:00:44.632829+0800 - INFO - 初始化代理对象
2025-03-07T09:00:44.632829+0800 - INFO - 初始化代理对象
2025-03-07T09:00:44.633010+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:00:44.633010+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:00:44.633098+0800 - INFO - 代理对象代号: comet
2025-03-07T09:00:44.633098+0800 - INFO - 代理对象代号: comet
2025-03-07T09:01:31.329481+0800 - INFO - 初始化代理对象
2025-03-07T09:01:31.329481+0800 - INFO - 初始化代理对象
2025-03-07T09:01:31.329691+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:01:31.329691+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:01:31.329762+0800 - INFO - 代理对象代号: comet
2025-03-07T09:01:31.329762+0800 - INFO - 代理对象代号: comet
2025-03-07T09:02:18.294306+0800 - INFO - 初始化代理对象
2025-03-07T09:02:18.294306+0800 - INFO - 初始化代理对象
2025-03-07T09:02:18.294467+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:02:18.294467+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:02:18.294542+0800 - INFO - 代理对象代号: comet
2025-03-07T09:02:18.294542+0800 - INFO - 代理对象代号: comet
2025-03-07T09:02:49.424696+0800 - INFO - 初始化代理对象
2025-03-07T09:02:49.424696+0800 - INFO - 初始化代理对象
2025-03-07T09:02:49.424863+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:02:49.424863+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:02:49.424947+0800 - INFO - 代理对象代号: comet
2025-03-07T09:02:49.424947+0800 - INFO - 代理对象代号: comet
2025-03-07T09:03:12.117053+0800 - INFO - 初始化代理对象
2025-03-07T09:03:12.117053+0800 - INFO - 初始化代理对象
2025-03-07T09:03:12.117278+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:03:12.117278+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:03:12.117377+0800 - INFO - 代理对象代号: comet
2025-03-07T09:03:12.117377+0800 - INFO - 代理对象代号: comet
2025-03-07T09:03:43.470032+0800 - INFO - 初始化代理对象
2025-03-07T09:03:43.470032+0800 - INFO - 初始化代理对象
2025-03-07T09:03:43.470267+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:03:43.470267+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:03:43.470342+0800 - INFO - 代理对象代号: comet
2025-03-07T09:03:43.470342+0800 - INFO - 代理对象代号: comet
2025-03-07T09:11:06.876601+0800 - INFO - 初始化代理对象
2025-03-07T09:11:06.876601+0800 - INFO - 初始化代理对象
2025-03-07T09:11:06.876858+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:11:06.876858+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:11:06.876965+0800 - INFO - 代理对象代号: comet
2025-03-07T09:11:06.876965+0800 - INFO - 代理对象代号: comet
2025-03-07T09:12:16.848236+0800 - INFO - 初始化代理对象
2025-03-07T09:12:16.848236+0800 - INFO - 初始化代理对象
2025-03-07T09:12:16.848397+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:12:16.848397+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:12:16.848476+0800 - INFO - 代理对象代号: comet
2025-03-07T09:12:16.848476+0800 - INFO - 代理对象代号: comet
2025-03-07T09:19:10.751685+0800 - INFO - 初始化代理对象
2025-03-07T09:19:10.751685+0800 - INFO - 初始化代理对象
2025-03-07T09:19:10.751843+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:19:10.751843+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:19:10.751912+0800 - INFO - 代理对象代号: comet
2025-03-07T09:19:10.751912+0800 - INFO - 代理对象代号: comet
2025-03-07T09:19:20.013536+0800 - INFO - 初始化代理对象
2025-03-07T09:19:20.013536+0800 - INFO - 初始化代理对象
2025-03-07T09:19:20.013686+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:19:20.013686+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:19:20.013757+0800 - INFO - 代理对象代号: comet
2025-03-07T09:19:20.013757+0800 - INFO - 代理对象代号: comet
2025-03-07T09:19:39.079365+0800 - INFO - 初始化代理对象
2025-03-07T09:19:39.079365+0800 - INFO - 初始化代理对象
2025-03-07T09:19:39.079590+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:19:39.079590+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:19:39.079663+0800 - INFO - 代理对象代号: comet
2025-03-07T09:19:39.079663+0800 - INFO - 代理对象代号: comet
2025-03-07T09:20:13.855104+0800 - INFO - 初始化代理对象
2025-03-07T09:20:13.855104+0800 - INFO - 初始化代理对象
2025-03-07T09:20:13.855261+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:20:13.855261+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:20:13.855328+0800 - INFO - 代理对象代号: comet
2025-03-07T09:20:13.855328+0800 - INFO - 代理对象代号: comet
2025-03-07T09:20:22.574788+0800 - INFO - 初始化代理对象
2025-03-07T09:20:22.574788+0800 - INFO - 初始化代理对象
2025-03-07T09:20:22.574961+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:20:22.574961+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:20:22.575035+0800 - INFO - 代理对象代号: comet
2025-03-07T09:20:22.575035+0800 - INFO - 代理对象代号: comet
2025-03-07T09:26:57.804810+0800 - INFO - 初始化代理对象
2025-03-07T09:26:57.804810+0800 - INFO - 初始化代理对象
2025-03-07T09:26:57.804965+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:26:57.804965+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:26:57.805033+0800 - INFO - 代理对象代号: comet
2025-03-07T09:26:57.805033+0800 - INFO - 代理对象代号: comet
2025-03-07T09:28:26.670684+0800 - INFO - 初始化代理对象
2025-03-07T09:28:26.670684+0800 - INFO - 初始化代理对象
2025-03-07T09:28:26.670920+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:28:26.670920+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:28:26.671025+0800 - INFO - 代理对象代号: comet
2025-03-07T09:28:26.671025+0800 - INFO - 代理对象代号: comet
2025-03-07T09:28:26.674242+0800 - INFO - 成功建立连接
2025-03-07T09:28:26.674242+0800 - INFO - 成功建立连接
2025-03-07T09:28:35.156211+0800 - INFO - 初始化代理对象
2025-03-07T09:28:35.156211+0800 - INFO - 初始化代理对象
2025-03-07T09:28:35.156372+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:28:35.156372+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:28:35.156458+0800 - INFO - 代理对象代号: comet
2025-03-07T09:28:35.156458+0800 - INFO - 代理对象代号: comet
2025-03-07T09:28:35.159041+0800 - INFO - 成功建立连接
2025-03-07T09:28:35.159041+0800 - INFO - 成功建立连接
2025-03-07T09:29:25.100332+0800 - INFO - 初始化代理对象
2025-03-07T09:29:25.100332+0800 - INFO - 初始化代理对象
2025-03-07T09:29:25.100478+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:29:25.100478+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:29:25.100548+0800 - INFO - 代理对象代号: comet
2025-03-07T09:29:25.100548+0800 - INFO - 代理对象代号: comet
2025-03-07T09:29:25.102459+0800 - INFO - 成功建立连接
2025-03-07T09:29:25.102459+0800 - INFO - 成功建立连接
2025-03-07T09:30:13.965473+0800 - INFO - 初始化代理对象
2025-03-07T09:30:13.965473+0800 - INFO - 初始化代理对象
2025-03-07T09:30:13.965675+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:30:13.965675+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:30:13.965765+0800 - INFO - 代理对象代号: comet
2025-03-07T09:30:13.965765+0800 - INFO - 代理对象代号: comet
2025-03-07T09:30:13.967862+0800 - INFO - 成功建立连接
2025-03-07T09:30:13.967862+0800 - INFO - 成功建立连接
2025-03-07T09:31:20.560819+0800 - INFO - 初始化代理对象
2025-03-07T09:31:20.560819+0800 - INFO - 初始化代理对象
2025-03-07T09:31:20.561346+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:31:20.561346+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:31:20.561512+0800 - INFO - 代理对象代号: comet
2025-03-07T09:31:20.561512+0800 - INFO - 代理对象代号: comet
2025-03-07T09:31:20.564821+0800 - INFO - 成功建立连接
2025-03-07T09:31:20.564821+0800 - INFO - 成功建立连接
2025-03-07T09:31:41.871167+0800 - INFO - 初始化代理对象
2025-03-07T09:31:41.871167+0800 - INFO - 初始化代理对象
2025-03-07T09:31:41.871318+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:31:41.871318+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T09:31:41.871391+0800 - INFO - 代理对象代号: comet
2025-03-07T09:31:41.871391+0800 - INFO - 代理对象代号: comet
2025-03-07T09:31:41.873516+0800 - INFO - 成功建立连接
2025-03-07T09:31:41.873516+0800 - INFO - 成功建立连接
2025-03-07T10:02:22.246919+0800 - INFO - 初始化代理对象
2025-03-07T10:02:22.246919+0800 - INFO - 初始化代理对象
2025-03-07T10:02:22.247153+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T10:02:22.247153+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T10:02:22.247261+0800 - INFO - 代理对象代号: comet
2025-03-07T10:02:22.247261+0800 - INFO - 代理对象代号: comet
2025-03-07T10:02:22.247736+0800 - INFO - 等待连接成功
2025-03-07T10:02:22.247736+0800 - INFO - 等待连接成功
2025-03-07T10:02:22.249670+0800 - INFO - 成功建立连接
2025-03-07T10:02:22.249670+0800 - INFO - 成功建立连接
2025-03-07T10:02:22.347928+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T10:02:22.347928+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T15:55:55.862879+0800 - INFO - 初始化代理对象
2025-03-07T15:55:55.862879+0800 - INFO - 初始化代理对象
2025-03-07T15:55:55.863020+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T15:55:55.863020+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T15:55:55.863103+0800 - INFO - 代理对象代号: comet
2025-03-07T15:55:55.863103+0800 - INFO - 代理对象代号: comet
2025-03-07T15:55:55.863455+0800 - INFO - 等待连接成功
2025-03-07T15:55:55.863455+0800 - INFO - 等待连接成功
2025-03-07T15:55:55.865329+0800 - INFO - 成功建立连接, 单向延迟 7.05718994140625e-05ms
2025-03-07T15:55:55.865329+0800 - INFO - 成功建立连接, 单向延迟 7.05718994140625e-05ms
2025-03-07T15:55:55.963668+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T15:55:55.963668+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T15:56:29.263974+0800 - INFO - 初始化代理对象
2025-03-07T15:56:29.263974+0800 - INFO - 初始化代理对象
2025-03-07T15:56:29.264145+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T15:56:29.264145+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T15:56:29.264238+0800 - INFO - 代理对象代号: comet
2025-03-07T15:56:29.264238+0800 - INFO - 代理对象代号: comet
2025-03-07T15:56:29.264733+0800 - INFO - 等待连接成功
2025-03-07T15:56:29.264733+0800 - INFO - 等待连接成功
2025-03-07T15:56:29.266574+0800 - INFO - 成功建立连接, 单向延迟 0ms
2025-03-07T15:56:29.266574+0800 - INFO - 成功建立连接, 单向延迟 0ms
2025-03-07T15:56:29.364981+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T15:56:29.364981+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T15:56:47.266556+0800 - INFO - 初始化代理对象
2025-03-07T15:56:47.266556+0800 - INFO - 初始化代理对象
2025-03-07T15:56:47.266726+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T15:56:47.266726+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T15:56:47.266820+0800 - INFO - 代理对象代号: comet
2025-03-07T15:56:47.266820+0800 - INFO - 代理对象代号: comet
2025-03-07T15:56:47.267230+0800 - INFO - 等待连接成功
2025-03-07T15:56:47.267230+0800 - INFO - 等待连接成功
2025-03-07T15:56:47.269156+0800 - INFO - 成功建立连接, 单向延迟 0.1ms
2025-03-07T15:56:47.269156+0800 - INFO - 成功建立连接, 单向延迟 0.1ms
2025-03-07T15:56:47.367454+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T15:56:47.367454+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T17:45:08.362971+0800 - INFO - 初始化代理对象
2025-03-07T17:45:08.362971+0800 - INFO - 初始化代理对象
2025-03-07T17:45:08.363174+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T17:45:08.363174+0800 - INFO - 卫星地址: ws://127.0.0.1:8765
2025-03-07T17:45:08.363287+0800 - INFO - 代理对象代号: comet
2025-03-07T17:45:08.363287+0800 - INFO - 代理对象代号: comet
2025-03-07T17:45:08.363894+0800 - INFO - 等待连接成功
2025-03-07T17:45:08.363894+0800 - INFO - 等待连接成功
2025-03-07T17:45:08.365733+0800 - INFO - 成功建立连接, 单向延迟 0.1ms
2025-03-07T17:45:08.365733+0800 - INFO - 成功建立连接, 单向延迟 0.1ms
2025-03-07T17:45:08.464116+0800 - INFO - 连接成功, 取消阻塞
2025-03-07T17:45:08.464116+0800 - INFO - 连接成功, 取消阻塞

6
comet/main.py Normal file
View File

@@ -0,0 +1,6 @@
def main():
print("Hello from comet!")
if __name__ == "__main__":
main()

7
comet/pyproject.toml Normal file
View File

@@ -0,0 +1,7 @@
[project]
name = "Comet"
version = "0.1.0"
description = "A onboard controller implementation of AiraPulsar Flight Control System"
readme = "README.md"
requires-python = ">=3.13"
dependencies = []

0
lib/__init__.py Normal file
View File

Binary file not shown.

4
lib/agency/__init__.py Normal file
View File

@@ -0,0 +1,4 @@
from .main import *
version = '0.1.0'
print(f"Powered by Moons Agency, version {version}")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

1
lib/vgl Symbolic link
View File

@@ -0,0 +1 @@
/home/ajax/Documents/Index/302A/vgl

1
moon/.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

View File

@@ -1,119 +0,0 @@
2025-03-07T08:44:59.049714+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T08:54:33.168394+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T08:56:35.504311+0800 - INFO - 新客户端连接: 1
2025-03-07T08:57:12.572151+0800 - INFO - 客户端断开连接: 1
2025-03-07T08:57:13.906086+0800 - INFO - 新客户端连接: 2
2025-03-07T08:57:18.478193+0800 - INFO - 客户端断开连接: 2
2025-03-07T08:58:55.383088+0800 - INFO - 新客户端连接: 3
2025-03-07T08:59:04.634280+0800 - INFO - 客户端断开连接: 3
2025-03-07T08:59:05.383848+0800 - INFO - 新客户端连接: 4
2025-03-07T08:59:51.560133+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T08:59:52.909275+0800 - INFO - 新客户端连接: 1
2025-03-07T08:59:55.915998+0800 - INFO - 客户端断开连接: 1
2025-03-07T09:00:43.283319+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:00:44.635715+0800 - INFO - 新客户端连接: 1
2025-03-07T09:01:29.896734+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:01:31.332525+0800 - INFO - 新客户端连接: 1
2025-03-07T09:02:17.026957+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:02:18.296634+0800 - INFO - 新客户端连接: 1
2025-03-07T09:02:48.143588+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:02:49.427049+0800 - INFO - 新客户端连接: 1
2025-03-07T09:03:10.834981+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:03:12.119704+0800 - INFO - 新客户端连接: 1
2025-03-07T09:03:12.119986+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:03:12.120071+0800 - INFO - 客户端断开连接: 1
2025-03-07T09:03:42.168476+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:03:43.472305+0800 - INFO - 新客户端连接: 1
2025-03-07T09:03:43.472547+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:11:05.352860+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:11:06.882419+0800 - INFO - 新客户端连接: 1
2025-03-07T09:11:06.882773+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:12:14.693477+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:12:16.851004+0800 - INFO - 新客户端连接: 1
2025-03-07T09:12:16.851656+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:19:09.007145+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:19:10.754140+0800 - INFO - 新客户端连接: 1
2025-03-07T09:19:10.754434+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:19:18.493238+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:19:20.016578+0800 - INFO - 新客户端连接: 1
2025-03-07T09:19:20.016862+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:19:37.700993+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:19:39.081530+0800 - INFO - 新客户端连接: 1
2025-03-07T09:19:39.081796+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:19:43.080448+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": "hi"}
2025-03-07T09:19:43.080720+0800 - ERROR - 无法解码 JSON 消息
2025-03-07T09:20:12.487057+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:20:13.857585+0800 - INFO - 新客户端连接: 1
2025-03-07T09:20:13.857880+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:20:14.799728+0800 - INFO - 客户端断开连接: 1
2025-03-07T09:20:17.208026+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:20:22.577076+0800 - INFO - 新客户端连接: 1
2025-03-07T09:20:22.577489+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:20:23.575751+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": "hi"}
2025-03-07T09:20:23.576044+0800 - ERROR - 无法解码 JSON 消息
2025-03-07T09:26:56.246176+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:26:57.807128+0800 - INFO - 新客户端连接: 1
2025-03-07T09:26:57.807419+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:26:58.805874+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": "hi"}
2025-03-07T09:26:58.806066+0800 - ERROR - 无法解码 JSON 消息
2025-03-07T09:28:25.117434+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:28:26.673876+0800 - INFO - 新客户端连接: 1
2025-03-07T09:28:26.674262+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:28:27.671936+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": "hi"}
2025-03-07T09:28:27.672177+0800 - ERROR - 无法解码 JSON 消息
2025-03-07T09:28:29.778081+0800 - INFO - 客户端断开连接: 1
2025-03-07T09:28:33.464911+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:28:35.158721+0800 - INFO - 新客户端连接: 1
2025-03-07T09:28:35.159064+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:28:36.157310+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": "hi"}
2025-03-07T09:28:36.157514+0800 - ERROR - 无法解码 JSON 消息
2025-03-07T09:29:18.205614+0800 - INFO - 客户端断开连接: 1
2025-03-07T09:29:22.053522+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:29:25.102228+0800 - INFO - 新客户端连接: 1
2025-03-07T09:29:25.102476+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:29:26.101162+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": "hi"}
2025-03-07T09:29:26.101351+0800 - ERROR - 无法解码 JSON 消息
2025-03-07T09:30:12.603632+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:30:13.967524+0800 - INFO - 新客户端连接: 1
2025-03-07T09:30:13.967874+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:30:14.966548+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": {"hi": "hi"}}
2025-03-07T09:30:14.966787+0800 - INFO - 客户端断开连接: 1
2025-03-07T09:31:19.129916+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:31:20.564382+0800 - INFO - 新客户端连接: 1
2025-03-07T09:31:20.564841+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:31:21.562523+0800 - INFO - 处理信息: {"id": "comet", "receiver": "1", "content": {"hi": "hi"}}
2025-03-07T09:31:21.562718+0800 - WARNING - 无法发送至端点
2025-03-07T09:31:31.503846+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T09:31:41.873175+0800 - INFO - 新客户端连接: 1
2025-03-07T09:31:41.873532+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T09:31:42.872072+0800 - INFO - 处理信息: {"id": "comet", "receiver": "*", "content": {"hi": "hi"}}
2025-03-07T09:31:42.872284+0800 - WARNING - 无法发送至端点
2025-03-07T09:31:42.872356+0800 - WARNING - 无法发送至端点
2025-03-07T10:02:07.173456+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T10:02:22.249420+0800 - INFO - 新客户端连接: 1
2025-03-07T10:02:22.249683+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T10:02:22.348277+0800 - INFO - 处理信息: {"id": "comet", "receiver": "*", "content": {"hi": "hi"}}
2025-03-07T10:02:22.348428+0800 - WARNING - 无法发送至端点
2025-03-07T10:02:22.348504+0800 - WARNING - 无法发送至端点
2025-03-07T15:55:54.389580+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T15:55:55.865014+0800 - INFO - 新客户端连接: 1
2025-03-07T15:55:55.865334+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T15:55:55.964049+0800 - INFO - 处理信息: {"id": "comet", "receiver": "*", "content": {"hi": "hi"}}
2025-03-07T15:55:55.964208+0800 - WARNING - 无法发送至端点
2025-03-07T15:55:55.964276+0800 - WARNING - 无法发送至端点
2025-03-07T15:55:58.304575+0800 - INFO - 客户端断开连接: 1
2025-03-07T15:56:27.769208+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T15:56:29.266347+0800 - INFO - 新客户端连接: 1
2025-03-07T15:56:29.266586+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T15:56:29.365433+0800 - INFO - 处理信息: {"id": "comet", "receiver": "*", "content": {"hi": "hi"}}
2025-03-07T15:56:29.365581+0800 - WARNING - 无法发送至端点
2025-03-07T15:56:29.365643+0800 - WARNING - 无法发送至端点
2025-03-07T15:56:45.972404+0800 - INFO - 启动"卫星"中继服务器: ws://0.0.0.0:8765
2025-03-07T15:56:47.268864+0800 - INFO - 新客户端连接: 1
2025-03-07T15:56:47.269164+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}
2025-03-07T15:56:47.367838+0800 - INFO - 处理信息: {"id": "comet", "receiver": "*", "content": {"hi": "hi"}}
2025-03-07T15:56:47.367979+0800 - WARNING - 无法发送至端点
2025-03-07T15:56:47.368041+0800 - WARNING - 无法发送至端点
2025-03-07T17:45:07.183410+0800 - INFO - 客户端断开连接: 1
2025-03-07T17:45:08.365484+0800 - INFO - 新客户端连接: 2
2025-03-07T17:45:08.365737+0800 - INFO - 处理信息: {"id": "comet", "receiver": "auth", "content": "auth"}

6
moon/main.py Normal file
View File

@@ -0,0 +1,6 @@
def main():
print("Hello from moon!")
if __name__ == "__main__":
main()

7
moon/pyproject.toml Normal file
View File

@@ -0,0 +1,7 @@
[project]
name = "Moon"
version = "0.1.0"
description = "A relay server implementation of AiraPulsar Flight Control System"
readme = "README.md"
requires-python = ">=3.13"
dependencies = []

1
pulsar/.python-version Normal file
View File

@@ -0,0 +1 @@
3.13

0
pulsar/agent_logs.log Normal file
View File

View File

@@ -0,0 +1,24 @@
import vgl
name = "Marking Lines"
def main(window):
frame = vgl.Frame().attach(window_object=window, poscale=(0,0), clone_name="Marking Line")
lines = list()
for i in range(0, 24):
lines.append(vgl.elements.Line(ends=[(0, i/24), (1, i/24)], color="green").attach(frame_object=frame))
for i in range(0, 32):
lines.append(vgl.elements.Line(ends=[(i/32, 0), (i/32, 1)], color="green").attach(frame_object=frame))
# We monitor events like this.
@window.observerize
def observer(info):
if info["delta"] == "key":
print(info)
if info["delta"] == "click":
if info["click"]:
print(info["cursor"]["poscale"])
# We make changes like this.
for i in lines:
i.set_color('#' + str((info['cursor']['position'][0] + info['cursor']['position'][1]*100 + info['cursor']['position'][0]*10000) % 999999).zfill(6))
observer()

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,25 @@
from lib import vgl
name = "Marking Lines"
def main(window):
frame = vgl.Frame().attach(window_object=window, poscale=(0,0), clone_name="Marking Line")
lines = list()
for i in range(0, 24):
lines.append(vgl.elements.Line(ends=[(0, i/24), (1, i/24)], color="green").attach(frame_object=frame))
for i in range(0, 32):
lines.append(vgl.elements.Line(ends=[(i/32, 0), (i/32, 1)], color="green").attach(frame_object=frame))
# We monitor events like this.
@window.observerize
def observer(info):
if info["delta"] == "key":
print(info)
if info["delta"] == "click":
if info["click"]:
print(info["cursor"]["poscale"])
# We make changes like this.
for i in lines:
i.set_color('#' + str((info['cursor']['position'][0] + info['cursor']['position'][1]*100 + info['cursor']['position'][0]*10000) % 999999).zfill(6))
observer()
#@vgl.loop # TODO
#def toloop():
# pass

15
pulsar/layouts.yaml Normal file
View File

@@ -0,0 +1,15 @@
horizontal_indicator:
- type: line
args:
ends: [(0.4, 0.5), (0.6, 0.5)]
color: green
- type: line
name: remote
args:
ends: [(0.4, 0.5), (0.6, 0.5)]
color: green
- type: line
args:
ends: [(0.4, 0.5), (0.6, 0.5)]
color: green

49
pulsar/main.py Normal file
View File

@@ -0,0 +1,49 @@
from lib import vgl
from lib import agency
import colorama
import os
import importlib.util
window = vgl.Window(title="Pulsar", size=(1600, 1000))
def loader():
components_dir = "components"
for i in os.listdir(components_dir):
if i.endswith(".py") and (not i.startswith("__")):
module_name = i[:-3]
module_path = os.path.join(components_dir, i)
spec = importlib.util.spec_from_file_location(module_name, module_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
try:
if hasattr(module, "main") and callable(module.main):
print(f"[ .... ] Starting {module.name} module")
try:
module.main(window=window)
print(f"[{colorama.Fore.GREEN} OK {colorama.Style.RESET_ALL}] Started {module.name} module")
except Exception as e:
print(f"[{colorama.Fore.RED}FAILED{colorama.Style.RESET_ALL}] Failed to start {module_name} module: {e}")
except:
print(f"Unsupported module: {module_name}.py")
def console():
print("You've entered Pulsar's command console, an embbedded Python interpreter for debugging & testing")
while True:
try:
i = input(">>> ")
if i == "q":
return
exec(i)
except:
print("An error occured & captured")
if __name__ == '__main__':
os.chdir(os.path.dirname(os.path.abspath(__file__)))
print("Welcome to AiraPulsar Client")
window.start()
loader()
console()
print("Quitting")
window.kill()
exit()

0
pulsar/numerator.py Normal file
View File

7
pulsar/pyproject.toml Normal file
View File

@@ -0,0 +1,7 @@
[project]
name = "Pulsar"
version = "0.1.0"
description = "A client implementation of AiraPulsar Flight Control System"
readme = "README.md"
requires-python = ">=3.13"
dependencies = []

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

48
pulsar/tester.py Normal file
View File

@@ -0,0 +1,48 @@
import vgl
import colorama
import os
import importlib.util
window = vgl.Window(title="Pulsar", size=(1024, 768))
def loader():
components_dir = "components"
for i in os.listdir(components_dir):
if i.endswith(".py") and (not i.startswith("__")):
module_name = i[:-3]
module_path = os.path.join(components_dir, i)
spec = importlib.util.spec_from_file_location(module_name, module_path)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
try:
if hasattr(module, "main") and callable(module.main):
print(f"[ .... ] Starting {module.name} module")
try:
module.main(window=window)
print(f"[{colorama.Fore.GREEN} OK {colorama.Style.RESET_ALL}] Started {module.name} module")
except Exception as e:
print(f"[{colorama.Fore.RED}FAILED{colorama.Style.RESET_ALL}] Failed to start {module_name} module: {e}")
except:
print(f"Unsupported module: {module_name}.py")
def console():
print("You've entered Pulsar's command console, an embbedded Python interpreter for debugging & testing")
while True:
try:
i = input(">>> ")
if i == "q":
return
exec(i)
except:
print("An error occured & captured")
if __name__ == '__main__':
os.chdir(os.path.dirname(os.path.abspath(__file__)))
print("Tester")
window.start()
loader()
console()
print("Quitting")
window.kill()
exit()

View File

@@ -1,3 +1,8 @@
# 实验与参考用代码
仅作技术分析验证与历史留存, 若要修改此项目代码, 不必处理此文件夹
若你要使用此软件, 可以克隆后直接将 testfield 文件夹删除
若你要使用此软件, 可以克隆后直接将 testfield 文件夹删除
子目录说明:
- legacy: 旧版飞控系统存档
- vgl: 矢量图形绘制库
- network: sin 波形传输
- visual: "总览"组件开发

27
testfield/kbemu/1.py Normal file
View File

@@ -0,0 +1,27 @@
import time
from pynput.keyboard import Controller
import threading
# 创建键盘控制器
keyboard = Controller()
def press_keys():
while True: # 持续循环
keyboard.press('1') # 按下 'w' 键
time.sleep(0.5) # 等待0.5秒
keyboard.release('w') # 释放 'w' 键
keyboard.press('d') # 按下 'd' 键
time.sleep(0.5) # 等待0.5秒
keyboard.release('d') # 释放 'd' 键
# 创建并启动线程
thread = threading.Thread(target=press_keys)
thread.daemon = True # 设置为守护线程
thread.start()
# 主线程可以在这里执行其他操作
try:
while True:
time.sleep(1) # 主线程保持运行
except KeyboardInterrupt:
print("程序已停止。")

View File

@@ -1,113 +0,0 @@
def generate_shape_dict(shape, **kwargs):
if shape == 'rect':
return {
'method': 'rect',
'pos': kwargs.get('pos', (0, 0)),
'size': kwargs.get('size', (1, 1)),
'color': kwargs.get('color', (255, 255, 255)),
'width': kwargs.get('width', 0) # 添加边框宽度
}
elif shape == 'line':
return {
'method': 'line',
'start_pos': kwargs.get('start_pos', (0, 0)),
'end_pos': kwargs.get('end_pos', (1, 1)),
'color': kwargs.get('color', (255, 255, 255))
}
elif shape == 'circle':
return {
'method': 'circle',
'center': kwargs.get('center', (0, 0)),
'radius': kwargs.get('radius', 1),
'color': kwargs.get('color', (255, 255, 255))
}
elif shape == 'ellipse':
return {
'method': 'ellipse',
'pos': kwargs.get('pos', (0, 0)),
'size': kwargs.get('size', (1, 1)),
'color': kwargs.get('color', (255, 255, 255))
}
elif shape == 'polygon':
return {
'method': 'polygon',
'pointlist': kwargs.get('pointlist', []),
'color': kwargs.get('color', (255, 255, 255))
}
elif shape == 'arc':
return {
'method': 'arc',
'pos': kwargs.get('pos', (0, 0)),
'size': kwargs.get('size', (1, 1)),
'color': kwargs.get('color', (255, 255, 255)),
'start_angle': kwargs.get('start_angle', 0),
'stop_angle': kwargs.get('stop_angle', 3.14)
}
elif shape == 'point':
return {
'method': 'point',
'pos': kwargs.get('pos', (0, 0)),
'color': kwargs.get('color', (255, 255, 255))
}
elif shape == 'lines':
return {
'method': 'lines',
'pointlist': kwargs.get('pointlist', []),
'color': kwargs.get('color', (255, 255, 255))
}
else:
raise ValueError("Unsupported shape type")
def main():
print("欢迎使用图形参数生成器!")
shape = input("请输入图形类型 (rect, line, circle, ellipse, polygon, arc, point, lines): ").strip().lower()
params = {}
if shape == 'rect':
params['pos'] = tuple(map(int, input("请输入矩形位置 (x y): ").split()))
params['size'] = tuple(map(int, input("请输入矩形大小 (width height): ").split()))
params['color'] = tuple(map(int, input("请输入矩形颜色 (R G B): ").split()))
params['width'] = int(input("请输入矩形边框宽度: ")) # 添加边框宽度输入
elif shape == 'line':
params['start_pos'] = tuple(map(int, input("请输入起始位置 (x y): ").split()))
params['end_pos'] = tuple(map(int, input("请输入结束位置 (x y): ").split()))
params['color'] = tuple(map(int, input("请输入线条颜色 (R G B): ").split()))
elif shape == 'circle':
params['center'] = tuple(map(int, input("请输入圆心位置 (x y): ").split()))
params['radius'] = int(input("请输入圆的半径: "))
params['color'] = tuple(map(int, input("请输入圆的颜色 (R G B): ").split()))
elif shape == 'ellipse':
params['pos'] = tuple(map(int, input("请输入椭圆位置 (x y): ").split()))
params['size'] = tuple(map(int, input("请输入椭圆大小 (width height): ").split()))
params['color'] = tuple(map(int, input("请输入椭圆颜色 (R G B): ").split()))
elif shape == 'polygon':
points = input("请输入多边形的点 (x1 y1 x2 y2 ...): ").split()
params['pointlist'] = [(int(points[i]), int(points[i + 1])) for i in range(0, len(points), 2)]
params['color'] = tuple(map(int, input("请输入多边形颜色 (R G B): ").split()))
elif shape == 'arc':
params['pos'] = tuple(map(int, input("请输入弧的位置 (x y): ").split()))
params['size'] = tuple(map(int, input("请输入弧的大小 (width height): ").split()))
params['color'] = tuple(map(int, input("请输入弧的颜色 (R G B): ").split()))
params['start_angle'] = float(input("请输入弧的起始角度 (弧度制): "))
params['stop_angle'] = float(input("请输入弧的结束角度 (弧度制): "))
elif shape == 'point':
params['pos'] = tuple(map(int, input("请输入点的位置 (x y): ").split()))
params['color'] = tuple(map(int, input("请输入点的颜色 (R G B): ").split()))
elif shape == 'lines':
points = input("请输入线段的点 (x1 y1 x2 y2 ...): ").split()
params['pointlist'] = [(int(points[i]), int(points[i + 1])) for i in range(0, len(points), 2)]
params['color'] = tuple(map(int, input("请输入线段颜色 (R G B): ").split()))
else:
print("不支持的图形类型")
return
# 生成图形字典
shape_dict = generate_shape_dict(shape, **params)
# 输出结果
print("生成的图形参数字典:")
print(shape_dict)
if __name__ == "__main__":
main()

View File

@@ -1,26 +0,0 @@
import pygame
import sys
from testfield.vgl.vgllib import *
pygame.init()
window_size = (800, 600)
window = pygame.display.set_mode(window_size)
frame = Frame("Main Frame", window_size)
# 注册一个矩形组件
frame.register("rectangle", {"method": "rect", "pos": (100, 100), "size": (200, 150), "color": (255, 0, 0)})
# 注册一个圆形组件
frame.register("circle", {"method": "circle", "center": (400, 300), "radius": 50, "color": (0, 255, 0)})
# 主循环
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
window.fill((0, 0, 0)) # 清空窗口
frame.drawall(frame.components) # 绘制所有组件
frame.show(window, (0, 0)) # 显示框架
pygame.display.flip() # 更新显示

View File

@@ -1,114 +0,0 @@
# Vector Graphics Library
# vgllib.py
import pygame
import uuid
class Graph:
@staticmethod
def rect(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0):
pygame.draw.rect(frame.surface, color=color, rect=(pos[0], pos[1], size[0], size[1]), width=width)
@staticmethod
def line(frame, start_pos: tuple, end_pos: tuple, color: tuple = (255, 255, 255)):
pygame.draw.aaline(frame.surface, color, start_pos, end_pos)
@staticmethod
def circle(frame, center: tuple, radius: int, color: tuple = (255, 255, 255), width: int = 0):
pygame.draw.circle(frame.surface, color, center, radius, width)
@staticmethod
def ellipse(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0):
rect=(pos[0], pos[1], size[0], size[1])
pygame.draw.ellipse(frame.surface, color, rect, width)
@staticmethod
def polygon(frame, pointlist: list, color: tuple = (255, 255, 255), width: int = 0):
pygame.draw.polygon(frame.surface, color, pointlist, width)
@staticmethod
def arc(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), start_angle: float = 0, stop_angle: float = 3.14, width: int = 1):
rect=(pos[0], pos[1], size[0], size[1])
pygame.draw.arc(frame.surface, color, rect, start_angle, stop_angle, width)
@staticmethod
def point(frame, pos: tuple, color: tuple = (255, 255, 255)):
pygame.draw.point(frame.surface, color, pos)
@staticmethod
def lines(frame, pointlist: list, color: tuple = (255, 255, 255)):
pygame.draw.aalines(frame.surface, color, closed=False, points=pointlist)
@staticmethod
def call(frame, method, **kwargs):
if hasattr(Graph, method):
getattr(Graph, method)(frame, **kwargs)
else:
print(f"方法 {method} 不存在")
class Frame(object):
components = dict()
components_stat = dict()
def __init__(self, name: str, size: tuple):
self.name = name
self.size = size
self.surface = pygame.Surface(size, flags=pygame.HWSURFACE)
self.is_hide = False
print("初始化子模块")
def show(self, window, position: tuple):
if not self.is_hide:
window.blit(self.surface, position)
def set_visible(self, newstat=True):
self.is_hide = newstat
def set_position(self, newposition):
self.position = newposition
def register(self, subname="", attr=None):
if subname == "":
subname = uuid.uuid4()
self.components[subname] = attr
self.components_stat[subname] = 1 # by default, not hiding
def draw(self, attr):
attr['pos'][0] = round(attr['pos'][0] / 100 * self.size[1])
attr['pos'][0] = round(attr['pos'][0] / 100 * self.size[1])
attr['pos'][0] = round(attr['pos'][0] / 100 * self.size[1])
attr['pos'][0] = round(attr['pos'][0] / 100 * self.size[1])
Graph.call(self, **attr)
def set_component_visible(self, subname, newstat):
self.components_stat[subname] = newstat
def drawall(self, attr):
for i in self.components.keys():
if self.components_stat[i]:
self.draw(self.components[i])
def clear(self, color=(0,0,0)):
self.surface.fill(color)
def loads(self, ):
# 示例
if __name__ == "__main__":
pygame.init()
window = pygame.display.set_mode((800, 600))
frame = Frame("Test", (800, 600))
frame.draw({'method':'rect', 'pos':(50, 50), 'size':(200, 100), 'color':(255, 0, 0)}) # 绘制红色矩形
# 主循环
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
window.fill((0, 0, 0)) # 清空窗口
frame.show(window, (0, 0)) # 显示帧
pygame.display.flip() # 更新显示
pygame.quit()

7
vgl/__init__.py Normal file
View File

@@ -0,0 +1,7 @@
import os
os.environ["PYGAME_HIDE_SUPPORT_PROMPT"] = "True"
from .main import *
from . import basic_elements as elements
version = '0.3.0'
print(f"Powered by Vector Graphic Layer, version {version}")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

96
vgl/basic_elements.py Normal file
View File

@@ -0,0 +1,96 @@
from .main import *
import pygame
import time
class Line(Element):
def __init__(self, ends = [(0.1, 0.1), (0.2, 0.2)], color = "#ffffff"):
self.color = color
self.ends = ends
def set_color(self, new_color):
self.color = new_color
def move(self, delta, duration):
self.add_task(group = "move", start_time = Aux.gettime(), duration = duration, delta = delta)
def update(self):
for i in self.tasks.get("move", []):
self.teleport(Aux.tuple_scale(tup = i['delta'], mul = Aux.getprogress(i)))
def render(self):
pygame.draw.aaline(self.attached_frame.surface, self.color, Aux.pixelizer(self.ends[0], self.attached_window), Aux.pixelizer(self.ends[1], self.attached_window))
class Rect(Element):
def __init__(self, nw_posc=(0.1, 0.1), se_posc=(0.2,0.2), color = "#114514", width = 0): # non-0 for "frame"
self.color = color
self.width = width
self.rect = (nw_posc[0], nw_posc[1], se_posc[0], se_posc[1])
def move(self, delta, duration):
self.add_task(group = "move", start_time = Aux.gettime(), duration = duration, delta = delta)
def update(self):
for i in self.tasks.get("move", []):
self.teleport(Aux.tuple_scale(tup = i['delta'], mul = Aux.getprogress(i)))
def render(self):
pygame.draw.rect(surface=self.attached_frame.surface, color=self.color, rect=Aux.pixelizer(self.rect, self.attached_window), width=self.width)
class Graph:
@staticmethod
def rect(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0):
pygame.draw.rect(frame.surface, color=color, rect=(pos[0], pos[1], size[0], size[1]), width=width)
@staticmethod
def line(frame, start_pos: tuple, end_pos: tuple, color: tuple = (255, 255, 255)):
pygame.draw.aaline(frame.surface, color, start_pos, end_pos)
@staticmethod
def circle(frame, center: tuple, radius: int, color: tuple = (255, 255, 255), width: int = 0):
pygame.draw.circle(frame.surface, color, center, radius, width)
@staticmethod
def ellipse(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), width: int = 0):
rect=(pos[0], pos[1], size[0], size[1])
pygame.draw.ellipse(frame.surface, color, rect, width)
@staticmethod
def polygon(frame, pointlist: list, color: tuple = (255, 255, 255), width: int = 0):
pygame.draw.polygon(frame.surface, color, pointlist, width)
@staticmethod
def arc(frame, pos: tuple = (0, 0), size: tuple = (1, 1), color: tuple = (255, 255, 255), start_angle: float = 0, stop_angle: float = 3.14, width: int = 1):
rect=(pos[0], pos[1], size[0], size[1])
pygame.draw.arc(frame.surface, color, rect, start_angle, stop_angle, width)
@staticmethod
def point(frame, pos: tuple, color: tuple = (255, 255, 255)):
pygame.draw.point(frame.surface, color, pos)
@staticmethod
def lines(frame, pointlist: list, color: tuple = (255, 255, 255)):
pygame.draw.aalines(frame.surface, color, closed=False, points=pointlist)
@staticmethod
def call(frame, method, **kwargs):
if hasattr(Graph, method):
getattr(Graph, method)(frame, **kwargs)
else:
print(f"方法 {method} 不存在")

283
vgl/main.py Normal file
View File

@@ -0,0 +1,283 @@
# Vector Graphics Library
# vgllib.py
import pygame
import uuid
import time
import threading
import copy
import queue
class Aux():
def gettime():
return round(time.time(), 1)
def getprogress(task):
return (Aux.gettime() - task["start"] / task["duration"])
def tuple_scale(tup, mul):
return (tup[0]*mul, tup[1]*mul)
def pixelizer(arg, base):
if not isinstance(base, tuple):
base = base.size
if isinstance(arg, int):
return arg * base
else:
if len(arg) == 2:
return (round(arg[0] * base[0]), round(arg[1] * base[1]))
if len(arg) == 4:
return (round(arg[0] * base[0]), round(arg[1] * base[1]), round(arg[2] * base[0]), round(arg[3] * base[1]))
def eventproc(events_dict, event, window_size):
"""events = {
"cursor": {
"position": (15,12),
"relative": (13,11),
"poscale": (0.1,0.5),
"relscale": (0.05,0.1),
},
"wheel": 1, # 远离用户为 1, 靠近为 -1, 无动作为 0
"click": [1, 2], # 被按下的按钮
#"focus": 1, # 或 0
"key": ["ctrl", "k"],
"delta": ""
}"""
if event.type == pygame.MOUSEMOTION:
events_dict["cursor"]["position"] = event.pos
events_dict["cursor"]["relative"] = event.rel
events_dict["cursor"]["poscale"] = (round(event.pos[0] / window_size[0], 3), round(event.pos[1] / window_size[1],3))
events_dict["cursor"]["relscale"] = (round(event.rel[0] / window_size[0], 3), round(event.rel[1] / window_size[1], 3))
events_dict["delta"] = "cursor"
elif event.type == pygame.MOUSEWHEEL:
events_dict["wheel"] = event.y # 远离用户为正,靠近为负
events_dict["delta"] = "wheel"
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button not in events_dict["click"]:
events_dict.setdefault("click", []).append(event.button)
events_dict["delta"] = "click"
elif event.type == pygame.MOUSEBUTTONUP:
if event.button in events_dict["click"]:
events_dict["click"].remove(event.button)
events_dict["delta"] = "click"
elif event.type == pygame.KEYDOWN:
keys = events_dict.setdefault("key", [])
key_name = pygame.key.name(event.key).lower()
# 简单的修饰键处理, 为兼容部分精简键盘 故合并左右功能键
if key_name in ["left ctrl", "right ctrl"]:
if "ctrl" not in keys:
keys.append("ctrl")
elif key_name in ["left shift", "right shift"]:
if "shift" not in keys:
keys.append("shift")
elif key_name in ["left alt", "right alt"]:
if "alt" not in keys:
keys.append("alt")
elif len(key_name) == 1: # 处理字母和数字
keys.append(key_name)
events_dict["delta"] = "key"
elif event.type == pygame.KEYUP:
events_dict["delta"] = "key"
if "key" in events_dict:
key_name = pygame.key.name(event.key).lower()
if key_name in ["left ctrl", "right ctrl"] and "ctrl" in events_dict["key"]:
events_dict["key"].remove("ctrl")
elif key_name in ["left shift", "right shift"] and "shift" in events_dict["key"]:
events_dict["key"].remove("shift")
elif key_name in ["left alt", "right alt"] and "alt" in events_dict["key"]:
events_dict["key"].remove("alt")
elif len(key_name) == 1 and key_name in events_dict["key"]:
events_dict["key"].remove(key_name)
else:
#print("不重要事件")
return 0
return 1
class Anchor(object):
"""
"锚定点" 对象
镜像
@: 矩阵乘法
*: 中心/任意参照点缩放
中点/比例点
"""
poscale = (0, 0) # 位置
fixed = 3 # 小数点后精度
def __init__(self, *args):
if isinstance(args[0], tuple) or isinstance(args[0], Anchor):
if isinstance(args[0], Anchor):
self.poscale = args[0].poscale
else:
self.poscale = args[0]
else:
self.poscale = (args[0], args[1])
def x(self):
return self.poscale[0]
def y(self):
return self.poscale[1]
def __add__(self, other):
"矩阵加法"
if isinstance(other, tuple):
return Anchor((self.poscale[0] + other[0], self.poscale[1] + other[1]))
elif isinstance(other, Anchor):
return Anchor((self.poscale[0] + other.poscale[0], self.poscale[1] + other.poscale[1]))
else:
raise TypeError("不支持的加法操作数类型")
def __mul__(self, other):
"中心倍增/倍缩"
if isinstance(other, tuple):
return Anchor((0.5 + other[0] * (self.poscale[0] - 0.5), 0.5 + other[1] * (self.poscale[1] - 0.5)))
elif isinstance(other, (int, float)):
return Anchor((0.5 + other * (self.poscale[0] - 0.5), 0.5 + other * (self.poscale[1] - 0.5)))
else:
raise TypeError("不支持的乘法操作数类型")
def __imul__(self, other):
result = self.__mul__(other)
self.poscale = result.poscale
return self
def __truediv__(self, other):
"乘以倒数"
if isinstance(other, (int, float)):
if other == 0:
return Anchor((0.5, 0.5))
else:
return self.__mul__(1 / other)
elif isinstance(other, Anchor) or isinstance(other, tuple):
divisor_x = other[0] if isinstance(other, tuple) else other.x()
divisor_y = other[1] if isinstance(other, tuple) else other.y()
# TODO: 错误代码, 应当予以修正
if divisor_x == 0 and divisor_y == 0:
return Anchor((0.5, 0.5))
if divisor_x == 0 and divisor_y == 0:
return Anchor((0.5, 0.5))
else:
return self.__mul__((1 / divisor_x, 1 / divisor_y))
else:
raise TypeError("不支持的除法操作数类型")
def __itruediv__(self, other):
"就地除法"
result = self.__truediv__(other)
self.poscale = result.poscale
return self
def __str__(self):
if self.fixed is not None:
return f"({round(self.poscale[0], self.fixed)}, {round(self.poscale[1], self.fixed)})"
else:
return f"({self.poscale[0]}, {self.poscale[1]})"
class Element(object):
is_hide = False
is_template = True
attached = None
attached_frame = None
attached_window = None
tasks = dict()
def __init__(self, name="Element"):
self.name = name
def attach(self, frame_object, clone_name=""):
if clone_name == "":
clone_name = str(uuid.uuid4())
clone = copy.deepcopy(self)
clone.is_template = False
frame_object.elements[clone_name] = clone
clone.attached_frame = frame_object
clone.attached_window = frame_object.attached_window
return clone
def teleport(self, delta: tuple):
if not self.is_template:
pass
def add_task(self, group, start_time, duration, **kwargs):
if group not in self.tasks():
self.tasks[group] = list()
self.tasks[group].append({"start": start_time, "duration":duration, "para":kwargs})
def render():
print("未配置渲染器")
pass
def update():
pass
class Frame(object):
surface = None
elements = dict()
is_hide = False
is_template = True
attached_window = None
poscale: tuple = (0, 0) # 左上角, 对于每个实例的位置矢量
def __init__(self, name="Frame"):
self.name = name
def attach(self, window_object, poscale, clone_name=""):
if clone_name == "":
clone_name = str(uuid.uuid4())
clone = copy.deepcopy(self)
clone.surface = pygame.Surface(window_object.size)
clone.poscale = poscale
clone.is_template = False
clone.attached_window = window_object
window_object.frames[clone_name] = clone
return window_object.frames[clone_name]
def render(self):
for i in self.elements.values():
i.render()
self.attached_window.screen.blit(self.surface, self.poscale)
class Window(object):
frames = dict()
events = {
"cursor": {
"position": (0,0),
"relative": (0,0),
"poscale": (0,0),
"relscale": (0,0),
},
"wheel": 0, # 远离用户为 1, 靠近为 -1, 无动作为 0
"click": [], # 被按下的按钮
"focus": 1, # 或 0
"key": [],
"delta": "" # 变化的键值, 避免多次调用
}
"""{
"cursor": {
"position": (15,12),
"relative": (13,11),
"poscale": (0.1,0.5),
"relscale": (0.05,0.1),
},
"wheel": 1, # 远离用户为 1, 靠近为 -1, 无动作为 0
"click": [1, 2], # 被按下的按钮
"focus": 1, # 或 0
"key": ["ctrl", "k"],
"delta": ["key"]
}"""
observers = list()
def __init__(self, title="Vector Graphic Layer Window", size: tuple=(1024,768)):
self.title = title
self.size = size
self.running = 1
pygame.init()
self.screen = pygame.display.set_mode(size)
pygame.display.set_caption(title)
def set_title(self, title):
self.title = title
pygame.display.set_caption(title)
def start(self):
self.thr = threading.Thread(target=self.main_loop, name="main_loop")
self.thr.start()
def kill(self):
self.running = 0
def main_loop(self):
while self.running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = 0
if_matters = Aux.eventproc(self.events, event, self.size)
if if_matters:
#print(self.observers)
for i in self.observers:
i(self.events)
#print(self.events)
for i in self.frames.values():
i.render()
pygame.display.flip()
pygame.time.delay(10)
pygame.quit()
def observerize(self, func):
def wrapper():
self.observers.append(func)
return wrapper
def remove_observer(self, func):
self.observers.remove(func)

28
vgl/test.py Normal file
View File

@@ -0,0 +1,28 @@
import pygame
import sys
# 初始化 Pygame
pygame.init()
# 设置窗口大小
screen = pygame.display.set_mode((800, 600))
# 设置颜色 (RGB)
background_color = (255, 255, 255) # 白色背景
line_color = (255, 0, 0) # 红色线条
# 主循环
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# 填充背景
screen.fill(background_color)
# 绘制抗锯齿线条
pygame.draw.aaline(screen, line_color, (100, 100), (700, 500))
# 更新显示
pygame.display.flip()