Re: 正在開發新遊戲:星•球
ejsolid196832
增加了拓撲排序―按法向量確定正面前後,動畫增加了Element Diff插值法。
增加了拓撲排序―按法向量確定正面前後,動畫增加了Element Diff插值法。
- 附件
-
ejsolid196832.js- (86.63 KiB) 已下载 75 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
在topological sort模式時,發生面的前後順序出錯,測試信息如下:
Face ID: ejs-36
Behind ejs-67
Evaluating ejs-36 against ejs-67 normal:
Vertex A3: dot = -2.0755 → Behind
Edge A2: dot = -2.0755 → Behind
Edge A3: dot = -0.0004 → Behind
Evaluating ejs-67 against ejs-36 normal:
Vertex B2: dot = -2972.5558 → Front
Vertex B3: dot = -2965.4797 → Front
Edge B1: dot = -1481.5409 → Front
Edge B2: dot = -2969.0177 → Front
Edge B3: dot = -1473.4847 → Front
Face ID: ejs-67
Behind ejs-36
Evaluating ejs-67 against ejs-36 normal:
Vertex A2: dot = -2972.5558 → Behind
Vertex A3: dot = -2965.4797 → Behind
Edge A1: dot = -1481.5409 → Behind
Edge A2: dot = -2969.0177 → Behind
Edge A3: dot = -1473.4847 → Behind
Evaluating ejs-36 against ejs-67 normal:
Vertex B3: dot = -2.0755 → Front
Edge B2: dot = -2.0755 → Front
Edge B3: dot = -0.0004 → Front
兩個面的計算結果都說在對方的後面,檢查算法是否存在問題。
Face ID: ejs-36
Behind ejs-67
Evaluating ejs-36 against ejs-67 normal:
Vertex A3: dot = -2.0755 → Behind
Edge A2: dot = -2.0755 → Behind
Edge A3: dot = -0.0004 → Behind
Evaluating ejs-67 against ejs-36 normal:
Vertex B2: dot = -2972.5558 → Front
Vertex B3: dot = -2965.4797 → Front
Edge B1: dot = -1481.5409 → Front
Edge B2: dot = -2969.0177 → Front
Edge B3: dot = -1473.4847 → Front
Face ID: ejs-67
Behind ejs-36
Evaluating ejs-67 against ejs-36 normal:
Vertex A2: dot = -2972.5558 → Behind
Vertex A3: dot = -2965.4797 → Behind
Edge A1: dot = -1481.5409 → Behind
Edge A2: dot = -2969.0177 → Behind
Edge A3: dot = -1473.4847 → Behind
Evaluating ejs-36 against ejs-67 normal:
Vertex B3: dot = -2.0755 → Front
Edge B2: dot = -2.0755 → Front
Edge B3: dot = -0.0004 → Front
兩個面的計算結果都說在對方的後面,檢查算法是否存在問題。
代码: 全选
在topological sort模式時,發生面的前後順序出錯,測試信息如下:
Face ID: ejs-36
Behind ejs-67
Evaluating ejs-36 against ejs-67 normal:
Vertex A3: dot = -2.0755 → Behind
Edge A2: dot = -2.0755 → Behind
Edge A3: dot = -0.0004 → Behind
Evaluating ejs-67 against ejs-36 normal:
Vertex B2: dot = -2972.5558 → Front
Vertex B3: dot = -2965.4797 → Front
Edge B1: dot = -1481.5409 → Front
Edge B2: dot = -2969.0177 → Front
Edge B3: dot = -1473.4847 → Front
Face ID: ejs-67
Behind ejs-36
Evaluating ejs-67 against ejs-36 normal:
Vertex A2: dot = -2972.5558 → Behind
Vertex A3: dot = -2965.4797 → Behind
Edge A1: dot = -1481.5409 → Behind
Edge A2: dot = -2969.0177 → Behind
Edge A3: dot = -1473.4847 → Behind
Evaluating ejs-36 against ejs-67 normal:
Vertex B3: dot = -2.0755 → Front
Edge B2: dot = -2.0755 → Front
Edge B3: dot = -0.0004 → Front
兩個面的計算結果都說在對方的後面,檢查算法是否存在問題。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
gemini pro調用了thinking:
代码: 全选
這是一個在實現 **Newell's Algorithm**(或 3D 多邊形拓撲排序/畫家算法修正版)時非常經典的幾何邏輯矛盾。日誌中顯示兩個面互相判定在對方的「後面」,導致拓撲排序(Topological Sort)產生環狀依賴(Circular Dependency)而發生錯誤。
根據您提供的測試信息與代碼片段,該算法目前存在 **三個核心問題**:
---
### 問題一:Test 4 的符號邏輯解讀錯誤(最直接的 Bug)
請仔細對比兩段日誌中**完全相同的一組幾何計算**(`ejs-67` 的頂點對抗 `ejs-36` 的法向量):
* **第一段日誌(以 `ejs-36` 為主體進行評估時):**
```text
Evaluating ejs-67 against ejs-36 normal:
Vertex B2: dot = -2972.5558 → Front
```
* **第二段日誌(以 `ejs-67` 為主體進行評估時):**
```text
Evaluating ejs-67 against ejs-36 normal:
Vertex A2: dot = -2972.5558 → Behind
```
#### 原因分析:
數學上,同一個點積計算得出了完全相同的負數數值:`-2972.5558`。
* **點積為負數($< 0$)** 代表該點位於平面的**反方向(Behind,後方空間)**。第二段日誌的解讀是正確的。
* 然而,在第一段日誌中(代碼此時處於 Newell's 算法的 **Test 4**:*判斷對方 Face B 的頂點是否全在自己 Face A 的前方*),代碼卻將負數的點積錯誤地標記成了 `→ Front`。
**代碼中的 Bug 邏輯推測:**
代碼在 Test 4 的循環中可能寫反了條件,或者錯誤地認為「只要是 Test 4,負數就代表 Front」。這導致 Test 4 出現了假陽性(False Positive),誤判定 `ejs-67` 全在 `ejs-36` 的前面,從而錯誤地得出 `ejs-36 Behind ejs-67` 的結論。
---
### 問題二:法向量未歸一化(Unnormalized Normal Vector)
請注意觀察點積的**數量級(Magnitude)**:
* `ejs-36` 頂點對抗 `ejs-67` 法向量時,點積為 `-2.0755` 與 `-0.0004`。
* `ejs-67` 頂點對抗 `ejs-36` 法向量時,點積高達 `-2972.5558`。
#### 原因分析:
這說明 **`ejs-36.normal3D` 這個法向量沒有被歸一化(Normalize)**。它的長度非常大(可能是通過叉乘計算出表面積後,沒有除以模長,模長大約為 $1486$)。
* 當法向量未歸一化時,點積的數值就不再代表真實的「投影距離」,而是被放大了上千倍。
* 這會直接導致**容差值(`epsilon`)失效**。例如日誌中的 `Edge A3: dot = -0.0004`,如果法向量放大了 1486 倍,這意味著實際的幾何距離只有 `-0.0004 / 1486 ≈ -2.6e-7`(幾何上這已經是共面 Coplanar 了)。但在未歸一化的情況下,它會因為小於 0 而被誤判為嚴格的 `Behind`。
---
### 問題三:2D 投影重疊檢查(2D Overlap Test)缺失或失效
在幾何學中,如果兩個多邊形都是朝向攝像機的(Front-facing),**它們是不可能在 2D 投影重疊的區域內,同時完全處於對方平面的後方的**(除非它們根本沒有 2D 重疊,或者其中一個是背面)。
#### 原因分析:
Newell's 算法有嚴格的檢查順序:
1. **Test 1 & 2**:檢查兩個面在 2D 投影上的 Bounding Box(X/Y 軸)或多邊形本身是否重疊。
2. **Test 3 & 4**:如果 2D 有重疊,才進一步用 3D 平面點積(Behind/Front)來決定誰遮擋誰。
如果您的算法**跳過了 2D 重疊檢查**,直接對場景中所有的面兩兩進行 3D 平面評估,那麼像這種「在空間中相距甚遠、互相在對方平面後方」的無效幾何關係,就會被錯誤地記錄為拓撲依賴邊,從而使拓撲排序直接崩潰。
---
### 🛠️ 修復建議
請檢查並修改 `ejsolid196832.js` 中對應的排序與幾何函數:
1. **修正 Test 4 的符號判定:**
定位到負責 `Evaluating B against A normal` 的代碼塊,確保判定邏輯如下:
```javascript
// 只有點積大於正向容差,才算在前方 (Front)
if (dot > epsilon) {
// Label: Front
} else if (dot < -epsilon) {
// Label: Behind (這會導致 Test 4 失敗,是正確的幾何反映)
}
```
2. **強制歸一化 3D 法向量:**
在計算 `normal3D` 的地方(通常是頂點叉乘之後),務必加上歸一化邏輯:
```javascript
let len = Math.sqrt(nx*nx + ny*ny + nz*nz);
if (len > 0) {
face.normal3D = { x: nx/len, y: ny/len, z: nz/len };
}
```
3. **確保 2D 過濾生效:**
在建立拓撲排序的圖(Graph)或進行比較時,必須先執行 `if (!doProjectionsOverlap(faceA, faceB)) return;`。只有 2D 投影有交集的面,才去計算 3D 點積排序。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
改進:
在打開測試時,將出現一個input篩選框,當輸入數字時,下面的測試信息(即ejs-test-result中的内容)只顯示對應的face id,多個id用「,」分隔。
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
在打開測試時,將出現一個input篩選框,當輸入數字時,下面的測試信息(即ejs-test-result中的内容)只顯示對應的face id,多個id用「,」分隔。
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
代码: 全选
為了實現您所述的功能,我們需要在初始化測試模式的地方添加一個 `<input>` 輸入框,並為其綁定 `input` 事件監聽器。每當使用者輸入數字(以逗號分隔)時,程式會解析這些 Face ID,並透過正則表達式比對 `.ejs-test-result` 內各條訊息的文本內容,決定顯示或隱藏該條訊息。
以下是明確的修改位置與對應需要替換/插入的英文代碼。
---
### 修改位置 1:在測試模式初始化區塊插入篩選輸入框與邏輯
**修改地方:** 請找到 `constructor` 中處理 `this.mode === 'test'` 的地方(或者負責建立/尋找 `.ejs-test-result` 的初始化方法內),插入以下程式碼。
**要替換/插入的代碼 (English):**
```javascript
// --- Insert this block inside the test initialization section (where this.mode === 'test') ---
const testResultContainer = this.container.querySelector('.ejs-test-result');
if (testResultContainer) {
// 1. Create the filter input element
const filterInput = document.createElement('input');
filterInput.type = 'text';
filterInput.className = 'ejs-test-filter';
filterInput.placeholder = 'Filter by Face ID (e.g., 1, 2, 5)';
filterInput.style.width = '100%';
filterInput.style.padding = '6px';
filterInput.style.marginBottom = '10px';
filterInput.style.boxSizing = 'border-box';
// 2. Insert the input box right before the test result container
testResultContainer.parentNode.insertBefore(filterInput, testResultContainer);
// 3. Add event listener to filter test results in real-time
filterInput.addEventListener('input', () => {
const query = filterInput.value.trim();
const entries = testResultContainer.children;
// If input is empty, show all test entries
if (!query) {
for (let i = 0; i < entries.length; i++) {
entries[i].style.display = '';
}
return;
}
// Split the input value by commas and filter out empty strings
const targetIds = query.split(',').map(id => id.trim()).filter(id => id.length > 0);
// Toggle visibility of each log entry based on the face IDs
for (let i = 0; i < entries.length; i++) {
const entryText = entries[i].textContent || '';
// Check if the entry text contains any of the targeted face IDs as a discrete number
const isMatch = targetIds.some(id => {
const regex = new RegExp(`\\b${id}\\b`);
return regex.test(entryText);
});
entries[i].style.display = isMatch ? '' : 'none';
}
});
}
// --- End of insertion ---
```
---
### 修改位置 2:確保測試訊息是以「子元素」形式寫入
**修改地方:**
為了讓上方的 `testResultContainer.children` 篩選機制正常運作,請檢查您程式碼中向 `.ejs-test-result` 寫入測試內容的地方。請確保每一條測試訊息都是以一個**獨立的子元素**(例如 `<div>`)添加,而不是直接用字串拼接(如 `innerHTML += "text<br>"`)。
**要替換/修改的代碼範例 (English):**
*如果您原本是這樣寫的(錯誤/不建議):*
```javascript
// Old approach that prevents element filtering
testResultContainer.innerHTML += `FaceA: ${faceA.id} vs FaceB: ${faceB.id}<br>`;
```
*請替換成以下結構(正確):*
```javascript
// New approach: Wrap each log entry into a child element so it can be filtered
const entryElement = document.createElement('div');
entryElement.className = 'test-result-entry';
entryElement.textContent = `FaceA: ${faceA.id} vs FaceB: ${faceB.id}`;
testResultContainer.appendChild(entryElement);
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
改進:
找到判定「是否在平面上」的相關代碼,如果想改成範圍在10以內算是在平面上,應該怎麼改?
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
找到判定「是否在平面上」的相關代碼,如果想改成範圍在10以內算是在平面上,應該怎麼改?
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
代码: 全选
在 `ejsolid196832.js` 中,判定點(或線段中點)是否在某個平面上的邏輯,是透過計算該點到平面的法向量點積(`dot`)來判斷的。當 `Math.abs(dot)` 小於某個極小值(Epsilon,例如 `1e-5`)時,即判定為在平面上。
若要將此判定範圍放寬至 **10 以內**,請按照以下說明修改程式碼:
### 1. 尋找修改位置
請在檔案中搜尋計算 `dot` 的位置(大約在處理面與面裁切或遮擋關係的邏輯中):
```javascript
const q = faceA.pts3D[0];
const dot = (midX - q.x) * faceA.normal3D.x + (midY - q.y) * faceA.normal3D.y + (midZ - q.z) * faceA.normal3D.z;
```
### 2. 替換後的程式碼
請將緊接在 `dot` 計算之後的條件判斷式(原本檢查是否接近 0 的邏輯)修改為檢查是否小於或等於 `10`:
**修改前(範例):**
```javascript
// Check if the point is strictly coplanar (on the plane) using a tiny epsilon
if (Math.abs(dot) < 1e-5) {
// In this scope: coplanar logic
}
```
**修改後(請替換為此段程式碼):**
```javascript
// Check if the point is within a distance of 10 from the plane
if (Math.abs(dot) <= 10) {
// In this scope: considered on the plane within a range of 10
}
```
*註:如果該區塊後續還有搭配 `else if (dot > 1e-5)` 或 `else if (dot < -1e-5)` 的正反面判定,也需要同步將對應的臨界值從微小值改為 `10` 與 `-10`(例如:`else if (dot > 10)` 與 `else if (dot < -10)`)。*https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
改進:
當判斷出一個面有邊在另一個面上,它會截取一段,再找到它的中點。現在想判斷這個線段的長度,如果這個線段很短,則判為在平面上。
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
當判斷出一個面有邊在另一個面上,它會截取一段,再找到它的中點。現在想判斷這個線段的長度,如果這個線段很短,則判為在平面上。
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
代码: 全选
為了實現「如果線段長度很短,則判定為在平面上」的邏輯,最直觀且安全的方法是在計算中點時同步計算該線段的長度。如果長度小於設定的閾值(例如 `1e-3`),我們將原本用來判斷平面的點積結果 `dot` 強制設為 `0`。這樣可以確保後續所有的條件分支(如原本判定是否在平面上的 `Math.abs(dot) < epsilon` 邏輯)都會自動將其歸類為「在平面上」。
請按照以下說明修改程式碼:
### 1. 尋找修改位置
請在檔案中找到計算 `clippedSegment`、中點(`midX, midY, midZ`)以及 `dot` 的程式碼區塊。
### 2. 替換程式碼
**修改前(Original Code):**
```javascript
if (clippedSegment) {
midX = (clippedSegment.start.x + clippedSegment.end.x) / 2;
midY = (clippedSegment.start.y + clippedSegment.end.y) / 2;
midZ = (clippedSegment.start.z + clippedSegment.end.z) / 2;
} else {
midX = (p1_3d.x + p2_3d.x) / 2;
midY = (p1_3d.y + p2_3d.y) / 2;
midZ = (p1_3d.z + p2_3d.z) / 2;
}
const q = faceA.pts3D[0];
const dot = (midX - q.x) * faceA.normal3D.x + (midY - q.y) * faceA.normal3D.y + (midZ - q.z) * faceA.normal3D.z;
```
**修改後(Replacement Code):**
```javascript
let dx, dy, dz;
if (clippedSegment) {
midX = (clippedSegment.start.x + clippedSegment.end.x) / 2;
midY = (clippedSegment.start.y + clippedSegment.end.y) / 2;
midZ = (clippedSegment.start.z + clippedSegment.end.z) / 2;
dx = clippedSegment.end.x - clippedSegment.start.x;
dy = clippedSegment.end.y - clippedSegment.start.y;
dz = clippedSegment.end.z - clippedSegment.start.z;
} else {
midX = (p1_3d.x + p2_3d.x) / 2;
midY = (p1_3d.y + p2_3d.y) / 2;
midZ = (p1_3d.z + p2_3d.z) / 2;
dx = p2_3d.x - p1_3d.x;
dy = p2_3d.y - p1_3d.y;
dz = p2_3d.z - p1_3d.z;
}
// Calculate the length of the segment
const segmentLength = Math.sqrt(dx * dx + dy * dy + dz * dz);
const q = faceA.pts3D[0];
// Changed 'const' to 'let' to allow modifying 'dot' based on the length condition
let dot = (midX - q.x) * faceA.normal3D.x + (midY - q.y) * faceA.normal3D.y + (midZ - q.z) * faceA.normal3D.z;
// If the segment is very short (e.g., length < 0.001), force it to be considered coplanar (on the plane)
if (segmentLength < 1e-3) {
dot = 0;
}
```
*註:程式碼中的 `1e-3`(即 `0.001`)為長度閾值,您可以根據實際需求調整此數值(例如改為 `1e-2` 或其他數值)來定義多短的線段算作「很短」。*https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
ejsolid196833.js
增加了兩個閥值。
增加了兩個閥值。
- 附件
-
ejsolid196833.js- (89.08 KiB) 已下载 15 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
改進:
在左側控制面板中,為this.config中的coplanarRange和segmentLengthRange增加兩個input輸入框。默認值分別為500和1。不需要滑動塊,只要input[number]。位於Visibility內的下方,僅當Topological Sort打開時才顯示,關閉時則隱藏。
需要給出所有要修改的地方和所要替換的代碼,不需給出全部代碼。
在左側控制面板中,為this.config中的coplanarRange和segmentLengthRange增加兩個input輸入框。默認值分別為500和1。不需要滑動塊,只要input[number]。位於Visibility內的下方,僅當Topological Sort打開時才顯示,關閉時則隱藏。
需要給出所有要修改的地方和所要替換的代碼,不需給出全部代碼。
代码: 全选
這是一項非常實用的改進!我們需要修改 `renderDOM` 來加入新的 UI 元素,修改 `cacheDOM` 來快取這些元素,並在 `bindEvents` 和 `syncDOM` 中加入相關的邏輯來處理顯示/隱藏及數據綁定。
以下是所有需要修改的地方與替換的代碼:
### 1. 修改 `renderDOM()` (加入 HTML 元素)
**尋找以下代碼:**
```javascript
<h2>Visibility</h2>
<div class="ejsolid-control-group">
<label><input type="checkbox" class="ejs-perspective" /> Perspective</label>
<label><input type="checkbox" class="ejs-topo-toggle" /> Topological Sort</label>
</div>
```
**替換為:**
```javascript
<h2>Visibility</h2>
<div class="ejsolid-control-group">
<label><input type="checkbox" class="ejs-perspective" /> Perspective</label>
<label><input type="checkbox" class="ejs-topo-toggle" /> Topological Sort</label>
<div class="ejs-topo-settings" style="display: none; flex-direction: column; gap: 10px; margin-left: 10px; padding-left: 10px; border-left: 2px solid #cbd5e1;">
<div class="ejsolid-row" style="grid-template-columns: 1fr 60px;">
<span>Coplanar Range</span>
<input type="number" class="ejs-coplanar-num" value="${this.config.coplanarRange}" step="1" />
</div>
<div class="ejsolid-row" style="grid-template-columns: 1fr 60px;">
<span>Segment Len Range</span>
<input type="number" class="ejs-segment-num" value="${this.config.segmentLengthRange}" step="0.1" />
</div>
</div>
</div>
```
---
### 2. 修改 `cacheDOM()` (快取新的 DOM 節點)
**尋找以下代碼:**
```javascript
topoToggle: this.container.querySelector('.ejs-topo-toggle'), // New: Cache the toggle
```
**替換為(在下方加入新的選擇器):**
```javascript
topoToggle: this.container.querySelector('.ejs-topo-toggle'), // New: Cache the toggle
topoSettings: this.container.querySelector('.ejs-topo-settings'),
coplanarNum: this.container.querySelector('.ejs-coplanar-num'),
segmentNum: this.container.querySelector('.ejs-segment-num'),
```
---
### 3. 修改 `bindEvents()` (處理數據綁定與切換顯示)
**第一部分:綁定 Input 的值到 `this.config**`
我們可以直接利用你現有的 `syncInputs` 輔助函數,將第一個參數 (range 節點) 設為 `null` 即可。
**尋找以下代碼:**
```javascript
// Bind inputs to config keys
syncInputs(this.dom.animTimeRange, this.dom.animTime, 'animTime', true, 1);
```
**在**上方**或**下方**加入:**
```javascript
syncInputs(null, this.dom.coplanarNum, 'coplanarRange', true, 1);
syncInputs(null, this.dom.segmentNum, 'segmentLengthRange', true, 2);
```
**第二部分:處理 Checkbox 切換時顯示/隱藏設置面板**
**尋找以下代碼:**
```javascript
if (this.dom.topoToggle) {
this.dom.topoToggle.oninput = () => {
this.config.topologicalSort = this.dom.topoToggle.checked;
this.draw();
};
}
```
**替換為:**
```javascript
if (this.dom.topoToggle) {
this.dom.topoToggle.oninput = () => {
this.config.topologicalSort = this.dom.topoToggle.checked;
if (this.dom.topoSettings) {
this.dom.topoSettings.style.display = this.config.topologicalSort ? 'flex' : 'none';
}
this.draw();
};
}
```
---
### 4. 修改 `syncDOM()` (同步狀態)
確保在重新讀取 JSON 或初始化時,面板的顯示狀態和數值是正確的。
**尋找以下代碼:**
```javascript
if (this.dom.topoToggle) this.dom.topoToggle.checked = this.config.topologicalSort;
```
**替換為:**
```javascript
if (this.dom.topoToggle) {
this.dom.topoToggle.checked = this.config.topologicalSort;
if (this.dom.topoSettings) {
this.dom.topoSettings.style.display = this.config.topologicalSort ? 'flex' : 'none';
}
}
if (this.dom.coplanarNum) this.dom.coplanarNum.value = this.config.coplanarRange;
if (this.dom.segmentNum) this.dom.segmentNum.value = this.config.segmentLengthRange;
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
當窄屏時,ejsolid-right改為放到最上方。
代码: 全选
這可以透過 CSS 的 `order` 屬性來輕鬆實現。在 Flexbox 佈局下,我們可以指定窄屏時讓 `.ejsolid-right` 排在最前面。順便幫你把原代碼中一段多餘的嵌套語法清理乾淨。
請在 `injectCSS()` 方法中找到這段 CSS 定義:
**尋找以下代碼:**
```javascript
.ejsolid-wrapper { display: flex; flex-direction: row; gap: 20px; height: 100vh; box-sizing: border-box; background-color: #f8f9fa; color: #2b2d42; padding: 20px; font-family: system-ui, -apple-system, sans-serif; }
@media (max-width: 850px) { .ejsolid-wrapper { flex-direction: column; height: auto; padding: 15px; overflow-y: auto; } .ejsolid-left { width: 100% !important; flex: none !important; } .ejsolid-right { width: 100%; height: auto; min-height: 400px; .ejsolid-panel { box-sizing: border-box; } } .ejsolid-panel { box-sizing: border-box; } }
```
**替換為:**
```javascript
.ejsolid-wrapper { display: flex; flex-direction: row; gap: 20px; height: 100vh; box-sizing: border-box; background-color: #f8f9fa; color: #2b2d42; padding: 20px; font-family: system-ui, -apple-system, sans-serif; }
@media (max-width: 850px) { .ejsolid-wrapper { flex-direction: column; height: auto; padding: 15px; overflow-y: auto; } .ejsolid-left { width: 100% !important; flex: none !important; order: 2; } .ejsolid-right { width: 100%; height: auto; min-height: 400px; order: 1; } .ejsolid-panel { box-sizing: border-box; } }
```https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
想不到bug在這裡!
誰叫你Fallback到整條線段的!浪費了我多少時間!!!AI也是不給力啊!不幫我發現這個問題!
代码: 全选
if (clippedSegment) {
midX = (clippedSegment.start.x + clippedSegment.end.x) / 2;
midY = (clippedSegment.start.y + clippedSegment.end.y) / 2;
midZ = (clippedSegment.start.z + clippedSegment.end.z) / 2;
dx = clippedSegment.end.x - clippedSegment.start.x;
dy = clippedSegment.end.y - clippedSegment.start.y;
dz = clippedSegment.end.z - clippedSegment.start.z;
} else {
// Fallback to full edge midpoint if clipping utility is missing
midX = (p1_3d.x + p2_3d.x) / 2;
midY = (p1_3d.y + p2_3d.y) / 2;
midZ = (p1_3d.z + p2_3d.z) / 2;
dx = p2_3d.x - p1_3d.x;
dy = p2_3d.y - p1_3d.y;
dz = p2_3d.z - p1_3d.z;
}
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
ejsolidh1968321
現在需要加上debug模式,如果沒有debug就沒有test。
現在需要加上debug模式,如果沒有debug就沒有test。
- 附件
-
ejsolid1968322.js- (88.36 KiB) 已下载 14 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
改進:
只有當div.ejsolid出現debug屬性,才會出現「TestFrknt Faces」欄目,否則隱藏這個欄目。
去掉segment len range輸入框,將其寫成一個固定值。
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
轉thinking:
只有當div.ejsolid出現debug屬性,才會出現「TestFrknt Faces」欄目,否則隱藏這個欄目。
去掉segment len range輸入框,將其寫成一個固定值。
需要明確給出所要修改的地方和要替換的代碼,不需給出全部代碼。所有的代碼和注釋都要使用英文。
轉thinking:
代码: 全选
為了實現您提出的改進需求,我們只需要修改 `renderDOM()` 方法中主模式(`else` 分支)對應的 HTML 模板字串。
以下是明確的修改位置與替換代碼:
### 修改位置
在 `EjSolid` 類別的 `renderDOM()` 方法中,找到處理 `this.mode !== 'mini'` 條件下的 `this.container.innerHTML` 區塊,定位到 `<h2>Visibility</h2>` 與 `<h2>Test Front Faces</h2>` 相關的 HTML 代碼。
#### 1. 原代碼內容:
```javascript
<h2>Visibility</h2>
<div class="ejsolid-control-group">
<label><input type="checkbox" class="ejs-perspective" /> Perspective</label>
<label><input type="checkbox" class="ejs-topo-toggle" /> Topological Sort</label>
<div class="ejs-topo-settings" style="display: none; flex-direction: column; gap: 10px; margin-left: 10px; padding-left: 10px; border-left: 2px solid #cbd5e1;">
<div class="ejsolid-row" style="grid-template-columns: 1fr 60px;">
<span>Coplanar Range</span>
<input type="number" class="ejs-coplanar-num" value="${this.config.coplanarRange}" step="1" />
</div>
<div class="ejsolid-row" style="grid-template-columns: 1fr 60px;">
<span>Segment Len Range</span>
<input type="number" class="ejs-segment-num" value="${this.config.segmentLengthRange}" step="0.1" />
</div>
</div>
</div>
<h2>Test Front Faces</h2>
<div class="ejsolid-control-group">
<div class="ejsolid-row" style="grid-template-columns: 1fr 1fr; gap: 10px;">
<button type="button" class="ejs-test-front-btn" style="padding: 8px 15px; border-radius: 6px;">Test Front Faces</button>
<button type="button" class="ejs-reset-test-btn" style="padding: 8px 15px; border-radius: 6px; background-color: #6c757d;">Reset</button>
</div>
<div class="ejs-test-results" style="max-height: 250px; overflow-y: auto; font-size: 12px; display: none; flex-direction: column; gap: 10px; padding: 5px; border: 1px solid #ddd; border-radius: 6px; background: #fafafa;"></div>
</div>
```
#### 2. 替換後的代碼:
請將上述區塊替換為以下代碼:
```javascript
<h2>Visibility</h2>
<div class="ejsolid-control-group">
<label><input type="checkbox" class="ejs-perspective" /> Perspective</label>
<label><input type="checkbox" class="ejs-topo-toggle" /> Topological Sort</label>
<div class="ejs-topo-settings" style="display: none; flex-direction: column; gap: 10px; margin-left: 10px; padding-left: 10px; border-left: 2px solid #cbd5e1;">
<div class="ejsolid-row" style="grid-template-columns: 1fr 60px;">
<span>Coplanar Range</span>
<input type="number" class="ejs-coplanar-num" value="${this.config.coplanarRange}" step="1" />
</div>
</div>
</div>
<h2 style="${this.container.hasAttribute('debug') ? '' : 'display: none;'}">Test Front Faces</h2>
<div class="ejsolid-control-group" style="${this.container.hasAttribute('debug') ? '' : 'display: none;'}">
<div class="ejsolid-row" style="grid-template-columns: 1fr 1fr; gap: 10px;">
<button type="button" class="ejs-test-front-btn" style="padding: 8px 15px; border-radius: 6px;">Test Front Faces</button>
<button type="button" class="ejs-reset-test-btn" style="padding: 8px 15px; border-radius: 6px; background-color: #6c757d;">Reset</button>
</div>
<div class="ejs-test-results" style="max-height: 250px; overflow-y: auto; font-size: 12px; display: none; flex-direction: column; gap: 10px; padding: 5px; border: 1px solid #ddd; border-radius: 6px; background: #fafafa;"></div>
</div>
```
### 改進說明
1. **控制「Test Front Faces」欄目顯隱**:在 `<h2>` 和隨後的 `.ejsolid-control-group` 元素中加入了 `style` 綁定,透過 `this.container.hasAttribute('debug')` 檢查 `div.ejsolid` 是否具有 `debug` 屬性。若無,則動態設置 `display: none;` 來隱藏該欄目。
2. **移除 Segment Len Range 輸入框**:直接刪除了原來的輸入框結構。由於系統原架構的 `syncInputs` 內部會安全檢查 DOM 節點(若為 `null` 則跳過事件監聽綁定),此時其值會安全地保持在建構子初始化時設定的預設固定值 `1e-6`(即 `this.config.segmentLengthRange`),不會引發任何 JavaScript 錯誤。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
為wordpress寫一個shortcode,能生成div.ejsolid[mode=mini],其content要有do_shortcode。同時引用一個js,這個js用媒體庫的id取到。如果頁面中存在多個,js只需引用一次。
代码: 全选
沒問題!這樣程式碼會更乾淨。我們把媒體庫 ID 直接固定(寫死)在程式碼裡面,短網址(Shortcode)就不需要帶入任何參數了。
請將程式碼更新為以下版本:
```php
function register_ejsolid_shortcode($atts, $content = null) {
// 1. 在這裡直接「寫死」你的媒體庫 JS 檔案 ID(請把 123 改成你實際的 ID)
$js_id = 123;
// 2. 透過媒體庫 ID 取得 JS 檔案的完整 URL
if ($js_id > 0) {
$js_url = wp_get_attachment_url($js_id);
if ($js_url) {
// 使用固定的 Handle 名稱 'ejsolid-static-js'
// WordPress 機制會自動判斷,不論頁面出現幾次這個 Shortcode,該 JS 都只會引用一次
wp_enqueue_script('ejsolid-static-js', $js_url, array(), null, true);
}
}
// 3. 處理內部內容(支援巢狀 Shortcode)
$processed_content = do_shortcode($content);
// 4. 輸出指定的 HTML 結構
return '<div class="ejsolid" mode="mini">' . $processed_content . '</div>';
}
add_shortcode('ejsolid', 'register_ejsolid_shortcode');
```
---
### 更新後的 Shortcode 使用方式
現在在 WordPress 編輯器中,你只需要最單純的標籤即可,完全不用傳入參數:
```text
[ejsolid]
這裡放你的內容,或者其他 [another_shortcode] 短網址 [/another_shortcode]
[/ejsolid]
```
### 運作邏輯
* **ID 固定**:你只需要修改程式碼中的 `$js_id = 123;`,後台編輯者就不用再去記媒體庫的 ID 是多少。
* **唯一引用**:因為 `wp_enqueue_script` 的第一個參數(Handle)被固定為 `'ejsolid-static-js'`,WordPress 只要偵測到這個標籤被註冊過,同一個頁面就不會再重複載入第二次。https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
代码: 全选
<script>
/**
* 強化版:保持原有 DOM 構建邏輯,添加編碼聲明並移除調試功能
*/
function openEjceesWindow() {
// 1. 獲取 WordPress 附件 URL
const scriptUrl = "<?php echo wp_get_attachment_url(19088); ?>";
if (!scriptUrl || scriptUrl.trim() === "") {
return;
}
try {
// 2. 構建文檔
const doc = document.implementation.createHTMLDocument("Ejcees Object");
// 設定 html 語言屬性
doc.documentElement.setAttribute('lang', 'en-US');
// 添加 Charset Meta (解決編碼警告關鍵)
const metaCharset = doc.createElement('meta');
metaCharset.setAttribute('charset', 'UTF-8');
doc.head.appendChild(metaCharset);
// Mobile Viewport
const metaView = doc.createElement('meta');
metaView.name = "viewport";
metaView.content = "width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no";
doc.head.appendChild(metaView);
const style = doc.createElement('style');
style.textContent = `
body, html { margin: 0; padding: 0; width: 100%; height: 100%; overflow: hidden; background: #222; color: white; }
.ejcees { width: 100vw; height: 100vh; display: block; }
`;
doc.head.appendChild(style);
// 3. 容器
const container = doc.createElement('div');
container.className = 'ejcees';
container.setAttribute('mode', 'main');
doc.body.appendChild(container);
// 4. 外部腳本
const extScript = doc.createElement('script');
extScript.src = scriptUrl;
doc.body.appendChild(extScript);
// 5. 初始化腳本 (移除 debug 邏輯)
const initScript = doc.createElement('script');
initScript.textContent = `
window.addEventListener('load', () => {
try {
const el = document.querySelector('.ejcees');
const mode = el.getAttribute('mode');
if (typeof Ejcees !== 'undefined') {
new Ejcees(el, mode);
}
} catch (err) {
console.error('Initialization Error:', err);
}
});
`;
doc.body.appendChild(initScript);
// 6. 序列化並打開
// 確保包含 <!DOCTYPE html> 以避免觸發怪異模式 (Quirks Mode)
const htmlString = `<!DOCTYPE html>\n${doc.documentElement.outerHTML}`;
// 在 Blob 類型中明確指定 charset=utf-8
const blob = new Blob([htmlString], { type: 'text/html;charset=utf-8' });
const url = URL.createObjectURL(blob);
const newWin = window.open(url, '_blank');
if (!newWin) {
console.warn('Pop-up blocked');
}
} catch (globalErr) {
console.error('Process error:', globalErr);
}
}
</script>
<button onclick="openEjceesWindow()">打開Ejcees單頁面</button><br><br>https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
Re: 正在開發新遊戲:星•球
把以下的svg圖標,換成一個能體現「旋轉動畫」的圖形。給出三種方案:
代码: 全选
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67"></path></svg>https://ejsoon.vip/
弈趣極光:享受思維樂趣
弈趣極光:享受思維樂趣
-
- 相似主题
- 回复总数
- 阅读次数
- 最新帖子
在线用户
正浏览此版面之用户: 没有注册用户 和 1 访客
