All Downloads are FREE. Search and download functionalities are using the official Maven repository.

lphystudio.core.layeredgraph.NodePaintUtils Maven / Gradle / Ivy

The newest version!
package lphystudio.core.layeredgraph;

import lphy.core.model.Generator;
import lphy.core.model.RandomVariable;
import lphy.core.model.Value;
import lphy.core.model.ValueUtils;
import lphy.core.parser.LPhyParserDictionary;
import lphy.core.vectorization.IID;
import lphy.core.vectorization.VectorizedDistribution;
import lphy.core.vectorization.VectorizedFunction;
import lphystudio.core.theme.ThemeColours;

import javax.swing.*;
import java.awt.*;
import java.awt.geom.*;
import java.text.DecimalFormat;

public class NodePaintUtils {

    static DecimalFormat format = new DecimalFormat();

    private static float FACTOR_LABEL_FONT_SIZE = 11.0f;
    private static double ARROWHEAD_WIDTH = 4;
    private static double ARROWHEAD_DEPTH = 10;

    private static JLabel renderer = new JLabel("", JLabel.CENTER);
    private static CellRendererPane crp = new CellRendererPane();


    public static void paintNode(LayeredNode properNode, Graphics2D g2d, JComponent component, LPhyParserDictionary parser) {
        NodeWrapper nodeWrapper = (NodeWrapper) properNode;

        if (!nodeWrapper.isDummy()) {
            LayeredGNode node = (LayeredGNode) nodeWrapper.wrappedNode();

            if (node.value() instanceof Value) {
                paintValueNode((Value) node.value(), node, g2d, component, parser);
            } else if (node.value() instanceof Generator) {
                paintGeneratorNode((Generator) node.value(), node, properNode, g2d);
            }
        }
    }

    private static void paintValueNode(Value value, LayeredGNode gNode, Graphics2D g2d, JComponent component, LPhyParserDictionary parser) {

        Shape shape = null;
        if (value instanceof RandomVariable) {
            shape = nodeCircle(gNode);
        } else if (value.getGenerator() != null) {
            shape = nodeDiamond(gNode);
        } else shape = nodeSquare(gNode);

        Color fillColor = ThemeColours.getFillColor(value, parser);
        Color borderColor = ThemeColours.getBorderColor(value, parser);

        g2d.setColor(fillColor);
        g2d.fill(shape);
        g2d.setColor(borderColor);
        g2d.draw(shape);

        String s = getNodeString(gNode, value, false);
        renderer.setText(s);
        crp.paintComponent(g2d, renderer, component,
                (int) (gNode.getX() - LayeredGNode.VAR_HEIGHT / 2.0), (int) (gNode.getY() - LayeredGNode.VAR_HEIGHT / 2.0), (int) LayeredGNode.VAR_HEIGHT, (int) LayeredGNode.VAR_HEIGHT);
    }

    private static Shape nodeCircle(LayeredNode node) {
        return new Ellipse2D.Double(node.getX() - LayeredGNode.VAR_HEIGHT / 2.0, node.getY() - LayeredGNode.VAR_HEIGHT / 2.0, LayeredGNode.VAR_HEIGHT, LayeredGNode.VAR_HEIGHT);
    }

    private static Shape nodeSquare(LayeredNode node) {
        return new Rectangle2D.Double(node.getX() - LayeredGNode.VAR_HEIGHT / 2.0, node.getY() - LayeredGNode.VAR_HEIGHT / 2.0, LayeredGNode.VAR_HEIGHT, LayeredGNode.VAR_HEIGHT);
    }

    private static Shape nodeDiamond(LayeredNode node) {
        GeneralPath path = new GeneralPath();

        double radius = LayeredGNode.VAR_HEIGHT / 2.0;

        path.moveTo(node.getX()-radius, node.getY());
        path.lineTo(node.getX(), node.getY() - radius);
        path.lineTo(node.getX() + radius, node.getY());
        path.lineTo(node.getX(), node.getY() + radius);
        path.closePath();

        return path;
    }

    private static void paintGeneratorNode(Generator generator, LayeredGNode node, LayeredNode properNode, Graphics2D g2d) {
        Rectangle2D rectangle2D = new Rectangle2D.Double(node.getX() - LayeredGNode.FACTOR_SIZE, node.getY() - LayeredGNode.FACTOR_SIZE, LayeredGNode.FACTOR_SIZE * 2.0, LayeredGNode.FACTOR_SIZE * 2.0);
        g2d.setColor(Color.white);
        g2d.fill(rectangle2D);
        g2d.setColor(Color.black);
        g2d.draw(rectangle2D);
    }

