正在開發新遊戲:星•球

分享身边的点滴趣事
回复
头像
ejsoon
一枝独秀
一枝独秀
帖子: 5653
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 179 次
被圈友点赞: 207 次
联系:

Re: 正在開發新遊戲:星•球

帖子 ejsoon »

改進checkEdgeNormalRelation這個函式:
首先檢測A面有沒有端點與B面干涉,如果有則用這個點與B面的法向量判定前後。如果沒有,則檢測B面有沒有端點與A面干涉,如果有則用這個點與A面的法向量判定前後。如果兩個面都沒有點與另一個面干涉,再用邊判定。排除點在面上的情況,當兩個面的點都處於另一個面上,則像之前那樣警告並返回null。

在用邊判定的時候,之前直接用的是邊的中點,現在改為先截取這條邊所干涉到另一個面的線段,之後再取這條線段的中點。

所有的代碼和注釋都要使用英文。

代码: 全选

  /**
   * Evaluates whether Face A is positioned in front of Face B based on normal vectors.
   * It iterates through all edges and returns true or false immediately upon finding a definitive relation.
   * If no definitive relation is found, it logs a warning listing the coplanar edges and returns null.
   * @param {Object} faceA - The first face object containing pts, pts3D, and normal3D.
   * @param {Object} faceB - The second face object containing pts, pts3D, and normal3D.
   * @returns {boolean|null} true if Face A is in front, false if Face A is behind, or null if inconclusive.
   */
  checkEdgeNormalRelation(faceA, faceB) {
    const coplanarEdgesA = [];
    const coplanarEdgesB = [];

    // ==========================================
    // Step 1: Evaluate projecting edges of Face A against Face B's plane
    // ==========================================
    for (let i = 0; i < faceA.pts.length; i++) {
      const p1_2d = faceA.pts[i];
      const p2_2d = faceA.pts[(i + 1) % faceA.pts.length];

      if (this.edgeProjects(p1_2d, p2_2d, faceB)) {
        const p1_3d = faceA.pts3D[i];
        const p2_3d = faceA.pts3D[(i + 1) % faceA.pts3D.length];

        const midX = (p1_3d.x + p2_3d.x) / 2;
        const midY = (p1_3d.y + p2_3d.y) / 2;
        const midZ = (p1_3d.z + p2_3d.z) / 2;

        const q = faceB.pts3D[0];

        const dot = (midX - q.x) * faceB.normal3D.x + (midY - q.y) * faceB.normal3D.y + (midZ - q.z) * faceB.normal3D.z;

        if (Math.abs(dot) > 1e-4) {
          return dot > 0; // true if front, false if behind
        } else {
          coplanarEdgesA.push(i);
        }
      }
    }

    // ==========================================
    // Step 2: Evaluate projecting edges of Face B against Face A's plane
    // ==========================================
    for (let i = 0; i < faceB.pts.length; i++) {
      const p1_2d = faceB.pts[i];
      const p2_2d = faceB.pts[(i + 1) % faceB.pts.length];

      if (this.edgeProjects(p1_2d, p2_2d, faceA)) {
        const p1_3d = faceB.pts3D[i];
        const p2_3d = faceB.pts3D[(i + 1) % faceB.pts3D.length];

        const midX = (p1_3d.x + p2_3d.x) / 2;
        const midY = (p1_3d.y + p2_3d.y) / 2;
        const 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;

        if (Math.abs(dot) > 1e-4) {
          return dot <= 0; // false if dot > 0 (A is behind), true if dot < 0 (A is front)
        } else {
          coplanarEdgesB.push(i);
        }
      }
    }

    // ==========================================
    // Step 3: Handle inconclusive cases
    // ==========================================
    if (coplanarEdgesA.length > 0) {
      console.warn(`Which edges of Face A are completely on Face B: Indices [${coplanarEdgesA.join(', ')}]`);
    }
    if (coplanarEdgesB.length > 0) {
      console.warn(`Which edges of Face B are completely on Face A: Indices [${coplanarEdgesB.join(', ')}]`);
    }
    if (coplanarEdgesA.length === 0 && coplanarEdgesB.length === 0) {
      console.warn('No overlapping projection edges found between Face A and Face B.');
    }

    return null;
  }

