Trying to find the closest object to the camera

I know this should be simple but I’m really struggling with this in Reactive programming.

Here’s what I’ve got:

(async function() {
    Promise.all (
        [
            Scene.root.findFirst('camTransform'),   // this is a child of the camera as the camera didn't work
            Scene.root.findFirst('Cube1'),
            Scene.root.findFirst('Cube2'),
            Scene.root.findFirst('Cube3'),
        ]
    ).then(getClosest).catch(errorHandler)

})();

function getClosest(objList){

    // get the pointsignals of the objects
    const camPos = objList[0].worldTransform.position;    // camera position
    const pos1 = objList[1].worldTransform.position;
    const pos2 = objList[2].worldTransform.position;  
    const pos3 = objList[3].worldTransform.position;  

   // get the distance of each object to the camera
    const dst1 = Reactive.distance(pos1,camPos).abs();
    const dst2 = Reactive.distance(pos2,camPos).abs();
    const dst3 = Reactive.distance(pos3,camPos).abs();

    // create an array of all the object distances
    const objDist = [dst1,dst2,dst3,dst4,dst5,dst6];

    // this works to get a bunch of boolean signals comparing two objects
    // however, it's not very useful for getting towards my final goal of comparing n objects
    const tt1 = objDist[2].lt(objDist[1]);
    const tt2 = objDist[3].lt(objDist[2]);
    const tt3 = objDist[4].lt(objDist[3]);

    //==== here's where I am completely failing. What I want to do is return the index of the object that 
    //==== is closest to the camera. I have tried numerous things that should be super easy in 
    //==== imperative coding but I can't get any of them to work here. Please help!!!

    // this should be an integer that I can pipe back to the patch editor to do something useful
    return closest;
}

sparkar-rx-min-distance.arprojpkg (17.3 KB)
const Scene = require('Scene');
const Reactive = require('Reactive');
const Diagnostics = require('Diagnostics');
const Patches = require('Patches');

(async () => {
    const [cam, targets] = await Promise.all([
        Scene.root.findFirst('Camera'),
        Scene.root.findByPath('**/targets/*'),
    ]);

    // Get the distance array (array of ScalarSignal)
    const distances = targets.map(traget => Reactive.distance(cam.worldTransform.position, traget.worldTransform.position));

    // Use reduce to get the min distance
    // The result will look like: Reactive.min(0, Reactive.min(1, Reactive.min(2, Reactive.min(3, 4))));
    const min = distances.reduce((acc, dist) => Reactive.min(acc, dist));

    // Compare the min value and all distance. If the value is equal the distance, return index of distance; if not, return -1;
    // Please note that the 'ind' and '-1' will be converted to ScalarSignal.
    const indexes = distances.map((cur, ind) => Reactive.eq(cur, min).ifThenElse(ind, -1));

    // Now the max value should be the index, because the signal in array is index or -1.
    const result = indexes.reduce((acc, cur) => Reactive.max(acc, cur));

    // Watch the index in console
    Diagnostics.watch('index', result);

    // or pass signal to patch
    Patches.inputs.setScalar('index', result);
})();
3 Likes

Map and reduce! Really slick solution!

Here’s an article on those methods. They are really incredibly useful for processing collections of objects.

2 Likes

Wow! Thank you both for the answers. I managed to hack something together yesterday that is functional but this is 100x more elegant. I will study your solution and links.

2 Likes