Author: paperwing
Date: 2012-01-26 14:45:49 -0800 (Thu, 26 Jan 2012)
New Revision: 28123
Modified:
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/rendering/RenderArcEdgesProcedure.java
Log:
generalization of circular arc edge drawing into coordinate generation followed
by coordinate rendering completed, about to test implementation with regular
styled edges before using the coordinate data to draw dashed and dotted edges
Modified:
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/rendering/RenderArcEdgesProcedure.java
===================================================================
---
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/rendering/RenderArcEdgesProcedure.java
2012-01-26 21:26:27 UTC (rev 28122)
+++
csplugins/trunk/toronto/yuedong/paperwing-impl/src/main/java/org/cytoscape/paperwing/internal/rendering/RenderArcEdgesProcedure.java
2012-01-26 22:45:49 UTC (rev 28123)
@@ -15,6 +15,8 @@
import org.cytoscape.model.CyNode;
import org.cytoscape.paperwing.internal.data.GraphicsData;
import org.cytoscape.paperwing.internal.geometric.Vector3;
+import org.cytoscape.paperwing.internal.rendering.shapes.EdgeShapeDrawer;
+import
org.cytoscape.paperwing.internal.rendering.shapes.EdgeShapeDrawer.EdgeShapeType;
import org.cytoscape.paperwing.internal.tools.GeometryToolkit;
import org.cytoscape.paperwing.internal.tools.RenderColor;
import org.cytoscape.paperwing.internal.tools.RenderToolkit;
@@ -38,9 +40,12 @@
private static final RenderColor DEFAULT_HOVER_COLOR =
new RenderColor(0.5, 0.5, 0.7);
+ /**
+ * The number of straight segments used to approximate a curved edge
+ */
private static final int NUM_SEGMENTS = 11;
- private int segmentListIndex;
+ private EdgeShapeDrawer shapeDrawer;
// Container for EdgeView objects that also adds information about
whether the
// edge is part of a series of edges that connect the same pair of nodes
@@ -59,6 +64,10 @@
protected int totalCoincidentEdges;
}
+ public RenderArcEdgesProcedure() {
+ shapeDrawer = new EdgeShapeDrawer();
+ }
+
// Analyze the network to obtain whether each edge is connecting 2
nodes that
// are already connected by other nodes
// Maybe add an optimization so we only have to re-analyze the network
each time it changes?
@@ -73,10 +82,9 @@
Map<Long, Integer> pairCoincidenceCount = new HashMap<Long,
Integer>(
networkView.getModel().getNodeCount());
long identifier;
- int sourceIndex, targetIndex;
+ int sourceIndex, targetIndex, edgeNumber;
int nodeCount = networkView.getModel().getNodeCount();
CyEdge edge;
- int edgeNumber;
for (View<CyEdge> edgeView : networkView.getEdgeViews()) {
edge = edgeView.getModel();
@@ -115,33 +123,16 @@
return edgeViewContainers;
}
-
@Override
public void initialize(GraphicsData graphicsData) {
- GL2 gl = graphicsData.getGlContext();
-
- segmentListIndex = gl.glGenLists(1);
-
- GLU glu = GLU.createGLU(gl);
-
- GLUquadric segmentQuadric = glu.gluNewQuadric();
- glu.gluQuadricDrawStyle(segmentQuadric, GLU.GLU_FILL);
- glu.gluQuadricNormals(segmentQuadric, GLU.GLU_SMOOTH); // TODO:
Experiment
-
// with GLU_FLAT for
-
// efficiency
-
- gl.glNewList(segmentListIndex, GL2.GL_COMPILE);
- glu.gluCylinder(segmentQuadric, SEGMENT_RADIUS, SEGMENT_RADIUS,
1.0,
- SEGMENT_SLICES, SEGMENT_STACKS);
- gl.glEndList();
+ shapeDrawer.initialize(graphicsData.getGlContext());
}
@Override
public void execute(GraphicsData graphicsData) {
CyNetworkView networkView = graphicsData.getNetworkView();
GL2 gl = graphicsData.getGlContext();
-
double distanceScale = graphicsData.getDistanceScale();
@@ -150,7 +141,6 @@
CyEdge edge;
Vector3 start, end;
- double curvedEdgeRadius, edgeRadialAngle;
for (EdgeViewContainer container : edgeViewContainers) {
edgeView = container.edgeView;
@@ -161,49 +151,19 @@
end = obtainCoordinates(edge.getTarget(), networkView,
distanceScale);
// TODO: Check for cases where the edge goes from a
node to itself
-
- if (start != null && end != null) {
- // Load name for edge pikcking
+ if (start != null && end != null && end.distance(start)
>= MIN_LENGTH) {
+
+ // Load name for edge picking
gl.glLoadName(edge.getIndex());
- // If there's only 1 edge between this pair of
nodes, draw it straight
- if (container.totalCoincidentEdges <= 1) {
- drawSegment(gl, start, end);
- // Otherwise, distribute the edges radially and
make them curved
- } else {
-
- // Level 1 has 2^2 - 1^1 = 3 edges,
level 2 has 3^3 - 2^2 = 5, level 3 has 7
- int edgeLevel = (int)
(Math.sqrt((double) container.edgeNumber));
- int maxLevel = (int)
(Math.sqrt((double) container.totalCoincidentEdges));
-
- int edgesInLevel = edgeLevel * 2 + 1;
-
- // Smaller edge level -> greater radius
- curvedEdgeRadius = start.distance(end)
* (0.5 + (double) 1.5 / Math.pow(edgeLevel, 2));
-
- // The outmost level is usually not
completed
- if (edgeLevel == maxLevel) {
- edgesInLevel = (int)
(container.totalCoincidentEdges - Math.pow(maxLevel, 2) + 1);
- }
-
- edgeRadialAngle = (double)
(container.edgeNumber - Math.pow(edgeLevel, 2)) / edgesInLevel * Math.PI * 2;
-
-// if (graphicsData.getFramesElapsed() ==
500) {
-// System.out.println("edgeNumber:
" + container.edgeNumber);
-//
System.out.println("totalCoincidentEdges: " + container.totalCoincidentEdges);
-// System.out.println("edgeLevel:
" + edgeLevel);
-// System.out.println("maxLevel: "
+ maxLevel);
-//
System.out.println("edgesInLevel: " + edgesInLevel);
-//
System.out.println("curvedEdgeRadius: " + curvedEdgeRadius);
-//
System.out.println("edgeRadialAngle: " + edgeRadialAngle);
-//
System.out.println("==================================");
-// }
-
- drawArcSegments(gl, start, end,
curvedEdgeRadius, edgeRadialAngle, NUM_SEGMENTS);
- }
+ // General points along the arc
+ Vector3[] points =
generateEdgeSpecificArcCoordinates(
+ start, end,
container.edgeNumber, container.totalCoincidentEdges);
+
+ // Draw the arc
+ drawRegularArc(gl, points);
}
}
-
}
// Picks a color according to the edgeView and passes it to OpenGL
@@ -226,6 +186,7 @@
color.multiplyGreen(1.5, 0.5, 1);
color.multiplyBlue(0.7, 0, 1);
} else if (edgeView.getModel().getIndex() ==
graphicsData.getSelectionData().getHoverEdgeIndex()) {
+
// Make hovered edges appear bluer
color.multiplyRed(0.7, 0, 1);
color.multiplyGreen(0.7, 0, 1);
@@ -254,8 +215,100 @@
return coordinates;
}
- private void drawArcSegments(GL2 gl, Vector3 start, Vector3 end, double
radius, double angle, int segments) {
- Vector3 displacement = end.subtract(start);
+
+ /**
+ * Generates a set of edge-specific arc coordinates, so that the set of
drawing coordinates
+ * representing the edge are made to not coincide with other edges that
connect the same pair of nodes
+ *
+ * The first of the coordinates is equal to the starting position, and
the last is equal to the
+ * terminal position.
+ *
+ * @param start The starting position of the edge
+ * @param end The terminal position of the edge
+ * @param edgeNumber The index of this edge out of all the edges that
connect the same pair of nodes,
+ * with 1 meaning it is the first of all the edges
+ * @param totalCoincidentEdges The total number of edges that connect
the same nodes as this edge
+ * @return
+ */
+ private Vector3[] generateEdgeSpecificArcCoordinates(Vector3 start,
Vector3 end, int edgeNumber, int totalCoincidentEdges) {
+
+ // If this is the only edge connecting these nodes, make it
straight and simply
+ // return the endpoints
+ if (totalCoincidentEdges == 1 && edgeNumber == 1) {
+ return new Vector3[] {start.copy(), end.copy()};
+ }
+
+ // Level 1 has 2^2 - 1^1 = 3 edges, level 2 has 3^3 - 2^2 = 5,
level 3 has 7
+ int edgeLevel = (int) (Math.sqrt((double) edgeNumber));
+ int maxLevel = (int) (Math.sqrt((double) totalCoincidentEdges));
+
+ int edgesInLevel = edgeLevel * 2 + 1;
+
+ // Smaller edge level -> greater radius
+ double curvedEdgeRadius = start.distance(end) * (0.5 + (double)
1.5 / Math.pow(edgeLevel, 2));
+
+ // The outmost level is usually not completed
+ if (edgeLevel == maxLevel) {
+ edgesInLevel = (int) (totalCoincidentEdges -
Math.pow(maxLevel, 2) + 1);
+ }
+
+ double edgeRadialAngle = (double) (edgeNumber -
Math.pow(edgeLevel, 2)) / edgesInLevel * Math.PI * 2;
+
+ return generateArcCoordinates(start, end, curvedEdgeRadius,
edgeRadialAngle, NUM_SEGMENTS);
+ }
+
+ /**
+ * Generates points along the arc of a circle connecting 2 positions in
3D space, given
+ * the desired arc of the circle, the angle to rotate the arc about the
displacement axis
+ * by the right-hand rule from the positive z-axis, and the number of
points desired.
+ *
+ * @param start The starting position of the arc
+ * @param end The terminal position of the arc
+ * @param radius Desired radius of the circle
+ * @param angle The angle to rotate the arc about the start-to-end
displacement axis, about
+ * the right-hand rule, from the positive z-axis.
+ * @param segments The number of straight segments to divide the arc
into. The number
+ * of points returned is equal to the number of segments + 1. Must be
at least 1.
+ * @return An array of position vectors representing the arc, where the
first point
+ * is equal to the start of the arc, and the last point is equal to the
end of the arc.
+ */
+ private Vector3[] generateArcCoordinates(Vector3 start, Vector3 end,
+ double radius, double angle, int segments) {
+
+ Vector3[] arcCoordinates = new Vector3[segments + 1];
+
+ Vector3 circleCenter = findCircleCenter(start, end, radius,
angle);
+ Vector3 startOffset = start.subtract(circleCenter);
+ Vector3 endOffset = end.subtract(circleCenter);
+ Vector3 rotationNormal = startOffset.cross(endOffset);
+
+ double arcAngle = startOffset.angle(endOffset);
+
+ double rotation = arcAngle / segments;
+
+ for (int i = 0; i < segments; i++) {
+ arcCoordinates[i] = startOffset.rotate(rotationNormal,
rotation * i);
+ }
+
+ arcCoordinates[segments + 1] = end.copy();
+
+ return arcCoordinates;
+ }
+
+ /**
+ * Finds the center of a circle passing through 2 points, rotated about
the displacement axis
+ * by a certain angle.
+ *
+ * @param first The first point on the circle
+ * @param second The second point on the circle
+ * @param radius The radius of the circle
+ * @param angle An angle of rotation, in radians, that corresponds to
the rotation
+ * by the right-hand rule about the axis going extending from the first
position vector
+ * towards the second
+ * @return A position vector representing the center of the circle
+ */
+ private Vector3 findCircleCenter(Vector3 first, Vector3 second, double
radius, double angle) {
+ Vector3 displacement = second.subtract(first);
double displacementLength = displacement.magnitude();
// Radius adjustment (can't draw an arc from start to end if
the radius of the arc is less than half that
@@ -279,52 +332,25 @@
circleCenterOffset.normalizeLocal();
circleCenterOffset.multiplyLocal(radius);
- Vector3 circleCenter = start.plus(circleCenterOffset);
-
-// drawSegment(gl, start, circleCenter);
-// drawSegment(gl, circleCenter, end);
-
- Vector3 rotationNormal = displacement.cross(circleCenterOffset);
-
- if (segments <= 1) {
- drawSegment(gl, start, end);
- } else {
- // Draw segments along the length of the arc
- double angleIncrement = arcAngle / segments;
- // Displacement vector from circle center to current
point
- Vector3 currentPointOffset =
start.subtract(circleCenter);
- Vector3 currentPoint =
circleCenter.plus(currentPointOffset);
- Vector3 previousPoint = currentPoint.copy();
-
- for (int i = 1; i <= segments; i ++) {
- currentPointOffset =
currentPointOffset.rotate(rotationNormal, angleIncrement);
- currentPoint =
circleCenter.plus(currentPointOffset);
- drawSegment(gl, previousPoint, currentPoint);
- previousPoint.set(currentPoint);
- }
- }
-
- // Need to obtain circle's center, and use a parametric
equation to obtain points along the arc between
- // start and end
+ return first.plus(circleCenterOffset);
}
- private void drawSegment(GL2 gl, Vector3 start, Vector3 end) {
- Vector3 displacement = end.subtract(start);
- double length = displacement.magnitude();
+ private void drawRegularArc(GL2 gl, Vector3[] points) {
+ Vector3 displacement;
- if (length > MIN_LENGTH) {
-
+ for (int i = 0; i < points.length - 1; i++) {
+ displacement = points[i + 1].subtract(points[i]);
+
gl.glPushMatrix();
- RenderToolkit.setUpFacingTransformation(gl, start,
displacement);
- gl.glScaled(1, 1, length);
- // need a scale transformation for segment radius?
+ // Setup transformations to draw the shape
+ RenderToolkit.setUpFacingTransformation(gl, points[i],
displacement);
+ gl.glScalef((float) SEGMENT_RADIUS, (float)
SEGMENT_RADIUS, (float) displacement.magnitude());
- gl.glCallList(segmentListIndex);
+ // Perform drawing
+ shapeDrawer.drawSegment(gl, EdgeShapeType.REGULAR);
+
gl.glPopMatrix();
- } else {
-// System.out.println("Edge length too small: " + length);
}
}
-
}
--
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.