graphics.Graph.java Source code

Java tutorial

Introduction

Here is the source code for graphics.Graph.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package graphics;

import org.lwjgl.opengl.GL11;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;

/**
 *
 * @author larsat
 */
public class Graph extends Sprite {

    private final int maxPoints;
    private final DataValues[] dataValues;
    //private boolean changed;
    private float minValue;
    private float maxValue;

    public Graph(int maxPoints, float xPos, float yPos, float sizeX, float sizeY) {
        super(xPos, yPos, sizeX, sizeY);
        this.maxPoints = maxPoints;
        if (maxPoints <= 1) {
            maxPoints = 2; // Must always be two or above to avoid graphical issues...
        }
        this.dataValues = new DataValues[maxPoints];
        //this.changed = false;
    }

    public void addValue(float value, String label) {
        for (int i = 1; i < dataValues.length; i++) {
            dataValues[i - 1] = dataValues[i];
        }
        dataValues[dataValues.length - 1] = new DataValues(value, label);
        //this.changed = true;
    }

    public void setMinMax() {
        for (DataValues dv : dataValues) {
            if (dv != null) {
                if (dv.getValue() > maxValue) {
                    maxValue = dv.getValue();
                }
                if (dv.getValue() < minValue) {
                    minValue = dv.getValue();
                }
            }
        }
    }

