/** * Returns the vertex, if any, whose shape contains (x, y). If (x,y) is contained in more than one * vertex's shape, returns the vertex whose center is closest to the pick point. * * @param layout the layout instance that records the positions for all vertices * @param x the x coordinate of the pick point * @param y the y coordinate of the pick point * @return the vertex whose shape contains (x,y), and whose center is closest to the pick point */ public V getVertex(Layout<V, E> layout, double x, double y) { V closest = null; double minDistance = Double.MAX_VALUE; Point2D ip = vv.getRenderContext() .getMultiLayerTransformer() .inverseTransform(Layer.VIEW, new Point2D.Double(x, y)); x = ip.getX(); y = ip.getY(); while (true) { try { for (V v : getFilteredVertices(layout)) { Shape shape = vv.getRenderContext().getVertexShapeTransformer().apply(v); // get the vertex location Point2D p = layout.apply(v); if (p == null) continue; // transform the vertex location to screen coords p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p); double ox = x - p.getX(); double oy = y - p.getY(); if (shape.contains(ox, oy)) { if (style == Style.LOWEST) { // return the first match return v; } else if (style == Style.HIGHEST) { // will return the last match closest = v; } else { // return the vertex closest to the // center of a vertex shape Rectangle2D bounds = shape.getBounds2D(); double dx = bounds.getCenterX() - ox; double dy = bounds.getCenterY() - oy; double dist = dx * dx + dy * dy; if (dist < minDistance) { minDistance = dist; closest = v; } } } } break; } catch (ConcurrentModificationException cme) { } } return closest; }
/** * Retrieves the shape template for <code>e</code> and transforms it according to the positions of * its endpoints in <code>layout</code>. * * @param layout the <code>Layout</code> which specifies <code>e</code>'s endpoints' positions * @param e the edge whose shape is to be returned * @return the transformed shape */ private Shape getTransformedEdgeShape(Layout<V, E> layout, E e) { Pair<V> pair = layout.getGraph().getEndpoints(e); V v1 = pair.getFirst(); V v2 = pair.getSecond(); boolean isLoop = v1.equals(v2); Point2D p1 = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, layout.apply(v1)); Point2D p2 = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, layout.apply(v2)); if (p1 == null || p2 == null) return null; float x1 = (float) p1.getX(); float y1 = (float) p1.getY(); float x2 = (float) p2.getX(); float y2 = (float) p2.getY(); // translate the edge to the starting vertex AffineTransform xform = AffineTransform.getTranslateInstance(x1, y1); Shape edgeShape = vv.getRenderContext().getEdgeShapeTransformer().apply(e); if (isLoop) { // make the loops proportional to the size of the vertex Shape s2 = vv.getRenderContext().getVertexShapeTransformer().apply(v2); Rectangle2D s2Bounds = s2.getBounds2D(); xform.scale(s2Bounds.getWidth(), s2Bounds.getHeight()); // move the loop so that the nadir is centered in the vertex xform.translate(0, -edgeShape.getBounds2D().getHeight() / 2); } else { float dx = x2 - x1; float dy = y2 - y1; // rotate the edge to the angle between the vertices double theta = Math.atan2(dy, dx); xform.rotate(theta); // stretch the edge to span the distance between the vertices float dist = (float) Math.sqrt(dx * dx + dy * dy); xform.scale(dist, 1.0f); } // transform the edge to its location and dimensions edgeShape = xform.createTransformedShape(edgeShape); return edgeShape; }
/** * Returns the vertices whose layout coordinates are contained in <code>Shape</code>. The shape is * in screen coordinates, and the graph vertices are transformed to screen coordinates before they * are tested for inclusion. * * @return the <code>Collection</code> of vertices whose <code>layout</code> coordinates are * contained in <code>shape</code>. */ public Collection<V> getVertices(Layout<V, E> layout, Shape shape) { Set<V> pickedVertices = new HashSet<V>(); // remove the view transform from the rectangle shape = vv.getRenderContext().getMultiLayerTransformer().inverseTransform(Layer.VIEW, shape); while (true) { try { for (V v : getFilteredVertices(layout)) { Point2D p = layout.apply(v); if (p == null) continue; p = vv.getRenderContext().getMultiLayerTransformer().transform(Layer.LAYOUT, p); if (shape.contains(p)) { pickedVertices.add(v); } } break; } catch (ConcurrentModificationException cme) { } } return pickedVertices; }