package com.nutiteq.components;
import com.nutiteq.utils.Utils;
/**
* Implements a projected position on a map as a set of 3 numbers: (x,y)
* projected pixel coordinates, (zoom) zoom level.
*/
public class MapPos {
private int x;
private int y;
private int zoom;
/**
* Constructor for MapPos.
*
* @param x
* x coordinate
* @param y
* y coordinate
* @param zoom
* zoom
*/
public MapPos(final int x, final int y, final int zoom) {
this.x = x;
this.y = y;
this.zoom = zoom;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZoom() {
return zoom;
}
public void setX(final int x) {
this.x = x;
}
public void setY(final int y) {
this.y = y;
}
public void setZoom(final int zoom) {
this.zoom = zoom;
}
/**
* Not part of public API Check if an image bounded by left, top, right,
* bottom can be displayed.
*
* @param x
* top-left corner
* @param y
* top-left corner
* @param width
* image width
* @param height
* image height
* @return true if visible, false otherwise
*/
public static boolean checkBounds(final int x, final int y, final int width, final int height,
final int screenWidth, final int screenHeight) {
return !(x < -width || y < -height || x >= screenWidth || y >= screenHeight);
}
/**
* Not part of public API Create a copy of this object.
*
* @return the newly created copy
*/
public MapPos copy() {
return new MapPos(x, y, zoom);
}
/**
* Equals only compares x, y, zoom.
*
* @param o
* other map pos object
* @return true if equal, false otherwise
*/
public boolean equals(final Object o) {
if (o == null || !(o instanceof MapPos)) {
return false;
}
final MapPos other = (MapPos) o;
return x == other.x && y == other.y && zoom == other.zoom;
}
public int hashCode() {
throw new RuntimeException("hashcode() has not been implemented!");
}
/**
* Not part of public API
*/
public boolean isVisible(final MapPos middlePoint, final int displayCenterX,
final int displayCenterY) {
return Utils.rectanglesIntersect(x, y, 1, 1, middlePoint.x - displayCenterX, middlePoint.y
- displayCenterY, displayCenterX * 2, displayCenterY * 2);
}
/**
* Not part of public API
*/
public int distanceInPixels(final MapPos pos) {
return distanceFromPointInPixels(pos.x, pos.y);
}
private int distanceFromPointInPixels(final int otherX, final int otherY) {
// TODO jaanus : check this
final int distanceX = Math.abs(x - otherX);
final int distanceY = Math.abs(y - otherY);
return (int) Math.floor(Math.sqrt(distanceX * distanceX + distanceY * distanceY));
}
public int distanceFromLineInPixels(final int x1, final int y1, final int x2, final int y2) {
if (x1 == x2 && y1 == y2) {
return distanceFromPointInPixels(x1, y1);
}
//http://www.ahristov.com/tutorial/geometry-games/point-line-distance.html
final double normalLength = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
return (int) Math.floor(Math.abs((x - x1) * (y2 - y1) - (y - y1) * (x2 - x1)) / normalLength);
//from http://stackoverflow.com/questions/910882/how-can-i-tell-if-a-point-is-nearby-a-certain-line
// return (int) Math.floor(Math.abs((x2 - x1) * (y1 - y) - (x1 - x) * (y2 - y1))
// / Math.sqrt(Float11.pow(x2 - x1, 2) + Float11.pow(y2 - y1, 2)));
//http://www.ocforums.com/archive/index.php/t-421519.html
// final int width = Math.abs(x2 - x1);
// final int height = Math.abs(y2 - y1);
// final int dx = x - x1;
// final int dy = y - y1;
// int distance;
//
// if (dx != 0 && width != 0) // if both lines are not vertical
// {
// final double angleToCorner = Math.atan(height / width);
// final double angleToPoint = Math.atan(dy / dx);
// distance = (int) Math.floor(Math.sqrt(dx * dx + dy * dy)
// * Math.sin(Math.abs(angleToCorner - angleToPoint)));
// } else // one or both slopes have zero divisor (are vertical)
// {
// distance = Math.abs(dx);
// }
//
// return distance;
}
public int distanceFromLineInPixels(final Point pOne, final Point pTwo) {
return distanceFromLineInPixels(pOne.getX(), pOne.getY(), pTwo.getX(), pTwo.getY());
}
public String toString() {
return new StringBuffer("map_pos:").append(x).append(":").append(y).append(":").append(zoom)
.toString();
}
}