Package org.graphstream.stream.file

Source Code of org.graphstream.stream.file.FileSinkTikZ$PointsWrapper

/*
* Copyright 2006 - 2013
*     Stefan Balev     <stefan.balev@graphstream-project.org>
*     Julien Baudry    <julien.baudry@graphstream-project.org>
*     Antoine Dutot    <antoine.dutot@graphstream-project.org>
*     Yoann Pigné      <yoann.pigne@graphstream-project.org>
*     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
*
* This file is part of GraphStream <http://graphstream-project.org>.
*
* GraphStream is a library whose purpose is to handle static or dynamic
* graph, create them from scratch, file or any source and display them.
*
* This program is free software distributed under the terms of two licenses, the
* CeCILL-C license that fits European law, and the GNU Lesser General Public
* License. You can  use, modify and/ or redistribute the software under the terms
* of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
* URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
*/
package org.graphstream.stream.file;

import java.awt.Color;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;

import org.graphstream.graph.Edge;
import org.graphstream.graph.Element;
import org.graphstream.graph.Node;
import org.graphstream.stream.GraphReplay;
import org.graphstream.ui.geom.Point3;
import org.graphstream.ui.graphicGraph.GraphicEdge;
import org.graphstream.ui.graphicGraph.GraphicGraph;
import org.graphstream.ui.graphicGraph.GraphicNode;
import org.graphstream.ui.graphicGraph.StyleGroup;
import org.graphstream.ui.graphicGraph.StyleGroupSet;
import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.FillMode;
import org.graphstream.ui.graphicGraph.stylesheet.StyleConstants.SizeMode;
import org.graphstream.ui.layout.springbox.implementations.SpringBox;

/**
* An export of a graph to PGF/TikZ format.
* <a>http://sourceforge.net/projects/pgf/</a>
*
* This allows to include graph in a latex document. Only
* <code>writeAll(Graph,*)</code> is working, dynamics is not handle. If the
* exported graph is a GraphicGraph, then CSS style of the graph will be used.
*
* For a better rendering, it is strongly recommended to run previously a layout
* algorithm that will add coordinates on nodes. Else, random coordinates will
* be choosen for nodes. Layout can be run in this way : <code>
* Graph g;
* ...
* SpringBox sbox = new SpringBox();
*
* g.addSink(sbox);
* sbox.addAttributeSink(g);
*
* do sbox.compute(); while (sbox.getStabilization() < 0.9);
*
* g.removeSink(sbox);
* sbox.remoteAttributeSink(g);
* </code>
*
* TikZ pictures are scalable so pixel units is not handle here. The picture is
* bounded in a box which width and height can be defined by adding attributes
* to the graph:
* <ul>
* <li>"ui.tikz.width"</li>
* <li>"ui.tikz.height"</li>
* </ul>
* The value of these attributes has to be considered as centimeters.
*
* Common supported style :
* <ul>
* <li>"fill-color", alpha is supported to</li>
* <li>"size" in "gu"</li>
* </ul>
*
* Node supported style :
* <ul>
* <li>"shape" with "box", "rounded-box", "circle", "triangle", "diamond"</li>
* <li>"stroke-mode" with "plain"</li>
* <li>"stroke-color", alpha is supported to</li>
* <li>"stroke-width" in "gu"</li>
* </ul>
*
* Edge supported style :
* <ul>
* </ul>
*/
public class FileSinkTikZ extends FileSinkBase {

  /**
   * Node attribute storing coordinates.
   */
  public static final String XYZ_ATTR = "xyz";

  /**
   * Graph attribute storing width of the TikZ picture.
   */
  public static final String WIDTH_ATTR = "ui.tikz.width";

  /**
   * Graph attribute storing height of the TikZ picture.
   */
  public static final String HEIGHT_ATTR = "ui.tikz.height";

  public static final double DEFAULT_WIDTH = 10;

  public static final double DEFAULT_HEIGHT = 10;

  /**
   * Define the default minimum size of nodes when using a dynamic size. This
   * size is in millimeter.
   */
  public static final double DISPLAY_MIN_SIZE_IN_MM = 2;

