Jump to content
Fiskey111

Vector3 Comparison

Recommended Posts

Hi Everyone,

Don't feel obligated to answer, it's no big deal if this question gets answered (I know I'm annoying and ask a lot of questions!)

I'm trying to set up my "Officer Shot" callout where you have to drive the cop to the nearest hospital.  I have the coordinates of the hospitals, but I'm not sure how to compare the four coordinates and find the closest one to the player.  Any ideas?

This are my vectors for the hospitals:

Spoiler

            Vector3 Zonah = new Vector3();
            Zonah.X = (-454);
            Zonah.Y = (-340);
            Zonah.Z = (34);

            Vector3 LosSantos = new Vector3();
            Zonah.X = (296);
            Zonah.Y = (-1442);
            Zonah.Z = (29);

            Vector3 Sandy = new Vector3();
            Zonah.X = (1827);
            Zonah.Y = (3693);
            Zonah.Z = (34);

            Vector3 Paleto = new Vector3();
            Zonah.X = (-242);
            Zonah.Y = (-6337);
            Zonah.Z = (32);

I was thinking about doing something with this:

            Vector3.Distance2D(Game.LocalPlayer.Character.Position, Zonah);
            Vector3.Distance2D(Game.LocalPlayer.Character.Position, LosSantos);
            Vector3.Distance2D(Game.LocalPlayer.Character.Position, Sandy);
            Vector3.Distance2D(Game.LocalPlayer.Character.Position, Paleto);

But I don't know how to compare those to find the shortest distance.

Thanks!

Share this post


Link to post
Share on other sites

What I do for my EMS spawning, is put them in a list and cycle through them checking each ones distance. I basically set the "min distance" to 100000, and for each item check if its distance is less than the min distance flag. Here's the code I'm using:

Spoiler

public static ExtendedSpawnPoint GetNearestSpawn(String zone, Vector3 target)
        {
            ExtendedSpawnPoint espSpawn = null;
            List<ExtendedSpawnPoint> ListOfSpawns = new List<ExtendedSpawnPoint>();
            float closestRange = 100000;

            ListOfSpawns = Serialization.LoadFromXML<ExtendedSpawnPoint>(zone);
            foreach (ExtendedSpawnPoint sp in ListOfSpawns)
            {
                if (sp.Position.DistanceTo(target) <closestRange)
                {
                    closestRange = sp.Position.DistanceTo(target);
                    espSpawn = sp;
                }
            }
            Game.LogTrivial(ListOfSpawns.Count + " possible locations. Closest is " + espSpawn.Street + " (" + espSpawn.Area + ", " + closestRange + ")");
            return espSpawn;
        }

I'm not sure if this is the best way or even remotely efficient, though I haven't noticed any significant lag so far. The ExtendedSpawnPoint and XML loading code is from LtFlash's great examples here: 

Edited by Darkmyre
Formatting

Share this post


Link to post
Share on other sites

If you have your position in a List, you can use LINQ. It adds a lot of extension methods to the collections, to use it add "using System.Linq;". You can use .OrderBy() and .First(), this is how I did it in my callouts.

Spoiler

public static Vector3 GetClosestPoliceStation(Vector3 position)
{    
    return PoliceStationsPositions.OrderBy(x => Vector3.TravelDistance(x, position)).First();
}

It orders the list depending on the TravelDistance and then gets the first item in the list.

Edited by alexguirre

Share this post


Link to post
Share on other sites
For a small set, a comparison as shown by Darkmyre and alexguirre is more than sufficient. If you have a very large data set (and also to reply to @Darkmyre's question whether it is efficient), a proper algorithm should be used. Just think of it as a maths problem: Let M be an euclidean space where you have a set S of points in M and a point p ∈ M. You want to find the closest point in S to p. Right now, using the naive approach, you have a runtime of O(dN) (d = dimensionality of M, N = cardinality of S) for getting the closest point.
 
To achieve better performance, there are many different ways, such as using a kd tree (O(log N) or a voronoi diagram (best would be to use 2d then and ignore z axis to reduce space requirements or check at last) etc. You could even use Locality Sensitive Hashing if you want to (overkill for 3d most likely though).

Share this post


Link to post
Share on other sites

So, how do I go about doing this?  I've tried to add this code in (attached) but I have no idea how to do this.  Honestly, I might just drop this, but I'd like to learn more about this.  If someone can either help me out (if you're willing) or point me to some sort of documents that can help me figure this all out, let me know!

Thanks!

help1.jpg

help2.jpg

Help3.jpg

Share this post


Link to post
Share on other sites

For the XML stuff, you'll need an XML file with your spawn points saved. I use this method as I have a range of different spawn points in different xml files (one for hospitals, another for fire, a big one with a bunch of residential places I've saved the coords of). This may actually be overkill for what you're after, especially since you have to go around manually saving the coords (the same thread has another excellent tool by LtFlash to do this), so I've rewritten my GetNearest function to use the vector3's you had:

public static Vector3 GetNearestHospital(Vector3 target)


        {
            Vector3 myHospital = new Vector3();
            List<Vector3> hospitals = new List<Vector3>();
            hospitals.Add(new Vector3(-454, -340, 34));
            hospitals.Add(new Vector3(296, -1442, 29));
            hospitals.Add(new Vector3(1827, 3693, 34));
            hospitals.Add(new Vector3(-242, -6337, 32));

            float closestRange = 100000;

            foreach (Vector3 sp in hospitals)
            {
                if (sp.DistanceTo(target) < closestRange)
                {
                    closestRange = sp.DistanceTo(target);
                    myHospital = sp;
                }
            }
            return myHospital;
        }

This should return the vector3 of the hospital thats closest to your target v3, for example:

Vector3 hospitalSpawn = GetNearestHospital(Game.LocalPlayer.Character.Position);
 would get the nearest hospital to the player.

(I know there's an inline way to build the list of vectors on one line, instead of needing to call Add() for each entry, but im not 100% on the formatting so went with the longer way I know)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×