改進checkEdgeNormalRelation這個函式:
首先檢測A面有沒有端點與B面干涉,如果有則用這個點與B面的法向量判定前後。如果沒有,則檢測B面有沒有端點與A面干涉,如果有則用這個點與A面的法向量判定前後。如果兩個面都沒有點與另一個面干涉,再用邊判定。排除點在面上的情況,當兩個面的點都處於另一個面上,則像之前那樣警告並返回null。

在用邊判定的時候,之前直接用的是邊的中點,現在改為先截取這條邊所干涉到另一個面的線段,之後再取這條線段的中點。

所有的代碼和注釋都要使用英文。
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 5653
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 179 次
被圈友点赞: 207 次
联系:

Re: 正在開發新遊戲:星•球

帖子 ejsoon »

gemini thinking:

代码: 全选

Here is the improved and refactored version of the `checkEdgeNormalRelation` method.

The implementation introduces a hierarchical assessment strategy: it first checks for projecting vertex interference to quickly resolve depth, falls back to calculating the midpoints of clipped edge segments if vertices are inconclusive, and tracks all coplanar elements to report deep diagnostics if they completely overlap.

All code syntax, variable names, and comments have been written in English.

```javascript
  /**
   * Evaluates whether Face A is positioned in front of Face B using normal vectors.
   * * Hierarchy of evaluation:
   * 1. Check if any vertices of Face A project inside Face B. If a non-coplanar vertex is found, determine relationship immediately.
   * 2. Check if any vertices of Face B project inside Face A. If a non-coplanar vertex is found, determine relationship immediately.
   * 3. Check intersecting edges of Face A against Face B using the midpoint of the clipped overlapping segment.
   * 4. Check intersecting edges of Face B against Face A using the midpoint of the clipped overlapping segment.
   * 5. If everything is coplanar or non-overlapping, log comprehensive warnings and return null.
   * * @param {Object} faceA - The first face object containing pts, pts3D, and normal3D.
   * @param {Object} faceB - The second face object containing pts, pts3D, and normal3D.
   * @returns {boolean|null} true if Face A is in front, false if Face A is behind, or null if inconclusive.
   */
  checkEdgeNormalRelation(faceA, faceB) {
    const coplanarVerticesA = [];
    const coplanarVerticesB = [];
    const coplanarEdgesA = [];
    const coplanarEdgesB = [];

    // ==========================================
    // Step 1: Evaluate projecting vertices of Face A against Face B's plane
    // ==========================================
    for (let i = 0; i < faceA.pts.length; i++) {
      const p_2d = faceA.pts[i];

      // Assuming pointProjects(pt2d, face) checks if the point's projection falls inside the face
      if (this.pointProjects && this.pointProjects(p_2d, faceB)) {
        const p_3d = faceA.pts3D[i];
        const q = faceB.pts3D[0];

        const dot = (p_3d.x - q.x) * faceB.normal3D.x + 
                    (p_3d.y - q.y) * faceB.normal3D.y + 
                    (p_3d.z - q.z) * faceB.normal3D.z;

        if (Math.abs(dot) > 1e-4) {
          return dot > 0; // true if Face A is in front, false if behind
        } else {
          coplanarVerticesA.push(i);
        }
      }
    }

    // ==========================================
    // Step 2: Evaluate projecting vertices of Face B against Face A's plane
    // ==========================================
    for (let i = 0; i < faceB.pts.length; i++) {
      const p_2d = faceB.pts[i];

      if (this.pointProjects && this.pointProjects(p_2d, faceA)) {
        const p_3d = faceB.pts3D[i];
        const q = faceA.pts3D[0];

        const dot = (p_3d.x - q.x) * faceA.normal3D.x + 
                    (p_3d.y - q.y) * faceA.normal3D.y + 
                    (p_3d.z - q.z) * faceA.normal3D.z;

        if (Math.abs(dot) > 1e-4) {
          return dot <= 0; // false if Face B is in front (meaning A is behind), true if Face B is behind
        } else {
          coplanarVerticesB.push(i);
        }
      }
    }

    // ==========================================
    // Step 3: Evaluate projecting edges of Face A against Face B's plane
    // ==========================================
    for (let i = 0; i < faceA.pts.length; i++) {
      const p1_2d = faceA.pts[i];
      const p2_2d = faceA.pts[(i + 1) % faceA.pts.length];

      if (this.edgeProjects(p1_2d, p2_2d, faceB)) {
        const p1_3d = faceA.pts3D[i];
        const p2_3d = faceA.pts3D[(i + 1) % faceA.pts3D.length];

        // Clip the edge to get only the segment that physically interferes with Face B's projection
        // Expects an object containing { start: {x,y,z}, end: {x,y,z} }
        const clippedSegment = this.getClippedSegment3D ? this.getClippedSegment3D(p1_2d, p2_2d, p1_3d, p2_3d, faceB) : null;
        
        let midX, midY, midZ;
        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 {
          // 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;
        }

        const q = faceB.pts3D[0];
        const dot = (midX - q.x) * faceB.normal3D.x + (midY - q.y) * faceB.normal3D.y + (midZ - q.z) * faceB.normal3D.z;

        if (Math.abs(dot) > 1e-4) {
          return dot > 0;
        } else {
          coplanarEdgesA.push(i);
        }
      }
    }

    // ==========================================
    // Step 4: Evaluate projecting edges of Face B against Face A's plane
    // ==========================================
    for (let i = 0; i < faceB.pts.length; i++) {
      const p1_2d = faceB.pts[i];
      const p2_2d = faceB.pts[(i + 1) % faceB.pts.length];

      if (this.edgeProjects(p1_2d, p2_2d, faceA)) {
        const p1_3d = faceB.pts3D[i];
        const p2_3d = faceB.pts3D[(i + 1) % faceB.pts3D.length];

        // Clip the edge to get only the segment that physically interferes with Face A's projection
        const clippedSegment = this.getClippedSegment3D ? this.getClippedSegment3D(p1_2d, p2_2d, p1_3d, p2_3d, faceA) : null;

        let midX, midY, midZ;
        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 {
          // 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;
        }

        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;

        if (Math.abs(dot) > 1e-4) {
          return dot <= 0;
        } else {
          coplanarEdgesB.push(i);
        }
      }
    }

    // ==========================================
    // Step 5: Handle inconclusive cases (Coplanar or Disjoint configurations)
    // ==========================================
    if (coplanarVerticesA.length > 0) {
      console.warn(`Vertices of Face A are completely coplanar on Face B: Indices [${coplanarVerticesA.join(', ')}]`);
    }
    if (coplanarVerticesB.length > 0) {
      console.warn(`Vertices of Face B are completely coplanar on Face A: Indices [${coplanarVerticesB.join(', ')}]`);
    }
    if (coplanarEdgesA.length > 0) {
      console.warn(`Edges of Face A are completely coplanar on Face B: Indices [${coplanarEdgesA.join(', ')}]`);
    }
    if (coplanarEdgesB.length > 0) {
      console.warn(`Edges of Face B are completely coplanar on Face A: Indices [${coplanarEdgesB.join(', ')}]`);
    }

    const totalCoplanarCount = coplanarVerticesA.length + coplanarVerticesB.length + coplanarEdgesA.length + coplanarEdgesB.length;
    if (totalCoplanarCount === 0) {
      console.warn('No overlapping projection elements (vertices or edges) found between Face A and Face B.');
    }

    return null;
  }

```