  /**
   * Define the default maximum size of nodes when using a dynamic size. This
   * size is in millimeter.
   */
  public static final double DISPLAY_MAX_SIZE_IN_MM = 10;

  protected PrintWriter out;

  protected HashMap<String, String> colors = new HashMap<String, String>();
  protected HashMap<String, String> classes = new HashMap<String, String>();
  protected HashMap<String, String> classNames = new HashMap<String, String>();

  protected int classIndex = 0;
  protected int colorIndex = 0;

  protected double width = Double.NaN;
  protected double height = Double.NaN;

  protected boolean layout = false;

  protected GraphicGraph buffer;

  protected String css = null;

  protected double minSize = 0;

  protected double maxSize = 0;

  protected double displayMinSize = DISPLAY_MIN_SIZE_IN_MM;

  protected double displayMaxSize = DISPLAY_MAX_SIZE_IN_MM;

  private double xmin, ymin, xmax, ymax;

  private PointsWrapper points;
  private Locale l = Locale.ROOT;

  protected static String formatId(String id) {
    return "node" + id.replaceAll("\\W", "_");
  }

  public FileSinkTikZ() {
    buffer = new GraphicGraph("tikz-buffer");
  }

  public double getWidth() {
    return width;
  }

  public void setWidth(double width) {
    this.width = width;
  }

  public double getHeight() {
    return height;
  }

  public void setHeight(double height) {
    this.height = height;
  }

  public void setDisplaySize(double min, double max) {
    this.displayMinSize = min;
    this.displayMaxSize = max;
  }

  public void setCSS(String css) {
    this.css = css;
  }

  public void setLayout(boolean layout) {
    this.layout = layout;
  }

  protected double getNodeX(Node n) {
    if (n.hasAttribute(XYZ_ATTR))
      return ((Number) (n.getArray(XYZ_ATTR)[0])).doubleValue();

    if (n.hasAttribute("x"))
      return n.getNumber("x");

    return Double.NaN;
  }

  protected double getNodeY(Node n) {
    if (n.hasAttribute(XYZ_ATTR))
      return ((Number) (n.getArray(XYZ_ATTR)[1])).doubleValue();

    if (n.hasAttribute("y"))
      return n.getNumber("y");

    return Double.NaN;
  }

  protected String getNodeStyle(Node n) {
    String style = "tikzgsnode";

    if (n instanceof GraphicNode) {
      GraphicNode gn = (GraphicNode) n;

      style = classNames.get(gn.style.getId());

      if (gn.style.getFillMode() == FillMode.DYN_PLAIN) {
        double uicolor = gn.getNumber("ui.color");

        if (Double.isNaN(uicolor))
          uicolor = 0;

        int c = gn.style.getFillColorCount();
        int s = 1;
        double d = 1.0 / (c - 1);

        while (s * d < uicolor && s < c)
          s++;

        uicolor -= (s - 1) * d;
        uicolor *= c;

        style += String.format(Locale.ROOT, ", fill=%s!%d!%s",
            checkColor(gn.style.getFillColor(0)),
            (int) (uicolor * 100),
            checkColor(gn.style.getFillColor(1)));
      }

      if (gn.style.getSizeMode() == SizeMode.DYN_SIZE) {
        double uisize = gn.getNumber("ui.size");

        if (Double.isNaN(uisize))
          uisize = minSize;

        uisize = (uisize - minSize) / (maxSize - minSize);
        uisize = uisize * (displayMaxSize - displayMinSize)
            + displayMinSize;

        style += String.format(Locale.ROOT, ", minimum size=%fmm",
            uisize);
      }
    }

    return style;
  }