    public static void paintNodeEdges(LayeredNode properNode, Graphics2D g2d, boolean showArgumentLabels, boolean straightEdges) {
        NodeWrapper nodeWrapper = (NodeWrapper) properNode;

        if (nodeWrapper.isDummy()) {
            if (!straightEdges) paintDummyNodeEdges(properNode, g2d);
        } else {

            LayeredGNode node = (LayeredGNode) nodeWrapper.wrappedNode();

            if (node.value() instanceof Value) {
                paintValueNodeEdges((Value) node.value(), properNode, g2d, showArgumentLabels, straightEdges);
            } else if (node.value() instanceof Generator) {
                paintGeneratorNodeEdges((Generator) node.value(), node, properNode, g2d);
            }
        }
    }

    private static void paintDummyNodeEdges(LayeredNode properNode, Graphics2D g2d) {
        double x1 = properNode.getX();
        double y1 = properNode.getY();

        if (properNode.isDummy()) {

            for (LayeredNode successor : properNode.getSuccessors()) {
                double x2 = successor.getX();
                double y2 = successor.getY();
                if (isWrappedParameterized(successor)) {
                    y2 -= LayeredGNode.FACTOR_SIZE;
                } else if (isWrappedValue(successor)) {
                    y2 -= LayeredGNode.VAR_HEIGHT / 2;
                }
                drawLine(g2d, x1, y1, x2, y2);
            }
        }
    }

    /**
     * @param value      the value to paint the node of
     * @param properNode the proper node representing this generator
     * @param g2d        the Graphics2D context to paint to
     */
    private static void paintValueNodeEdges(Value value, LayeredNode properNode, Graphics2D g2d, boolean showArgumentLabels, boolean straightLines) {

        double x1 = properNode.getX();
        double y1 = properNode.getY() + LayeredGNode.VAR_HEIGHT / 2;

        double delta = g2d.getFontMetrics().getAscent() / 2.0;

        for (LayeredNode successor : properNode.getSuccessors()) {

            if (straightLines) {
                successor = getUnwrappedNonDummySuccessor(successor);
            }

            double x2 = successor.getX();
            double y2 = successor.getY() - (successor.isDummy() ? 0.0 : LayeredGNode.FACTOR_SIZE);
            drawLine(g2d, x1, y1, x2, y2);
            if (showArgumentLabels) {
                Generator generator = null;
                if (straightLines) {
                    generator = (Generator) ((LayeredGNode) successor).value();
                } else generator = (Generator) getUnwrappedNonDummySuccessor(successor).value();

                String label = generator.getParamName(value);
                g2d.setColor(Color.gray);
                g2d.drawString(label, (int) Math.round((x1 + x2) / 2.0 - g2d.getFontMetrics().stringWidth(label) / 2.0), (int) Math.round((y1 + y2) / 2.0 + delta));
                g2d.setColor(Color.black);
            }
        }
    }

    /**
     * @param generator  the generator to paint the node of
     * @param node       the LayerdNode representing this Generator
     * @param properNode the proper node representing this generator
     * @param g2d        the Graphics2D context to paint to
     */
    private static void paintGeneratorNodeEdges(Generator generator, LayeredNode node, LayeredNode properNode, Graphics2D g2d) {

        // is this a vectorized Generator?
        boolean vectorized = (generator instanceof VectorizedDistribution || generator instanceof VectorizedFunction || generator instanceof IID);

        String str = generator.getName();
        Integer size = 0;
        if (vectorized) {
            str += "[";

            Value replicatesValue = null;
            if (generator instanceof VectorizedDistribution) {
                replicatesValue = ((VectorizedDistribution)generator).getReplicatesValue();
                size = ((VectorizedDistribution)generator).getComponentDistributions().size();
            } else if (generator instanceof VectorizedFunction) {
                replicatesValue = ((VectorizedFunction)generator).getReplicatesValue();
                size = ((VectorizedFunction)generator).getComponentFunctions().size();
            } else if (generator instanceof IID) {
                replicatesValue = ((IID)generator).getReplicates();
                size = ((IID)generator).size();

            }
            if (replicatesValue != null) {
                str += replicatesValue.isAnonymous() ? replicatesValue.codeString() : replicatesValue.getId();
            } else {
                str += size;
            }

            str += "]";
        }

        LayeredNode properSuccessor = properNode.getSuccessors().get(0);

        Point2D q = properSuccessor.getPosition();

        Font font = g2d.getFont();
        Font newFont = vectorized ? font.deriveFont(Font.BOLD, FACTOR_LABEL_FONT_SIZE) : font.deriveFont(FACTOR_LABEL_FONT_SIZE);
        g2d.setFont(newFont);

        double delta = g2d.getFontMetrics().getAscent() / 2.0;

        g2d.drawString(str, (float) (node.getX() + LayeredGNode.FACTOR_SIZE + LayeredGNode.FACTOR_LABEL_GAP), (float) (node.getY() + delta));
        if (vectorized) g2d.setFont(font);

        double x1 = node.getX();
        double y1 = node.getY() + (properSuccessor.isDummy() ? 0.0 : LayeredGNode.FACTOR_SIZE);
        double x2 = q.getX();
        double y2 = q.getY() - LayeredGNode.VAR_HEIGHT / 2;

        drawArrowLine(g2d, x1, y1, x2, y2, ARROWHEAD_DEPTH, ARROWHEAD_WIDTH);
    }

