package com.ericsson.tic.vi; import java.lang.Cloneable; /** * Keeps track of relationships between nodes. * * @author Sami Matilainen * @version 1.0 (2008-12-04) */ public class GraphNodeRel implements Cloneable { /** Node a. Node a and b define the relationship. */ public GraphNode a; /** Node b. Node a and b define the relationship. */ public GraphNode b; /** A set of coordinates which defines the control point for node a on the globe. Note: curved lines. */ public float[] globeCurvedControlPointA; /** A set of coordinates which defines the control point for node b on the globe. Note: curved lines. */ public float[] globeCurvedControlPointB; /** A set of coordinates which defines the control point for node a on the globe. Note: straight lines. */ public float[] globeStraightControlPointA; /** A set of coordinates which defines the control point for node b on the globe. Note: straight lines. */ public float[] globeStraightControlPointB; /** A set of coordinates which defines the control point for node a on the plane. Note: straight lines. */ public float[] planeControlPointA; /** A set of coordinates which defines the control point for node b on the plane. Note: straight lines. */ public float[] planeControlPointB; /** The control point for node a. */ public float[] controlPointA; /** The control point for node b. */ public float[] controlPointB; /** A target for control point a. */ public float[] controlTargetA; /** A target for control point b. */ public float[] controlTargetB; /** A speed vector for a. */ public float[] speedA; /** A speed vector for b. */ public float[] speedB; /** The speed. */ public float speed; /** The id of this relation. */ public int id; /** * Create a graph node relationship. * * @param id The id of this relationship. * @param a The first node of the relationship. * @param b The second node of the relationship. */ public GraphNodeRel(int id, GraphNode a, GraphNode b) { this.id = id; this.a = a; this.b = b; this.speed = 0.1f; this.speedA = new float[3]; this.speedB = new float[3]; this.speedA[0] = 0.0f; this.speedA[1] = 0.0f; this.speedA[2] = 0.0f; this.speedB[0] = 0.0f; this.speedB[1] = 0.0f; this.speedB[2] = 0.0f; this.controlTargetA = new float[3]; this.controlTargetB = new float[3]; this.controlTargetA[0] = 0.0f; this.controlTargetA[1] = 0.0f; this.controlTargetA[2] = 0.0f; this.controlTargetB[0] = 0.0f; this.controlTargetB[1] = 0.0f; this.controlTargetB[2] = 0.0f; } /** * Creates control points for the bezier curves. * Even straight lines have control points. */ public void createControlPoints() { // naming convention: // XY is a vector pointing from X to Y // example: AB is a vector from (a1, a2, a3) to (b1, b2, b3) // example: 0B is a vector pointing from Origin (0,0,0) to B // example: AB0A is the combined vector from the AB+0A operation float[] globeTargetA = a.sphericalAsCarteesian(); float[] globeTargetB = b.sphericalAsCarteesian(); float[] planeTargetA = {a.xPlanar, a.yPlanar, a.zPlanar}; float[] planeTargetB = {b.xPlanar, b.yPlanar, b.zPlanar}; float[] globeABVector = { globeTargetB[0] - globeTargetA[0], globeTargetB[1] - globeTargetA[1], globeTargetB[2] - globeTargetA[2] }; float[] globeBAVector = { globeTargetA[0] - globeTargetB[0], globeTargetA[1] - globeTargetB[1], globeTargetA[2] - globeTargetB[2] }; float[] planeABVector = { planeTargetB[0] - planeTargetA[0], planeTargetB[1] - planeTargetA[1], planeTargetB[2] - planeTargetA[2] }; float[] planeBAVector = { planeTargetA[0] - planeTargetB[0], planeTargetA[1] - planeTargetB[1], planeTargetA[2] - planeTargetB[2] }; float[] globe0AVector = globeTargetA; float[] globe0BVector = globeTargetB; float normAB = (float)Math.sqrt(globeABVector[0]*globeABVector[0] + globeABVector[1]*globeABVector[1] + globeABVector[2]*globeABVector[2]); float[] AB0A = new float[3]; float[] BA0B = new float[3]; // the following assumes no nodes exist on the poles! AB0A[0] = (normAB * 0.5f) * globeABVector[0] + (normAB * 0.9f) * globe0AVector[0]; AB0A[1] = (normAB * 0.5f) * globeABVector[1] + (normAB * 0.9f) * globe0AVector[1]; AB0A[2] = (normAB * 0.5f) * globeABVector[2] + (normAB * 0.9f) * globe0AVector[2]; BA0B[0] = (normAB * 0.5f) * globeBAVector[0] + (normAB * 0.9f) * globe0BVector[0]; BA0B[1] = (normAB * 0.5f) * globeBAVector[1] + (normAB * 0.9f) * globe0BVector[1]; BA0B[2] = (normAB * 0.5f) * globeBAVector[2] + (normAB * 0.9f) * globe0BVector[2]; globeCurvedControlPointA = new float[3]; globeCurvedControlPointA[0] = globeTargetA[0] + AB0A[0]; globeCurvedControlPointA[1] = globeTargetA[1] + AB0A[1]; globeCurvedControlPointA[2] = globeTargetA[2] + AB0A[2]; globeCurvedControlPointB = new float[3]; globeCurvedControlPointB[0] = globeTargetB[0] + BA0B[0]; globeCurvedControlPointB[1] = globeTargetB[1] + BA0B[1]; globeCurvedControlPointB[2] = globeTargetB[2] + BA0B[2]; globeStraightControlPointA = new float[3]; globeStraightControlPointA[0] = globeTargetA[0] + 0.5f * globeABVector[0]; globeStraightControlPointA[1] = globeTargetA[1] + 0.5f * globeABVector[1]; globeStraightControlPointA[2] = globeTargetA[2] + 0.5f * globeABVector[2]; globeStraightControlPointB = new float[3]; globeStraightControlPointB[0] = globeTargetB[0] + 0.5f * globeBAVector[0]; globeStraightControlPointB[1] = globeTargetB[1] + 0.5f * globeBAVector[1]; globeStraightControlPointB[2] = globeTargetB[2] + 0.5f * globeBAVector[2]; planeControlPointA = new float[3]; planeControlPointA[0] = planeTargetA[0] + 0.5f * planeABVector[0]; planeControlPointA[1] = planeTargetA[1] + 0.5f * planeABVector[1]; planeControlPointA[2] = planeTargetA[2] + 0.5f * planeABVector[2]; planeControlPointB = new float[3]; planeControlPointB[0] = planeTargetB[0] + 0.5f * planeBAVector[0]; planeControlPointB[1] = planeTargetB[1] + 0.5f * planeBAVector[1]; planeControlPointB[2] = planeTargetB[2] + 0.5f * planeBAVector[2]; controlPointA = new float[3]; controlPointB = new float[4]; controlPointA[0] = globeCurvedControlPointA[0]; controlPointA[1] = globeCurvedControlPointA[1]; controlPointA[2] = globeCurvedControlPointA[2]; controlPointB[0] = globeCurvedControlPointB[0]; controlPointB[1] = globeCurvedControlPointB[1]; controlPointB[2] = globeCurvedControlPointB[2]; setTargetsOnPlane(); } /** * Make the control points move towards their target destinations. */ public void moveTowardsTargets() { if (controlPointA[0] == controlTargetA[0] && controlPointA[1] == controlTargetA[1] && controlPointA[2] == controlTargetA[2]) { // do nothing } else { float xTemp = controlPointA[0] + speedA[0]; float yTemp = controlPointA[1] + speedA[1]; float zTemp = controlPointA[2] + speedA[2]; if ((speedA[0] > 0 && xTemp > controlTargetA[0]) || (speedA[0] < 0 && xTemp < controlTargetA[0])) { controlPointA[0] = controlTargetA[0]; } else { controlPointA[0] = xTemp; } if ((speedA[1] > 0 && yTemp > controlTargetA[1]) || (speedA[1] < 0 && yTemp < controlTargetA[1])) { controlPointA[1] = controlTargetA[1]; } else { controlPointA[1] = yTemp; } if ((speedA[2] > 0 && zTemp > controlTargetA[2]) || (speedA[2] < 0 && zTemp < controlTargetA[2])) { controlPointA[2] = controlTargetA[2]; } else { controlPointA[2] = zTemp; } } if (controlPointB[0] == controlTargetB[0] && controlPointB[1] == controlTargetB[1] && controlPointB[2] == controlTargetB[2]) { // do nothing } else { float xTemp = controlPointB[0] + speedB[0]; float yTemp = controlPointB[1] + speedB[1]; float zTemp = controlPointB[2] + speedB[2]; if ((speedB[0] > 0 && xTemp > controlTargetB[0]) || (speedB[0] < 0 && xTemp < controlTargetB[0])) { controlPointB[0] = controlTargetB[0]; } else { controlPointB[0] = xTemp; } if ((speedB[1] > 0 && yTemp > controlTargetB[1]) || (speedB[1] < 0 && yTemp < controlTargetB[1])) { controlPointB[1] = controlTargetB[1]; } else { controlPointB[1] = yTemp; } if ((speedB[2] > 0 && zTemp > controlTargetB[2]) || (speedB[2] < 0 && zTemp < controlTargetB[2])) { controlPointB[2] = controlTargetB[2]; } else { controlPointB[2] = zTemp; } } } /** * Set the movements speed of the control points. */ private void setSpeedVectors() { float xVec = controlTargetA[0] - controlPointA[0]; float yVec = controlTargetA[1] - controlPointA[1]; float zVec = controlTargetA[2] - controlPointA[2]; float norm = (float)Math.sqrt(xVec*xVec + yVec*yVec + zVec*zVec); if (norm == 0) { speedA[0] = 0.0f; speedA[1] = 0.0f; speedA[2] = 0.0f; return; } speedA[0] = (xVec/norm) * speed; speedA[1] = (yVec/norm) * speed; speedA[2] = (zVec/norm) * speed; xVec = controlTargetB[0] - controlPointB[0]; yVec = controlTargetB[1] - controlPointB[1]; zVec = controlTargetB[2] - controlPointB[2]; norm = (float)Math.sqrt(xVec*xVec + yVec*yVec + zVec*zVec); if (norm == 0) { speedB[0] = 0.0f; speedB[1] = 0.0f; speedB[2] = 0.0f; return; } speedB[0] = (xVec/norm) * speed; speedB[1] = (yVec/norm) * speed; speedB[2] = (zVec/norm) * speed; } /** * Set the target on the plane. */ public void setTargetsOnPlane() { controlTargetA[0] = planeControlPointA[0]; controlTargetA[1] = planeControlPointA[1]; controlTargetA[2] = planeControlPointA[2]; controlTargetB[0] = planeControlPointB[0]; controlTargetB[1] = planeControlPointB[1]; controlTargetB[2] = planeControlPointB[2]; setSpeedVectors(); } /** * Set the target on the globe using curved lines. */ public void setTargetsOnGlobeCurved() { controlTargetA[0] = globeCurvedControlPointA[0]; controlTargetA[1] = globeCurvedControlPointA[1]; controlTargetA[2] = globeCurvedControlPointA[2]; controlTargetB[0] = globeCurvedControlPointB[0]; controlTargetB[1] = globeCurvedControlPointB[1]; controlTargetB[2] = globeCurvedControlPointB[2]; setSpeedVectors(); } /** * Set the target on the globe using straight lines. */ public void setTargetsOnGlobeStraight() { controlTargetA[0] = globeStraightControlPointA[0]; controlTargetA[1] = globeStraightControlPointA[1]; controlTargetA[2] = globeStraightControlPointA[2]; controlTargetB[0] = globeStraightControlPointB[0]; controlTargetB[1] = globeStraightControlPointB[1]; controlTargetB[2] = globeStraightControlPointB[2]; setSpeedVectors(); } /** * Clones this GraphNodeRel object. */ public Object clone() throws CloneNotSupportedException { GraphNodeRel clone = (GraphNodeRel)super.clone(); clone.a = (GraphNode)this.a.clone(); clone.b = (GraphNode)this.b.clone(); clone.globeCurvedControlPointA = (float[])this.globeCurvedControlPointA.clone(); clone.globeCurvedControlPointB = (float[])this.globeCurvedControlPointB.clone(); clone.globeStraightControlPointA = (float[])this.globeStraightControlPointA.clone(); clone.globeStraightControlPointB = (float[])this.globeStraightControlPointB.clone(); clone.planeControlPointA = (float[])this.planeControlPointA.clone(); clone.planeControlPointB = (float[])this.planeControlPointB.clone(); clone.globeCurvedControlPointA = (float[])this.globeCurvedControlPointA.clone(); clone.globeCurvedControlPointA = (float[])this.globeCurvedControlPointA.clone(); clone.controlPointA = (float[])this.controlPointA.clone(); clone.controlPointB = (float[])this.controlPointB.clone(); clone.controlTargetA = (float[])this.controlTargetA.clone(); clone.controlTargetB = (float[])this.controlTargetB.clone(); clone.speedA = (float[])this.speedA.clone(); clone.speedB = (float[])this.speedB.clone(); return clone; } /** * Print out some of the more important attributes. For debugging. */ public void print() { System.out.println(a.type.name + " " + a.id + " -- " + b.type.name + " " + b.id); } }