  protected String getEdgeStyle(Edge e) {
    String style = "tikzgsnode";

    if (e instanceof GraphicEdge) {
      GraphicEdge ge = (GraphicEdge) e;

      style = classNames.get(ge.style.getId());

      if (ge.style.getFillMode() == FillMode.DYN_PLAIN) {
        double uicolor = ge.getNumber("ui.color");

        if (Double.isNaN(uicolor))
          uicolor = 0;

        int c = ge.style.getFillColorCount();
        int s = 1;
        double d = 1.0 / (c - 1);

        while (s * d < uicolor && s < c)
          s++;

        uicolor -= (s - 1) * d;
        uicolor *= c;

        style += String.format(Locale.ROOT, ", draw=%s!%d!%s",
            checkColor(ge.style.getFillColor(s - 1)),
            (int) (uicolor * 100),
            checkColor(ge.style.getFillColor(s)));
      }

      if (ge.style.getSizeMode() == SizeMode.DYN_SIZE) {
        double uisize = ge.getNumber("ui.size");

        if (Double.isNaN(uisize) || uisize < 0.01)
          uisize = 1;

        style += String
            .format(Locale.ROOT, ", line width=%fpt", uisize);
      }
    }

    return style;
  }

  protected String checkColor(Color c) {
    String rgb = String.format(Locale.ROOT, "%.3f,%.3f,%.3f",
        c.getRed() / 255.0f, c.getGreen() / 255.0f,
        c.getBlue() / 255.0f);

    if (colors.containsKey(rgb))
      return colors.get(rgb);

    String key = String.format("tikzC%02d", colorIndex++);
    colors.put(rgb, key);

    return key;
  }