    private static void drawLine(Graphics2D g, double x1, double y1, double x2, double y2) {
        Line2D line = new Line2D.Double(x1, y1, x2, y2);
        g.draw(line);
    }

    /**
     * Draw an arrow line between two points.
     *
     * @param g the graphics component.
     * @param d the width of the arrow.
     * @param h the height of the arrow.
     */
    private static void drawArrowLine(Graphics2D g, double x1, double y1, double x2, double y2, double d, double h) {

        if (!Double.isNaN(x1) && !Double.isNaN(x2)) {

            double dx = x2 - x1, dy = y2 - y1;
            double D = Math.sqrt(dx * dx + dy * dy);
            double xm = D - d, xn = xm, ym = h, yn = -h, x;
            double sin = dy / D, cos = dx / D;

            x = xm * cos - ym * sin + x1;
            ym = xm * sin + ym * cos + y1;
            xm = x;

            x = xn * cos - yn * sin + x1;
            yn = xn * sin + yn * cos + y1;
            xn = x;

            Line2D.Double line = new Line2D.Double(x1, y1, x2, y2);

            GeneralPath p = new GeneralPath();
            p.moveTo(x2, y2);
            p.lineTo(xm, ym);
            p.lineTo(xn, yn);
            p.closePath();


            g.draw(line);
            g.fill(p);
        }
    }

    private static LayeredGNode getUnwrappedNonDummySuccessor(LayeredNode successor) {
        if (successor.isDummy()) return getUnwrappedNonDummySuccessor(successor.getSuccessors().get(0));
        return (LayeredGNode) ((NodeWrapper) successor).wrappedNode();
    }

    private static boolean isWrappedParameterized(LayeredNode v) {
        return !v.isDummy() && v instanceof NodeWrapper && ((NodeWrapper) v).wrappedNode() instanceof LayeredGNode &&
                ((LayeredGNode) ((NodeWrapper) v).wrappedNode()).value() instanceof Generator;
    }

    private static boolean isWrappedValue(LayeredNode v) {
        return !v.isDummy() && v instanceof NodeWrapper && ((NodeWrapper) v).wrappedNode() instanceof LayeredGNode &&
                ((LayeredGNode) ((NodeWrapper) v).wrappedNode()).value() instanceof Value;
    }

    public static String getNodeString(LayeredGNode node, Value v, boolean showValue) {

        Object value = v.value();

        String name = v.getId();
        if (node.getSuccessors().size() == 1 && v.isAnonymous()) {
//            name = "[" + ((Generator) ((LayeredGNode) node.getSuccessors().get(0)).value()).getParamName(v) + "]";
            // https://github.com/LinguaPhylo/linguaPhylo/issues/249
            name = ((Generator) ((LayeredGNode) node.getSuccessors().get(0)).value()).getParamName(v);
        }
        if (name == null) name = "null";

        String displayName = name;

        if (displayName.length() > 7) {
            displayName = "" + displayName + "";
        }

        if (ValueUtils.isMultiDimensional(value)) {
            return "

" + displayName + "

"; } String valueString = ""; if (showValue) { if (value instanceof Double) { valueString = format.format(value); } else { valueString = value.toString(); if (value instanceof String) { if (valueString.length() > 8) { valueString = valueString.length() + " chars"; if (valueString.length() > 10) { valueString = "string"; } } } } valueString = "

" + valueString + "

"; } return "

" + displayName + "

" + valueString + "
"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy