I'm developing a project that given a set of coordinates (lat and longitude) needs to find all the points that are closer than a given distance (in Km).
I have working implementation that iterates over each point and for each point iterates over all the other points. This is O(n^2). I'd like to know what approach could I follow to improve this, having in mind that I don't want the closest point but the ones that are closer than x Km (also I'd like to be able to do the opposite, finding all the points that are further away than x Km).
If you could provide some ideas and algorithms it would be nice. Also code examples would be nice, specially in Scala (I'm developing this project Scala).
For this problem I'd use a java library (this is possible in Scala).
Calculating distances on earth is much more difficult than you think. The earth is not a pefect sphere for example.
The main library for doing 'geo stuff' in java is JTS: http://tsusiatsoftware.net/jts/main.html
You can also take a look at Geotools or maybe even a GIS-database like PostGIS (built on Postgresql), but that might be overkill for your project
Answering myself a few months late. Well I ended up using using KD-Tree to implement this. I based myself on this Java implementation: http://people.cs.vt.edu/~shaffer/Book/JAVA/progs/KDtree/
However I made some modifications to it (including porting it to Scala) and adapting it to my specific problem around Geocaches. The resulting code was the following:
/*
* Based on
* http://people.cs.vt.edu/~shaffer/Book/JAVA/progs/KDtree/
*
* That code is made available as part of this textbook on Data Structures:
* http://people.cs.vt.edu/~shaffer/Book/
*/
//A node for a KDTree
class KDNode[E] {
private var key_value : Array[Double] = null //key for this node
def key = key_value
def key_=(k : Array[Double]) { key_value = k }
private var element_value: E = _ //Element for this node
def element = element_value
def element_=(e : E) {element_value = e}
private var left_value : KDNode[E] = null //Pointer to left child
def left = left_value
def left_=(l : KDNode[E]) {left_value = l}
private var right_value : KDNode[E] = null //Pointer to right child
def right = right_value
def right_=(r : KDNode[E]) {right_value = r}
/** Constructors */
def this(k : Array[Double], value : E) =
{
this()
key = k
element = value
}
def this(k : Array[Double], value : E, l : KDNode[E], r : KDNode[E]) =
{
this(k,value)
left = l
right = r
}
//Checks if it's a leaf
def isLeaf : Boolean =
{
return (left == null) && (right == null)
}
}
//Trait for a basic Dictionary that will be used as basis for our KDTree
trait Dictionary[K,V] {
def size: Int
def insert(key: K, value: V)
def remove(key: K): V
def find(key: K): V
def clear
def isEmpty: Boolean
}
/**
* A extended trait that defines that the key of the dictionary is an array of
* doubles and defines the need of a method called regionSearchGeo (very
* important for All Years 5 & 6 stats)
*/
trait GeoDictionary[E] extends Dictionary[Array[Double], E] {
def regionSearchGeo(k: Array[Double], radius: Double) : List[E]
}
/**
* Our implementation of a KDTree. It's based on the code provided in the
* reference above, but had a few key areas modified for geographic searching.
* For example, this KDtree is a 3D Tree. The keys are Latitude, Longitude and
* the Year of the cache (that was also included to speed thins even further)
*/
class K3DGeoTree[E] extends GeoDictionary[E]{
private var root : KDNode[E] = null
private val D : Int = 3 // Only supporting 2D points in this implementation
private var nodecount : Int = 0 // Number of nodes in the KD tree
/**
* Implementing everything that is required by the Dictionary trait
* Some private auxiliary methods are also present
*/
def clear() = { root = null }
def isEmpty() : Boolean = { root == null }
def size() : Int = { return nodecount }
def insert(pt : Array[Double], value : E) = {
root = inserthelp(root, pt, value, 0)
nodecount=nodecount+1
}
def inserthelp(rt : KDNode[E], key : Array[Double], value : E, level : Int)
: KDNode[E] = {
if (rt == null) return new KDNode[E](key, value)
val rtkey : Array[Double] = rt.key
if (rtkey(level) > key(level))
rt.left = inserthelp(rt.left, key, value, (level+1)%D)
else
rt.right = inserthelp(rt.right, key, value, (level+1)%D)
return rt
}
private def findmin(rt : KDNode[E], descrim : Int, level : Int): KDNode[E]= {
var temp1 : KDNode[E] = null
var temp2 : KDNode[E] = null
var key1 : Array[Double] = null
var key2 : Array[Double] = null
if (rt == null) return null
temp1 = findmin(rt.left, descrim, (level+1)%D)
if (temp1 != null) key1 = temp1.key
if (descrim != level) {
temp2 = findmin(rt.right, descrim, (level+1)%D)
if (temp2 != null) key2 = temp2.key
if ((temp1 == null) || ((temp2 != null) && (key1(descrim) > key2(descrim))))
temp1 = temp2
key1 = key2
} // Now, temp1 has the smaller value
var rtkey : Array[Double] = rt.key
if ((temp1 == null) || (key1(descrim) > rtkey(descrim)))
return rt
else
return temp1
}
def find(key : Array[Double]) : E = { return findhelp(root, key, 0) }
private def findhelp(rt : KDNode[E], key : Array[Double], level : Int) : E ={
if (rt == null) return null.asInstanceOf[E]
val it : E = rt.element
val itkey : Array[Double]= rt.key
if ((itkey(0) == key(0)) && (itkey(1) == key(1)))
return rt.element
if (itkey(level) > key(level))
return findhelp(rt.left, key, (level+1)%D)
else
return findhelp(rt.right, key, (level+1)%D)
}
def remove(key : Array[Double]) : E = {
val temp : E = findhelp(root, key, 0) // First find it
if (temp != null) {
root = removehelp(root, key, 0) // Now remove it
nodecount=nodecount-1
}
return temp
}
private def removehelp(rt : KDNode[E], key : Array[Double], level : Int)
: KDNode[E] = {
if (rt == null) return null
val rtkey : Array[Double] = rt.key
if (key(level) < rtkey(level))
rt.left = removehelp(rt.left, key, (level+1)%D)
else if (key(level) > rtkey(level))
rt.right = removehelp(rt.right, key, (level+1)%D)
else { // Found it
if (rt.right == null)
if (rt.left == null) // Just drop element
return null
else { // Switch subtree to right
rt.right = rt.left
rt.left = null
}
val temp : KDNode[E] = findmin(rt.right, level, (level+1)%D)
rt.right = removehelp(rt.right, temp.key, (level+1)%D)
rt.element = temp.element
}
return rt
}
/**
* Implementing the GeoDictionary trait
*/
def regionSearchGeo(point: Array[Double], radius: Double) : List[E] =
{
val pointGeo : GeoLocation = GeoLocation.fromDegrees(point(0), point(1))
/**
* Calculates a bounding rectangle that contains the circle with the given
* radius. This will be explained later in the corresponding class
*/
val boundingRect = pointGeo.boundingCoordinates(radius)
//Return the caches found
return rsGeoHelp(root, point, radius, boundingRect, 0)
}
/**
* Auxiliary region search function that does all the heavy work
*/
private def rsGeoHelp(rt : KDNode[E], point : Array[Double], radius : Double,
boundingRect : Tuple2[GeoLocation,GeoLocation],
lev : Int): List[E] = {
if (rt == null) return Nil
val rtkey : Array[Double] = rt.key
var found : List[E] = Nil
//Checks if the current node is in the desired radius (and also the year)
if (InCircleGeo(point, radius, rtkey))
found = List(rt.element)
//First Dimension is latitude
if(lev % D == 0){
if (rtkey(lev) >= boundingRect._1.degLat)
found = found:::rsGeoHelp(rt.left, point, radius, boundingRect, (lev+1)%D)
if (rtkey(lev) <= boundingRect._2.degLat)
found = found:::rsGeoHelp(rt.right, point, radius, boundingRect, (lev+1)%D)
}
//Second Dimension is Longitude
else if(lev % D == 1){
if (rtkey(lev) >= boundingRect._1.degLon)
found = found:::rsGeoHelp(rt.left, point, radius, boundingRect, (lev+1)%D)
if (rtkey(lev) <= boundingRect._2.degLon)
found = found:::rsGeoHelp(rt.right, point, radius, boundingRect, (lev+1)%D)
}
//Third and last dimension is the year
else{
found = found:::rsGeoHelp(rt.left, point, radius, boundingRect, (lev+1)%D)
if (rtkey(lev) <= point(lev))
found = found:::rsGeoHelp(rt.right, point, radius, boundingRect, (lev+1)%D)
}
//Return the found nodes (in our case it will be caches)
return found
}
private def InCircleGeo(point : Array[Double], radius : Double,
coord : Array[Double]) : Boolean = {
//Creates a GeoLocation object for each point
val pointGeo : GeoLocation = GeoLocation.fromDegrees(point(0), point(1))
val coordGeo : GeoLocation = GeoLocation.fromDegrees(coord(0), coord(1))
/**
* If the year is smaller than the query point and the distance is within
* radius return true. Else it's false.
*/
return (coord(0) != point(0) && coord(1) != point(1) && coord(2) <= point(2)
&& pointGeo.distanceTo(coordGeo) < radius)
}
}
/**
* This class encapsulates a series of utility methods to deal with geographic
* coordinates. It was based on the information in the link below that gives
* a very good insight about how to do math with geographic coordinates and
* also provides some Java samples that we used as an inspiration for this
* class.
* Link: http://janmatuschek.de/LatitudeLongitudeBoundingCoordinates
*/
//Companion object of Class GeoLocation to define static methods and variables
object GeoLocation {
//Min maxs in terms of Latitude and Longitude accross the globe
private val MIN_LAT : Double = math.toRadians(-90) // -PI/2
private val MAX_LAT : Double = math.toRadians(90) // PI/2
private val MIN_LON : Double = math.toRadians(-180) // -PI
private val MAX_LON : Double = math.toRadians(180) // PI
/**
* Earth radius. This value is the most used but there are others that may
* give slightly different results.
*/
private val RADIUS : Double = 6372.8
/**
* A factory method that creates a GeoLocation object from given latitude and
* longitude in degrees
*/
def fromDegrees(latitude : Double, longitude : Double) : GeoLocation = {
val result : GeoLocation = new GeoLocation()
result.radLat = math.toRadians(latitude)
result.radLon = math.toRadians(longitude)
result.degLat = latitude
result.degLon = longitude
result.checkBounds
return result
}
/**
* A factory method that creates a GeoLocation object from given latitude and
* longitude in radians
*/
def fromRadians(latitude : Double, longitude : Double) : GeoLocation = {
val result : GeoLocation = new GeoLocation()
result.radLat = latitude
result.radLon = longitude
result.degLat = math.toDegrees(latitude)
result.degLon = math.toDegrees(longitude)
result.checkBounds
return result
}
}
/**
* The GeoLocation class itself. The constructor is private use the factory
* methods above.
*/
class GeoLocation private{
/**
* Getters and Setters implemented as properties with syntactic sugar
* This properties contain the latitude and longitude in degrees and radians
*/
private var radLat_value : Double = _
def radLat = radLat_value
private def radLat_=(k : Double) { radLat_value = k }
private var radLon_value : Double = _
def radLon = radLon_value
private def radLon_=(k : Double) { radLon_value = k }
private var degLat_value : Double = _
def degLat = degLat_value
private def degLat_=(k : Double) { degLat_value = k }
private var degLon_value : Double = _
def degLon = degLon_value
private def degLon_=(k : Double) { degLon_value = k }
/**
* Check if the vales are valid considering the MIN and MAX for latitude and
* longitude.
*/
private def checkBounds = {
if (radLat < GeoLocation.MIN_LAT || radLat > GeoLocation.MAX_LAT ||
radLon < GeoLocation.MIN_LON || radLon > GeoLocation.MAX_LON)
throw new IllegalArgumentException()
}
/**
* Function to calculate the distance between this GeoLocation and the given
* GeoLocation.
*
* Check the reference above and
* http://en.wikipedia.org/wiki/Haversine_formula
* for more information.
*/
def distanceTo(location : GeoLocation) : Double = {
return math.acos(math.sin(radLat) * math.sin(location.radLat) +
math.cos(radLat) * math.cos(location.radLat) *
math.cos(radLon - location.radLon)) * GeoLocation.RADIUS
}
/**
* This method is very important for the search made in the K3DTree.
* It allows us to make a bouding rectangle with the given distance/radius
* that is geometrically correct. Check the reference above to learn more
* about the math involved.
*/
def boundingCoordinates(distance : Double)
: Tuple2[GeoLocation, GeoLocation] = {
if (distance < 0d) throw new IllegalArgumentException()
// Angular distance in radians on a great circle
val radDist : Double = distance / GeoLocation.RADIUS
//Initialize local variables to check for poles
var minLat : Double = radLat - radDist
var maxLat : Double = radLat + radDist
var minLon : Double = 0
var maxLon : Double = 0
//Normal case
if (minLat > GeoLocation.MIN_LAT && maxLat < GeoLocation.MAX_LAT) {
val deltaLon : Double = math.asin(math.sin(radDist) / math.cos(radLat))
minLon = radLon - deltaLon
if (minLon < GeoLocation.MIN_LON) minLon += 2d * math.Pi
maxLon = radLon + deltaLon
if (maxLon > GeoLocation.MAX_LON) maxLon -= 2d * math.Pi
}
//Special case in which a pole is within the distance
else{
minLat = math.max(minLat, GeoLocation.MIN_LAT)
maxLat = math.min(maxLat, GeoLocation.MAX_LAT)
minLon = GeoLocation.MIN_LON
maxLon = GeoLocation.MAX_LON
}
/**
* Each of the bounding points (one in the south-west, bottom-left,
* and other in the north-east, top-right)
*/
val swPoint : GeoLocation = GeoLocation.fromRadians(minLat, minLon)
val nePoint : GeoLocation = GeoLocation.fromRadians(maxLat, maxLon)
//Return the tuple with the two points
return (swPoint, nePoint)
}
}
The whole code is documented so I hope this helps someone with a similar problem. In this specific problem I had to deal with years besides latitude and longitude, so I added an extra dimension. But for a more general geographic problem it's even easier to do it with only two dimensions (one for latitude and one for longitude).
Related
Given a 2d matrix, I have a start cell, end cell, cells that must be visited and cells that cannot be visited.
What would be the optimal way to find a path that:
starts at the start cell
ends at the end cell
passes through all must visit cell
does not pass through any cell that cannot be visited
does not pass any cell twice
we can only move left, right, up and down
The matrix size can be at most 10x10.
For example:
S - start
E - end
0 - can visit
X - can not visit
M - must visit
S 0 0 M 0
0 0 0 X 0
0 M 0 0 0
0 X 0 0 0
0 0 0 0 E
One solution would be:
* 0 * * *
* 0 * X *
* * * 0 *
0 X 0 0 *
0 0 0 0 *
The path doesn't necessarily should be the shortest one, but it would be nice if it can be, and it can be calculated quiet fast.
You can model the grid with a class Grid that would have a width and a height, and a set of must locations a set of mustNot locations:
public class Grid {
private final int width;
private final int height;
private final Set<Location> must = new HashSet<>();
private final Set<Location> mustNot = new HashSet<>();
public Grid(int width, int height,
Collection<Location> must, Collection<Location> mustNot) {
this.width = width;
this.height = height;
this.must.addAll(must);
this.mustNot.addAll(mustNot);
}
In that class, you would have a method solve that would take a start location and an end location, and would return the best path:
public PathNode solve(Location start, Location end) {
...
}
class Location looks like this:
public class Location {
public final int row;
public final int col;
public Location(int row, int col) {
this.row = row;
this.col = col;
}
#Override
public int hashCode() {
int hash = 7;
hash = 41 * hash + this.row;
hash = 41 * hash + this.col;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Location other = (Location) obj;
if (this.row != other.row) {
return false;
}
return this.col == other.col;
}
#Override
public String toString() {
return "(" + row + ", " + col + ')';
}
}
Basically, it's a row and a col.
A path is a linked list of PathNodes:
public class PathNode {
public final Location loc;
public final PathNode link;
public PathNode(Location loc, PathNode link) {
this.loc = loc;
this.link = link;
}
public boolean contains(Location loc) {
PathNode n = this;
while (n != null) {
if (n.loc.equals(loc)) {
return true;
}
n = n.link;
}
return false;
}
}
I've added a contains method because of the condition that a path must not go through the same location twice.
Now, the algorithm is a breadth-first search:
public PathNode solve(Location start, Location end) {
List<PathNode> paths = new ArrayList<>();
if (validLoc(start.row, start.col) == null) {
return null;
}
paths.add(new PathNode(start, null));
for (int i = 0; i < paths.size(); ++i) {
PathNode path = paths.get(i);
Location loc = path.loc;
if (loc.equals(end)) {
// at the end point, we must still check the path goes through
// all the 'must' cells
if (allMustInPath(path)) {
// found a path
return path;
}
} else {
addToPaths(path, left(loc), paths);
addToPaths(path, right(loc), paths);
addToPaths(path, up(loc), paths);
addToPaths(path, down(loc), paths);
}
}
return null;
}
We still need a few more methods:
private Location left(Location loc) {
return validLoc(loc.row, loc.col-1);
}
private Location right(Location loc) {
return validLoc(loc.row, loc.col+1);
}
private Location up(Location loc) {
return validLoc(loc.row-1, loc.col);
}
private Location down(Location loc) {
return validLoc(loc.row+1, loc.col);
}
private Location validLoc(int row, int col) {
if (row >= 0 && row < height && col >= 0 && col < width) {
Location loc = new Location(row, col);
return mustNot.contains(loc) ? null : loc;
}
return null;
}
private boolean allMustInPath(PathNode path) {
for (Location loc: must) {
if (!path.contains(loc)) {
return false;
}
}
return true;
}
private void addToPaths(PathNode path, Location loc, List<PathNode> paths) {
if (loc == null) {
return;
}
loc = validLoc(loc.row, loc.col);
if (loc != null && !path.contains(loc)) {
paths.add(new PathNode(loc, path));
}
}
The path returned by the solve method, is actually in backward order. For your example above, it finds the path that you mentionned:
Grid grid = new Grid(5,5,
Arrays.asList(
new Location(0,3),
new Location(2,1)),
Arrays.asList(
new Location(1,3),
new Location(3,1)));
PathNode path = grid.solve(
new Location(0,0),
new Location(4,4));
if (path == null) {
System.out.println("No solution found");
}
while (path != null) {
System.out.println(path.loc);
path = path.link;
}
(4, 4)
(3, 4)
(2, 4)
(1, 4)
(0, 4)
(0, 3)
(0, 2)
(1, 2)
(2, 2)
(2, 1)
(1, 1)
(0, 1)
(0, 0)
Essentially, you need to calculate the minimum spanning tree ( MST, google it ).
Start with the cells that must be visited. These will be the nodes in the graph you apply the MST algorithm to. Find the lengths of the shortest paths between each pair of nodes ( in such a small problem you can easily do that manually ) These will be the links, and link costs you input to the MST.
Input the constructed graph to the MST method in your favorite graph-theory library.
For a more complicated version of this problem, which is solved using the same technique, see How to find a shortest path in a graph that while travelling it, you can "see" all the nodes within a radius
I try to use the theta* algorithm (aigamedev.com/open/tutorial/lazy-theta-star) to find the fastest path on a rectangular grid. Distances are euqlidian, but speed between nodes is time dependent and varies between directions. So the triangle inequality, which is a prerequisite for the algorithm, is violated. Still it works excellently in most cases. How could I modify the code to work nicely also in turbulent areas? I suspect I may have to reevaluate some closed nodes and put them back into the open list. If so, under what conditions? An extensive web search hasn't helped.
vertex_t *thetastar(vertex_t *startnode, vertex_t *finishnode, double starttime) {
vertex_t *s, *s1;
double gold, gnew;
int dir; //8 directions to search for node neighbours
//Initialize
vertex[0].row = startnode->row;
vertex[0].col = startnode->col;
vertex[0].g = starttime;
vertex[0].h = h(&vertex[0], finishnode);
vertex[0].open = true;
vertex[0].closed = false;
vertex[0].parent = &vertex[0];
openlist[0] = &vertex[0];
openlist[1] = NULL;
//Find path
while ((s = pop(openlist)) != NULL) {
if (s->row == finishnode->row && s->col == finishnode->col) {
return s;
}
s->closed = true;
for (dir = 0; dir < 8; dir++) {
if ((s1 = nghbrvis(s, dir)) != NULL) {
if (!s1->closed) {
if (!s1->open) {
s1->g = inftime;
s1->parent = NULL;
}
gold = s1->g;
//Path 2
if (lineofsight(s->parent, s1)) {
gnew = (s->parent)->g + c(s->parent, s1);
if (gnew < s1->g) {
s1->parent = s->parent;
s1->g = gnew;
} }
//Path 1
gnew = s->g + c(s, s1);
if (gnew < s1->g) {
s1->parent = s;
s1->g = gnew;
}
if (s1->g < gold) {
s1->h = h(s1, finishnode);
if (s1->open)
remove(s1, openlist);
insert(s1, openlist);
} } } } }
return NULL;
}
I have a grid [40 x 15] with 2 to 16 units on it, and unknown amount of obstacles.
How to find the shortest path to all the units from my unit location.
I have two helper methods that we can consider as O(1)
getMyLocation() - return the (x, y) coordinates of my location on the grid
investigateCell(x, y) - return information about cell at (x,y) coordinates
I implemented A* search algorithm, that search simultaneously to all the directions. At the end it output a grid where each cell have a number representing the distance from my location, and collection of all the units on the grid. It performs with O(N) where N is the number of cells - 600 in my case.
I implement this using AS3, unfortunately it takes my machine 30 - 50 milliseconds to calculate.
Here is my source code. Can you suggest me a better way?
package com.gazman.strategy_of_battle_package.map
{
import flash.geom.Point;
/**
* Implementing a path finding algorithm(Similar to A* search only there is no known target) to calculate the shortest path to each cell on the map.
* Once calculation is complete the information will be available at cellsMap. Each cell is a number representing the
* number of steps required to get to that location. Enemies and Allies will be represented with negative distance. Also the enemy and Allys
* coordinations collections are provided. Blocked cells will have the value 0.<br><br>
* Worth case and best case efficiency is O(N) where N is the number of cells.
*/
public class MapFilter
{
private static const PULL:Vector.<MapFilter> = new Vector.<MapFilter>();
public var cellsMap:Vector.<Vector.<int>>;
public var allys:Vector.<Point>;
public var enemies:Vector.<Point>;
private var stack:Vector.<MapFilter>;
private var map:Map;
private var x:int;
private var y:int;
private var count:int;
private var commander:String;
private var hash:Object;
private var filtered:Boolean;
public function filter(map:Map, myLocation:Point, commander:String):void{
filtered = true;
this.commander = commander;
this.map = map;
this.x = myLocation.x;
this.y = myLocation.y;
init();
cellsMap[x][y] = 1;
excecute();
while(stack.length > 0){
var length:int = stack.length;
for(var i:int = 0; i < length; i++){
var mapFilter:MapFilter = stack.shift();
mapFilter.excecute();
PULL.push(mapFilter);
}
}
}
public function navigateTo(location:Point):Point{
if(!filtered){
throw new Error("Must filter before navigating");
}
var position:int = Math.abs(cellsMap[location.x][location.y]);
if(position == 0){
throw new Error("Target unreachable");
}
while(position > 2){
if(canNavigateTo(position, location.x + 1, location.y)){
location.x++;
}
else if(canNavigateTo(position, location.x - 1, location.y)){
location.x--;
}
else if(canNavigateTo(position, location.x, location.y + 1)){
location.y++;
}
else if(canNavigateTo(position, location.x, location.y - 1)){
location.y--;
}
position = cellsMap[location.x][location.y];
}
return location;
throw new Error("Unexpected filtering error");
}
private function canNavigateTo(position:int, targetX:int, targetY:int):Boolean
{
return isInMapRange(targetX, targetY) && cellsMap[targetX][targetY] < position && cellsMap[targetX][targetY] > 0;
}
private function excecute():void
{
papulate(x + 1, y);
papulate(x - 1, y);
papulate(x, y + 1);
papulate(x, y - 1);
}
private function isInMapRange(x:int, y:int):Boolean{
return x < cellsMap.length &&
x >= 0 &&
y < cellsMap[0].length &&
y >= 0;
}
private function papulate(x:int, y:int):void
{
if(!isInMapRange(x,y) ||
cellsMap[x][y] != 0 ||
hash[x + "," + y] != null ||
map.isBlocked(x,y)){
return;
}
// we already checked that is not block
// checking if there units
if(map.isEmpty(x,y)){
cellsMap[x][y] = count;
addTask(x,y);
}
else{
cellsMap[x][y] = -count;
if(map.isAlly(x,y, commander)){
hash[x + "," + y] = true;
allys.push(new Point(x,y));
}
else {
hash[x + "," + y] = true;
enemies.push(new Point(x,y));
}
}
}
private function addTask(x:int, y:int):void
{
var mapFilter:MapFilter = PULL.pop();
if(mapFilter == null){
mapFilter = new MapFilter();
}
mapFilter.commander = commander;
mapFilter.hash = hash;
mapFilter.map = map;
mapFilter.cellsMap = cellsMap;
mapFilter.allys = allys;
mapFilter..enemies = enemies;
mapFilter.stack = stack;
mapFilter.count = count + 1;
mapFilter.x = x;
mapFilter.y = y;
stack.push(mapFilter);
}
private function init():void
{
hash = new Object();
cellsMap = new Vector.<Vector.<int>>();
for(var i:int = 0; i < map.width;i++){
cellsMap.push(new Vector.<int>);
for(var j:int = 0; j < map.height;j++){
cellsMap[i].push(0);
}
}
allys = new Vector.<Point>();
enemies = new Vector.<Point>();
stack = new Vector.<MapFilter>();
count = 2;
}
}
}
You can use Floyd Warshall to find the shortest path between every pair of points. This would be O(|V|^3) and you would not have to run it for each unit, just once on each turn. It's such a simple algorithm I suspect it might be faster in practice than running something like BFS / Bellman Ford for each unit.
i have a lot of charts, each in a different JInternalFrame:
But the horizontal axis should be aligned to the same point(maybe the red line). The problem is, that the space for the label is set automatically by jFreechart.
So i tried to find a solution for multiline ticklabels. I found this:
int optionsCount = state.getStatusOptions().toArray().length;
String[] grade = new String[optionsCount + 1];
grade[0] = "";
for (int x = 1; x < optionsCount + 1; x++) {
//grade[x] ="blaa"+x;//state.getStatusOptions().get(x - 1);
//grade[x]="1.line\n2.line\n3.line";
grade[x] = newLineString(state.getStatusOptions().get(x - 1), 5);
}
// grade[1]="1.line\n2.line";
SymbolAxis rangeAxis;
rangeAxis = new SymbolAxis("", grade){
#Override
protected Rectangle2D getLabelEnclosure(Graphics2D g2, RectangleEdge edge) {
Rectangle2D l = super.getLabelEnclosure(g2, edge);
l.setRect(l.getX(),l.getY(),l.getWidth()*0.5,l.getHeight());
return l;
}
#Override
protected AxisState drawTickMarksAndLabels(Graphics2D g2, double cursor, Rectangle2D plotArea, Rectangle2D dataArea, RectangleEdge edge) {
AxisState state = new AxisState(cursor);
if (isAxisLineVisible()) {
drawAxisLine(g2, cursor, dataArea, edge);
}
double ol = getTickMarkOutsideLength();
double il = getTickMarkInsideLength();
List ticks = refreshTicks(g2, state, dataArea, edge);
state.setTicks(ticks);
g2.setFont(getTickLabelFont());
Iterator iterator = ticks.iterator();
// remember the max number of lines used in any label
int maxLinesUsed = 0;
while (iterator.hasNext()) {
ValueTick tick = (ValueTick) iterator.next();
if (isTickLabelsVisible()) {
g2.setPaint(getTickLabelPaint());
float[] anchorPoint = calculateAnchorPoint(tick, cursor, dataArea, edge);
g2.draw(plotArea);
g2.setPaint(Color.green);
g2.draw(dataArea);
g2.setPaint(getTickLabelPaint());
// split by "\n" and draw text in a new line for each result
String tickText = tick.getText();
int line = 1;
for (String tickTextLine : tickText.split("\n")) {
float x = anchorPoint[0];
// one row down...
float y = anchorPoint[1] + line * g2.getFont().getSize();
TextUtilities.drawRotatedString(tickTextLine, g2, x, y, tick.getTextAnchor(), tick.getAngle(), tick
.getRotationAnchor());
line++;
}
// if we used more lines than any time before remember it
if (line > maxLinesUsed) {
maxLinesUsed = line;
}
}
if (isTickMarksVisible() && tick.getTickType().equals(TickType.MAJOR)) {
float xx = (float) valueToJava2D(tick.getValue(), dataArea, edge);
Line2D mark = null;
g2.setStroke(getTickMarkStroke());
g2.setPaint(getTickMarkPaint());
if (edge == RectangleEdge.LEFT) {
mark = new Line2D.Double(cursor - ol, xx, cursor + il, xx);
} else if (edge == RectangleEdge.RIGHT) {
mark = new Line2D.Double(cursor + ol, xx, cursor - il, xx);
} else if (edge == RectangleEdge.TOP) {
mark = new Line2D.Double(xx, cursor - ol, xx, cursor + il);
} else if (edge == RectangleEdge.BOTTOM) {
mark = new Line2D.Double(xx, cursor + ol, xx, cursor - il);
}
g2.draw(mark);
}
}
// need to work out the space used by the tick labels...
// so we can update the cursor...
// patched using maxLinesUsed => we need more space because of multiple lines
double used = 0.0;
if (isTickLabelsVisible()) {
if (edge == RectangleEdge.LEFT) {
used += findMaximumTickLabelWidth(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
state.cursorLeft(used);
} else if (edge == RectangleEdge.RIGHT) {
used = findMaximumTickLabelWidth(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
state.cursorRight(used);
} else if (edge == RectangleEdge.TOP) {
used = findMaximumTickLabelHeight(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
state.cursorUp(used);
} else if (edge == RectangleEdge.BOTTOM) {
used = findMaximumTickLabelHeight(ticks, g2, plotArea, isVerticalTickLabels()) * maxLinesUsed;
state.cursorDown(used);
}
}
return state;
}
};
As you can see in the picture above, the new line function works, but the spacing for the labels does not work. I tried to override the getLabelEnclosure method, but its given string is just "".
Does anyone know a solution for my problem. Either the multiline or an other way to align the charts?
thanks!
Override the reserveSpace function and in the place where the height is calculated modify it with the number of rows you need:
Rectangle2D labelEnclosure = getLabelEnclosure(g2, edge);
if (RectangleEdge.isTopOrBottom(edge)) {
double labelHeight = labelEnclosure.getHeight();
space.add(labelHeight + **YOUR_NUMBER_OF_ROWS** * tickLabelHeight, edge);
} else if (RectangleEdge.isLeftOrRight(edge)) {
double labelWidth = labelEnclosure.getWidth();
space.add(labelWidth + tickLabelWidth, edge);
}
return space;
I try to use something like this in a WCF Service:
I have a Table with an offer with Latitude and Longitude. And the Position from the User. In the Query I need the Distance from the user to the offer, and order to this.
private double Distanze(double LAT1, double LON1, double LAT2, double LON2)
{
double e = (3.1415926538 * LAT1 / 180);
double f = (3.1415926538 * LON1 / 180);
double g = (3.1415926538 * LAT2 / 180);
double h = (3.1415926538 * LON2 / 180);
double i = (Math.Cos(e) * Math.Cos(g) *
Math.Cos(f) * Math.Cos(h) + Math.Cos(e) *
Math.Sin(f) * Math.Cos(g) * Math.Sin(h) +
Math.Sin(e) * Math.Sin(g));
double j = (Math.Acos(i));
double k = (6371 * j);
return k;
}
and in the query:
public IQueryable<V1_Off_Offert> Get_myOffert()
{
var User = GetCurrentPers_ID();
if (User != 0)
{
double lat = GetCurrentPOS().LAT;
double lon = GetCurrentPOS().LON;
var query = from c in this.ObjectContext.C1_OFF_OFFERT
where c.C1_PERS_PERSON_ID == User
select new V1_Off_Offert()
{
ID = c.ID,
//......
LAT = (double)c.C1_ORT_GEO.LAT,
LON = (double)c.C1_ORT_GEO.LON,
//This it dosnt Work
Distanz = (double)Distanze((double)c.C1_ORT_GEO.LAT, (double)c.C1_ORT_GEO.LON, lat, lon),
Radius = (double)c.DISTANZ
};
return query;
}
else return null;
}
Is there a way to realize this?
Okay, I see what the problem is. LINQ to SQL is trying to translate Distanze to SQL. It can't, so it dies. You need to do the projection after you've already executed the query on the database.
I Try this:
public IQueryable<V1_Off_Offert> Get_myOffert()
{
var User = GetCurrentPers_ID();
if (User != 0)
{
double lat = GetCurrentPOS().LAT;
double lon = GetCurrentPOS().LON;
var query = from c in this.ObjectContext.C1_OFF_OFFERT
where c.C1_PERS_PERSON_ID == User
select new V1_Off_Offert()
{
ID = c.ID,
Image = c.Image,
Start_Datum = c.VON,
End_Datum = c.BIS,
Name = c.C1_KEY_WORT.WORT,
Text = c.TEXT,
Preis = (decimal)c.PREIS != 0 ? (decimal)c.PREIS : 0,
WORT = c.C1_GRUP_GRUPPE.C1_KEY_WORT.WORT,
PERS_ID = (int)c.C1_PERS_PERSON_ID,
//COM_ID = (int)c.C1_COM_COMP_ID,
EH_ID = c.C1_OFF_EINHEIT_ID,
LAT = (double)c.C1_ORT_GEO.LAT,
LON = (double)c.C1_ORT_GEO.LON,
//Distanz = (double)Distanze((double)c.C1_ORT_GEO.LAT, (double)c.C1_ORT_GEO.LON, lat, lon),
Radius = (double)c.DISTANZ
//LAT = c.C1_ORT_GEO.LAT != null ? (double)c.C1_ORT_GEO.LAT : 0
};
foreach (V1_Off_Offert T in query)
{
T.Distanz = Distanze(T.LAT, T.LON, lat, lon);
}
return query;
}
else return null;
}
this Works:
foreach (V1_Off_Offert T in query)
{
T.Distanz = Distanze(T.LAT, T.LON, lat, lon);
}
Is there a way to use the first Way
maybe as lambda expression.
but it is not so elegant to put the Result of the foreach in to the query!!!