Check if a location is closer than the other

Discussion in 'Plugin Help/Development/Requests' started by Ryzzzen, Nov 26, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    Ryzzzen

    Sorry for my bad english...

    Hi guys, i want to check if a inn is closer than the other, and teleport it after, but i don't know how to do this..

    Some ideas?

    By the way, there is not only two inns, there is "a lot" of inns, i need to check every inns.
     
  2. Offline

    Skionz

    Ryzzzen Use Location#distance(Location)
     
    ChipDev likes this.
  3. Offline

    Ryzzzen

    I want to use several inns in a configuration file, use Location#distance(Location) isn't a problem, the problem is how to do this with severals locations.. I want something to optimized.
     
  4. Ryzzzen Skionz When you're comparing distances to see which one is smaller or larger, use distanceSquared() not distance() as distance() calls a relatively costly sqrt(), which isn't needed when only trying to see which one is bigger :)

    Edit Ryzzzen - get the list of locations, and loop over them. Compare each one and just return the lowest value
     
    Skionz likes this.
  5. Offline

    Skionz

    AdamQpzm Nice to know. Is Math.sqrt() that slow?
     
  6. Skionz Personally I've never tried to benchmark it, but the JavaDocs for distance() say that it "calls the costly sqrt()", so I take that as a sign it's a non-trivial difference :p
     
    Skionz likes this.
  7. Offline

    Totom3

    Skionz AdamQpzm I did some benchmarks once, ran 30 000 000 calls of Math.sqrt() with warmup, it took an average of 10-11 nanoseconds per call. Not sure if that's considered a lot. :oops:
     
  8. Offline

    Ryzzzen

    Hi, i tried this:

    Code:java
    1. double[] locsDistances = {
    2. l1.distanceSquared(pLoc),
    3. l2.distanceSquared(pLoc),
    4. l3.distanceSquared(pLoc),
    5. l4.distanceSquared(pLoc),
    6. l5.distanceSquared(pLoc),
    7. l6.distanceSquared(pLoc),
    8. l7.distanceSquared(pLoc),
    9. l8.distanceSquared(pLoc),
    10. l9.distanceSquared(pLoc),
    11. l10.distanceSquared(pLoc) // "l" = locations, pLoc = loc of player
    12. };
    13.  
    14. public double getMinValue(double[] locsDistances){ // return minimal distance
    15. double minValue = locsDistances[0];
    16. for(int i=1;i<locsDistances.length;i++){
    17. if(locsDistances[I] < minValue){ [/I]
    18. [I] minValue = locsDistances[I]; [/I][/I]
    19. [I] } [/I]
    20. [I] } [/I]
    21. [I] return minValue; [/I]
    22. [I] }[/I]
    23.  
    24.  
    25. [I][/I]


    Why i see (i) (/i) ? (with [] )
    But i get only the minimal distance, not the location.
    I'm sorry, if you can help me, you save me. I don't know what to do.
    I don't know if this word exists in english, but i'm sorry for the "Indentation" of my code.
     
  9. This is just a formatting problem we have here sometimes, nothing to worry about, we know you don't really have that in your code :)
    Right, what you want to do is make an array of the locations, not the distances. Then change your getMinLocaation() method to take a location array, and the location you want to compare it with (in this case pLoc). Perform the distanceSquared() check inside this method, and do the same thing with the minValue = locsDistances[] but this time with a Location, not a double :)
    Yep, that's a word :p



    To be fair, your benchmarking method might be flawed :p
     
  10. Offline

    Tecno_Wizard

    Seeing as the only way to calculate it is by looping through numbers until the program finds a match- yes. It is that costly.
     
  11. Offline

    Lurvik

    Code:java
    1. Location locs = { ll, l2, l3, l4, l5, l6, l7, l8, l9, l10 };
    2.  
    3. public Location getLowestDistance (Location source, Location[] locs)
    4. Location shortest = Locs[0];
    5. for (Location loc : locs) {
    6. if (loc.distanceSquared(source) < shortest.distanceSquared(source))
    7. shortest = loc;
    8. }
    9. return shortest;
    10. }


    Do something like that instead.
     
  12. Offline

    Rocoty

    What about the control group?
     
  13. Offline

    Ryzzzen


    It works now. Thanks for all!

    Oh, sorry i forgot something. How i can add more than 10 locations, using the configuration file ? Because i get locations in a list in configuration file, but the plugin only get 10 locations..

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 29, 2016
  14. Offline

    Lurvik

    Depends on how you're structuring it. Do you have a set way to define the locations? Must it be in YAML?

    When I read that I thought "That'll be easy, just get a list of locations, make a new one based on the coordinates and check. Easy, I'll do it in 5 minutes." 30 minutes later I realised that it wasn't so very easy. I had a structure like this:
    "locations:
    first:
    world: world
    x: 40..."
    which I thought would be the best, but apparently not. I wrote up some confusing code that would get all the nodes under "location" (first, second, third etc), then create a new Location based on the cordinates. It was horrid code even though I tried making it as straight forward as possible. I suggest you'd store the coordinates in something like JSON instead, or any other markup language that has anonymous sections.
     
  15. Offline

    teej107

  16. Offline

    Lurvik

    Oh my... I got so focused on trying to solve it the way I first thought out that I didn't consider doing it like that :p. *hangs head low in shame*
     
  17. Offline

    Ryzzzen

    I do not know how to explain..
    I have theses functions for convert locations to strings, and strings to locations:
    Code:java
    1. public static String locToString(Location l)
    2. {
    3. StringBuilder sb = new StringBuilder();
    4.  
    5. sb.append(l.getWorld().getName());
    6. sb.append(",");
    7. sb.append(Integer.toString(l.getBlockX()));
    8. sb.append(",");
    9. sb.append(Integer.toString(l.getBlockY()));
    10. sb.append(",");
    11. sb.append(Integer.toString(l.getBlockZ()));
    12.  
    13. return sb.toString();
    14. }
    15.  
    16. public static Location stringToLoc(String s)
    17. {
    18. List<String> elementList = Arrays.asList(s.split(","));
    19.  
    20. World world = Bukkit.getWorld(elementList.get(0));
    21. int x = Integer.parseInt(elementList.get(1));
    22. int y = Integer.parseInt(elementList.get(2));
    23. int z = Integer.parseInt(elementList.get(3));
    24. Location crateLocation = new Location(world, x, y, z);
    25.  
    26. return crateLocation;
    27. }
    28.  

    but, i get locations like that:

    Code:java
    1. public Location fastLoc(Player p){
    2. List<?> list = InnConfiguration.Config.getList("Inns");
    3. Object[] s = list.toArray();
    4. Integer i = s.length;
    5.  
    6. Location l1 = LocationsManager.stringToLoc((String) s[0]);
    7. Location l2 = LocationsManager.stringToLoc((String) s[1]);
    8. Location l3 = LocationsManager.stringToLoc((String) s[2]);
    9. Location l4 = LocationsManager.stringToLoc((String) s[3]);
    10. Location l5 = LocationsManager.stringToLoc((String) s[4]);
    11. Location l6 = LocationsManager.stringToLoc((String) s[5]);
    12. Location l7 = LocationsManager.stringToLoc((String) s[6]);
    13. Location l8 = LocationsManager.stringToLoc((String) s[7]);
    14. Location l9 = LocationsManager.stringToLoc((String) s[8]);
    15. Location l10 = LocationsManager.stringToLoc((String) s[9]);
    16. Location pLoc = p.getLocation();
    17.  
    18. Location[] locs = { l1, l2, l3, l4, l5, l6, l7, l8, l9, l10 };
    19. return LocationsManager.getLowestDistance(pLoc, locs);
    20. }
    21.  


    I don't know what to do. I think i can use "for" but the problem is how.. i want to replace theses "l1" "l2" "l3" etc by a function who create locations by using the list, without adding locations manually in the code. Sorry for my english.
     
  18. Offline

    Lurvik

    Ryzzzen

    You could modify your "getLowestDistance" method to handle a string List instead of Location array. Then you could do something liek this:
    Code:Java
    1. private List<String> locs = InnConfiguration.Config.getList("Inns");
    2.  
    3.  
    4. public Location fastLoc(Player p) {
    5. return LocationsManager.getLowestDistance(p.getLocation, locs);
    6. }


    Or even better, just scrap that method, and use that one line instead :p
     
  19. Offline

    Dudemister1999

    I'm a little late to the party, but what if you added all distances to a list, used Collections.sort(), and collected the first value? Would that work? (Not actually sure)
     
  20. Offline

    Lurvik

    No, that would give him the lowest(?) value, not the lowest distance to a specific Location. For all we know, two of the locations are (0, 0, 0) and (500, 64, 500) but the player location is (1000, 64, 1000). Sorting it would give the first location, when the shortest location is actually the second.
     
  21. Offline

    mythbusterma


    Just as an aside, since when is this the only way to calculate a square root? That's certainly not the only way, and I SERIOUSLY doubt that's how it's implemented, incidentally the implementation of it is in native code, and one of the most popular implementations uses the code as follows:

    Code:
    /* generate sqrt(x) bit by bit */
    ix0 += ix0 + ((ix1 & sign)>>31);
    ix1 += ix1;
    q = q1 = s0 = s1 = 0; /* [q,q1] = sqrt(x) */
    r = 0x00200000; /* r = moving bit from right to left */
     
    while (r != 0) {
        t = s0 + r;
        if (t <= ix0) {
            s0 = t+r;
            ix0 -= t;
            q += r;
        }
        ix0 += ix0 + ((ix1&sign)>>31);
        ix1 += ix1;
        r>>=1;
    }
    // cut for brevity
    
    Which certainly is not iterating to find numbers in a set, it merely iterates over every bit in the float.
    So I don't really feel this call is truly "expensive," as the documentation might suggest, unless anyone has evidence otherwise?
     
  22. Offline

    Ryzzzen

    I have a problem: how i transform this "for" for the list ?

    Code:java
    1. for (Location loc : locs) {
    2. if (loc.distanceSquared(source) < shortest.distanceSquared(source))
    3. shortest = loc;
    4. }
    5.  
     
  23. Offline

    Lurvik

    Code:Java
    1. public Location getLowestDistance(Location source, List<String> locs) {
    2. List<Location> locList = new ArrayList<Location>();
    3.  
    4. for (String coords : locs) {
    5. String[] coord = coords.split(",");
    6. Location loc = new Location(Bukkit.getWorld(coord[0]), coord[1], coord[2], coord[3]);
    7. locList.add(loc);
    8. }
    9.  
    10. getLowestDistance(source, locList.toArray());
    11. }


    Ryzzzen You could do something like that (keep your method, just add that one after it). :p
     
  24. Offline

    Ryzzzen

    Thanks, i'll try this.

    EDIT:

    Error: Object cannot be cast to Location. (In the Bukkit console, not IDE)

    Actual code:

    Code:java
    1. public static Location getLowestDistance(Location source, Location[] locs)
    2. {
    3. Location shortest = locs[0];
    4. for (Location loc : locs) {
    5. if (loc.distanceSquared(source) < shortest.distanceSquared(source))
    6. shortest = loc;
    7. }
    8. return shortest;
    9. }
    10.  
    11. public static Location getLowestDistance(Location source, List<?> locs) {
    12. List<Location> locList = new ArrayList<Location>();
    13. List<String> loc = (List<String>) locs;
    14. for (String coords : loc) {
    15. String[] coord = coords.split(",");
    16. Location loc1 = new Location(Bukkit.getWorld(coord[0]), Integer.parseInt(coord[1]), Integer.parseInt(coord[2]), Integer.parseInt(coord[3]));
    17. locList.add(loc1);
    18. }
    19.  
    20. return getLowestDistance(source, (Location[]) locList.toArray());
    21. }
    22.  


    I changed a little the code, for parse coords for the location, and for cast the List<?> into a List<String> because i can't use the method with the list. I hope you understand me xD
     
  25. Offline

    Lurvik

    Ryzzzen Instead of casting it, change the second parameter to "List<String> locs". You shouldn't need the cast at the return ("(Location[])locList.toArray()". What line gives that error?
     
  26. Offline

    Ryzzzen

    Actual code:

    Code:java
    1. public static Location getLowestDistance(Location source, Location[] locs)
    2. {
    3. Location shortest = locs[0];
    4. for (Location loc : locs) {
    5. if (loc.distanceSquared(source) < shortest.distanceSquared(source))
    6. shortest = loc;
    7. }
    8. return shortest;
    9. }
    10.  
    11. public static Location getLowestDistance(Location source, List<String> locs) {
    12. List<Location> locList = new ArrayList<Location>();
    13. List<String> loc = (List<String>) locs;
    14. for (String coords : loc) {
    15. String[] coord = coords.split(",");
    16. Location loc1 = new Location(Bukkit.getWorld(coord[0]), Integer.parseInt(coord[1]), Integer.parseInt(coord[2]), Integer.parseInt(coord[3]));
    17. locList.add(loc1);
    18. }
    19.  
    20. return getLowestDistance(source, (Location[]) locList.toArray());
    21. }
    22. }
    23.  


    There isn't spoilers ?
     
  27. Offline

    mrCookieSlime

    Moved to Alternatives Section.
     
  28. Offline

    Ryzzzen

  29. Online

    timtower Administrator Administrator Moderator

    Because you are running spigot
     
  30. Offline

    Ryzzzen

    Ah, okay.
     
Thread Status:
Not open for further replies.

Share This Page