v9.5: 實作標籤完全不重疊算法
- 新增 _calculate_lane_conflicts_v2() 分開返回標籤重疊和線穿框分數 - 修改泳道選擇算法,優先選擇無標籤重疊的泳道 - 兩階段搜尋:優先側別無可用泳道則嘗試另一側 - 增強日誌輸出,顯示標籤範圍和詳細衝突分數 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
393
IMPROVEMENTS_v4.md
Normal file
393
IMPROVEMENTS_v4.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# 時間軸標籤避碰改進(v4.0) - 防止線條交錯
|
||||
|
||||
## 新增改進(v4.0)
|
||||
|
||||
### 問題描述
|
||||
v3.0 雖然解決了文字框重疊問題,但仍存在以下問題:
|
||||
1. ❌ 連接線互相交錯
|
||||
2. ❌ 連接線穿過其他文字框
|
||||
3. ❌ 密集事件時視覺混亂
|
||||
|
||||
### 解決方案
|
||||
|
||||
#### 1. **智能路徑分層**
|
||||
|
||||
**核心概念**:讓不同層級的連接線使用不同的中間高度/寬度,避免交錯。
|
||||
|
||||
```python
|
||||
# 水平時間軸(L 形折線的中間高度)
|
||||
base_ratio = 0.45 # 基礎高度比例
|
||||
layer_offset = (layer % 6) * 0.10 # 每層偏移 10%,每 6 層循環
|
||||
mid_y_ratio = base_ratio + layer_offset
|
||||
mid_y = label_y * mid_y_ratio
|
||||
|
||||
# 垂直時間軸(L 形折線的中間寬度)
|
||||
base_ratio = 0.45 # 基礎寬度比例
|
||||
layer_offset = (layer % 6) * 0.10 # 每層偏移 10%
|
||||
mid_x_ratio = base_ratio + layer_offset
|
||||
mid_x = label_x * mid_x_ratio
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 層級 0:中間點在 45% 位置
|
||||
- 層級 1:中間點在 55% 位置
|
||||
- 層級 2:中間點在 65% 位置
|
||||
- 層級 3:中間點在 75% 位置
|
||||
- 層級 4:中間點在 85% 位置
|
||||
- 層級 5:中間點在 95% 位置
|
||||
- 層級 6:循環回 45% 位置
|
||||
|
||||
#### 2. **避開文字框核心區域**
|
||||
|
||||
防止線條的水平段太接近文字框中心:
|
||||
|
||||
```python
|
||||
# 如果計算出的中間點太接近文字框位置,則強制調整
|
||||
if abs(mid_y - label_y) < abs(label_y) * 0.15:
|
||||
mid_y = label_y * 0.35 # 設為更安全的距離
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- ✅ 線條不會直接穿過文字框中心
|
||||
- ✅ 保持至少 15% 的安全距離
|
||||
|
||||
#### 3. **增加文字框間距**
|
||||
|
||||
調整碰撞檢測參數,確保文字框之間有足夠空間:
|
||||
|
||||
```python
|
||||
# 標籤寬度(包含時間+標題+描述)
|
||||
label_width_ratio = 0.15 # 15% 的時間軸寬度
|
||||
|
||||
# 安全邊距
|
||||
safety_margin = total_seconds * 0.01 # 1% 的額外緩衝
|
||||
|
||||
# 最小水平間距
|
||||
min_horizontal_gap = total_seconds * 0.03 # 3% 的時間軸寬度
|
||||
|
||||
# 層級垂直間距
|
||||
layer_spacing = 1.0 # 層級之間的垂直距離
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整改進歷程
|
||||
|
||||
### v1.0(初版)
|
||||
- ❌ 直線連接
|
||||
- ❌ 標籤固定位置
|
||||
- ❌ 只有日期
|
||||
- ❌ 容易重疊
|
||||
|
||||
### v2.0(2D 避碰)
|
||||
- ✅ Z 形折線
|
||||
- ✅ 標籤可偏移
|
||||
- ✅ 智能避碰
|
||||
- ⚠️ 折線可能交錯
|
||||
|
||||
### v3.0(平滑曲線 + 時間分離)
|
||||
- ✅ 平滑曲線(虛線 + 半透明)
|
||||
- ✅ 時間顯示在點旁邊
|
||||
- ✅ 標題與時間分離
|
||||
- ⚠️ 用戶反饋:需要簡化
|
||||
|
||||
### v3.1(簡化版)
|
||||
- ✅ L 形直角折線(取代曲線)
|
||||
- ✅ 時間+標題+描述統一顯示
|
||||
- ✅ 時分秒精度
|
||||
- ⚠️ 文字框重疊
|
||||
|
||||
### v3.2(增加間距)
|
||||
- ✅ 增加標籤寬度(15%)
|
||||
- ✅ 增加層級間距(1.0)
|
||||
- ✅ 添加安全邊距(1%)
|
||||
- ⚠️ 線條仍會交錯
|
||||
|
||||
### v4.0(智能路徑分層 - 初版)
|
||||
- ✅ 不同層級使用不同高度/寬度
|
||||
- ✅ 線條避開文字框核心區域
|
||||
- ✅ 文字框之間充足間距
|
||||
- ⚠️ 仍有交錯問題(用戶反饋)
|
||||
|
||||
### v4.1(當前版本 - 鏡像分布 + 距離感知)
|
||||
- ✅ **上下/左右鏡像分布策略**
|
||||
- ✅ **根據跨越距離動態調整路徑**
|
||||
- ✅ **10層循環,60%範圍變化**
|
||||
- ✅ **長距離線條自動降低高度**
|
||||
- ✅ **線條交錯最小化**
|
||||
- ✅ **整體視覺清晰專業**
|
||||
|
||||
---
|
||||
|
||||
## v4.1 核心改進
|
||||
|
||||
### 1. **鏡像分布策略**
|
||||
|
||||
**問題**:v4.0 中上下兩側的線條使用相同的分層策略,容易在中間區域交錯。
|
||||
|
||||
**解決**:上下(或左右)兩側使用鏡像分布:
|
||||
|
||||
```python
|
||||
# 水平時間軸
|
||||
if is_upper_side: # 上方
|
||||
base_ratio = 0.25 # 從 25% 開始
|
||||
layer_offset = layer_group * 0.06 # 正向增長: 25% -> 85%
|
||||
else: # 下方
|
||||
base_ratio = 0.85 # 從 85% 開始
|
||||
layer_offset = -layer_group * 0.06 # 負向增長: 85% -> 25%
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 上方 layer 0 在 25%,下方 layer 0 在 85% → 分隔明顯
|
||||
- 上方 layer 5 在 55%,下方 layer 5 在 55% → 在中間匯合
|
||||
- 上方 layer 9 在 79%,下方 layer 9 在 31% → 接近但不重疊
|
||||
|
||||
### 2. **距離感知調整**
|
||||
|
||||
**問題**:長距離線條容易穿過中間的文字框。
|
||||
|
||||
**解決**:根據跨越距離動態調整中間點高度:
|
||||
|
||||
```python
|
||||
x_span_ratio = abs(x_diff_seconds) / total_range
|
||||
|
||||
if x_span_ratio > 0.3: # 跨越超過 30% 時間軸
|
||||
# 上方線條降低,下方線條升高,避開中間區域
|
||||
distance_adjustment = -0.10 if is_upper_side else 0.10
|
||||
elif x_span_ratio > 0.15: # 跨越 15-30%
|
||||
distance_adjustment = -0.05 if is_upper_side else 0.05
|
||||
else:
|
||||
distance_adjustment = 0 # 短距離不調整
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- ✅ 短距離線條:保持原有層級策略
|
||||
- ✅ 中距離線條:輕微調整 5%
|
||||
- ✅ 長距離線條:大幅調整 10%,遠離文字框密集區
|
||||
|
||||
### 3. **增加層級循環週期**
|
||||
|
||||
```python
|
||||
layer_group = layer % 10 # 從 6 層增加到 10 層
|
||||
```
|
||||
|
||||
**效果**:
|
||||
- 提供更多的高度選擇(10 個不同高度)
|
||||
- 減少不同層級使用相同高度的機率
|
||||
- 更細緻的分布
|
||||
|
||||
---
|
||||
|
||||
## 技術細節
|
||||
|
||||
### 路徑分層算法(v4.1)
|
||||
|
||||
**計算公式**:
|
||||
```
|
||||
mid_y_ratio = base_ratio + layer_offset + distance_adjustment
|
||||
mid_y_ratio = max(0.20, min(mid_y_ratio, 0.90)) # 限制範圍
|
||||
mid_y = label_y * mid_y_ratio
|
||||
```
|
||||
|
||||
**參數範圍**:
|
||||
- `base_ratio`: 上方 0.25,下方 0.85
|
||||
- `layer_offset`: -0.54 到 +0.54 (10層 × 6%)
|
||||
- `distance_adjustment`: -0.10 到 +0.10
|
||||
- **總範圍**: 20% 到 90%(70% 的可用空間)
|
||||
|
||||
### 路徑分層算法(v4.0 舊版)
|
||||
|
||||
**水平時間軸**:
|
||||
```
|
||||
事件點 (event_x, 0)
|
||||
↓ 垂直上升
|
||||
中間點 (event_x, mid_y) ← 根據層級調整
|
||||
→ 水平移動
|
||||
轉折點 (label_x, mid_y)
|
||||
↓ 垂直下降
|
||||
文字框 (label_x, label_y)
|
||||
```
|
||||
|
||||
**垂直時間軸**:
|
||||
```
|
||||
事件點 (0, event_y)
|
||||
→ 水平移動
|
||||
中間點 (mid_x, event_y) ← 根據層級調整
|
||||
↓ 垂直移動
|
||||
轉折點 (mid_x, label_y)
|
||||
→ 水平移動
|
||||
文字框 (label_x, label_y)
|
||||
```
|
||||
|
||||
### 碰撞檢測策略
|
||||
|
||||
1. **計算標籤佔用範圍**(包含安全邊距)
|
||||
2. **嘗試在同層級放置**(無偏移)
|
||||
3. **嘗試水平偏移**(左側 1x, 2x, 3x)
|
||||
4. **嘗試水平偏移**(右側 1x, 2x, 3x)
|
||||
5. **創建新層級**(如果都無法容納)
|
||||
|
||||
### 性能優化
|
||||
|
||||
- **時間複雜度**:O(n × m × k)
|
||||
- n = 事件數
|
||||
- m = 平均層級數(通常 < 5)
|
||||
- k = 偏移嘗試次數(最多 7 次)
|
||||
|
||||
- **空間複雜度**:O(n × m)
|
||||
|
||||
---
|
||||
|
||||
## 調整建議
|
||||
|
||||
如果仍有線條交錯問題,可以調整以下參數:
|
||||
|
||||
### 1. 增加層級偏移幅度
|
||||
```python
|
||||
# renderer_timeline.py 第 336 行和第 566 行
|
||||
layer_offset = (layer % 6) * 0.12 # 從 0.10 增加到 0.12
|
||||
```
|
||||
|
||||
### 2. 降低基礎比例
|
||||
```python
|
||||
# renderer_timeline.py 第 335 行和第 565 行
|
||||
base_ratio = 0.40 # 從 0.45 降低到 0.40
|
||||
```
|
||||
|
||||
### 3. 增加循環週期
|
||||
```python
|
||||
# renderer_timeline.py 第 336 行和第 566 行
|
||||
layer_offset = (layer % 8) * 0.10 # 從 6 層循環改為 8 層循環
|
||||
```
|
||||
|
||||
### 4. 增加文字框間距
|
||||
```python
|
||||
# renderer_timeline.py 第 81、88、230、449 行
|
||||
label_width_ratio = 0.18 # 從 0.15 增加到 0.18
|
||||
min_horizontal_gap = total_seconds * 0.04 # 從 0.03 增加到 0.04
|
||||
layer_spacing = 1.2 # 從 1.0 增加到 1.2
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 測試方法
|
||||
|
||||
```batch
|
||||
start_dev.bat
|
||||
```
|
||||
|
||||
訪問 http://localhost:12010,測試示範檔案:
|
||||
- `demo_project_timeline.csv` - 15 個事件
|
||||
- `demo_life_events.csv` - 11 個事件
|
||||
- `demo_product_roadmap.csv` - 14 個事件
|
||||
|
||||
**預期效果**:
|
||||
- ✅ 文字框之間無重疊
|
||||
- ✅ 連接線分散在不同高度
|
||||
- ✅ 線條避開文字框核心區域
|
||||
- ✅ 線條交錯大幅減少
|
||||
- ✅ 整體視覺清晰易讀
|
||||
|
||||
---
|
||||
|
||||
## 視覺效果示意(v4.1)
|
||||
|
||||
### 鏡像分布示意
|
||||
|
||||
```
|
||||
100% ╔══════════════════════════════════════╗
|
||||
║ ║
|
||||
85% ╟────┐ 下方 Layer 0 (base) ║
|
||||
║ │ ║
|
||||
79% ╟────┘ 下方 Layer 1 ║
|
||||
║ ║
|
||||
70% ╟───── 中間區域(避開) ║
|
||||
║ ║
|
||||
55% ╟────┐ 上方/下方 Layer 5 (匯合點) ║
|
||||
║ │ ║
|
||||
40% ╟───── 中間區域(避開) ║
|
||||
║ ║
|
||||
31% ╟────┐ 上方 Layer 1 ║
|
||||
║ │ ║
|
||||
25% ╟────┘ 上方 Layer 0 (base) ║
|
||||
║ ║
|
||||
20% ╚══════════════════════════════════════╝
|
||||
▲
|
||||
└─ 時間軸 (0%)
|
||||
```
|
||||
|
||||
**特點**:
|
||||
- ✅ 上下兩側從不同端點開始
|
||||
- ✅ 在中間區域匯合,但錯開
|
||||
- ✅ 最大程度利用 70% 的垂直空間
|
||||
- ✅ 避免在中間區域(40%-70%)密集重疊
|
||||
|
||||
### 距離感知調整示意
|
||||
|
||||
```
|
||||
短距離 (< 15%):
|
||||
●─────┐
|
||||
└──□ 使用標準層級高度
|
||||
|
||||
中距離 (15%-30%):
|
||||
●─────────┐
|
||||
└──□ 降低 5%(上方)或升高 5%(下方)
|
||||
|
||||
長距離 (> 30%):
|
||||
●──────────────┐
|
||||
└──□ 降低 10%(上方)或升高 10%(下方)
|
||||
遠離中間密集區
|
||||
```
|
||||
|
||||
### 線條分層(v4.0 舊版)
|
||||
```
|
||||
┌─────────┐
|
||||
│文字框 3 │ (層級2)
|
||||
└─────────┘
|
||||
↑
|
||||
│ (mid_y = 65%)
|
||||
├────────────
|
||||
┌─────────┐
|
||||
│文字框 2 │ (層級1)
|
||||
└─────────┘
|
||||
↑
|
||||
│ (mid_y = 55%)
|
||||
────┼────────────
|
||||
┌─────────┐
|
||||
│文字框 1 │ (層級0)
|
||||
└─────────┘
|
||||
↑
|
||||
────┘ (mid_y = 45%)
|
||||
●
|
||||
時間軸
|
||||
```
|
||||
|
||||
### 避開核心區域
|
||||
```
|
||||
┌───────────┐
|
||||
│ 文字框 │
|
||||
│ 核心區域 │ ← 線條不會穿過這裡
|
||||
│ │
|
||||
└───────────┘
|
||||
↑
|
||||
────────┘ (保持安全距離)
|
||||
●
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**版本**: v4.0
|
||||
**更新日期**: 2025-11-05
|
||||
**作者**: Claude AI
|
||||
|
||||
## 關鍵改進總結
|
||||
|
||||
| 項目 | v3.2 | v4.0 | v4.1 | 改進方法 |
|
||||
|-----|------|------|------|---------|
|
||||
| 文字框重疊 | ✅ 已解決 | ✅ 已解決 | ✅ 已解決 | 增加間距與安全邊距 |
|
||||
| 線條交錯 | ❌ 嚴重 | ⚠️ 仍存在 | ✅ 最小化 | 鏡像分布 + 距離感知 |
|
||||
| 線條穿框 | ❌ 經常 | ⚠️ 偶爾 | ✅ 極少 | 距離感知動態調整 |
|
||||
| 視覺清晰度 | ⚠️ 中等 | ✅ 良好 | ✅ 優秀 | 多層次優化 |
|
||||
| 配置靈活性 | ✅ 可調 | ✅ 高度可調 | ✅ 智能自適應 | 動態參數計算 |
|
||||
| 層級分布 | 單向 | 單向 | 鏡像 | 上下/左右對稱策略 |
|
||||
| 距離處理 | 固定 | 固定 | 動態 | 根據跨越距離調整 |
|
||||
Reference in New Issue
Block a user