public void clear() {
    // System.err.println("run clear");
    ForceSimulator fsim = getForceSimulator();
    fsim.clear();

    // make sure we have force items to work with
    TupleSet t = (TupleSet) m_vis.getGroup(m_nodeGroup);

    Iterator iter = m_vis.visibleItems(m_nodeGroup);
    while (iter.hasNext()) {
      VisualItem item = (VisualItem) iter.next();
      if (!item.canGet(ANCHORITEM, ForceItem.class)) break;
      // get force item
      ForceItem fitem = (ForceItem) item.get(FORCEITEM);
      if (fitem != null) {
        fitem.location[0] = (float) item.getEndX();
        fitem.location[1] = (float) item.getEndY();
        fitem.mass = getMassValue(item);

        // get spring anchor
        ForceItem aitem = (ForceItem) item.get(ANCHORITEM);
        // only reset if an anchor exists
        if (aitem != null) {
          aitem.location[0] = fitem.location[0];
          aitem.location[1] = fitem.location[1];

          fsim.addItem(fitem);
          fsim.addSpring(fitem, aitem, 0);
        }
      }
    }
  }
    protected void initSimulator(ForceSimulator fsim) {
      // make sure we have force items to work with
      TupleSet t = (TupleSet) m_vis.getGroup(m_group);
      t.addColumns(ANCHORITEM_SCHEMA);
      t.addColumns(FORCEITEM_SCHEMA);

      Iterator iter = m_vis.visibleItems(m_nodeGroup);
      while (iter.hasNext()) {
        VisualItem item = (VisualItem) iter.next();
        // get force item
        ForceItem fitem = (ForceItem) item.get(FORCEITEM);
        if (fitem == null) {
          fitem = new ForceItem();
          item.set(FORCEITEM, fitem);
        }
        fitem.location[0] = (float) item.getEndX();
        fitem.location[1] = (float) item.getEndY();
        fitem.mass = getMassValue(item);

        // get spring anchor
        ForceItem aitem = (ForceItem) item.get(ANCHORITEM);
        if (aitem == null) {
          aitem = new ForceItem();
          item.set(ANCHORITEM, aitem);
          aitem.location[0] = fitem.location[0];
          aitem.location[1] = fitem.location[1];
        }

        fsim.addItem(fitem);
        fsim.addSpring(fitem, aitem, 0);
      }
    }
 public void reset() {
   Iterator iter = m_vis.visibleItems(m_nodeGroup);
   while (iter.hasNext()) {
     VisualItem item = (VisualItem) iter.next();
     ForceItem aitem = (ForceItem) item.get(ANCHORITEM);
     if (aitem != null) {
       aitem.location[0] = (float) item.getEndX();
       aitem.location[1] = (float) item.getEndY();
     }
   }
   super.reset();
 }
  /** @see prefuse.action.Action#run(double) */
  public void run(double frac) {
    VisualItem lastItem = null;

    Rectangle2D bounds = getLayoutBounds();
    float floor =
        (float)
            (m_horiz
                ? (m_top ? bounds.getMaxX() : bounds.getMinX())
                : (m_top ? bounds.getMinY() : bounds.getMaxY()));
    int bias = (m_horiz ? 0 : 1);

    // TODO: generalize this -- we want tuplesReversed available for general sets
    Iterator iter = ((ITable) m_vis.getGroup(m_group)).tuplesReversed();
    while (iter.hasNext()) {
      VisualItem item = (VisualItem) iter.next();
      boolean prev = item.isStartVisible();
      boolean cur = item.isVisible();

      if (!prev && cur) {
        // newly visible, update contour
        float[] f = (float[]) item.get(m_polyField);
        if (f == null) continue;

        if (lastItem == null) {
          // no previous items, smash values to the floor
          for (int i = 0; i < f.length; i += 2) f[i + bias] = floor;
        } else {
          // previous visible item, smash values to the
          // visible item's contour
          float[] l = (float[]) lastItem.get(m_polyField);
          for (int i = 0; i < f.length / 2; i += 2)
            f[i + bias] = f[f.length - 2 - i + bias] = l[i + bias];
        }
      } else if (prev && cur) {
        // this item was previously visible, remember it
        lastItem = item;
      }
    }
  }
  @SuppressWarnings("unchecked")
  protected List<RendererListItem> getList(VisualItem vi) {
    List<RendererListItem> list;
    // = (List<RendererListItem>) vi.get( "vcache" );
    // if ( list == null )

    list = new LinkedList<RendererListItem>();

    ArtifactNode node = (ArtifactNode) vi.get("node");

    list.add(new TextItem(node.artifact.getDependencyConflictId(), true, false, true));

    return list;
  }
  protected Shape getRawShape(VisualItem item) {
    Rectangle2D bounds = super.getRawShape(item).getBounds2D();
    double x = bounds.getX();
    double y = bounds.getY();
    double width = bounds.getWidth();
    double height = bounds.getHeight();
    Shape result = null;

    nl.cwi.sen1.graph.types.Shape shape =
        (nl.cwi.sen1.graph.types.Shape) item.get(GraphConstants.SHAPE);
    if (shape.isDiamond()) {
      result = getDiamondShape(x, y, width, height);
    } else if (shape.isBox()) {
      result = getBoxShape(x, y, width, height);
    } else if (shape.isEllipse()) {
      result = getEllipseShape(x, y, width, height);
    } else if (shape.isCircle()) {
      result = getCircleShape(x, y, width, height);
    } else {
      result = getBoxShape(x, y, width, height);
    }

    return new GraphCompositeShape(super.getRawShape(item), result);
  }
    @Override
    public void render(Graphics2D g, VisualItem item) {

      if (item.isVisible()) {
        item.setShape(Constants.SHAPE_RECTANGLE);
        RectangularShape shape = (RectangularShape) getShape(item);
        if (shape != null) {

          shape
              .getBounds2D()
              .setRect(
                  (double) item.get(VisualItem.X),
                  (double) item.get(VisualItem.Y),
                  item.getSize(),
                  item.getSize());

          // draw basic glyph
          Color strokeColor = ColorLib.getColor(item.getStrokeColor());
          Color fillColor = ColorLib.getColor(item.getFillColor());

          //                    int size = (int)item.getSize();
          int x = (int) item.getX() + bufferPx;
          int y = (int) item.getY() + bufferPx;
          int w = (int) item.getDouble(WIDTH) - 2 * bufferPx;
          int h = (int) item.getDouble(HEIGHT) - 2 * bufferPx;
          g.setPaint(fillColor);
          g.fillRect(x, y, w, h);

          // draw string on-top of glyph, filling the glyph's area

          //                    String s = "doc=" + item.getString(NODE_NAME) + "\n";
          String s = "";

          // set text: full document if no search term, else excerpts containing the search term
          String queryStr = searchQ.getSearchSet().getQuery();
          String focusText = item.getString(DocumentGridTable.NODE_FOCUS_TEXT);
          if (queryStr != null
              && !queryStr.isEmpty()
              && focusText != null
              && !focusText.equals("null")
              && !focusText.equals("")) {
            // if search query and terms present in document, use term-containing spans
            s += focusText;
          } else if (queryStr != null
              && !queryStr.isEmpty()
              && focusText.equals(FOCUS_SENT_SPLITTER)) {
            // if search query but no terms present in document, use blank
            s += "";
          } else if ((queryStr == null || queryStr.isEmpty()) && item.canGetInt(NODE_ID)) {
            // if no search query, build feature-oriented summary based on color attribute
            s = controller.getDocumentSummary(item.getInt(NODE_ID), colorAttrName);
          }

          // TODO : idea: set font size dynamically based on number of active nodes? based on size
          // of rect?
          int fontSize = 10;

          item.setFont(FontLib.getFont("Tahoma", Font.PLAIN, fontSize));

          Font f = item.getFont();

          // compute width, height for the given text
          // NOTE: this logic has been moved into drawStringMultiline
          //                    int[] textDims = getTextDims(g, f, s);

          // debug
          //                    System.out.println("debug: "+this.getClass().getName()+":
          // drawStringMultiline at x="+x1+", y="+y1+", w="+w+", h="+h);
          drawStringMultiline(g, f, s, x, y, w, h);
        }
      }
    }