  /**
   * Convert a StyleGroup to tikz style.
   *
   * @param group
   *            the style group to convert
   * @return string representation of the style group usable in TikZ.
   */
  protected String getTikzStyle(StyleGroup group) {
    StringBuilder buffer = new StringBuilder();
    LinkedList<String> style = new LinkedList<String>();

    for (int i = 0; i < group.getFillColorCount(); i++)
      checkColor(group.getFillColor(i));

    switch (group.getType()) {
    case NODE: {
      if (group.getFillMode() != FillMode.DYN_PLAIN) {
        String fill = checkColor(group.getFillColor(0));
        style.add("fill=" + fill);
      }

      if (group.getFillColor(0).getAlpha() < 255)
        style.add(String.format(Locale.ROOT, "fill opacity=%.2f", group
            .getFillColor(0).getAlpha() / 255.0f));

      switch (group.getStrokeMode()) {
      case DOTS:
      case DASHES:
      case PLAIN:
        String stroke = checkColor(group.getStrokeColor(0));
        style.add("draw=" + stroke);
        style.add("line width="
            + String.format(Locale.ROOT, "%.1fpt",
                group.getStrokeWidth().value));

        if (group.getStrokeColor(0).getAlpha() < 255)
          style.add(String.format(Locale.ROOT, "draw opacity=%.2f",
              group.getStrokeColor(0).getAlpha() / 255.0f));

        break;
      default:
        System.err.printf("unhandled stroke mode : %s%n",
            group.getStrokeMode());
      }

      switch (group.getShape()) {
      case CIRCLE:
        style.add("circle");
        break;
      case ROUNDED_BOX:
        style.add("rounded corners=2pt");
      case BOX:
        style.add("rectangle");
        break;
      case TRIANGLE:
        style.add("isosceles triangle");
        break;
      case DIAMOND:
        style.add("diamond");
        break;
      default:
        System.err.printf("unhandled shape : %s%n", group.getShape());
      }

      String text = checkColor(group.getTextColor(0));
      style.add("text=" + text);

      switch (group.getSize().units) {
      case GU:
        style.add("minimum size="
            + String.format(Locale.ROOT, "%.1fcm",
                group.getSize().values.get(0)));
        break;
      case PX:
        style.add("minimum size="
            + String.format(Locale.ROOT, "%.1fpt",
                group.getSize().values.get(0)));
        break;
      default:
        System.err
            .printf("%% [warning] units %s are not compatible with TikZ.%n",
                group.getSize().units);
      }

      style.add("inner sep=0pt");
    }
      break;
    case EDGE: {
      if (group.getFillMode() != FillMode.DYN_PLAIN) {
        String fill = checkColor(group.getFillColor(0));
        style.add("draw=" + fill);
      }

      if (group.getFillColor(0).getAlpha() < 255)
        style.add(String.format(Locale.ROOT, "draw opacity=%.2f", group
            .getFillColor(0).getAlpha() / 255.0f));

      switch (group.getSize().units) {
      case PX:
      case GU:
        style.add("line width="
            + String.format(Locale.ROOT, "%.1fpt",
                group.getSize().values.get(0)));
        break;
      default:
        System.err
            .printf("%% [warning] units %s are not compatible with TikZ.%n",
                group.getSize().units);
      }
    }
      break;
    default:
      System.err.printf("unhandled group type : %s%n", group.getType());
    }

    for (int i = 0; i < style.size(); i++) {
      if (i > 0)
        buffer.append(",");

      buffer.append(style.get(i));
    }

    return buffer.toString();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.file.FileSinkBase#outputHeader()
   */
  protected void outputHeader() throws IOException {
    out = (PrintWriter) output;

    colors.clear();
    classes.clear();
    classNames.clear();

    buffer.clear();
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.file.FileSinkBase#outputEndOfFile()
   */
  protected void outputEndOfFile() throws IOException {
    if (Double.isNaN(width)) {
      if (buffer.hasNumber(WIDTH_ATTR))
        width = buffer.getNumber(WIDTH_ATTR);
      else
        width = DEFAULT_WIDTH;
    }

    if (Double.isNaN(height)) {
      if (buffer.hasNumber(HEIGHT_ATTR))
        height = buffer.getNumber(HEIGHT_ATTR);
      else
        height = DEFAULT_WIDTH;
    }

    checkLayout();

    if (css != null)
      buffer.addAttribute("ui.stylesheet", css);

    points = new PointsWrapper();

    //
    // Begin tikzpicture
    //
    out.printf("%%%n%% Do not forget \\usepackage{tikz} in header.%n%%%n");
    out.printf("\\begin{tikzpicture}");

    checkAndOutputStyle();
    checkXYandSize();

    for (Node n : buffer.getEachNode()) {
      double x, y;

      x = getNodeX(n);
      y = getNodeY(n);

      if (Double.isNaN(x) || Double.isNaN(y)) {
        x = Math.random() * width;
        y = Math.random() * height;
      } else {
        x = width * (x - xmin) / (xmax - xmin);
        y = height * (y - ymin) / (ymax - ymin);
      }

      out.printf(l, "\t\\node[inner sep=0pt] (%s) at (%f,%f) {};%n",
          formatId(n.getId()), x, y);
    }

    StyleGroupSet sgs = buffer.getStyleGroups();

    for (HashSet<StyleGroup> groups : sgs.zIndex()) {
      for (StyleGroup group : groups) {
        switch (group.getType()) {
        case NODE:
          for (Element e : group.elements())
            outputNode((Node) e);
          break;
        case EDGE:
          for (Element e : group.elements())
            outputEdge((Edge) e);
          break;
        default:
        }
      }
    }

    //
    // End of tikzpicture.
    //
    out.printf("\\end{tikzpicture}%n");
  }

  private void checkLayout() {
    if (!layout)
      return;

    SpringBox sbox = new SpringBox();

    GraphReplay replay = new GraphReplay("replay");
    replay.addSink(sbox);
    sbox.addAttributeSink(buffer);

    replay.replay(buffer);

    do
      sbox.compute();
    while (sbox.getStabilization() < 0.9);

    buffer.removeSink(sbox);
    sbox.removeAttributeSink(buffer);
  }

  private void checkXYandSize() {
    xmin = ymin = Double.MAX_VALUE;
    xmax = ymax = Double.MIN_VALUE;

    for (Node n : buffer.getEachNode()) {
      double x, y;

      x = getNodeX(n);
      y = getNodeY(n);

      if (!Double.isNaN(x) && !Double.isNaN(y)) {
        xmin = Math.min(xmin, x);
        xmax = Math.max(xmax, x);
        ymin = Math.min(ymin, y);
        ymax = Math.max(ymax, y);
      } else {
        System.err.printf("%% [warning] missing node (x,y).%n");
      }

      if (n.hasNumber("ui.size")) {
        minSize = Math.min(minSize, n.getNumber("ui.size"));
        maxSize = Math.max(maxSize, n.getNumber("ui.size"));
      }
    }

    if (minSize == maxSize)
      maxSize += 1;

    for (Edge e : buffer.getEachEdge()) {
      points.setElement(e);

      if (points.check()) {
        for (int i = 0; i < points.getPointsCount(); i++) {
          double x = points.getX(i);
          double y = points.getY(i);

          xmin = Math.min(xmin, x);
          xmax = Math.max(xmax, x);
          ymin = Math.min(ymin, y);
          ymax = Math.max(ymax, y);
        }
      }
    }
  }

  private void checkAndOutputStyle() {
    String nodeStyle = "circle,draw=black,fill=black";
    String edgeStyle = "draw=black";
    StyleGroupSet sgs = buffer.getStyleGroups();

    for (StyleGroup sg : sgs.groups()) {
      String key = String.format("class%02d", classIndex++);
      classNames.put(sg.getId(), key);
      classes.put(key, getTikzStyle(sg));
    }

    out.printf("[%n");

    for (String key : classes.keySet())
      out.printf(l, "\t%s/.style={%s},%n", key, classes.get(key));

    out.printf(l, "\ttikzgsnode/.style={%s},%n", nodeStyle);
    out.printf(l, "\ttikzgsedge/.style={%s}%n", edgeStyle);

    out.printf("]%n");

    for (String rgb : colors.keySet())
      out.printf(l, "\t\\definecolor{%s}{rgb}{%s}%n", colors.get(rgb),
          rgb);
  }

  private void outputNode(Node n) {
    String label;
    String style = getNodeStyle(n);

    label = n.hasAttribute("label") ? (String) n.getLabel("label") : "";

    out.printf(l, "\t\\node[%s] at (%s) {%s};%n", style,
        formatId(n.getId()), label);
  }

  private void outputEdge(Edge e) {
    String style = getEdgeStyle(e);
    String uiPoints = "";
    points.setElement(e);

    if (points.check()) {
      for (int i = 0; i < points.getPointsCount(); i++) {
        double x, y;

        x = points.getX(i);
        y = points.getY(i);
        x = width * (x - xmin) / (xmax - xmin);
        y = height * (y - ymin) / (ymax - ymin);

        uiPoints = String
            .format(l, "%s-- (%.3f,%.3f) ", uiPoints, x, y);
      }
    }

    out.printf(l, "\t\\draw[%s] (%s) %s%s (%s);%n", style, formatId(e
        .getSourceNode().getId()), uiPoints, e.isDirected() ? "->"
        : "--", formatId(e.getTargetNode().getId()));
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#graphAttributeAdded(java.lang.String
   * , long, java.lang.String, java.lang.Object)
   */
  public void graphAttributeAdded(String sourceId, long timeId,
      String attribute, Object value) {
    buffer.graphAttributeAdded(sourceId, timeId, attribute, value);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#graphAttributeChanged(java.lang.
   * String, long, java.lang.String, java.lang.Object, java.lang.Object)
   */
  public void graphAttributeChanged(String sourceId, long timeId,
      String attribute, Object oldValue, Object newValue) {
    buffer.graphAttributeChanged(sourceId, timeId, attribute, oldValue,
        newValue);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#graphAttributeRemoved(java.lang.
   * String, long, java.lang.String)
   */
  public void graphAttributeRemoved(String sourceId, long timeId,
      String attribute) {
    buffer.graphAttributeRemoved(sourceId, timeId, attribute);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#nodeAttributeAdded(java.lang.String,
   * long, java.lang.String, java.lang.String, java.lang.Object)
   */
  public void nodeAttributeAdded(String sourceId, long timeId, String nodeId,
      String attribute, Object value) {
    buffer.nodeAttributeAdded(sourceId, timeId, nodeId, attribute, value);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#nodeAttributeChanged(java.lang.String
   * , long, java.lang.String, java.lang.String, java.lang.Object,
   * java.lang.Object)
   */
  public void nodeAttributeChanged(String sourceId, long timeId,
      String nodeId, String attribute, Object oldValue, Object newValue) {
    buffer.nodeAttributeChanged(sourceId, timeId, nodeId, attribute,
        oldValue, newValue);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#nodeAttributeRemoved(java.lang.String
   * , long, java.lang.String, java.lang.String)
   */
  public void nodeAttributeRemoved(String sourceId, long timeId,
      String nodeId, String attribute) {
    buffer.nodeAttributeRemoved(sourceId, timeId, nodeId, attribute);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#edgeAttributeAdded(java.lang.String,
   * long, java.lang.String, java.lang.String, java.lang.Object)
   */
  public void edgeAttributeAdded(String sourceId, long timeId, String edgeId,
      String attribute, Object value) {
    buffer.edgeAttributeAdded(sourceId, timeId, edgeId, attribute, value);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#edgeAttributeChanged(java.lang.String
   * , long, java.lang.String, java.lang.String, java.lang.Object,
   * java.lang.Object)
   */
  public void edgeAttributeChanged(String sourceId, long timeId,
      String edgeId, String attribute, Object oldValue, Object newValue) {
    buffer.edgeAttributeChanged(sourceId, timeId, edgeId, attribute,
        oldValue, newValue);
  }

  /*
   * (non-Javadoc)
   *
   * @see
   * org.graphstream.stream.AttributeSink#edgeAttributeRemoved(java.lang.String
   * , long, java.lang.String, java.lang.String)
   */
  public void edgeAttributeRemoved(String sourceId, long timeId,
      String edgeId, String attribute) {
    buffer.edgeAttributeRemoved(sourceId, timeId, edgeId, attribute);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.ElementSink#nodeAdded(java.lang.String, long,
   * java.lang.String)
   */
  public void nodeAdded(String sourceId, long timeId, String nodeId) {
    buffer.nodeAdded(sourceId, timeId, nodeId);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.ElementSink#nodeRemoved(java.lang.String,
   * long, java.lang.String)
   */
  public void nodeRemoved(String sourceId, long timeId, String nodeId) {
    buffer.nodeRemoved(sourceId, timeId, nodeId);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.ElementSink#edgeAdded(java.lang.String, long,
   * java.lang.String, java.lang.String, java.lang.String, boolean)
   */
  public void edgeAdded(String sourceId, long timeId, String edgeId,
      String fromNodeId, String toNodeId, boolean directed) {
    buffer.edgeAdded(sourceId, timeId, edgeId, fromNodeId, toNodeId,
        directed);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.ElementSink#edgeRemoved(java.lang.String,
   * long, java.lang.String)
   */
  public void edgeRemoved(String sourceId, long timeId, String edgeId) {
    buffer.edgeRemoved(sourceId, timeId, edgeId);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.ElementSink#graphCleared(java.lang.String,
   * long)
   */
  public void graphCleared(String sourceId, long timeId) {
    buffer.graphCleared(sourceId, timeId);
  }

  /*
   * (non-Javadoc)
   *
   * @see org.graphstream.stream.ElementSink#stepBegins(java.lang.String,
   * long, double)
   */
  public void stepBegins(String sourceId, long timeId, double step) {
    buffer.stepBegins(sourceId, timeId, step);
  }

  protected class PointsWrapper {
    Object[] points;

    PointsWrapper() {
    }

    public void setElement(Element e) {
      if (e.hasArray("ui.points"))
        points = e.getArray("ui.points");
      else
        points = null;
    }

    public boolean check() {
      if (points == null)
        return false;

      for (int i = 0; i < points.length; i++) {
        if (!(points[i] instanceof Point3)
            && !points[i].getClass().isArray())
          return false;
      }

      return true;
    }

    public int getPointsCount() {
      return points == null ? 0 : points.length;
    }

    public double getX(int i) {
      if (points == null || i >= points.length)
        return Double.NaN;

      Object p = points[i];

      if (p instanceof Point3)
        return ((Point3) p).x;
      else {
        Object x = Array.get(p, 0);

        if (x instanceof Number)
          return ((Number) x).doubleValue();
        else
          return Array.getDouble(p, 0);
      }
    }

    public double getY(int i) {
      if (i >= points.length)
        return Double.NaN;

      Object p = points[i];

      if (p instanceof Point3)
        return ((Point3) p).y;
      else {
        Object y = Array.get(p, 0);

        if (y instanceof Number)
          return ((Number) y).doubleValue();
        else
          return Array.getDouble(p, 1);
      }
    }
  }
}
TOP

Related Classes of org.graphstream.stream.file.FileSinkTikZ$PointsWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.