174 lines
7.1 KiB
Plaintext
174 lines
7.1 KiB
Plaintext
import MilCon
|
|
import typing
|
|
import math
|
|
|
|
|
|
class _HPos:
|
|
x: str
|
|
y: str
|
|
z: str
|
|
|
|
class RelativePos:
|
|
def __init__(self, x: str | int | float = "~", y: str | int | float = "~", z: str | int | float = "~"):
|
|
self.x: str = str(x) if isinstance(x, (int, float)) else x
|
|
self.y: str = str(y) if isinstance(y, (int, float)) else y
|
|
self.z: str = str(z) if isinstance(z, (int, float)) else z
|
|
def __str__(self):
|
|
return f"{self.x} {self.y} {self.z}"
|
|
@classmethod
|
|
def FromString(cls, s: str):
|
|
parts = s.split()
|
|
if len(parts) != 3 or not all(p.startswith('~') for p in parts): raise ValueError("Catch A Error As RelativePos ~x ~y ~z")
|
|
return cls(*parts)
|
|
def ToAbsolute(self, reference: _HPos=None):
|
|
def ParseCoord(coord: str, ref):
|
|
if coord.startswith('~'): return ref + (float(coord[1:]) if len(coord) > 1 else 0.0)
|
|
else: return float(coord)
|
|
ref_x = reference.x if reference and reference.x.startswith('~') else 0.0
|
|
ref_y = reference.y if reference and reference.y.startswith('~') else 0.0
|
|
ref_z = reference.z if reference and reference.z.startswith('~') else 0.0
|
|
abs_x = ParseCoord(self.x, ref_x)
|
|
abs_y = ParseCoord(self.y, ref_y)
|
|
abs_z = ParseCoord(self.z, ref_z)
|
|
return RelativePos(abs_x, abs_y, abs_z)
|
|
|
|
class LocalCoordinatesPos:
|
|
def __init__(self, x: str | int | float = "^", y: str | int | float = "^", z: str | int | float = "^"):
|
|
self.x: str = str(x) if isinstance(x, (int, float)) else x
|
|
self.y: str = str(y) if isinstance(y, (int, float)) else y
|
|
self.z: str = str(z) if isinstance(z, (int, float)) else z
|
|
def __str__(self):
|
|
return f"{self.x} {self.y} {self.z}"
|
|
@classmethod
|
|
def FromString(cls, s: str):
|
|
parts = s.split()
|
|
if len(parts) != 3 or not all(p.startswith('^') for p in parts): raise ValueError("Catch A Error As LocalCoordinatesPos ^x ^y ^z")
|
|
return cls(*parts)
|
|
def ToAbsolute(self, reference: _HPos=None):
|
|
def ParseCoord(coord: str, ref):
|
|
if coord.startswith('^'): return ref + (float(coord[1:]) if len(coord) > 1 else 0.0)
|
|
else: return float(coord)
|
|
ref_x = reference.x if reference and reference.x.startswith('^') else 0.0
|
|
ref_y = reference.y if reference and reference.y.startswith('^') else 0.0
|
|
ref_z = reference.z if reference and reference.z.startswith('^') else 0.0
|
|
abs_x = ParseCoord(self.x, ref_x)
|
|
abs_y = ParseCoord(self.y, ref_y)
|
|
abs_z = ParseCoord(self.z, ref_z)
|
|
return LocalCoordinatesPos(abs_x, abs_y, abs_z)
|
|
|
|
class Delta:
|
|
def __init__(self, x: int = 0, y: int = 0, z: int = 0):
|
|
self.x, self.y, self.z = x, y, z
|
|
def __str__(self):
|
|
return f"{self.x} {self.y} {self.z}"
|
|
class Command():
|
|
def __init__(self, command):
|
|
self.command = command
|
|
def __str__(self):
|
|
return self.command
|
|
class ExecuteSubCommandRule(typing.TypedDict):
|
|
mode: MilCon._execute_sub_commands
|
|
text: Command
|
|
|
|
def _Bool2Str(self, value: bool):
|
|
return "true" if value else "false"
|
|
def _WithValue(self, value: str | int):
|
|
return f" {value}" if value else ""
|
|
|
|
def _Pos1ToPos2(pos1: RelativePos, pos2: RelativePos, radios: int):
|
|
abs_pos1 = pos1.ToAbsolute()
|
|
abs_pos2 = pos2.ToAbsolute()
|
|
x1, y1, z1 = abs_pos1.x, abs_pos1.y, abs_pos1.z
|
|
x2, y2, z2 = abs_pos2.x, abs_pos2.y, abs_pos2.z
|
|
delta_x = (x2 - x1) / (radios + 1)
|
|
delta_y = (y2 - y1) / (radios + 1)
|
|
delta_z = (z2 - z1) / (radios + 1)
|
|
points = []
|
|
for i in range(1, radios + 1):
|
|
x = x1 + delta_x * i
|
|
y = y1 + delta_y * i
|
|
z = z1 + delta_z * i
|
|
points.append(RelativePos(x, y, z))
|
|
return points
|
|
|
|
def _Pos1ToPos2WithPoints(radios: int, radian: int, pos1: RelativePos, pos2: RelativePos, *poses: RelativePos):
|
|
# 参数验证
|
|
if radios <= len(poses) + 2:
|
|
raise ValueError("radios must be greater than len(poses) + 2")
|
|
if radian < 0:
|
|
raise ValueError("radian must be non-negative")
|
|
|
|
# 转换为绝对坐标
|
|
abs_pos1 = pos1.ToAbsolute()
|
|
abs_poses = [p.ToAbsolute() for p in poses]
|
|
abs_pos2 = pos2.ToAbsolute()
|
|
|
|
# 所有点按顺序排列
|
|
all_points = [abs_pos1] + abs_poses + [abs_pos2]
|
|
num_segments = len(all_points) - 1
|
|
|
|
# 计算每段的点数
|
|
points_per_segment = (radios - num_segments + 1) // num_segments
|
|
remainder = (radios - num_segments + 1) % num_segments
|
|
|
|
# 生成点
|
|
points = []
|
|
for i in range(num_segments):
|
|
start = all_points[i]
|
|
end = all_points[i + 1]
|
|
|
|
# 当前段的点数
|
|
current_points = points_per_segment + (1 if i < remainder else 0)
|
|
|
|
# 计算增量
|
|
delta_x = (float(end.x) - float(start.x)) / (current_points + 1)
|
|
delta_y = (float(end.y) - float(start.y)) / (current_points + 1)
|
|
delta_z = (float(end.z) - float(start.z)) / (current_points + 1)
|
|
|
|
# 生成当前段的点
|
|
for j in range(1, current_points + 1):
|
|
x = float(start.x) + delta_x * j
|
|
y = float(start.y) + delta_y * j
|
|
z = float(start.z) + delta_z * j
|
|
|
|
# 如果 radian 不为 0 且 poses 存在,则在中间点附近向外偏移
|
|
if radian != 0 and len(poses) > 0 and i < len(poses):
|
|
# 计算当前点与中间点的距离比例
|
|
t = j / (current_points + 1)
|
|
# 使用正弦函数生成弧形偏移
|
|
offset = radian * math.sin(t * math.pi)
|
|
|
|
# 计算垂直于路径的方向(简单实现,可以改进为真正的 3D 垂直)
|
|
# 这里假设偏移方向为 (1, 1, 1) 的某个分量,实际应根据路径方向计算
|
|
x += offset * 0.577 # 0.577 ≈ 1 / sqrt(3)
|
|
y += offset * 0.577
|
|
z += offset * 0.577
|
|
|
|
points.append(RelativePos(x, y, z))
|
|
|
|
return points
|
|
|
|
'''def _Pos1ToPos2WithPoints(radios: int, pos1: RelativePos, pos2: RelativePos, *poses: RelativePos):
|
|
if radios <= len(poses) + 2:
|
|
raise ValueError("radios must be greater than len(poses) + 2")
|
|
abs_pos1 = pos1.ToAbsolute()
|
|
abs_poses = [p.ToAbsolute() for p in poses]
|
|
abs_pos2 = pos2.ToAbsolute()
|
|
all_points = [abs_pos1] + abs_poses + [abs_pos2]
|
|
num_segments = len(all_points) - 1
|
|
points_per_segment = (radios - num_segments + 1) // num_segments
|
|
remainder = (radios - num_segments + 1) % num_segments
|
|
points = []
|
|
for i in range(num_segments):
|
|
start = all_points[i]
|
|
end = all_points[i + 1]
|
|
current_points = points_per_segment + (1 if i < remainder else 0)
|
|
delta_x = (float(end.x) - float(start.x)) / (current_points + 1)
|
|
delta_y = (float(end.y) - float(start.y)) / (current_points + 1)
|
|
delta_z = (float(end.z) - float(start.z)) / (current_points + 1)
|
|
for j in range(1, current_points + 1):
|
|
x = float(start.x) + delta_x * j
|
|
y = float(start.y) + delta_y * j
|
|
z = float(start.z) + delta_z * j
|
|
points.append(RelativePos(x, y, z))
|
|
return points''' |