### Key Enhancements Made:

1. **Hierarchical Vertex Optimization**: Vertices are validated before executing complex edge calculations. If any vertex cleanly resides inside the opposing face projection (and isn't coplanar), spatial sorting resolves instantly.
2. **Clipped Edge Midpoints**: Instead of evaluating the geometric center of the whole edge—which might dangle outside of the overlap territory—the code invokes an assumed helper method `this.getClippedSegment3D(...)` to narrow down the segment bounds strictly to the overlapping region before sampling the midpoint.
3. **Comprehensive Diagnostics Tracking**: Trackers for `coplanarVerticesA` and `coplanarVerticesB` were introduced alongside the edge trackers to output highly precise geometry logs whenever elements collapse into an ambiguous coplanar state.
https://ejsoon.vip/
弈趣極光:享受思維樂趣
头像
ejsoon
一枝独秀
一枝独秀
帖子: 5653
注册时间: 2022年 11月 18日 17:36
为圈友点赞: 179 次
被圈友点赞: 207 次
联系:

Re: 正在開發新遊戲:星•球

帖子 ejsoon »

ejsolid19682

下一步:在測試中加上測端點。
附件
ejsolid1968.js
(55.84 KiB) 已下载 2 次
ejsolid19682.js
(72.28 KiB) 已下载 1 次
https://ejsoon.vip/
弈趣極光:享受思維樂趣
回复

在线用户

正浏览此版面之用户: Google [Bot] 和 2 访客