簡體   English   中英

找到最近的 3d 點

[英]Find the nearest 3d point

假設我有一個玩家位於: X: 100, Y: 100, Z: 100我想找到以下哪一個點最接近並獲取它的 ID。:

ID: 1, X: 200; Y: 200; Z: 100,
ID: 2, X: 150; Y: 300; Z: 300,
ID: 3, X: 300; Y: 200; Z: 100,
ID: 4, X: 50; Y: 100; Z: 200

我怎么能做到? 它背后的數學原理是什么? 如果有幫助,我已經有了以下代碼:

var returnVehicles = [];
        mp.vehicles.forEachInRange(player.position, 100, (vehicle) => {
                if(vehicle.ownerID == player.id) {
                    returnVehicles.push(vehicle.position, vehicle.id);
                }
            }
        );

它循環遍歷范圍為 100 的車輛,並將屬於玩家的車輛的 ID 和位置添加到數組中。 但是,我不知道該怎么辦。

有人向我推薦了 .sort() 方法,但這似乎不起作用,因為它只獲取最小的坐標,而不是最近的坐標。

@編輯:我的完整代碼

function distance3D(posA, posB) {
    const dX = posA.X - posB.X;
    const dY = posA.Y - posB.Y;
    const dZ = posA.Z - posB.Z;
    return Math.sqrt(dX * dX + dY * dY + dZ * dZ);
}

const vehiclesAndDistances = [];

function lockPlayerVehicle (player) {
    let vehicle = player.vehicle;
    if (vehicle) {
        //IRRELEVANT
    }
    else {
        mp.vehicles.forEachInRange(player.position, 40, (vehicle) => {
                if(vehicle.ownerID == player.id) {
                    vehiclesAndDistances.push({vehicle, distance: distance3D(player, vehicle),});
                }
            }
        );
        vehiclesAndDistances.sort((a, b) => a.distance - b.distance);
        player.outputChatBox("Lista Pequena: " + String(vehiclesAndDistances[0]));
        console.log(vehiclesAndDistances[0], vehiclesAndDistances[0].vehicle.model)
    };
}
mp.events.add("keypress:DOWNARROW", lockPlayerVehicle);

對於少量車輛,只需使用勾股算法求出車輛與玩家之間的距離就足夠了。 (對於多個(或者如果您需要經常循環),您可能需要研究空間分區算法,例如四叉樹,以使查找更有效。)


// Assumes posA and posB are both objects with X, Y, Z members.
function distance3D(posA, posB) {
  const dX = posA.X - posB.X;
  const dY = posA.Y - posB.Y;
  const dZ = posA.Z - posB.Z;
  return Math.sqrt(dX * dX + dY * dY + dZ * dZ);
}

// Stores objects of shape `{vehicle: ..., distance: number}`
const vehiclesAndDistances = [];

mp.vehicles.forEachInRange(player.position, 100, (vehicle) => {
  if (vehicle.ownerID == player.id) {
    vehiclesAndDistances.push({
      vehicle,
      distance: distance3D(player, vehicle),
    });
  }
});
// Sort the array by the distance
vehiclesAndDistances.sort((a, b) => a.distance - b.distance);

編輯:正如評論中所討論的,如果您只需要最近的點,您可以將其重新表述為

let closestDistance = undefined;
let closestVehicle = undefined;

mp.vehicles.forEachInRange(player.position, 100, (vehicle) => {
  if (vehicle.ownerID === player.id) {
    const distance = distance3D(player, vehicle);
    if (closestDistance === undefined || distance < closestDistance) {
      closestVehicle = vehicle;
      closestDistance = distance;
    }
  }
});

您可以使用距離公式 將其應用於每個點並選擇最小值。 時間復雜度是線性的,但您可能在每幀循環中運行它,因此整體復雜度是二次的。 有可用的優化。

不改變時間復雜度的可能的微優化包括避免平方根運算、一次性保存最小值等。

 const dist = (a, b) => Math.sqrt( (bX - aX) ** 2 + (bY - aY) ** 2 + (bZ - aZ) ** 2 ); const closest = (target, points, eps=0.00001) => { const distances = points.map(e => dist(target, e)); const closest = Math.min(...distances); return points.find((e, i) => distances[i] - closest < eps); }; const player = {X: 100, Y: 100, Z: 100}; const points = [ {ID: 1, X: 200, Y: 200, Z: 100}, {ID: 2, X: 150, Y: 300, Z: 300}, {ID: 3, X: 300, Y: 200, Z: 100}, {ID: 4, X: 50, Y: 100, Z: 200} ]; console.log(closest(player, points));

您可以將dist概括為在任何維度上工作,如下所示:

const dist = (a, b) => Math.sqrt(
  Object.keys(a).map(k => (b[k] - a[k]) ** 2)
    .reduce((a, e) => a + e)  
);

您可以使用歐氏距離計算公式。 將所有坐標放在一個數組中,並使用 map 創建一個新的距離數組,該數組是通過實現歐幾里德公式得出的。 您可以按升序或降序對數組的元素進行排序並找到距離

 let currData = [{ ID: 1, X: 200, Y: 200, Z: 100 }, { ID: 2, X: 150, Y: 300, Z: 300 }, { ID: 3, X: 300, Y: 200, Z: 100 }, { ID: 4, X: 50, Y: 100, Z: 200 } ] const vehlPos = { X: 250, Y: 400, Z: 600 }; let getDist = currData.map((item) => { const xdiff = Math.pow((vehlPos.X - item.X), 2); const ydiff = Math.pow((vehlPos.Y - item.Y), 2); const zdiff = Math.pow((vehlPos.Z - item.Z), 2); return Math.sqrt(xdiff + ydiff + zdiff) }); console.log(getDist)

您可以將對象轉換為點並使用矢量函數。

這是 3D 矢量類的一個稍微完整的示例

 const main = () => { const player = { X: 100, Y: 100, Z: 100 }; const points = [ { ID: 1, X: 200, Y: 200, Z: 100 }, { ID: 2, X: 150, Y: 300, Z: 300 }, { ID: 3, X: 300, Y: 200, Z: 100 }, { ID: 4, X: 50, Y: 100, Z: 200 } ]; console.log(findClosestPoint(player, points)); }; const findClosestPoint = (player, points) => { let { X, Y, Z } = player; const pos = new Vector3D(X, Y, Z), minDist = points.reduce((res, point, index) => { let { X, Y, Z } = point; const value = pos.distanceTo(new Vector3D(X, Y, Z)); return value < res.value ? { index, value } : res; }, { index: -1, value: Number.MAX_VALUE }); console.log('Min distance:', minDist.value); return points[minDist.index]; }; class Vector3D { constructor (x, y, z) { this.x = x; this.y = y; this.z = z; } distanceTo (other) { return Math.sqrt( Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2) + Math.pow(this.z - other.z, 2) ); } } main();
 .as-console-wrapper { top: 0; max-height: 100% !important; }

輸出

Min distance: 111.80339887498948
{
  "ID": 4,
  "X": 50,
  "Y": 100,
  "Z": 200
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM