Advertisement
Deedlit

JPS pathfinding.

Oct 22nd, 2013
347
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 10.96 KB | None | 0 0
  1. /*
  2.  * This program is free software: you can redistribute it and/or modify it under
  3.  * the terms of the GNU General Public License as published by the Free Software
  4.  * Foundation, either version 3 of the License, or (at your option) any later
  5.  * version.
  6.  *
  7.  * This program is distributed in the hope that it will be useful, but WITHOUT
  8.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  9.  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  10.  * details.
  11.  *
  12.  * You should have received a copy of the GNU General Public License along with
  13.  * this program. If not, see <http://www.gnu.org/licenses/>.
  14.  */
  15. package com.java.evacs.geoengine;
  16.  
  17. import javolution.util.FastList;
  18.  
  19. import java.util.concurrent.locks.ReentrantLock;
  20.  
  21. /**
  22.  * ==============================================<br>
  23.  * NodeBuffer - JumpPointSearch pathfinding engine<br>
  24.  * ==============================================<br>
  25.  * @author Deedlit(piotrekloud@gmail.com)
  26.  */
  27. public class NodeBuffer
  28. {
  29.     private final ReentrantLock _lock = new ReentrantLock();
  30.     private final int _mapSize;
  31.     private final Node[][] _buffer;
  32.  
  33.     private long _timeStamp = 0;
  34.     private long _lastElapsedTime = 0;
  35.  
  36.     private int startX, startY, endX, endY;
  37.  
  38.     private int[] tmpXY;
  39.     private int[][] neighbors;
  40.  
  41.     private float ng;
  42.     private Node tmpNode, cur;
  43.     private Node[] successors, possibleSuccess;
  44.     private FastList<Node> trail;
  45.  
  46.     private Heap _heap;
  47.     private final Grid _grid;
  48.  
  49.     public NodeBuffer(int size, Grid grid)
  50.     {
  51.         _mapSize = size;
  52.         _buffer = new Node[_mapSize][_mapSize];
  53.         _heap = new Heap();
  54.         _grid = grid;
  55.     }
  56.  
  57.     public final boolean lock()
  58.     {
  59.         return _lock.tryLock();
  60.     }
  61.  
  62.     public final FastList<Node> findPath(int x, int y, int tx, int ty)
  63.     {
  64.         _heap = new Heap();
  65.  
  66.         startX = x;
  67.         startY = y;
  68.         endX = tx;
  69.         endY = ty;
  70.  
  71.         getNode(startX, startY).updateGHFP(0, 0, null);
  72.         heapAdd(getNode(startX, startY));
  73.         while (true)
  74.         {
  75.             cur = heapPopNode();
  76.             if (cur.x == endX && cur.y == endY)
  77.             {
  78.                 trail = pathCreate(cur);
  79.                 return trail;
  80.             }
  81.             possibleSuccess = identifySuccessors(cur);
  82.             for (int i = 0; i < possibleSuccess.length; i++)
  83.             {
  84.                 if (possibleSuccess[i] != null)
  85.                 {
  86.                     heapAdd(possibleSuccess[i]);
  87.                 }
  88.             }
  89.             if (heapSize() == 0)
  90.             {
  91.                 break;
  92.             }
  93.         }
  94.         return null;
  95.     }
  96.  
  97.  
  98.     /**
  99.      * zwraca węzły do których były skoki z podanego węzła
  100.      *
  101.      * @param node
  102.      *
  103.      * @return
  104.      */
  105.     public Node[] identifySuccessors(Node node)
  106.     {
  107.         successors = new Node[8];
  108.         neighbors = getNeighborsPrune(node);
  109.         for (int i = 0; i < neighbors.length; i++)
  110.         {
  111.             tmpXY = jump(neighbors[i][0], neighbors[i][1], node.x, node.y);
  112.             if (tmpXY[0] != -1)
  113.             {
  114.                 int x = tmpXY[0];
  115.                 int y = tmpXY[1];
  116.                 ng = (toPointApprox(x, y, node.x, node.y) + node.g);
  117.                 if (getNode(x, y).f <= 0 || getNode(x, y).g > ng)
  118.                 {
  119.                     getNode(x, y).updateGHFP(toPointApprox(x, y, node.x, node.y) + node.g, toPointApprox(x, y, endX, endY), node);
  120.                     successors[i] = getNode(x, y);
  121.                 }
  122.             }
  123.         }
  124.         return successors;
  125.     }
  126.  
  127.     /**
  128.      * metoda rekursywnie szuka w kierunku nadrzędnego położenia (px,py), z obecnego (x,y)
  129.      * zatrzyma się i zwróci aktualną wartość w 3 sytuacjach:
  130.      *
  131.      * 1) aktualna pozycja, to pozycja docelowa (endX, endY)
  132.      * 2) aktualna pozycja to wymuszona sąsiadująca do której można przejść.
  133.      * 3) aktualna jest satysfakcjonująca jako krok do pozycji satysfakcjonującej 1) lub 2)
  134.      *
  135.      * @param x (int)
  136.      * @param y (int)
  137.      * @param px (int)
  138.      * @param py (int)
  139.      *
  140.      * @return (int[]={x, y})
  141.      */
  142.     public int[] jump(int x, int y, int px, int py)
  143.     {
  144.         int[] jx = {-1, -1};
  145.         int[] jy = {-1, -1};
  146.         int dx = (x - px) / Math.max(Math.abs(x - px), 1); //ponieważ nadrzędne nie zawsze są w sąsiedztwie, to jest wykorzystywane w celu znalezienia nadrzędnych -> podrzędnych (dla x)
  147.         int dy = (y - py) / Math.max(Math.abs(y - py), 1); //ponieważ nadrzędne nie zawsze są w sąsiedztwie, to jest wykorzystywane w celu znalezienia nadrzędnych -> podrzędnych (dla y)
  148.  
  149.         if (!walkable(x, y))
  150.         { //jeśli ta pozycja jest przeszkodą, zwróć null {-1,-1}
  151.             return tmpInt(-1, -1);
  152.         }
  153.         if (x == this.endX && y == this.endY)
  154.         {   //znaleziono punkt docelowy!
  155.             return tmpInt(x, y);
  156.         }
  157.         if (dx != 0 && dy != 0)
  158.         {  //gdy x i y zmieniły się, to poruszamy się po skosie
  159.             if ((walkable(x - dx, y + dy) && !walkable(x - dx, y)) ||
  160.                     (walkable(x + dx, y - dy) && !walkable(x, y - dy)))
  161.             {
  162.                 return tmpInt(x, y);
  163.             }
  164.         }
  165.         else
  166.         { //sprawdź w poziomie/pionie
  167.             if (dx != 0)
  168.             { //poruszanie po x
  169.                 if ((walkable(x + dx, y + 1) && !walkable(x, y + 1)) ||
  170.                         (walkable(x + dx, y - 1) && !walkable(x, y - 1)))
  171.                 {
  172.                     return tmpInt(x, y);
  173.                 }
  174.             }
  175.             else
  176.             {
  177.                 if ((walkable(x + 1, y + dy) && !walkable(x + 1, y)) ||  //poruszanie po y
  178.                         (walkable(x - 1, y + dy) && !walkable(x - 1, y)))
  179.                 {
  180.                     return tmpInt(x, y);
  181.                 }
  182.             }
  183.         }
  184.  
  185.         if (dx != 0 && dy != 0)
  186.         { //gdy poruszamy się po skosie, sprawdź w poszukiwaniu poziomych/pionowych punktów skoku
  187.             jx = jump(x + dx, y, x, y);
  188.             jy = jump(x, y + dy, x, y);
  189.             if (jx[0] != -1 || jy[0] != -1)
  190.             {
  191.                 return tmpInt(x, y);
  192.             }
  193.         }
  194.         if (walkable(x + dx, y) || walkable(x, y + dy))
  195.         { //poruszamy się po skosie, należy upewnić się że jeden poziomy/pionowy sąsiad umożliwia ruch
  196.             return jump(x + dx, y + dy, x, y);
  197.         }
  198.         else
  199.         { //jeśli staramy się poruszać po skosie, ale jest blokada na dwóch rogach dotykających sąsiednich węzłów, wracamy wartość null
  200.             return tmpInt(-1, -1);
  201.         }
  202.     }
  203.  
  204.     /**
  205.      * Zwraca węzły, które należy połączyć szeregowo w zależności od lokalizacji macierzystego, w stosunku do danego węzła.
  206.      *
  207.      * @param node (Node)
  208.      *
  209.      * @return (ArrayList<Node>)
  210.      */
  211.     public int[][] getNeighborsPrune(Node node)
  212.     {
  213.         Node parent = node.parent;    //nadrzędny węzeł
  214.         int x = node.x;
  215.         int y = node.y;
  216.         int px, py, dx, dy;
  217.         int[][] neighbors = new int[5][2];
  218.         //odrzucanie węzłów
  219.         if (parent != null)
  220.         {
  221.             px = parent.x;
  222.             py = parent.y;
  223.             //oblicz znormalizowany kierunek ruchu
  224.             dx = (x - px) / Math.max(Math.abs(x - px), 1);
  225.             dy = (y - py) / Math.max(Math.abs(y - py), 1);
  226.             //szukaj po przekątnych
  227.             if (dx != 0 && dy != 0)
  228.             {
  229.                 if (walkable(x, y + dy))
  230.                 {
  231.                     neighbors[0] = (tmpInt(x, y + dy));
  232.                 }
  233.                 if (walkable(x + dx, y))
  234.                 {
  235.                     neighbors[1] = (tmpInt(x + dx, y));
  236.                 }
  237.                 if (walkable(x, y + dy) || walkable(x + dx, y))
  238.                 {
  239.                     neighbors[2] = (tmpInt(x + dx, y + dy));
  240.                 }
  241.                 if (!walkable(x - dx, y) && walkable(x, y + dy))
  242.                 {
  243.                     neighbors[3] = (tmpInt(x - dx, y + dy));
  244.                 }
  245.                 if (!walkable(x, y - dy) && walkable(x + dx, y))
  246.                 {
  247.                     neighbors[4] = (tmpInt(x + dx, y - dy));
  248.                 }
  249.             }
  250.             else
  251.             {
  252.                 if (dx == 0)
  253.                 {
  254.                     if (walkable(x, y + dy))
  255.                     {
  256.                         if (walkable(x, y + dy))
  257.                         {
  258.                             neighbors[0] = (tmpInt(x, y + dy));
  259.                         }
  260.                         if (!walkable(x + 1, y))
  261.                         {
  262.                             neighbors[1] = (tmpInt(x + 1, y + dy));
  263.                         }
  264.                         if (!walkable(x - 1, y))
  265.                         {
  266.                             neighbors[2] = (tmpInt(x - 1, y + dy));
  267.                         }
  268.                     }
  269.                 }
  270.                 else
  271.                 {
  272.                     if (walkable(x + dx, y))
  273.                     {
  274.                         if (walkable(x + dx, y))
  275.                         {
  276.                             neighbors[0] = (tmpInt(x + dx, y));
  277.                         }
  278.                         if (!walkable(x, y + 1))
  279.                         {
  280.                             neighbors[1] = (tmpInt(x + dx, y + 1));
  281.                         }
  282.                         if (!walkable(x, y - 1))
  283.                         {
  284.                             neighbors[2] = (tmpInt(x + dx, y - 1));
  285.                         }
  286.                     }
  287.                 }
  288.             }
  289.         }
  290.         else
  291.         {//zwróć sąsiadujące
  292.             return getNeighbors(node);
  293.         }
  294.  
  295.         return neighbors; //zwróć sąsiadujące węzły
  296.     }
  297.  
  298.     public final void free()
  299.     {
  300.         trail = null;
  301.         tmpXY = null;
  302.         neighbors = null;
  303.  
  304.         ng = 0;
  305.         tmpNode = null;
  306.         cur = null;
  307.         successors = null;
  308.         possibleSuccess = null;
  309.  
  310.         _heap = null;
  311.  
  312.         Node node;
  313.         for (int i = 0; i < _mapSize; i++)
  314.             for (int j = 0; j < _mapSize; j++)
  315.             {
  316.                 node = _buffer[i][j];
  317.                 if (node != null)
  318.                     node.free();
  319.  
  320.                 _buffer[i][j] = null;
  321.             }
  322.  
  323.         _lock.unlock();
  324.         _lastElapsedTime = System.currentTimeMillis() - _timeStamp;
  325.     }
  326.  
  327.     public final long getElapsedTime()
  328.     {
  329.         return _lastElapsedTime;
  330.     }
  331.  
  332.     public int[][] getNeighbors(Node node)
  333.     {
  334.         int[][] neighbors = new int[8][2];
  335.         int x = node.x;
  336.         int y = node.y;
  337.         boolean d0 = false;
  338.         boolean d1 = false;
  339.         boolean d2 = false;
  340.         boolean d3 = false;
  341.  
  342.         if (walkable(x, y - 1))
  343.         {
  344.             neighbors[0] = (tmpInt(x, y - 1));
  345.             d0 = d1 = true;
  346.         }
  347.         if (walkable(x + 1, y))
  348.         {
  349.             neighbors[1] = (tmpInt(x + 1, y));
  350.             d1 = d2 = true;
  351.         }
  352.         if (walkable(x, y + 1))
  353.         {
  354.             neighbors[2] = (tmpInt(x, y + 1));
  355.             d2 = d3 = true;
  356.         }
  357.         if (walkable(x - 1, y))
  358.         {
  359.             neighbors[3] = (tmpInt(x - 1, y));
  360.             d3 = d0 = true;
  361.         }
  362.         if (d0 && walkable(x - 1, y - 1))
  363.         {
  364.             neighbors[4] = (tmpInt(x - 1, y - 1));
  365.         }
  366.         if (d1 && walkable(x + 1, y - 1))
  367.         {
  368.             neighbors[5] = (tmpInt(x + 1, y - 1));
  369.         }
  370.         if (d2 && walkable(x + 1, y + 1))
  371.         {
  372.             neighbors[6] = (tmpInt(x + 1, y + 1));
  373.         }
  374.         if (d3 && walkable(x - 1, y + 1))
  375.         {
  376.             neighbors[7] = (tmpInt(x - 1, y + 1));
  377.         }
  378.         return neighbors;
  379.     }
  380.  
  381.     /**
  382.      * Sprawdzenie czy węzeł x,y można przejść.
  383.      *
  384.      * @param x (int)
  385.      * @param y (int)
  386.      *
  387.      * @return (boolean) true jeśli węzeł nie jest przeszkodą i nie jest poza mapą.
  388.      */
  389.     public boolean walkable(int x, int y)
  390.     {
  391.         try
  392.         {
  393.             return getNode(x, y).pass;
  394.         }
  395.         catch (Exception e)
  396.         {
  397.             return false;
  398.         }
  399.     }
  400.  
  401.     public FastList<Node> pathCreate(Node node)
  402.     {
  403.         FastList<Node> trail = new FastList<Node>();
  404.         while (node.parent != null)
  405.         {
  406.             try
  407.             {
  408.                 trail.add(0, new Node(node));
  409.             }
  410.             catch (Exception e) {}
  411.             node = node.parent;
  412.         }
  413.         return trail;
  414.     }
  415.  
  416.     public void heapAdd(Node node)
  417.     {
  418.         float[] tmp = {node.x, node.y, node.f};
  419.         _heap.add(tmp);
  420.     }
  421.  
  422. //--------------------------STOS-----------------------------------//
  423.  
  424.     /** @return (int) rozmiar stosu */
  425.     public int heapSize()
  426.     {
  427.         return _heap.getSize();
  428.     }
  429.  
  430.     /** @return (Node) zwraca poprawny węzeł */
  431.     public Node heapPopNode()
  432.     {
  433.         float[] tmp = _heap.pop();
  434.         return getNode((int) tmp[0], (int) tmp[1]);
  435.     }
  436.  
  437. //---------------------------------------------------------//
  438.  
  439.     public int[] tmpInt(int x, int y)
  440.     {
  441.         int[] tmpIntsTmpInt = {x, y};  //create the tmpInt's tmpInt[]
  442.         return tmpIntsTmpInt;         //return it
  443.     }
  444.  
  445.     /**
  446.      * getFunc - węzeł w x, y
  447.      *
  448.      * @param x (int)
  449.      * @param y (int)
  450.      *
  451.      * @return (Node)
  452.      */
  453.     public Node getNode(int x, int y)
  454.     {
  455.         if (_buffer[x][y] != null)
  456.             return _buffer[x][y];
  457.         try
  458.         {
  459.             _buffer[x][y] = new Node(_grid.getNode(x, y));
  460.             return _buffer[x][y];
  461.         }
  462.         catch (Exception e)
  463.         {
  464.             return null;
  465.         }
  466.     }
  467.  
  468.     public float toPointApprox(float x, float y, int tx, int ty)
  469.     {
  470.         return (float) Math.sqrt(Math.pow(Math.abs(x - tx), 2) + Math.pow(Math.abs(y - ty), 2));
  471.     }
  472. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement