You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
267 lines
11 KiB
267 lines
11 KiB
from math import cos, pi
|
|
import matplotlib.pyplot as plt
|
|
|
|
blue_fill_color = (0.4, 0.8, 1.0, 0.6)
|
|
blue_edge_color = (0.4, 0.8, 1.0, 0.3)
|
|
red_fill_color = (1.0, 0.8, 0.4, 0.6)
|
|
red_edge_color = (1.0, 0.8, 0.4, 0.3)
|
|
draw_state = 0
|
|
|
|
plt.rcParams['font.family'] = ['Times New Roman', 'SimSun']
|
|
plt.rcParams['mathtext.fontset'] = 'stix'
|
|
plt.rcParams['font.size'] = 16
|
|
|
|
def read_meta_data(filename):
|
|
with open(filename, 'r', encoding='utf-8') as file:
|
|
content = file.read()
|
|
|
|
blocks = [block.strip() for block in content.strip().split('\n\n')]
|
|
meta_data = {}
|
|
|
|
meta_data['type'] = blocks[0].strip()
|
|
|
|
lines = blocks[1].strip().split('\n')
|
|
meta_data['chain_range'] = []
|
|
meta_data['chain_double_sided'] = []
|
|
meta_data['chain_point_to_pos_side'] = []
|
|
for i, line in enumerate(lines):
|
|
line = line.strip()
|
|
parts = line.split()
|
|
meta_data['chain_range'].append((int(parts[0]), int(parts[1])))
|
|
meta_data['chain_double_sided'].append(True if parts[2] == 'true' else False)
|
|
meta_data['chain_point_to_pos_side'].append(True if parts[3] == 'true' else False)
|
|
|
|
meta_data['aabb'] = []
|
|
lines = blocks[2].strip().split('\n')
|
|
parts = lines[0].strip().split()
|
|
for part in parts: meta_data['aabb'].append(float(part))
|
|
|
|
meta_data['parallel_to_u'] = []
|
|
meta_data['parallel_to_v'] = []
|
|
meta_data['intersect_u'] = []
|
|
meta_data['intersect_v'] = []
|
|
lines = blocks[3].strip().split('\n')
|
|
parts = lines[0].strip().split()
|
|
for part in parts: meta_data['parallel_to_v'].append(float(part))
|
|
parts = lines[1].strip().split()
|
|
for part in parts: meta_data['intersect_u'].append(float(part))
|
|
parts = lines[2].strip().split()
|
|
for part in parts: meta_data['parallel_to_u'].append(float(part))
|
|
parts = lines[3].strip().split()
|
|
for part in parts: meta_data['intersect_v'].append(float(part))
|
|
|
|
# print("Meta Data:")
|
|
# print(f"Type: {meta_data['type']}")
|
|
# print("Chain Ranges:")
|
|
# for i, chain_range in enumerate(meta_data['chain_range']):
|
|
# print(f" Subchain {i+1}: {chain_range[0]} to {chain_range[1]}")
|
|
# print("Chain Double Sided:")
|
|
# for i, double_sided in enumerate(meta_data['chain_double_sided']):
|
|
# print(f" Subchain {i+1}: {'Yes' if double_sided else 'No'}")
|
|
# print("Chain Point to Pos Side:")
|
|
# for i, point_to_pos_side in enumerate(meta_data['chain_point_to_pos_side']):
|
|
# print(f" Subchain {i+1}: {'Yes' if point_to_pos_side else 'No'}")
|
|
# print("Parallel to U:", meta_data['parallel_to_u'])
|
|
# print("Intersect U:", meta_data['intersect_u'])
|
|
# print("Parallel to V:", meta_data['parallel_to_v'])
|
|
# print("Intersect V:", meta_data['intersect_v'])
|
|
|
|
return meta_data
|
|
|
|
def read_integral_points(filename):
|
|
integral_points = []
|
|
with open(filename, 'r', encoding='utf-8') as file:
|
|
content = file.read()
|
|
|
|
lines = content.strip().split('\n')
|
|
for line in lines:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
parts = line.split()
|
|
try:
|
|
u = float(parts[0])
|
|
v = float(parts[1])
|
|
weight = float(parts[2])
|
|
integral_points.append((u, v, weight))
|
|
except ValueError:
|
|
print(f"警告: 积分点行 '{line}' 包含非数字内容,跳过")
|
|
continue
|
|
|
|
# 对权值进行一致化并存储到最后一维
|
|
min_weight = min(weight for _, _, weight in integral_points)
|
|
max_weight = max(weight for _, _, weight in integral_points)
|
|
for i in range(len(integral_points)):
|
|
u, v, weight = integral_points[i]
|
|
normalized_weight = (weight - min_weight) / (max_weight - min_weight) if max_weight > min_weight else 0
|
|
integral_points[i] = (u, v, weight, normalized_weight)
|
|
|
|
return integral_points
|
|
|
|
def read_and_plot_polylines(filename, meta_data, integral_points):
|
|
# 读取文件内容
|
|
with open(filename, 'r', encoding='utf-8') as file:
|
|
content = file.read()
|
|
|
|
# 按空行分割不同的折线段区块
|
|
# strip() 用于移除开头和结尾的空行,split('\n\n') 按连续换行分割
|
|
blocks = [block.strip() for block in content.strip().split('\n\n')]
|
|
|
|
# 创建图形
|
|
plt.figure(figsize=(10, 8))
|
|
|
|
# 处理每个区块
|
|
for i, block in enumerate(blocks):
|
|
if not block: # 跳过空区块
|
|
continue
|
|
|
|
# 匹配chain的meta信息
|
|
double_sided = False
|
|
point_to_pos_side = False
|
|
for (chain_range, double_sided_, point_to_pos_side_) in zip(meta_data['chain_range'],
|
|
meta_data['chain_double_sided'],
|
|
meta_data['chain_point_to_pos_side']):
|
|
if chain_range[0] <= i < chain_range[1]:
|
|
double_sided = double_sided_
|
|
point_to_pos_side = point_to_pos_side_
|
|
break
|
|
|
|
# 将区块分割成行
|
|
lines = block.strip().split('\n')
|
|
|
|
# 存储当前折线段的点
|
|
x_points = []
|
|
y_points = []
|
|
|
|
# 处理每一行
|
|
for line in lines:
|
|
line = line.strip()
|
|
if not line: # 跳过空行
|
|
continue
|
|
|
|
# 分割两个double数值
|
|
parts = line.split()
|
|
|
|
try:
|
|
x = float(parts[0])
|
|
y = float(parts[1])
|
|
x_points.append(x)
|
|
y_points.append(y)
|
|
except ValueError:
|
|
print(f"警告: 区块 {i+1} 的行 '{line}' 包含非数字内容,跳过")
|
|
continue
|
|
|
|
if draw_state > 0:
|
|
for ((x1, x2), (y1, y2)) in zip(zip(x_points, x_points[1:]), zip(y_points, y_points[1:])):
|
|
delta_x = x2 - x1
|
|
delta_y = y2 - y1
|
|
# (delta_y, -delta_x) 为正方向向量
|
|
point_to_neg_x = (not point_to_pos_side and delta_y > 0) or (point_to_pos_side and delta_y < 0)
|
|
point_to_pos_x = (point_to_pos_side and delta_y > 0) or (not point_to_pos_side and delta_y < 0)
|
|
point_to_neg_y = (not point_to_pos_side and delta_x < 0) or (point_to_pos_side and delta_x > 0)
|
|
point_to_pos_y = (point_to_pos_side and delta_x < 0) or (not point_to_pos_side and delta_x > 0)
|
|
if double_sided:
|
|
if draw_state == 1:
|
|
plt.fill([-100, -100, 100, 100], [y1, y2, y2, y1], facecolor=blue_fill_color, edgecolor=blue_edge_color)
|
|
elif draw_state == 2:
|
|
plt.fill([x1, x2, x2, x1], [-100, -100, 100, 100], facecolor=red_fill_color, edgecolor=red_edge_color)
|
|
else:
|
|
if draw_state == 1:
|
|
if point_to_neg_x:
|
|
plt.fill([x1, x2, -100, -100], [y1, y2, y2, y1], facecolor=blue_fill_color, edgecolor=blue_edge_color)
|
|
elif point_to_pos_x:
|
|
plt.fill([x1, x2, 100, 100], [y1, y2, y2, y1], facecolor=blue_fill_color, edgecolor=blue_edge_color)
|
|
elif draw_state == 2:
|
|
if point_to_neg_y:
|
|
plt.fill([x1, x1, x2, x2], [y1, -100, -100, y2], facecolor=red_fill_color, edgecolor=red_edge_color)
|
|
elif point_to_pos_y:
|
|
plt.fill([x1, x1, x2, x2], [y1, 100, 100, y2], facecolor=red_fill_color, edgecolor=red_edge_color)
|
|
|
|
# 绘制当前折线段
|
|
plt.plot(x_points, y_points,
|
|
marker='o',
|
|
linestyle='-',
|
|
color='black',
|
|
label=f'Subchain {i+1}',
|
|
linewidth=2,
|
|
markersize=4)
|
|
|
|
# 绘制平行线和交点
|
|
if draw_state == 3:
|
|
for u in meta_data['parallel_to_u']:
|
|
plt.axhline(y=u, color='red', linestyle='--', linewidth=3, alpha=0.7)
|
|
for v in meta_data['parallel_to_v']:
|
|
plt.axvline(x=v, color='red', linestyle='--', linewidth=3, alpha=0.7)
|
|
for i in range(len(meta_data['intersect_u'])):
|
|
u = meta_data['intersect_u'][i]
|
|
v = meta_data['intersect_v'][i]
|
|
# 加粗交点标记
|
|
plt.plot(u, v, marker='x', color='red', markersize=12, markeredgewidth=2, label=f'Intersect {i+1}')
|
|
|
|
# 绘制带权值的积分点
|
|
if draw_state == 4:
|
|
u_vals, v_vals, weights, normalized_weights = zip(*integral_points)
|
|
plt.scatter(u_vals, v_vals, c=normalized_weights, cmap='viridis', s=50, alpha=0.7, label='Integral Points')
|
|
print(f"积分点权值总和: {sum(weights)}")
|
|
|
|
x_min = meta_data['aabb'][0]
|
|
x_max = meta_data['aabb'][2]
|
|
y_min = meta_data['aabb'][1]
|
|
y_max = meta_data['aabb'][3]
|
|
x_range = x_max - x_min
|
|
y_range = y_max - y_min
|
|
if x_range == 0:
|
|
x_padding = abs(x_max) * 0.1 if x_max != 0 else 0.5
|
|
else:
|
|
x_padding = max(x_range * 0.05, x_range * 0.005)
|
|
if y_range == 0:
|
|
y_padding = abs(y_max) * 0.1 if y_max != 0 else 0.5
|
|
else:
|
|
y_padding = max(y_range * 0.05, y_range * 0.005)
|
|
|
|
# 设置坐标轴范围
|
|
plt.xlim(x_min - x_padding, x_max + x_padding)
|
|
plt.ylim(y_min - y_padding, y_max + y_padding)
|
|
|
|
# 提示AABB
|
|
plt.plot([x_min, x_max, x_max, x_min, x_min],
|
|
[y_min, y_min, y_max, y_max, y_min],
|
|
linestyle='-',
|
|
color='green',
|
|
label='AABB',
|
|
linewidth=1)
|
|
|
|
# 设置图形属性
|
|
# plt.title('')
|
|
plt.xlabel('u坐标')
|
|
plt.ylabel('v坐标')
|
|
plt.grid(True, alpha=0.3)
|
|
# plt.legend()
|
|
|
|
# 保持x和y轴比例相同(但会因y轴padding而稍有不同)
|
|
plt.gca().set_aspect('auto')
|
|
|
|
# 显示图形
|
|
plt.tight_layout()
|
|
plt.show()
|
|
|
|
# 使用示例
|
|
if __name__ == "__main__":
|
|
# 或者使用您自己的文件
|
|
filename = input("请输入文件路径: ").strip()
|
|
print("绘制模式选项:")
|
|
print("0: 仅绘制折线段")
|
|
print("1: 绘制折线段并标注U方向可行域")
|
|
print("2: 绘制折线段并标注V方向可行域")
|
|
print("3: 绘制折线段并标注U和V方向的区间分段")
|
|
print("4: 绘制折线段并绘制带权值的积分点")
|
|
draw_state = int(input("请输入绘制模式:").strip())
|
|
|
|
try:
|
|
meta_data = read_meta_data(filename + ".meta")
|
|
integral_points = read_integral_points(filename + ".int2d")
|
|
read_and_plot_polylines(filename + ".txt", meta_data, integral_points)
|
|
except FileNotFoundError:
|
|
print(f"错误: 文件 '{filename}' 未找到")
|
|
except Exception as e:
|
|
print(f"发生错误: {e}")
|