繁体   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