use of org.cytoscape.graph.render.immed.EdgeAnchors in project cytoscape-impl by cytoscape.
the class InnerCanvas method computeEdgesIntersecting.
// Puts [last drawn] edges intersecting onto stack; as RootGraph indices.
// Depends on the state of several member variables, such as m_hash.
// Clobbers m_stack and m_ptBuff.
// The rectangle extents are in component coordinate space.
// IMPORTANT: Code that calls this method should be holding m_lock.
final void computeEdgesIntersecting(final int xMini, final int yMini, final int xMaxi, final int yMaxi, final LongStack stack) {
m_ptBuff[0] = xMini;
m_ptBuff[1] = yMini;
m_view.xformComponentToNodeCoords(m_ptBuff);
final double xMin = m_ptBuff[0];
final double yMin = m_ptBuff[1];
m_ptBuff[0] = xMaxi;
m_ptBuff[1] = yMaxi;
m_view.xformComponentToNodeCoords(m_ptBuff);
final double xMax = m_ptBuff[0];
final double yMax = m_ptBuff[1];
// Positive.
LongEnumerator edgeNodesEnum = m_hash.elements();
m_stack.empty();
final int edgeNodesCount = edgeNodesEnum.numRemaining();
for (int i = 0; i < edgeNodesCount; i++) m_stack.push(edgeNodesEnum.nextLong());
m_hash.empty();
edgeNodesEnum = m_stack.elements();
stack.empty();
final CyNetwork graph = m_view.m_drawPersp;
if ((m_lastRenderDetail & GraphRenderer.LOD_HIGH_DETAIL) == 0) {
// We won't need to look up arrows and their sizes.
for (int i = 0; i < edgeNodesCount; i++) {
// Positive.
final long node = edgeNodesEnum.nextLong();
final CyNode nodeObj = graph.getNode(node);
if (!m_view.m_spacial.exists(node, m_view.m_extentsBuff, 0))
// Will happen if e.g. node was removed.
continue;
final float nodeX = (m_view.m_extentsBuff[0] + m_view.m_extentsBuff[2]) / 2;
final float nodeY = (m_view.m_extentsBuff[1] + m_view.m_extentsBuff[3]) / 2;
final Iterable<CyEdge> touchingEdges = graph.getAdjacentEdgeIterable(nodeObj, CyEdge.Type.ANY);
for (CyEdge e : touchingEdges) {
final long edge = e.getSUID();
final long otherNode = node ^ e.getSource().getSUID().longValue() ^ e.getTarget().getSUID().longValue();
if (m_hash.get(otherNode) < 0) {
m_view.m_spacial.exists(otherNode, m_view.m_extentsBuff, 0);
final float otherNodeX = (m_view.m_extentsBuff[0] + m_view.m_extentsBuff[2]) / 2;
final float otherNodeY = (m_view.m_extentsBuff[1] + m_view.m_extentsBuff[3]) / 2;
m_line.setLine(nodeX, nodeY, otherNodeX, otherNodeY);
if (m_line.intersects(xMin, yMin, xMax - xMin, yMax - yMin))
stack.push(edge);
}
}
m_hash.put(node);
}
} else {
// Last render high detail.
for (int i = 0; i < edgeNodesCount; i++) {
// Positive.
final long node = edgeNodesEnum.nextLong();
final CyNode nodeObj = graph.getNode(node);
if (!m_view.m_spacial.exists(node, m_view.m_extentsBuff, 0))
continue;
/* Will happen if e.g. node was removed. */
final byte nodeShape = m_view.m_nodeDetails.getShape(nodeObj);
final Iterable<CyEdge> touchingEdges = graph.getAdjacentEdgeIterable(nodeObj, CyEdge.Type.ANY);
for (CyEdge edge : touchingEdges) {
// final int edge = e.getIndex(); // Positive.
final double segThicknessDiv2 = m_view.m_edgeDetails.getWidth(edge) / 2.0d;
final long otherNode = node ^ edge.getSource().getSUID().longValue() ^ edge.getTarget().getSUID().longValue();
final CyNode otherNodeObj = graph.getNode(otherNode);
if (m_hash.get(otherNode) < 0) {
m_view.m_spacial.exists(otherNode, m_extentsBuff2, 0);
final byte otherNodeShape = m_view.m_nodeDetails.getShape(otherNodeObj);
final byte srcShape;
final byte trgShape;
final float[] srcExtents;
final float[] trgExtents;
if (node == edge.getSource().getSUID().longValue()) {
srcShape = nodeShape;
trgShape = otherNodeShape;
srcExtents = m_view.m_extentsBuff;
trgExtents = m_extentsBuff2;
} else {
// node == graph.edgeTarget(edge).
srcShape = otherNodeShape;
trgShape = nodeShape;
srcExtents = m_extentsBuff2;
trgExtents = m_view.m_extentsBuff;
}
final ArrowShape srcArrow;
final ArrowShape trgArrow;
final float srcArrowSize;
final float trgArrowSize;
if ((m_lastRenderDetail & GraphRenderer.LOD_EDGE_ARROWS) == 0) {
srcArrow = trgArrow = ArrowShapeVisualProperty.NONE;
srcArrowSize = trgArrowSize = 0.0f;
} else {
srcArrow = m_view.m_edgeDetails.getSourceArrowShape(edge);
trgArrow = m_view.m_edgeDetails.getTargetArrowShape(edge);
srcArrowSize = ((srcArrow == ArrowShapeVisualProperty.NONE) ? 0.0f : m_view.m_edgeDetails.getSourceArrowSize(edge));
trgArrowSize = ((trgArrow == ArrowShapeVisualProperty.NONE) ? 0.0f : m_view.m_edgeDetails.getTargetArrowSize(edge));
}
final EdgeAnchors anchors = (((m_lastRenderDetail & GraphRenderer.LOD_EDGE_ANCHORS) == 0) ? null : m_view.m_edgeDetails.getAnchors(edge));
if (!GraphRenderer.computeEdgeEndpoints(m_grafx, srcExtents, srcShape, srcArrow, srcArrowSize, anchors, trgExtents, trgShape, trgArrow, trgArrowSize, m_floatBuff1, m_floatBuff2))
continue;
m_grafx.getEdgePath(srcArrow, srcArrowSize, trgArrow, trgArrowSize, m_floatBuff1[0], m_floatBuff1[1], anchors, m_floatBuff2[0], m_floatBuff2[1], m_path);
GraphRenderer.computeClosedPath(m_path.getPathIterator(null), m_path2);
if (m_path2.intersects(xMin - segThicknessDiv2, yMin - segThicknessDiv2, (xMax - xMin) + (segThicknessDiv2 * 2), (yMax - yMin) + (segThicknessDiv2 * 2)))
stack.push(edge.getSUID().longValue());
}
}
m_hash.put(node);
}
}
}
use of org.cytoscape.graph.render.immed.EdgeAnchors in project cytoscape-impl by cytoscape.
the class DEdgeDetails method getAnchors.
@Override
public EdgeAnchors getAnchors(final CyEdge edge) {
final DEdgeView edgeView = (DEdgeView) dGraphView.getDEdgeView(edge);
if (edgeView == null)
return null;
final EdgeAnchors returnThis = edgeView;
if (returnThis.numAnchors() > 0)
return returnThis;
final CyNetwork graph = dGraphView.m_drawPersp;
final long srcNodeIndex = edgeView.getModel().getSource().getSUID();
final long trgNodeIndex = edgeView.getModel().getTarget().getSUID();
// Calculate anchors necessary for self edges.
if (srcNodeIndex == trgNodeIndex) {
dGraphView.m_spacial.exists(srcNodeIndex, m_extentsBuff, 0);
final double w = ((double) m_extentsBuff[2]) - m_extentsBuff[0];
final double h = ((double) m_extentsBuff[3]) - m_extentsBuff[1];
final double x = (((double) m_extentsBuff[0]) + m_extentsBuff[2]) / 2.0d;
final double y = (((double) m_extentsBuff[1]) + m_extentsBuff[3]) / 2.0d;
final double nodeSize = Math.max(w, h);
int i = 0;
final List<CyEdge> selfEdgeList = graph.getConnectingEdgeList(edgeView.getModel().getSource(), edgeView.getModel().getSource(), CyEdge.Type.ANY);
for (final CyEdge selfEdge : selfEdgeList) {
// while (selfEdges.hasNext())
// final int e2 = selfEdges.nextInt();
final long e2 = selfEdge.getSUID();
if (e2 == edge.getSUID())
break;
if (((EdgeAnchors) dGraphView.getDEdgeView(e2)).numAnchors() == 0)
i++;
}
final int inx = i;
return new EdgeAnchors() {
@Override
public int numAnchors() {
return 2;
}
@Override
public void getAnchor(int anchorInx, float[] anchorArr, int offset) {
if (anchorInx == 0) {
anchorArr[offset] = (float) (x - (((inx + 3) * nodeSize) / 2.0d));
anchorArr[offset + 1] = (float) y;
} else if (anchorInx == 1) {
anchorArr[offset] = (float) x;
anchorArr[offset + 1] = (float) (y - (((inx + 3) * nodeSize) / 2.0d));
}
}
};
}
// exist between two nodes. This has no effect if user specified anchors exist on the edge.
while (true) {
// By consistently ordering the source and target nodes, dx and dy
// will always
// be calculated according to the same orientation. This allows the
// offset
// calculation to toggle the edges from side to side without any
// overlap.
final long tmpSrcIndex = Math.min(srcNodeIndex, trgNodeIndex);
final long tmpTrgIndex = Math.max(srcNodeIndex, trgNodeIndex);
// Sort the connecting edges.
final CyNode tmpSrc = graph.getNode(tmpSrcIndex);
final CyNode tmpTrg = graph.getNode(tmpTrgIndex);
final List<CyEdge> conEdgeList = graph.getConnectingEdgeList(tmpSrc, tmpTrg, CyEdge.Type.ANY);
// final IntIterator conEdges = graph.edgesConnecting(tmpSrc,
// tmpTrg,
// true, true, true);
m_heap.empty();
for (final CyEdge conEdge : conEdgeList) {
// while (conEdges.hasNext())
// m_heap.toss(conEdges.nextInt());
m_heap.toss(conEdge.getSUID());
}
final LongEnumerator otherEdges = m_heap.orderedElements(false);
long otherEdge = otherEdges.nextLong();
// (i.e. we're at the end of the list?).
if (otherEdge == edge.getSUID())
break;
// So we don't count the other edge twice?
DEdgeView otherEdgeView = dGraphView.getDEdgeView(otherEdge);
if (otherEdgeView == null)
continue;
int i = (((EdgeAnchors) otherEdgeView).numAnchors() == 0) ? 1 : 0;
// Count the number of other edges.
while (true) {
if (edge.getSUID() == (otherEdge = otherEdges.nextLong()) || otherEdge == -1)
break;
if (((EdgeAnchors) otherEdgeView).numAnchors() == 0)
i++;
}
final int inx = i;
// Get source node size and position.
dGraphView.m_spacial.exists(tmpSrcIndex, m_extentsBuff, 0);
final double srcW = ((double) m_extentsBuff[2]) - m_extentsBuff[0];
final double srcH = ((double) m_extentsBuff[3]) - m_extentsBuff[1];
final double srcX = (((double) m_extentsBuff[0]) + m_extentsBuff[2]) / 2.0d;
final double srcY = (((double) m_extentsBuff[1]) + m_extentsBuff[3]) / 2.0d;
// Get target node size and position.
dGraphView.m_spacial.exists(tmpTrgIndex, m_extentsBuff, 0);
final double trgW = ((double) m_extentsBuff[2]) - m_extentsBuff[0];
final double trgH = ((double) m_extentsBuff[3]) - m_extentsBuff[1];
final double trgX = (((double) m_extentsBuff[0]) + m_extentsBuff[2]) / 2.0d;
final double trgY = (((double) m_extentsBuff[1]) + m_extentsBuff[3]) / 2.0d;
// Used for determining the space between the edges.
final double nodeSize = Math.max(Math.max(Math.max(srcW, srcH), trgW), trgH);
// Midpoint between nodes.
final double midX = (srcX + trgX) / 2;
final double midY = (srcY + trgY) / 2;
// Distance in X and Y dimensions.
// Note that dx and dy may be negative. This is OK, because this will ensure
// that the handle is always correctly placed offset from the midpoint of,
// and perpendicular to, the original edge.
final double dx = trgX - srcX;
final double dy = trgY - srcY;
// Distance or length between nodes.
final double len = Math.sqrt((dx * dx) + (dy * dy));
if (((float) len) == 0.0f)
break;
// This determines which side of the first edge and how far from the first
// edge the other edge should be placed.
// - Divide by 2 puts consecutive edges at the same distance from the center because of integer math.
// - Modulo puts consecutive edges on opposite sides.
// - Node size is for consistent scaling.
final double offset = ((inx + 1) / 2) * (inx % 2 == 0 ? 1 : -1) * nodeSize;
// Depending on orientation sine or cosine. This adjusts the length
// of the offset according the appropriate X and Y dimensions.
final double normX = dx / len;
final double normY = dy / len;
// Calculate the anchor points.
final double anchorX = midX + (offset * normY);
final double anchorY = midY - (offset * normX);
return new EdgeAnchors() {
public int numAnchors() {
return 1;
}
public void getAnchor(int inx, float[] arr, int off) {
arr[off] = (float) anchorX;
arr[off + 1] = (float) anchorY;
}
};
}
return returnThis;
}
use of org.cytoscape.graph.render.immed.EdgeAnchors in project cytoscape-impl by cytoscape.
the class GraphRenderer method renderGraph.
/**
* Renders a graph.
* @param netView the network view; nodes in this graph must correspond to
* objKeys in nodePositions (the SpacialIndex2D parameter) and vice versa.
* @param nodePositions defines the positions and extents of nodes in graph;
* each entry (objKey) in this structure must correspond to a node in graph
* (the CyNetwork parameter) and vice versa; the order in which nodes are
* rendered is defined by a non-reversed overlap query on this structure.
* @param lod defines the different levels of detail; an appropriate level
* of detail is chosen based on the results of method calls on this
* object.
* @param nodeDetails defines details of nodes such as colors, node border
* thickness, and shape; the node arguments passed to methods on this
* object will be nodes in the graph parameter.
* @param edgeDetails defines details of edges such as colors, thickness,
* and arrow type; the edge arguments passed to methods on this
* object will be edges in the graph parameter.
* @param nodeBuff this is a computational helper that is required in the
* implementation of this method; when this method returns, nodeBuff is
* in a state such that an edge in graph has been rendered by this method
* if and only if it touches at least one node in this nodeBuff set;
* no guarantee made regarding edgeless nodes.
* @param grafx the graphics context that is to render this graph.
* @param bgPaint the background paint to use when calling grafx.clear().
* @param xCenter the xCenter parameter to use when calling grafx.clear().
* @param yCenter the yCenter parameter to use when calling grafx.clear().
* @param scaleFactor the scaleFactor parameter to use when calling
* grafx.clear().
* @param dependencies
* @return bits representing the level of detail that was rendered; the
* return value is a bitwise-or'ed value of the LOD_* constants.
*/
public static final int renderGraph(final CyNetworkView netView, final SpacialIndex2D nodePositions, final GraphLOD lod, final NodeDetails nodeDetails, final EdgeDetails edgeDetails, final LongHash nodeBuff, final GraphGraphics grafx, final Paint bgPaint, final double xCenter, final double yCenter, final double scaleFactor, final boolean haveZOrder, final Set<VisualPropertyDependency<?>> dependencies) {
// Make sure we keep our promise.
nodeBuff.empty();
if (grafx == null || grafx.image == null)
return 0;
final CyNetwork graph = netView.getModel();
// Define the visible window in node coordinate space.
final float xMin;
// Define the visible window in node coordinate space.
final float yMin;
// Define the visible window in node coordinate space.
final float xMax;
// Define the visible window in node coordinate space.
final float yMax;
xMin = (float) (xCenter - ((0.5d * grafx.image.getWidth(null)) / scaleFactor));
yMin = (float) (yCenter - ((0.5d * grafx.image.getHeight(null)) / scaleFactor));
xMax = (float) (xCenter + ((0.5d * grafx.image.getWidth(null)) / scaleFactor));
yMax = (float) (yCenter + ((0.5d * grafx.image.getHeight(null)) / scaleFactor));
// Define buffers. These are of the few objects we're instantiating
// directly in this method.
final float[] floatBuff1;
// Define buffers. These are of the few objects we're instantiating
// directly in this method.
final float[] floatBuff2;
// Define buffers. These are of the few objects we're instantiating
// directly in this method.
final float[] floatBuff3;
// Define buffers. These are of the few objects we're instantiating
// directly in this method.
final float[] floatBuff4;
// Define buffers. These are of the few objects we're instantiating
// directly in this method.
final float[] floatBuff5;
final double[] doubleBuff1;
final double[] doubleBuff2;
final GeneralPath path2d;
floatBuff1 = new float[4];
floatBuff2 = new float[4];
floatBuff3 = new float[2];
floatBuff4 = new float[2];
floatBuff5 = new float[8];
doubleBuff1 = new double[4];
doubleBuff2 = new double[2];
path2d = new GeneralPath();
// Determine the number of nodes and edges that we are about to render.
final int renderNodeCount;
final int renderEdgeCount;
final byte renderEdges;
long start = System.currentTimeMillis();
{
final SpacialEntry2DEnumerator nodeHits = nodePositions.queryOverlap(xMin, yMin, xMax, yMax, null, 0, false);
final int visibleNodeCount = nodeHits.numRemaining();
final int totalNodeCount = graph.getNodeCount();
final int totalEdgeCount = graph.getEdgeCount();
renderEdges = lod.renderEdges(visibleNodeCount, totalNodeCount, totalEdgeCount);
if (renderEdges > 0) {
int runningNodeCount = 0;
for (int i = 0; i < visibleNodeCount; i++) {
nodeHits.nextExtents(floatBuff1, 0);
if ((floatBuff1[0] != floatBuff1[2]) && (floatBuff1[1] != floatBuff1[3]))
runningNodeCount++;
}
renderNodeCount = runningNodeCount;
renderEdgeCount = totalEdgeCount;
} else if (renderEdges < 0) {
int runningNodeCount = 0;
for (int i = 0; i < visibleNodeCount; i++) {
nodeHits.nextExtents(floatBuff1, 0);
if ((floatBuff1[0] != floatBuff1[2]) && (floatBuff1[1] != floatBuff1[3]))
runningNodeCount++;
}
renderNodeCount = runningNodeCount;
renderEdgeCount = 0;
} else {
int runningNodeCount = 0;
int runningEdgeCount = 0;
for (int i = 0; i < visibleNodeCount; i++) {
final long node = nodeHits.nextExtents(floatBuff1, 0);
if ((floatBuff1[0] != floatBuff1[2]) && (floatBuff1[1] != floatBuff1[3]))
runningNodeCount++;
final Iterable<CyEdge> touchingEdges = graph.getAdjacentEdgeIterable(graph.getNode(node), CyEdge.Type.ANY);
for (CyEdge e : touchingEdges) {
if (!edgeDetails.isVisible(e))
continue;
final long edge = e.getSUID();
final long otherNode = node ^ e.getSource().getSUID() ^ e.getTarget().getSUID();
if (nodeBuff.get(otherNode) < 0)
runningEdgeCount++;
}
nodeBuff.put(node);
}
renderNodeCount = runningNodeCount;
renderEdgeCount = runningEdgeCount;
nodeBuff.empty();
}
}
// System.out.println("renderEdgeCount: "+renderEdgeCount);
// System.out.println("time: "+(System.currentTimeMillis()-start)+"ms");
// Based on number of objects we are going to render, determine LOD.
final int lodBits;
{
int lodTemp = 0;
if (lod.detail(renderNodeCount, renderEdgeCount)) {
lodTemp |= LOD_HIGH_DETAIL;
if (lod.nodeBorders(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_NODE_BORDERS;
if (lod.nodeLabels(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_NODE_LABELS;
if (lod.edgeArrows(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_EDGE_ARROWS;
if (lod.dashedEdges(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_DASHED_EDGES;
if (lod.edgeAnchors(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_EDGE_ANCHORS;
if (lod.edgeLabels(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_EDGE_LABELS;
if ((((lodTemp & LOD_NODE_LABELS) != 0) || ((lodTemp & LOD_EDGE_LABELS) != 0)) && lod.textAsShape(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_TEXT_AS_SHAPE;
if (lod.customGraphics(renderNodeCount, renderEdgeCount))
lodTemp |= LOD_CUSTOM_GRAPHICS;
}
lodBits = lodTemp;
}
// Clear the background.
{
if (bgPaint != null)
grafx.clear(bgPaint, xCenter, yCenter, scaleFactor);
}
// on top of the edge it belongs to.
if (renderEdges >= 0) {
final SpacialEntry2DEnumerator nodeHits;
if (renderEdges > 0)
// We want to render edges in the same order (back to front) that
// we would use to render just edges on visible nodes; this is assuming
// that our spacial index has the subquery order-preserving property.
nodeHits = nodePositions.queryOverlap(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, null, 0, false);
else
nodeHits = nodePositions.queryOverlap(xMin, yMin, xMax, yMax, null, 0, false);
if ((lodBits & LOD_HIGH_DETAIL) == 0) {
// Low detail.
final int nodeHitCount = nodeHits.numRemaining();
for (int i = 0; i < nodeHitCount; i++) {
final long node = nodeHits.nextExtents(floatBuff1, 0);
// Casting to double and then back we could achieve better accuracy
// at the expense of performance.
final float nodeX = (floatBuff1[0] + floatBuff1[2]) / 2;
final float nodeY = (floatBuff1[1] + floatBuff1[3]) / 2;
Iterable<CyEdge> touchingEdges = graph.getAdjacentEdgeIterable(graph.getNode(node), CyEdge.Type.ANY);
for (CyEdge edge : touchingEdges) {
if (!edgeDetails.isVisible(edge))
continue;
final long otherNode = node ^ edge.getSource().getSUID() ^ edge.getTarget().getSUID();
if (nodeBuff.get(otherNode) < 0) {
// Has not yet been rendered.
nodePositions.exists(otherNode, floatBuff2, 0);
grafx.drawEdgeLow(nodeX, nodeY, // accuracy and performance.
(floatBuff2[0] + floatBuff2[2]) / 2, (floatBuff2[1] + floatBuff2[3]) / 2, edgeDetails.getColorLowDetail(edge));
}
}
nodeBuff.put(node);
}
} else {
// High detail.
while (nodeHits.numRemaining() > 0) {
final long node = nodeHits.nextExtents(floatBuff1, 0);
final CyNode cyNode = graph.getNode(node);
final byte nodeShape = nodeDetails.getShape(cyNode);
Iterable<CyEdge> touchingEdges = graph.getAdjacentEdgeIterable(cyNode, CyEdge.Type.ANY);
for (final CyEdge edge : touchingEdges) {
if (!edgeDetails.isVisible(edge))
continue;
final long otherNode = node ^ edge.getSource().getSUID() ^ edge.getTarget().getSUID();
final CyNode otherCyNode = graph.getNode(otherNode);
if (nodeBuff.get(otherNode) < 0) {
if (!nodePositions.exists(otherNode, floatBuff2, 0))
continue;
// throw new IllegalStateException("nodePositions not recognizing node that exists in graph: "+otherCyNode.toString());
final byte otherNodeShape = nodeDetails.getShape(otherCyNode);
// Compute node shapes, center positions, and extents.
final byte srcShape;
// Compute node shapes, center positions, and extents.
final byte trgShape;
final float[] srcExtents;
final float[] trgExtents;
if (node == edge.getSource().getSUID()) {
srcShape = nodeShape;
trgShape = otherNodeShape;
srcExtents = floatBuff1;
trgExtents = floatBuff2;
} else {
// node == graph.edgeTarget(edge).
srcShape = otherNodeShape;
trgShape = nodeShape;
srcExtents = floatBuff2;
trgExtents = floatBuff1;
}
// Compute visual attributes that do not depend on LOD.
final float thickness = edgeDetails.getWidth(edge);
final Stroke edgeStroke = edgeDetails.getStroke(edge);
final Paint segPaint = edgeDetails.getPaint(edge);
// Compute arrows.
final ArrowShape srcArrow;
final ArrowShape trgArrow;
final float srcArrowSize;
final float trgArrowSize;
final Paint srcArrowPaint;
final Paint trgArrowPaint;
if ((lodBits & LOD_EDGE_ARROWS) == 0) {
// Not rendering arrows.
trgArrow = srcArrow = ArrowShapeVisualProperty.NONE;
trgArrowSize = srcArrowSize = 0.0f;
trgArrowPaint = srcArrowPaint = null;
} else {
// Rendering edge arrows.
srcArrow = edgeDetails.getSourceArrowShape(edge);
trgArrow = edgeDetails.getTargetArrowShape(edge);
srcArrowSize = ((srcArrow == ArrowShapeVisualProperty.NONE) ? 0.0f : edgeDetails.getSourceArrowSize(edge));
trgArrowSize = ((trgArrow == ArrowShapeVisualProperty.NONE) ? 0.0f : edgeDetails.getTargetArrowSize(edge));
srcArrowPaint = ((srcArrow == ArrowShapeVisualProperty.NONE) ? null : edgeDetails.getSourceArrowPaint(edge));
trgArrowPaint = ((trgArrow == ArrowShapeVisualProperty.NONE) ? null : edgeDetails.getTargetArrowPaint(edge));
}
// Compute the anchors to use when rendering edge.
final EdgeAnchors anchors = (((lodBits & LOD_EDGE_ANCHORS) == 0) ? null : edgeDetails.getAnchors(edge));
if (!computeEdgeEndpoints(grafx, srcExtents, srcShape, srcArrow, srcArrowSize, anchors, trgExtents, trgShape, trgArrow, trgArrowSize, floatBuff3, floatBuff4))
continue;
final float srcXAdj = floatBuff3[0];
final float srcYAdj = floatBuff3[1];
final float trgXAdj = floatBuff4[0];
final float trgYAdj = floatBuff4[1];
grafx.drawEdgeFull(srcArrow, srcArrowSize, srcArrowPaint, trgArrow, trgArrowSize, trgArrowPaint, srcXAdj, srcYAdj, anchors, trgXAdj, trgYAdj, thickness, edgeStroke, segPaint);
// Take care of edge anchor rendering.
if (anchors != null) {
for (int k = 0; k < anchors.numAnchors(); k++) {
final float anchorSize;
if ((anchorSize = edgeDetails.getAnchorSize(edge, k)) > 0.0f) {
anchors.getAnchor(k, floatBuff4, 0);
grafx.drawNodeFull(GraphGraphics.SHAPE_RECTANGLE, (float) (floatBuff4[0] - (anchorSize / 2.0d)), (float) (floatBuff4[1] - (anchorSize / 2.0d)), (float) (floatBuff4[0] + (anchorSize / 2.0d)), (float) (floatBuff4[1] + (anchorSize / 2.0d)), edgeDetails.getAnchorPaint(edge, k), 0.0f, null, null);
}
}
}
// Take care of label rendering.
if ((lodBits & LOD_EDGE_LABELS) != 0) {
final int labelCount = edgeDetails.getLabelCount(edge);
for (int labelInx = 0; labelInx < labelCount; labelInx++) {
final String text = edgeDetails.getLabelText(edge, labelInx);
final Font font = edgeDetails.getLabelFont(edge, labelInx);
final double fontScaleFactor = edgeDetails.getLabelScaleFactor(edge, labelInx);
final Paint paint = edgeDetails.getLabelPaint(edge, labelInx);
final Position textAnchor = edgeDetails.getLabelTextAnchor(edge, labelInx);
final Position edgeAnchor = edgeDetails.getLabelEdgeAnchor(edge, labelInx);
final float offsetVectorX = edgeDetails.getLabelOffsetVectorX(edge, labelInx);
final float offsetVectorY = edgeDetails.getLabelOffsetVectorY(edge, labelInx);
final Justification justify;
if (text.indexOf('\n') >= 0)
justify = edgeDetails.getLabelJustify(edge, labelInx);
else
justify = Justification.JUSTIFY_CENTER;
final double edgeAnchorPointX;
final double edgeAnchorPointY;
final double edgeLabelWidth = edgeDetails.getLabelWidth(edge);
// in any case.
if (edgeAnchor == Position.WEST) {
edgeAnchorPointX = srcXAdj;
edgeAnchorPointY = srcYAdj;
} else if (edgeAnchor == Position.EAST) {
edgeAnchorPointX = trgXAdj;
edgeAnchorPointY = trgYAdj;
} else if (edgeAnchor == Position.CENTER) {
if (!grafx.getEdgePath(srcArrow, srcArrowSize, trgArrow, trgArrowSize, srcXAdj, srcYAdj, anchors, trgXAdj, trgYAdj, path2d)) {
continue;
}
// Count the number of path segments. This count
// includes the initial SEG_MOVETO. So, for example, a
// path composed of 2 cubic curves would have a numPaths
// of 3. Note that numPaths will be at least 2 in all
// cases.
final int numPaths;
{
final PathIterator pathIter = path2d.getPathIterator(null);
int numPathsTemp = 0;
while (!pathIter.isDone()) {
// pathIter.currentSegment().
numPathsTemp++;
pathIter.next();
}
numPaths = numPathsTemp;
}
// Compute "midpoint" of edge.
if ((numPaths % 2) != 0) {
final PathIterator pathIter = path2d.getPathIterator(null);
for (int i = numPaths / 2; i > 0; i--) pathIter.next();
final int subPathType = pathIter.currentSegment(floatBuff5);
if (subPathType == PathIterator.SEG_LINETO) {
edgeAnchorPointX = floatBuff5[0];
edgeAnchorPointY = floatBuff5[1];
} else if (subPathType == PathIterator.SEG_QUADTO) {
edgeAnchorPointX = floatBuff5[2];
edgeAnchorPointY = floatBuff5[3];
} else if (subPathType == PathIterator.SEG_CUBICTO) {
edgeAnchorPointX = floatBuff5[4];
edgeAnchorPointY = floatBuff5[5];
} else
throw new IllegalStateException("got unexpected PathIterator segment type: " + subPathType);
} else {
// numPaths % 2 == 0.
final PathIterator pathIter = path2d.getPathIterator(null);
for (int i = numPaths / 2; i > 0; i--) {
if (i == 1) {
final int subPathType = pathIter.currentSegment(floatBuff5);
if ((subPathType == PathIterator.SEG_MOVETO) || (subPathType == PathIterator.SEG_LINETO)) {
floatBuff5[6] = floatBuff5[0];
floatBuff5[7] = floatBuff5[1];
} else if (subPathType == PathIterator.SEG_QUADTO) {
floatBuff5[6] = floatBuff5[2];
floatBuff5[7] = floatBuff5[3];
} else if (subPathType == PathIterator.SEG_CUBICTO) {
floatBuff5[6] = floatBuff5[4];
floatBuff5[7] = floatBuff5[5];
} else
throw new IllegalStateException("got unexpected PathIterator segment type: " + subPathType);
}
pathIter.next();
}
final int subPathType = pathIter.currentSegment(floatBuff5);
if (subPathType == PathIterator.SEG_LINETO) {
edgeAnchorPointX = (0.5d * floatBuff5[6]) + (0.5d * floatBuff5[0]);
edgeAnchorPointY = (0.5d * floatBuff5[7]) + (0.5d * floatBuff5[1]);
} else if (subPathType == PathIterator.SEG_QUADTO) {
edgeAnchorPointX = (0.25d * floatBuff5[6]) + (0.5d * floatBuff5[0]) + (0.25d * floatBuff5[2]);
edgeAnchorPointY = (0.25d * floatBuff5[7]) + (0.5d * floatBuff5[1]) + (0.25d * floatBuff5[3]);
} else if (subPathType == PathIterator.SEG_CUBICTO) {
edgeAnchorPointX = (0.125d * floatBuff5[6]) + (0.375d * floatBuff5[0]) + (0.375d * floatBuff5[2]) + (0.125d * floatBuff5[4]);
edgeAnchorPointY = (0.125d * floatBuff5[7]) + (0.375d * floatBuff5[1]) + (0.375d * floatBuff5[3]) + (0.125d * floatBuff5[5]);
} else
throw new IllegalStateException("got unexpected PathIterator segment type: " + subPathType);
}
} else
throw new IllegalStateException("encountered an invalid EDGE_ANCHOR_* constant: " + edgeAnchor);
final MeasuredLineCreator measuredText = new MeasuredLineCreator(text, font, grafx.getFontRenderContextFull(), fontScaleFactor, (lodBits & LOD_TEXT_AS_SHAPE) != 0, edgeLabelWidth);
doubleBuff1[0] = -0.5d * measuredText.getMaxLineWidth();
doubleBuff1[1] = -0.5d * measuredText.getTotalHeight();
doubleBuff1[2] = 0.5d * measuredText.getMaxLineWidth();
doubleBuff1[3] = 0.5d * measuredText.getTotalHeight();
lemma_computeAnchor(textAnchor, doubleBuff1, doubleBuff2);
final double textXCenter = edgeAnchorPointX - doubleBuff2[0] + offsetVectorX;
final double textYCenter = edgeAnchorPointY - doubleBuff2[1] + offsetVectorY;
TextRenderingUtils.renderHorizontalText(grafx, measuredText, font, fontScaleFactor, (float) textXCenter, (float) textYCenter, justify, paint, (lodBits & LOD_TEXT_AS_SHAPE) != 0);
}
}
}
}
nodeBuff.put(node);
}
}
}
// Render nodes and labels. A label is not necessarily on top of every
// node; it is only on top of the node it belongs to.
{
final SpacialEntry2DEnumerator nodeHits = nodePositions.queryOverlap(xMin, yMin, xMax, yMax, null, 0, false);
if ((lodBits & LOD_HIGH_DETAIL) == 0) {
// Low detail.
final int nodeHitCount = nodeHits.numRemaining();
for (int i = 0; i < nodeHitCount; i++) {
final CyNode node = graph.getNode(nodeHits.nextExtents(floatBuff1, 0));
if ((floatBuff1[0] != floatBuff1[2]) && (floatBuff1[1] != floatBuff1[3]))
grafx.drawNodeLow(floatBuff1[0], floatBuff1[1], floatBuff1[2], floatBuff1[3], nodeDetails.getColorLowDetail(node));
}
} else {
// High detail.
SpacialEntry2DEnumerator zHits = nodeHits;
if (haveZOrder) {
zHits = new SpacialEntry2DEnumeratorZSort(nodePositions, nodeHits);
}
while (zHits.numRemaining() > 0) {
final long node = zHits.nextExtents(floatBuff1, 0);
final CyNode cyNode = graph.getNode(node);
renderNodeHigh(netView, grafx, cyNode, floatBuff1, doubleBuff1, doubleBuff2, nodeDetails, lodBits, dependencies);
// Take care of label rendering.
if ((lodBits & LOD_NODE_LABELS) != 0) {
// Potential label rendering.
final int labelCount = nodeDetails.getLabelCount(cyNode);
for (int labelInx = 0; labelInx < labelCount; labelInx++) {
final String text = nodeDetails.getLabelText(cyNode, labelInx);
final Font font = nodeDetails.getLabelFont(cyNode, labelInx);
final double fontScaleFactor = nodeDetails.labelScaleFactor(cyNode, labelInx);
final Paint paint = nodeDetails.getLabelPaint(cyNode, labelInx);
final Position textAnchor = nodeDetails.getLabelTextAnchor(cyNode, labelInx);
final Position nodeAnchor = nodeDetails.getLabelNodeAnchor(cyNode, labelInx);
final float offsetVectorX = nodeDetails.getLabelOffsetVectorX(cyNode, labelInx);
final float offsetVectorY = nodeDetails.getLabelOffsetVectorY(cyNode, labelInx);
final Justification justify;
if (text.indexOf('\n') >= 0)
justify = nodeDetails.getLabelJustify(cyNode, labelInx);
else
justify = Justification.JUSTIFY_CENTER;
final double nodeLabelWidth = nodeDetails.getLabelWidth(cyNode);
doubleBuff1[0] = floatBuff1[0];
doubleBuff1[1] = floatBuff1[1];
doubleBuff1[2] = floatBuff1[2];
doubleBuff1[3] = floatBuff1[3];
lemma_computeAnchor(nodeAnchor, doubleBuff1, doubleBuff2);
final double nodeAnchorPointX = doubleBuff2[0];
final double nodeAnchorPointY = doubleBuff2[1];
final MeasuredLineCreator measuredText = new MeasuredLineCreator(text, font, grafx.getFontRenderContextFull(), fontScaleFactor, (lodBits & LOD_TEXT_AS_SHAPE) != 0, nodeLabelWidth);
doubleBuff1[0] = -0.5d * measuredText.getMaxLineWidth();
doubleBuff1[1] = -0.5d * measuredText.getTotalHeight();
doubleBuff1[2] = 0.5d * measuredText.getMaxLineWidth();
doubleBuff1[3] = 0.5d * measuredText.getTotalHeight();
lemma_computeAnchor(textAnchor, doubleBuff1, doubleBuff2);
final double textXCenter = nodeAnchorPointX - doubleBuff2[0] + offsetVectorX;
final double textYCenter = nodeAnchorPointY - doubleBuff2[1] + offsetVectorY;
TextRenderingUtils.renderHorizontalText(grafx, measuredText, font, fontScaleFactor, (float) textXCenter, (float) textYCenter, justify, paint, (lodBits & LOD_TEXT_AS_SHAPE) != 0);
}
}
}
}
}
// System.out.println("total time: "+(System.currentTimeMillis()-start)+"ms");
return lodBits;
}
Aggregations