Author: paperwing
Date: 2011-06-29 07:21:33 -0700 (Wed, 29 Jun 2011)
New Revision: 25973
Modified:
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Graphics.java
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Vector3.java
Log:
added curved edges implementation, added basic support for having more than 1
edge between the same pair of nodes, NaN issue with edges needs to be fixed
Modified:
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Graphics.java
===================================================================
---
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Graphics.java
2011-06-29 02:49:11 UTC (rev 25972)
+++
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Graphics.java
2011-06-29 14:21:33 UTC (rev 25973)
@@ -7,6 +7,7 @@
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.Set;
+import java.util.TreeMap;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
@@ -34,6 +35,10 @@
private static final float SMALL_SPHERE_RADIUS = 0.102f; // 0.015f
private static final float EDGE_RADIUS = 0.018f;
+ private static final float EDGE_CURVE_DISTANCE = 0.7f;
+ private static final float EDGE_CURVE_FACTOR = 0.31f;
+ private static final int EDGES_PER_RADIUS = 3;
+
/*
* This value controls distance scaling when converting from node
* coordinates to drawing coordinates
@@ -68,7 +73,7 @@
private int nodeListIndex;
private int edgeListIndex;
-
+
private long startTime;
private long endTime;
private int framesElapsed = 0;
@@ -182,6 +187,9 @@
double frameRate = framesElapsed / duration;
System.out.println("Average fps over " +
duration + " seconds: "
+ frameRate);
+
+ startTime = System.nanoTime();
+ framesElapsed = 0;
}
if (pressed.contains(KeyEvent.VK_C)) {
@@ -323,11 +331,11 @@
}
if (held.contains(KeyEvent.VK_W)) {
- camera.moveForward();
+ camera.moveUp();
}
if (held.contains(KeyEvent.VK_S)) {
- camera.moveBackward();
+ camera.moveDown();
}
if (held.contains(KeyEvent.VK_A)) {
@@ -339,11 +347,11 @@
}
if (held.contains(KeyEvent.VK_Q)) {
- camera.moveDown();
+ camera.moveBackward();
}
if (held.contains(KeyEvent.VK_E)) {
- camera.moveUp();
+ camera.moveForward();
}
keys.update();
@@ -570,6 +578,182 @@
View<CyNode> sourceView;
View<CyNode> targetView;
+ int nodeCount = networkView.getModel().getNodeCount();
+
+ int sourceIndex;
+ int targetIndex;
+
+ // A unique identifier (as far as this method is concerned) for
each pair of nodes
+ long pairIdentifier;
+
+ TreeMap<Long, Integer> pairs = new TreeMap<Long, Integer>();
+
+ // Points 0 and 2 represent endpoints of the quadratic Bezier
curve, while
+ // point 1 represents the approach point
+ Vector3 p0 = new Vector3();
+ Vector3 p1 = new Vector3();
+ Vector3 p2 = new Vector3();
+
+ Vector3 p1Offset;
+ Vector3 direction;
+
+ for (View<CyEdge> edgeView : networkView.getEdgeViews()) {
+
+ sourceView =
networkView.getNodeView(edgeView.getModel().getSource());
+ targetView =
networkView.getNodeView(edgeView.getModel().getTarget());
+ sourceIndex = sourceView.getModel().getIndex();
+ targetIndex = targetView.getModel().getIndex();
+
+ // These indices rely on CyNode's guarantee that
NodeIndex < NumOfNodes
+ assert sourceIndex < nodeCount;
+ assert targetIndex < nodeCount;
+
+ // Identify this pair of nodes so we'll know if we've
drawn an edge between them before
+ if (sourceIndex > targetIndex) {
+ pairIdentifier = nodeCount * targetIndex +
targetIndex;
+ } else {
+ pairIdentifier = nodeCount * sourceIndex +
sourceIndex;
+ }
+
+ // Have we visited an edge between these nodes before?
+ if (pairs.containsKey(pairIdentifier)) {
+ pairs.put(pairIdentifier,
pairs.get(pairIdentifier) + 1);
+ } else {
+ pairs.put(pairIdentifier, 1);
+ }
+
+ // Find p0, p1, p2 for the Bezier curve
+
p0.set(sourceView.getVisualProperty(RichVisualLexicon.NODE_X_LOCATION),
+
sourceView.getVisualProperty(RichVisualLexicon.NODE_Y_LOCATION),
+
sourceView.getVisualProperty(RichVisualLexicon.NODE_Z_LOCATION));
+ p0.divideLocal(DISTANCE_SCALE);
+
+
p2.set(targetView.getVisualProperty(RichVisualLexicon.NODE_X_LOCATION),
+
targetView.getVisualProperty(RichVisualLexicon.NODE_Y_LOCATION),
+
targetView.getVisualProperty(RichVisualLexicon.NODE_Z_LOCATION));
+ p2.divideLocal(DISTANCE_SCALE);
+
+ p1 = p0.add(p2);
+ p1.divideLocal(2);
+
+ direction = p2.subtract(p0);
+ p1Offset = direction.cross(0, 1, 0);
+ p1Offset.normalizeLocal();
+ p1Offset.multiplyLocal(EDGE_CURVE_FACTOR *
Math.sqrt(direction.magnitude()));
+
+ p1.addLocal(p1Offset);
+ p1.rotate(direction, 2 * Math.PI *
(pairs.get(pairIdentifier) - 1) / EDGES_PER_RADIUS);
+
+ drawQuadraticEdge(gl, p0, p1, p2, 5);
+ }
+ }
+
+ private void drawQuadraticEdge(GL2 gl, Vector3 p0, Vector3 p1, Vector3
p2, int numSegments) {
+ // Equation for Quadratic Bezier curve:
+ // B(t) = (1 - t)^2P0 + 2(1 - t)tP1 + t^2P2, t in [0, 1]
+
+ double parameter;
+
+ Vector3 current;
+ Vector3[] points = new Vector3[numSegments + 1];
+ double[] pointAngle = new double[numSegments + 1];
+
+ Vector3 lastDirection = null;
+ Vector3 currentDirection;
+
+ points[0] = new Vector3(p0);
+ for (int i = 1; i < numSegments; i++) {
+ // Obtain points along the Bezier curve
+ parameter = (double) i / numSegments;
+
+ current = p0.multiply(Math.pow(1 - parameter, 2));
+ current.addLocal(p1.multiply(2 * (1 - parameter) *
parameter));
+ current.addLocal(p2.multiply(parameter * parameter));
+
+ points[i] = new Vector3(current);
+
+ // Obtain the angle between the ith and (i - 1)th
segment, for i in the open interval (1, numSegments)
+ currentDirection = points[i].subtract(points[i - 1]);
+ if (lastDirection != null) {
+ // Note that this loop can only find the angle
at the (i - 1)th point
+ pointAngle[i - 1] =
lastDirection.angle(currentDirection);
+ }
+ lastDirection = currentDirection;
+ }
+
+ // Obtain the angle between the last 2 segments, if there is
more than 1 segment
+ if (numSegments > 1) {
+ pointAngle[numSegments - 1] =
p2.subtract(points[numSegments - 1]).angle(lastDirection);
+ }
+ points[numSegments] = new Vector3(p2);
+
+ double currentAngle;
+ double extend1 = 0;
+ double extend2;
+ Vector3 direction;
+ for (int i = 0; i < numSegments; i++) {
+ currentAngle = pointAngle[i + 1];
+
+ // currentAngle is likely calculated from an acos
operation
+ assert (!Double.isNaN(currentAngle));
+
+ // Extend by c * tan(theta/2)
+ extend2 = EDGE_RADIUS * Math.tan(currentAngle / 2);
+
+ // TODO: Find alternative
+ if (Double.isNaN(extend2)) {
+ extend2 = 0;
+ }
+
+// if (framesElapsed == 2) {
+// System.out.println("Segment: " + i);
+// System.out.println("Current segment angle: " +
currentAngle);
+// System.out.println("Current extend1: " +
extend1);
+// System.out.println("Current extend2: " +
extend2);
+// }
+
+ direction = points[i + 1].subtract(points[i]);
+ direction.normalizeLocal();
+ drawSingleEdge(gl,
+
points[i].subtract(direction.multiply(extend1)),
+ points[i +
1].add(direction.multiply(extend2)));
+
+// drawSingleEdge(gl,
+// points[i],
+// points[i + 1]);
+
+ extend1 = extend2;
+ }
+
+
+ }
+
+ private void drawQuadraticEdgeOld(GL2 gl, Vector3 p0, Vector3 p1,
Vector3 p2, int numSegments) {
+ // Equation for Quadratic Bezier curve:
+ // B(t) = (1 - t)^2P0 + 2(1 - t)tP1 + t^2P2, t in [0, 1]
+
+ double parameter;
+
+ Vector3 current = p0;
+ Vector3 next;
+
+ for (int i = 1; i < numSegments; i++) {
+ parameter = (double) i / numSegments;
+
+ next = p0.multiply(Math.pow(1 - parameter, 2));
+ next.addLocal(p1.multiply(2 * (1 - parameter) *
parameter));
+ next.addLocal(p2.multiply(parameter * parameter));
+
+ drawSingleEdge(gl, current, next);
+
+ current = next;
+ }
+ }
+
+ private void drawEdgesOld(GL2 gl) {
+ View<CyNode> sourceView;
+ View<CyNode> targetView;
+
float x1, x2, y1, y2, z1, z2;
for (View<CyEdge> edgeView : networkView.getEdgeViews()) {
@@ -585,48 +769,27 @@
y2 =
targetView.getVisualProperty(RichVisualLexicon.NODE_Y_LOCATION).floatValue() /
DISTANCE_SCALE;
z2 =
targetView.getVisualProperty(RichVisualLexicon.NODE_Z_LOCATION).floatValue() /
DISTANCE_SCALE;
- drawSingleEdge(gl, x1, y1, z1, x2, y2, z2);
+ // drawSingleEdge(gl, x1, y1, z1, x2, y2, z2);
}
-
- /*
- // gl.glColor3f(0.9f, 0.1f, 0.1f);
- for (int i = 0; i < EDGE_COUNT; i++) {
- gl.glTranslatef(edges[i].x, edges[i].y, edges[i].z);
- gl.glRotatef(edges[i].rotateAngle, edges[i].rotateAxisX,
- edges[i].rotateAxisY,
edges[i].rotateAxisZ);
- gl.glScalef(1.0f, 1.0f, edges[i].length);
- gl.glCallList(edgeListIndex);
- gl.glScalef(1.0f, 1.0f, 1.0f / edges[i].length);
- // glut.glutSolidCylinder(EDGE_RADIUS, edges[i].length,
- // EDGE_SLICES_DETAIL, EDGE_STACKS_DETAIL);
-
- // gl.glCallList(nodeListIndex);
- // Undo the transformation operations we performed above
- gl.glRotatef(-edges[i].rotateAngle,
edges[i].rotateAxisX,
- edges[i].rotateAxisY,
edges[i].rotateAxisZ);
- gl.glTranslatef(-edges[i].x, -edges[i].y, -edges[i].z);
- }
- */
}
- private void drawSingleEdge(GL2 gl, float x1, float y1, float z1, float
x2,
- float y2, float z2) {
+ private void drawSingleEdge(GL2 gl, Vector3 start, Vector3 end) {
gl.glPushMatrix();
- gl.glTranslatef(x1, y1, z1);
+ // TODO: Consider using a Vector3f object for just floats, to
use translatef instead of translated
+ gl.glTranslated(start.x(), start.y(), start.z());
Vector3 current = new Vector3(0, 0, 1);
- Vector3 direction = new Vector3(x2 - x1, y2 - y1, z2 - z1);
+ Vector3 direction = end.subtract(start);
Vector3 rotateAxis = current.cross(direction);
- // TODO: Consider using a Vector3f object for just floats
gl.glRotated(Math.toDegrees(direction.angle(current)),
rotateAxis.x(), rotateAxis.y(),
rotateAxis.z());
gl.glScalef(1.0f, 1.0f, (float) direction.magnitude());
gl.glCallList(edgeListIndex);
-
+
gl.glPopMatrix();
}
@@ -667,7 +830,7 @@
private void createDisplayLists(GL2 gl) {
nodeListIndex = gl.glGenLists(1);
edgeListIndex = gl.glGenLists(1);
-
+
GLUT glut = new GLUT();
GLU glu = new GLU();
@@ -685,8 +848,6 @@
gl.glNewList(edgeListIndex, GL2.GL_COMPILE);
glu.gluCylinder(quadric, EDGE_RADIUS, EDGE_RADIUS, 1.0,
EDGE_SLICES_DETAIL, EDGE_STACKS_DETAIL);
- // glut.glutSolidCylinder(EDGE_RADIUS, 1.0f, EDGE_SLICES_DETAIL,
- // EDGE_STACKS_DETAIL);
gl.glEndList();
}
Modified:
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Vector3.java
===================================================================
---
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Vector3.java
2011-06-29 02:49:11 UTC (rev 25972)
+++
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/Vector3.java
2011-06-29 14:21:33 UTC (rev 25973)
@@ -44,6 +44,10 @@
z = other.z;
}
+ public Vector3 add(Vector3 other) {
+ return new Vector3(x + other.x, y + other.y, z + other.z);
+ }
+
public void addLocal(Vector3 other) {
x += other.x;
y += other.y;
@@ -66,9 +70,16 @@
double lengthSquare = x * x + y * y + z * z;
double otherLengthSquare = other.x * other.x + other.y *
other.y + other.z * other.z;
- double angle = Math.acos((x * other.x + y * other.y + z *
other.z)/Math.sqrt(lengthSquare * otherLengthSquare));
+ // TODO: Check if alternative is needed to prevent NaN
+ double cosArgument = (x * other.x + y * other.y + z *
other.z)/Math.sqrt(lengthSquare * otherLengthSquare);
- return angle;
+ if (cosArgument >= 1) {
+ return 0;
+ } else if (cosArgument <= -1) {
+ return Math.PI;
+ } else {
+ return Math.acos(cosArgument);
+ }
}
public Vector3 cross(Vector3 other) {
@@ -76,6 +87,11 @@
z * other.x - x * other.z, x * other.y - y *
other.x);
}
+ public Vector3 cross(double x, double y, double z) {
+ return new Vector3(this.y * z - this.z * y,
+ this.z * x - this.x * z, this.x * y - this.y *
x);
+ }
+
public double dot(Vector3 other) {
return (x * other.x + y * other.y + z * other.z);
}
@@ -94,6 +110,12 @@
z = scalar * z;
}
+ public void divideLocal(double scalar) {
+ x = x / scalar;
+ y = y / scalar;
+ z = z / scalar;
+ }
+
public Vector3 normalize() {
double length = Math.sqrt(x * x + y * y + z * z);
if (length > Double.MIN_NORMAL) {
--
You received this message because you are subscribed to the Google Groups
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/cytoscape-cvs?hl=en.