package com.ericsson.tic.vi; import java.lang.Cloneable; /** * A node in a graph which is mapped onto a plane or onto a sphere/globe. * * @author Sami Matilainen * @version 1.0 (2008-12-04) */ public class GraphNode extends Pickable implements Cloneable { /** A unique identifier for this node. */ public int id; /** The type of this node. */ public NodeType type; /** Color as a 3f value (RGB) */ public float[] colorf; /** Current coordinate. */ public float x, y, z; /** A label associated with this node. */ public Label label; /** Planar Coordinate (default -2 <= x < 2) */ public float xPlanar; /** Planar Coordinate (default -1 <= y < 1) */ public float yPlanar; /** Planar Coordinate (default z = 0.0) */ public float zPlanar; /** User Planar Coordinate (default -2 <= x < 2) */ public float xUser; /** User Planar Coordinate (default -1 <= y < 1) */ public float yUser; /** User Planar Coordinate (default z = 0.0) */ public float zUser; /** Texture coordinate (should correspond to planar coordinate) */ public float xTex, yTex; /** Longitutude in degrees. */ public float lon; /** Latitude in degrees. */ public float lat; /** Radius of globe. */ public float rad; /** The travel-target of this node. */ private float xTarget, yTarget, zTarget; /** The speed of this node. */ public float speed; /** The speed of this node. */ private float xSpeed, ySpeed, zSpeed; /** The weight of this node (used for calculating tention between nodes) */ private float weight; /** Indicates wheter this node is expanded or not. */ public boolean expanded; public String title; /** * Creates a node at coordinate 0, 0, 0 (on the map) * Which corresponds to a longitude latitude position of * 0 degrees lat, 0 degrees long. * * @param id the id of this node. * @param type the type of this node. */ public GraphNode(int id, NodeType type, String title) { this.id = id; this.type = type; this.title = title; this.expanded = false; this.colorf = new float[3]; this.colorf[0] = 1.0f; this.colorf[1] = 1.0f; this.colorf[2] = 1.0f; this.x = 0.0f; this.y = 0.0f; this.z = 0.0f; this.xPlanar = 0.0f; this.yPlanar = 0.0f; this.zPlanar = 0.0f; this.xTarget = 0.0f; this.yTarget = 0.0f; this.zTarget = 0.0f; this.weight = 1.0f; this.rad = 1.0f; this.xUser = 0.0f; this.yUser = 0.0f; this.zUser = 0.0f; textureFromPlanar(); sphericalFromPlanar(); setSpeedVector(0.1f); this.label = new Label(id, title); this.label.xPlane = this.xPlanar * 1.5f; this.label.yPlane = this.yPlanar * 1.5f; this.label.zPlane = this.label.id * 0.002f; float[] temp = sphericalAsCarteesian(); this.label.xGlobe = temp[0] * 1.7f; this.label.yGlobe = temp[1] * 2.0f; this.label.zGlobe = temp[2] * 1.7f; this.label.x = this.label.xPlane; this.label.y = this.label.yPlane; this.label.z = this.label.zPlane; } /** * Creates a node at coordinate x, y, z (on the map) * * @param id the id of this node. * @param type the type of this node. * @param title The Title of the node. * @param x The x-coordinate. [-2 < x < 2] * @param y The y-coordinate. [-1 < y < 1] * @param z The z-coordinate should be 0 */ public GraphNode(int id, NodeType type, String title, float x, float y, float z) { this.id = id; this.type = type; this.title = title; this.expanded = false; this.colorf = new float[3]; this.colorf[0] = 1.0f; this.colorf[1] = 1.0f; this.colorf[2] = 1.0f; this.x = x; this.y = y; this.z = z; this.xPlanar = x; this.yPlanar = y; this.zPlanar = z; this.xTarget = x; this.yTarget = y; this.zTarget = z; this.weight = 1.0f; this.rad = 1.0f; this.xUser = x; this.yUser = y; this.zUser = z; textureFromPlanar(); sphericalFromPlanar(); setSpeedVector(0.1f); this.label = new Label(id, title); this.label.xPlane = this.xPlanar * 1.5f; this.label.yPlane = this.yPlanar * 1.5f; this.label.zPlane = this.label.id * 0.002f; float[] temp = sphericalAsCarteesian(); this.label.xGlobe = temp[0] * 1.7f; this.label.yGlobe = temp[1] * 2.0f; this.label.zGlobe = temp[2] * 1.7f; this.label.x = this.label.xPlane; this.label.y = this.label.yPlane; this.label.z = this.label.zPlane; } /** * Sets the user coordinates. * * @param xUser The x coordinate. * @param yUser The y coordinate. * @param zUser The z coordinate. */ public void setUser(float xUser, float yUser, float zUser) { this.xUser = xUser; this.yUser = yUser; this.zUser = zUser; } /** * Sets the coordinates of the node by using planar coordinates. * * @param xPlanar The x coordinate. * @param yPlanar The y coordinate. * @param zPlanar The z coordinate. */ public void setPlanar(float xPlanar, float yPlanar, float zPlanar) { this.xPlanar = xPlanar; this.yPlanar = yPlanar; this.zPlanar = zPlanar; sphericalFromPlanar(); textureFromPlanar(); } /** * Sets the coordinates of the node by using spherical coordinates. * * @param lon The longitude. * @param lat The latitude. * @param rad The radious of the Sphere/Globe/Earth.. */ public void setSpherical(float lon, float lat, float rad) { this.lon = lon; this.lat = lat; this.rad = rad; planarFromSpherical(); textureFromPlanar(); } /** * Sets the planar coordinates from the spherical coordinates. */ private void planarFromSpherical() { this.x = this.lon / 90.0f; this.y = (float)Math.sin(this.lat * (Math.PI/180.0f)); // this.z = this.z; // should not change print(); } /** * Sets the spherical coordinates from the planar coordinates. */ private void sphericalFromPlanar() { this.lon = this.x * 90.0f; // this step is neccesary since openGL does not // wrap the texture cylindrically as one would assume! float temp = (float)Math.sin(this.y*Math.PI/2); this.lat = (float)(Math.asin(temp)) * (float)(180.0f/Math.PI); // this.rad = this.rad; // should not change } /** * Sets the texture coordinates from the planar coordinates. */ private void textureFromPlanar() { this.xTex = (int)(this.x * 512.0f + 2 * 512.0f); this.yTex = (int)(this.y * 512.0f + 512.0f); } /** * Sets the planar coordinates from the texture coordinates. */ private void planarFromTexture() { this.x = (1.0f / 512.0f) * ((float)xTex - 2 * 512.0f); this.y = (1.0f / 512.0f) * ((float)yTex - 2 * 512.0f); } /** * Set the speed of this node. * * @param speed The speed. */ public void setSpeed(float speed) { this.speed = speed; } /** * Set the speedvector. * * @param speed The speed. */ public void setSpeedVector(float speed) { setSpeed(speed); setSpeedVector(); } /** * Set the speedvector. */ private void setSpeedVector() { float xVec = xTarget - x; float yVec = yTarget - y; float zVec = zTarget - z; float norm = (float)Math.sqrt(xVec*xVec + yVec*yVec + zVec*zVec); if (norm == 0) { xSpeed = 0.0f; ySpeed = 0.0f; zSpeed = 0.0f; return; } xSpeed = (xVec/norm) * speed; ySpeed = (yVec/norm) * speed; zSpeed = (zVec/norm) * speed; } /** * Sets the traveling target of this node. * * @param xTarget The x coordinate of the target. * @param yTarget The y coordinate of the target. * @param zTarget The z coordinate of the target. */ public void setTarget(float xTarget, float yTarget, float zTarget) { this.xTarget = xTarget; this.yTarget = yTarget; this.zTarget = zTarget; setSpeedVector(); } /** * Sets the target on the globe surface. */ public void setTargetOnGlobe() { this.xTarget = this.rad * (float)Math.cos((this.lat) * (Math.PI/180.0f)) * (float)Math.sin((this.lon) * (Math.PI/180.0f)); this.yTarget = this.rad * (float)Math.sin((this.lat) * (Math.PI/180.0f)); this.zTarget = this.rad * (float)Math.cos((this.lat) * (Math.PI/180.0f)) * (float)Math.cos((this.lon) * (Math.PI/180.0f)); setSpeedVector(); } /** * Sets the target on the plane. */ public void setTargetOnPlane() { this.xTarget = this.xPlanar; this.yTarget = this.yPlanar; this.zTarget = this.zPlanar; setSpeedVector(); } /** * Return carteesian coordinates from spherical once. * * @return A triple of carteesian coordinates. (x, y, z) */ public float[] sphericalAsCarteesian() { float[] ret = new float[3]; ret[0] = this.rad * (float)Math.cos((this.lat) * (Math.PI/180.0f)) * (float)Math.sin((this.lon) * (Math.PI/180.0f)); ret[1] = this.rad * (float)Math.sin((this.lat) * (Math.PI/180.0f)); ret[2] = this.rad * (float)Math.cos((this.lat) * (Math.PI/180.0f)) * (float)Math.cos((this.lon) * (Math.PI/180.0f)); return ret; } /** * Take a step towards the target. * How long the step is depends on the speed. */ public void moveTowardsTarget() { if (x == xTarget && y == yTarget && z == zTarget) { return; } float xTemp = x + xSpeed; float yTemp = y + ySpeed; float zTemp = z + zSpeed; if ((xSpeed > 0 && xTemp > xTarget) || (xSpeed < 0 && xTemp < xTarget)) { x = xTarget; } else { x = xTemp; } if ((ySpeed > 0 && yTemp > yTarget) || (ySpeed < 0 && yTemp < yTarget)) { y = yTarget; } else { y = yTemp; } if ((zSpeed > 0 && zTemp > zTarget) || (zSpeed < 0 && zTemp < zTarget)) { z = zTarget; } else { z = zTemp; } } /** * Stops moving. */ public void stopMoving() { xTarget = x; yTarget = y; zTarget = z; } /** * Print out some of the more important attributes. For debugging. */ public void print() { System.out.println(" lon: " + lon); System.out.println(" lat: " + lat); System.out.println(" rad: " + rad); System.out.println("xPlanar: " + xPlanar); System.out.println("yPlanar: " + yPlanar); System.out.println("zPlanar: " + zPlanar); System.out.println(" x: " + x); System.out.println(" y: " + y); System.out.println(" z: " + z); System.out.println("xTarget: " + xTarget); System.out.println("yTarget: " + yTarget); System.out.println("zTarget: " + zTarget); System.out.println(" type: " + type.name); System.out.println("----------------------"); } /** * Clones this graph node. */ public Object clone() throws CloneNotSupportedException { GraphNode clone = (GraphNode)super.clone(); clone.label = (Label)this.label.clone(); return clone; } }