    @Override
    public void draw() {
        //if (this.changed) {
        setMinMax();
        float margin = 20;
        // White backdrop...
        GL11.glColor3f(1, 1, 1);
        GL11.glBegin(GL11.GL_POLYGON);
        GL11.glVertex2f(this.xPos, this.yPos);
        GL11.glVertex2f(this.xPos + this.sizeX, this.yPos);
        GL11.glVertex2f(this.xPos + this.sizeX, this.yPos + this.sizeY);
        GL11.glVertex2f(this.xPos, this.yPos + this.sizeY);
        GL11.glEnd();

        // Black lines around...
        GL11.glColor3f(0, 0, 0);
        GL11.glBegin(GL11.GL_LINE_LOOP);
        GL11.glVertex2f(this.xPos, this.yPos);
        GL11.glVertex2f(this.xPos + this.sizeX, this.yPos);
        GL11.glVertex2f(this.xPos + this.sizeX, this.yPos + this.sizeY);
        GL11.glVertex2f(this.xPos, this.yPos + this.sizeY);
        GL11.glEnd();

        // Moves origo where it should be, based on the dataset...
        GL11.glColor4f(0, 0, 0, 0.25f);
        float origo = this.yPos + 2 * margin;
        if (maxValue == 0 && minValue == 0) {
            origo += (this.sizeY - 3 * margin) / 2;
        } else if (maxValue <= 0 && minValue < 0) {
            origo += this.sizeY - 3 * margin;
        } else if (maxValue > 0 && minValue < 0) {
            origo += ((minValue * -1) / (maxValue + (minValue * -1))) * (this.sizeY - 3 * margin);
        }
        GL11.glBegin(GL11.GL_LINES);
        GL11.glVertex2f(this.xPos + margin, origo);
        GL11.glVertex2f(this.xPos + this.sizeX - margin, origo);
        GL11.glEnd();

        // draws tabs on the origo-line where the values should be put...
        float tabs = 5;
        for (int i = 0; i < dataValues.length; i++) {
            GL11.glBegin(GL11.GL_LINES);
            GL11.glVertex2f(this.xPos + margin + (i * (this.sizeX - 2 * margin) / (this.dataValues.length - 1)),
                    origo + tabs);
            GL11.glVertex2f(this.xPos + margin + (i * (this.sizeX - 2 * margin) / (this.dataValues.length - 1)),
                    origo - tabs);
            GL11.glEnd();
        }
        Line2D.Double[] lines = new Line2D.Double[dataValues.length - 1];
        for (int i = 0; i < lines.length; i++) {
            if (dataValues[i] == null) {
                continue;
            }
            float x = this.xPos + margin + (i * (this.sizeX - 2 * margin) / (this.dataValues.length - 1));
            float y = (this.yPos + 2 * margin) + ((this.sizeY - 3 * margin)
                    * ((this.dataValues[i].getValue() + Math.abs(minValue)) / (maxValue + Math.abs(minValue))));
            float x2 = this.xPos + margin + ((i + 1) * (this.sizeX - 2 * margin) / (this.dataValues.length - 1));
            float y2 = (this.yPos + 2 * margin) + ((this.sizeY - 3 * margin)
                    * ((this.dataValues[i + 1].getValue() + Math.abs(minValue)) / (maxValue + Math.abs(minValue))));
            lines[i] = new Line2D.Double(x, y, x2, y2);
        }

        // Draws the value-lines on the graph...
        Line2D.Double origLine = new Line2D.Double(this.xPos + margin, origo,
                this.xPos + margin + (this.sizeX - 2 * margin), origo);
        GL11.glLineWidth(2);
        GL11.glShadeModel(GL11.GL_FLAT);
        GL11.glBegin(GL11.GL_LINE_STRIP);
        for (Line2D.Double line : lines) {
            if (line == null) {
                continue;
            }
            if (line.intersectsLine(origLine)) {
                Point2D interSect = getIntersection(line, origLine);
                if (line.y1 > origo) {
                    GL11.glColor4f(0, 1, 0, 1);
                    GL11.glVertex2d(line.x1, line.y1);
                    GL11.glVertex2d(interSect.getX(), interSect.getY());
                    GL11.glColor4f(1, 0, 0, 1);
                    GL11.glVertex2d(line.x2, line.y2);
                } else {
                    GL11.glColor4f(1, 0, 0, 1);
                    GL11.glVertex2d(line.x1, line.y1);
                    GL11.glVertex2d(interSect.getX(), interSect.getY());
                    GL11.glColor4f(0, 1, 0, 1);
                    GL11.glVertex2d(line.x2, line.y2);
                }
            } else {
                if (line.y1 > origo) {
                    GL11.glColor4f(0, 1, 0, 1);
                    GL11.glVertex2d(line.x1, line.y1);
                    GL11.glVertex2d(line.x2, line.y2);
                } else {
                    GL11.glColor4f(1, 0, 0, 1);
                    GL11.glVertex2d(line.x1, line.y1);
                    GL11.glVertex2d(line.x2, line.y2);
                }
            }
        }
        GL11.glEnd();
        GL11.glLineWidth(1);
        GL11.glShadeModel(GL11.GL_SMOOTH);

        // Black lines around box inside the graph...
        GL11.glColor4f(0, 0, 0, 1);
        GL11.glBegin(GL11.GL_LINE_LOOP);
        GL11.glVertex2f(this.xPos + margin, this.yPos + 2 * margin);
        GL11.glVertex2f(this.xPos + this.sizeX - margin, this.yPos + 2 * margin);
        GL11.glVertex2f(this.xPos + this.sizeX - margin, this.yPos + this.sizeY - margin);
        GL11.glVertex2f(this.xPos + margin, this.yPos + this.sizeY - margin);
        GL11.glEnd();

        //this.changed = false;
        origLine = null;
        //}
    }

    public int getMaxPoints() {
        return maxPoints;
    }

    public float getMinValue() {
        return minValue;
    }

    public float getMaxValue() {
        return maxValue;
    }

    public Point2D getIntersection(final Line2D.Double line1, final Line2D.Double line2) {
        final double x1, y1, x2, y2, x3, y3, x4, y4;
        x1 = line1.x1;
        y1 = line1.y1;
        x2 = line1.x2;
        y2 = line1.y2;
        x3 = line2.x1;
        y3 = line2.y1;
        x4 = line2.x2;
        y4 = line2.y2;
        final double x = ((x2 - x1) * (x3 * y4 - x4 * y3) - (x4 - x3) * (x1 * y2 - x2 * y1))
                / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
        final double y = ((y3 - y4) * (x1 * y2 - x2 * y1) - (y1 - y2) * (x3 * y4 - x4 * y3))
                / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
        return new Point2D.Double(x, y);
    }

    private class DataValues {

        private float value;
        private String label;

        public DataValues(float value, String label) {
            this.value = value;
            this.label = label;
        }

        public float getValue() {
            return value;
        }

        public String getLabel() {
            return label;
        }
    }
}