简体   繁体   English

找到最近的 3d 点

[英]Find the nearest 3d point

Let's say I have a player located at: X: 100, Y: 100, Z: 100 and I want to find which of the following points is the closest and get it's ID.:假设我有一个玩家位于: 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

How could I do it?我怎么能做到? What are the maths behind it?它背后的数学原理是什么? If it helps, I already have the following code:如果有帮助,我已经有了以下代码:

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

It loops through the vehicles in a range of a 100 and adds into an array the IDs and positions of the ones that belong to the player.它循环遍历范围为 100 的车辆,并将属于玩家的车辆的 ID 和位置添加到数组中。 However, I don't know what to do with this.但是,我不知道该怎么办。

Someone recommend me the .sort() method, but that doesn't seem to work, as it only gets the smallest coordinate, not the nearest.有人向我推荐了 .sort() 方法,但这似乎不起作用,因为它只获取最小的坐标,而不是最近的坐标。

@EDIT: MY FULL CODE @编辑:我的完整代码

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);

For a small number of vehicles, simply using the Pythagorean algorithm to find the distance between the vehicle and the player is enough.对于少量车辆,只需使用勾股算法求出车辆与玩家之间的距离就足够了。 (For more than a few (or if you need to loop this often) you could need to look into a space-partitioning algorithm such as quadtrees to make the lookup more effective.) (对于多个(或者如果您需要经常循环),您可能需要研究空间分区算法,例如四叉树,以使查找更有效。)


// 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);

EDIT: As discussed in the comments, if you only need the nearest point, you can reformulate this as编辑:正如评论中所讨论的,如果您只需要最近的点,您可以将其重新表述为

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;
    }
  }
});

You can use the distance formula .您可以使用距离公式 Apply it to each point and choose the minimum.将其应用于每个点并选择最小值。 Time complexity is linear, but you're probably running this in a loop per frame, so the overall complexity is quadratic.时间复杂度是线性的,但您可能在每帧循环中运行它,因此整体复杂度是二次的。 There are optimizations available.有可用的优化。 See

Possible micro-optimizations that don't change the time complexity include avoiding the square root operation, saving the min in one pass, etc.不改变时间复杂度的可能的微优化包括避免平方根运算、一次性保存最小值等。

 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));

You can generalize dist to work in any dimension as follows:您可以将dist概括为在任何维度上工作,如下所示:

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

You can use euclidean distance calculating formula.您可以使用欧氏距离计算公式。 Put all the coordinates in an array and use map to create a new array of distance which is derived by implementing euclidean formula.将所有坐标放在一个数组中,并使用 map 创建一个新的距离数组,该数组是通过实现欧几里德公式得出的。 You can sort the element of the array in ascending or descending order and find the distance您可以按升序或降序对数组的元素进行排序并找到距离

 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)

You could convert your objects to points and use vector functions.您可以将对象转换为点并使用矢量函数。

Here is a somewhat-complete example of a 3D vector class.这是 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; }

Output输出

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