Graph2D

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Graph2D

Post by chronologicaldot »

I wanted to contribute something to the engine, so I wrote up a graph. Then I discovered this:
http://irrlicht.sourceforge.net/forum/v ... =9&t=33060

The graph element I've created has some different features than the promoted graph (although I imagine Sudi's trumps mine).
The thought in its design is to make it so you can easily embed it in other GUI elements (even stripping it of most features to the point where it doesn't even look like it exists! XD ) but offering conveniences. I tried to make it as easy as possible to use.

>> It possess a resizable graph window. i.e. I can set it to display points from x=-10 to x=23.45 and y=-6 to y=-3 and it will do that. I can also scale the graph's x or y axis by a percentage.

>> As for drawing the points: It does as you would expect: You simply give it an x and y value in its coordinate system (via drawOnGraph(vector2df,SColor=black)), and it draws the point on the graph in irrlicht's coordinate system. (And yes, the y-axis get's flipped.) I plan on adding the ability to add points based on polar-coordinates. The order of addition of points to the graph is irrelevant, as it should be. The graph can also be conveniently cleared, as it should be.

>> Optional x or y axis and x or y axis tick marks. Tick mark spacing is optional. It can also draw lines instead of ticks, effectively drawing a grid.

>> Custom colors for everything - axis and points.

>> Optional background.

>> Convenience of an instance of my incrementor class, Inc, posted here (http://irrlicht.sourceforge.net/forum/v ... 41#p277141) for traversing the graph (x or y direction). (I'll show you an example in a second.)

>> All of this is can be serialized and deserialized, btw. I also would have made a GUIElementFactory but I wasn't sure what way you guys wanted that implemented.


HEADS UP: The simple implementation requires my Incrementor class and my Range class (the latter for only some features, so you can scratch it if you want). Once again, both can be found here:
http://irrlicht.sourceforge.net/forum/v ... 41#p277141
I intend to put all of this stuff in a zip file and upload it onto my website for your convenience, but I'll do that when it's not so late at night.
My website: http://chronologicaldot.web44.net

IGraph2D.h
(abstract class)

Code: Select all

/*
Simple Graph
(c) Nicolaus Anderson
Created Jan 7, 2013
 
License: Same terms as irrlicht
*/
 
#include <irrlicht.h>
 
#ifndef _IGRAPH2D_
#define _IGRAPH2D_
 
namespace irr
{
namespace gui
{
 
//! Class Graph 2D
/*
Purpose: To plot 2D math functions.
*/
class IGraph2D : public IGUIElement
{
public:
 
    IGraph2D( IGUIEnvironment* envir, IGUIElement* parent, irr::s32 id, irr::core::recti& rectangle )
        : IGUIElement( EGUIET_ELEMENT, envir, parent, id, rectangle )
    {
    }
 
    ~IGraph2D()
    {
    }
 
        //! Set graph size
    /* NOT the same as scaling.
    This function changes the ranges of values in the graph without changing
    the size of the graph as a GUI element.
    */
    virtual void setGraphSize( irr::core::rectf& size )=0;
 
        //! Set graph size along one dimension
    /* NOT the same as scaling.
    This function changes the ranges of values of ONE AXIS in the graph without
    changing the size of the graph as a GUI element.
    \param size - New axis min or max
    \param isMax - If the value given is for the maximum
    */
    virtual void setGraphSizeX( irr::f32 size, bool isMax=true )=0;
    virtual void setGraphSizeY( irr::f32 size, bool isMax=true )=0;
 
        //! Set scale
    /* Changes the scale of the ranges of values in the graph without changing
    the size of the graph itself.
    NOTE: Since this is a scaling, the rectangle being passed in should be the
    percentage change (i.e. multiplier for the current values). */
    virtual void setScale( irr::core::rectf& scale )=0;
 
        //! Get graph size
    /* Returns the size of the graph. */
    virtual irr::core::rectf getGraphSize()=0;
 
        //! Draw
    /* Draws the GUI element. */
    virtual void draw()=0;
 
        //! Clear graph
    /* Erases everything in the graph. */
    virtual void clearGraph()=0;
 
    //-------------------------------
    // Drawing area functions / Spaz
 
        //! Set point color
    /* Sets the color of the points to be displayed. */
    virtual void setPointColor( irr::video::SColor color )=0;
 
        //! Set x-axis color
    /* Sets the color that will be used in drawing the line representing
    the x-axis. */
    virtual void setXAxisColor( irr::video::SColor color )=0;
 
        //! Set y-axis color
    /* Sets the color that will be used in drawing the line representing
    the y-axis. */
    virtual void setYAxisColor( irr::video::SColor color )=0;
 
    //-----------------------------
    
    //! Serialize attributes
    virtual void serializeAttributes(
        irr::io::IAttributes* out,
        irr::io::SAttributeReadWriteOptions* options=0
        )=0;
 
    //! Deserialize attributes
    virtual void deserializeAttributes(
        irr::io::IAttributes* in,
        irr::io::SAttributeReadWriteOptions* options=0
        )=0;
};
 
} // end namespace gui
} // end namespace irr
 
#endif // define _IGRAPH2D_
SGraph2D
(header class of the simple implementation)

Code: Select all

/*
Simple Graph
(c) Nicolaus Anderson
Created Jan 7, 2013
 
License: Same terms as irrlicht
*/
 
#include "IGraph2D.h"
#include <Range.h>
#include <IncrementorT.h>
 
#ifndef __SIMPLEGRAPH2D_H__
#define __SIMPLEGRAPH2D_H__
 
namespace irr
{
namespace gui
{
 
//! Class Graph 2D
/*
Purpose: To plot 2D math functions.
*/
class SGraph2D : public IGraph2D
{
        //! Graph Image
    /* The actual graph itself: a chain of points that need to be
    drawn. */
    irr::core::array<irr::video::S3DVertex> graphImage;
 
        //! Graph window
    /* This is the range of values that the graphed values are forced
    to fit into. It is a user-set range. */
    irr::core::rectf window;
 
        //! Markers (e.g. tick marks)
    bool UseMarkers;    // whether to use markers or not
    bool UseTicks;      // whether to use ticks or lines (if markers are in use)
    irr::f32 markXgap;  // spacing between markings on the x-axis
    irr::f32 markYgap;  // spacing between markings on the y-axis
    bool showXaxisMarks;    // whether the x-axis marks should be displayed
    bool showYaxisMarks;    // whether the y-axis marks should be displayed
 
        //! Axis displaying flags
    bool showXaxis;
    bool showYaxis;
 
        //! Colors
 
            // Background color
    irr::video::SColor background_color;
    bool hasBackground;
 
            // Axis colors
    irr::video::SColor xaxis_color;
    irr::video::SColor yaxis_color;
 
            // Point color
    irr::video::SColor point_color;
 
            // Tick marks / lines perpendicular to the axis
    irr::video::SColor xmark_color;
    irr::video::SColor ymark_color;
 
 
    // The video driver for drawing on screen
    irr::video::IVideoDriver* viddriver;
 
public:
 
        //! Constructor
    SGraph2D(
                // GUI element parameters
            IGUIEnvironment* envir,
            IGUIElement* parent,
            irr::s32 id,
            irr::core::recti& rectangle,
                // Graph parameters
            irr::core::rectf& graphWindow,
            bool marks = false,
            bool ticks = false
            )
        : IGraph2D( envir, parent, id, rectangle ),
        window( graphWindow ),
        UseMarkers( marks ),
        showXaxisMarks( marks ),
        showYaxisMarks( marks ),
        UseTicks( ticks ),
        markXgap(1.0f),
        markYgap(1.0f),
        showXaxis( true ),
        showYaxis( true ),
        background_color( irr::video::SColor( 255, 0, 0, 0 ) ),
        hasBackground( true ),
        xaxis_color( irr::video::SColor( 255, 0, 125, 0 ) ),
        yaxis_color( irr::video::SColor( 255, 0, 125, 0 ) ),
        point_color( irr::video::SColor( 255, 255, 0, 0 ) ),
        xmark_color( irr::video::SColor( 255, 0, 125, 0 ) ),
        ymark_color( irr::video::SColor( 255, 0, 125, 0 ) )
    {
        viddriver = Environment->getVideoDriver();
    }
 
        //! Destructor
    ~SGraph2D()
    {
    }
 
        //! Set graph size
    /* NOT the same as scaling.
    This function changes the ranges of values in the graph without changing
    the size of the graph as a GUI element.
    */
    virtual void setGraphSize( irr::core::rectf& size );
 
        //! Set graph size along one dimension
    /* NOT the same as scaling.
    This function changes the ranges of values of ONE AXIS in the graph without
    changing the size of the graph as a GUI element.
    \param size - New axis min or max
    \param isMax - If the value given is for the maximum
    */
    virtual void setGraphSizeX( irr::f32 size, bool isMax=true );
    virtual void setGraphSizeY( irr::f32 size, bool isMax=true );
 
        //! Set scale
    /* Changes the scale of the ranges of values in the graph without changing
    the size of the graph itself.
    NOTE: Since this is a scaling, the rectangle being passed in should be the
    percentage change (i.e. multiplier for the current values). */
    virtual void setScale( irr::core::rectf& scale );
 
        //! Reallocate Memory for Graph
    /* In order to allow the graph to draw points quickly, this function is
    available to reallocate storage space for the data points.
    Old data points will not be destroyed and thus must be overwritten. */
    void ReallocateGraphSpace();
 
        //! Get graph size
    /* Returns the size of the graph. */
    virtual irr::core::rectf getGraphSize();
 
    // Graphing region
 
        //! Get Graph X-Axis Range
    /* Returns the range of values that will be visible when the graph is
    drawn. */
    Range<irr::f32> getXAxisRange();
 
        //! Get Graph Y-Axis Range
    /* Returns the range of values that will be visible when the graph is
    drawn. */
    Range<irr::f32> getYAxisRange();
 
        //! Get Iterable Range for X-Axis
    /* Returns an incrementor whose range spans the visible x-axis of the
    graph, whose step yields one point per pixel acroos the screen, and whose
    starting position is the one necessary for all points drawn with this as
    a guide to cross the entire graph window. */
    Inc<irr::f32> getIterableXRange();
 
        //! Get Iterable Range for Y-Axis
    /* Returns an incrementor whose range spans the visible y-axis of the
    graph, whose step yields one point per pixel acroos the screen, and whose
    starting position is the one necessary for all points drawn with this as
    a guide to cross the entire graph window. */
    Inc<irr::f32> getIterableYRange();
 
 
    // Other ----
 
        //! Set step size
    /* Sets the spacing between tick marks (if any). */
    void markerSpacingX( irr::f32 gap=1.0f );
    void markerSpacingY( irr::f32 gap=1.0f );
 
        //! Draw
    /* Draws the GUI element. */
    virtual void draw();
 
        //! Clear graph
    /* Erases everything in the graph. */
    virtual void clearGraph();
 
 
    //-------------------------------
    // Drawing area functions / Spaz
 
        //! Set if there is a background
    void useBackground( bool use=true );
 
        //! Set background color
    /* Sets the color to be displayed behind the graph. */
    void setBackgroundColor( irr::video::SColor color );
 
        //! Set point color
    /* Sets the color of the points to be displayed. */
    virtual void setPointColor( irr::video::SColor color );
 
        //! Set x-axis color
    /* Sets the color that will be used in drawing the line representing
    the x-axis. */
    virtual void setXAxisColor( irr::video::SColor color );
 
        //! Set y-axis color
    /* Sets the color that will be used in drawing the line representing
    the y-axis. */
    virtual void setYAxisColor( irr::video::SColor color );
 
        //! Show x-axis
    /* Shows the x-xais if desired. */
    void setShowXAxis( bool show=true );
 
        //! Show y-axis
    /* Shows the y-axis if desired. */
    void setShowYAxis( bool show=true );
 
 
    //----- Tick marks vs lines
    /* Either tick marks (three pixels crossing the line) or perpendicular
    lines can be used to show the step size. */
 
        //! Set to use tick marks instead of lines
    void useTicks();
 
        //! Set to use perpendicular lines instead of tick marks
    void useLines();
 
        //! Set to use no markers
    void useNoMarkers();
 
        //! Set to show the x-axis markers
    void showXAxisMarkers( bool show=true );
 
        //! Set to show the y-axis markers
    void showYAxisMarkers( bool show=true );
 
        //! Set x-axis tick color / perpendicular line color
    void setXAxisMarkerColor( irr::video::SColor color );
 
        //! Set y-axis tick color / perpendicular line color
    void setYAxisMarkerColor( irr::video::SColor color );
 
    //-----------------------------
    
        //! Serialize attributes
    virtual void serializeAttributes(
        irr::io::IAttributes* out,
        irr::io::SAttributeReadWriteOptions* options=0
        );
 
        //! Deserialize attributes
    virtual void deserializeAttributes(
        irr::io::IAttributes* in,
        irr::io::SAttributeReadWriteOptions* options=0
        );
 
 
    // ------------ Drawing functions ------------
 
        //! Draw to the graph
    /* Draws on the graph a single point whose coordinates are preppared
    according to the graph's coordinate system.
    You should use this function for standard operations. */
    void drawOnGraph(
        irr::core::vector2df point,
        irr::video::SColor color=irr::video::SColor(255,0,0,0)
        );
 
        //! Draw to the graph
    /* Draws on the graph a single point whose coordinates are preppared for
    the AbsoluteRect and need merely be shifted. */
    void drawRawPoint(
        irr::core::vector2df point,
        irr::video::SColor color=irr::video::SColor(255,0,0,0)
        );
 
protected:
 
        //! Draw directly to the GUI element
    /* Draws to the GUI element by handling the relative offset
    of the GUI element from the upperleft corner of the screen. */
    void drawToGUI( irr::core::vector2di point, irr::video::SColor color );
    void drawToGUI( irr::core::line2df line, irr::video::SColor color );
};
 
} // end namespace gui
} // end namespace irr
 
#endif // define __SIMPLEGRAPH2D_H__
SGraph.cpp
(cpp file of the simple implementation)

Code: Select all

/*
Simple Graph
(c) Nicolaus Anderson
Created Jan 7, 2013
 
License: Same terms as irrlicht
*/
 
#include "SGraph2D.h"
 
#ifndef __SIMPLEGRAPH2D_CPP__
#define __SIMPLEGRAPH2D_CPP__
 
void irr::gui::SGraph2D::setGraphSize( irr::core::rectf& size )
{
    window = size;
 
    ReallocateGraphSpace();
}
 
void irr::gui::SGraph2D::setGraphSizeX( irr::f32 size, bool isMax )
{
    if ( isMax )
    {
        window.LowerRightCorner.X = size;
    } else {
        window.UpperLeftCorner.X = size;
    }
 
    ReallocateGraphSpace();
}
 
void irr::gui::SGraph2D::setGraphSizeY( irr::f32 size, bool isMax )
{
    if ( isMax )
    {
        window.UpperLeftCorner.Y = size;
    } else {
        window.LowerRightCorner.Y = size;
    }
 
    ReallocateGraphSpace();
}
 
void irr::gui::SGraph2D::setScale( irr::core::rectf& scale )
{
    window.UpperLeftCorner.X *= scale.UpperLeftCorner.X;
    window.UpperLeftCorner.Y *= scale.UpperLeftCorner.Y;
    window.LowerRightCorner.X *= scale.LowerRightCorner.X;
    window.LowerRightCorner.Y *= scale.LowerRightCorner.Y;
 
    window.repair();
 
    ReallocateGraphSpace();
}
 
void irr::gui::SGraph2D::ReallocateGraphSpace()
{
    graphImage.reallocate(
        (irr::u32)AbsoluteRect.getWidth(),
        false
        );
}
 
irr::core::rectf irr::gui::SGraph2D::getGraphSize()
{
    return window;
}
 
Range<irr::f32> irr::gui::SGraph2D::getXAxisRange()
{
    return Range<irr::f32>(
                window.UpperLeftCorner.X,
                window.LowerRightCorner.X
                );
}
 
Range<irr::f32> irr::gui::SGraph2D::getYAxisRange()
{
    return Range<irr::f32>(
                window.UpperLeftCorner.Y,
                window.LowerRightCorner.Y
                );
}
 
Inc<irr::f32> irr::gui::SGraph2D::getIterableXRange()
{
    Inc<irr::f32> inc(CYC_REPEAT);
 
    inc.setRange( getXAxisRange() );
    inc.setStep( window.getWidth() / ((irr::f32)AbsoluteRect.getWidth()) );
    inc.restart();
 
    return inc;
}
 
Inc<irr::f32> irr::gui::SGraph2D::getIterableYRange()
{
    Inc<irr::f32> inc(CYC_REPEAT);
 
    inc.setRange( getYAxisRange() );
    inc.setStep( window.getHeight() / ((irr::f32)AbsoluteRect.getHeight()) );
    inc.restart();
 
    return inc;
}
 
void irr::gui::SGraph2D::markerSpacingX( irr::f32 gap )
{
    markXgap = gap;
}
 
void irr::gui::SGraph2D::markerSpacingY( irr::f32 gap )
{
    markYgap = gap;
}
 
void irr::gui::SGraph2D::draw()
{
    // Don't bother doing anything if this isn't visible
    if ( !IsVisible || AbsoluteRect.getArea() == 0 || window.getArea() == 0.0f )
        return;
 
    // variables...
 
    irr::core::vector2di point; /* point to be drawn on screen representing
                                a point from the MathFunc */
 
        /* Marker offset
        - used to ensure the markers are drawn from the center outward. */
    Inc<irr::f32> markerIter;   /* no wrapping because we want
                                out-of-bounds checking */
        // Marker line - drawn on the GUI graph screen
    irr::core::line2df marker;
 
 
    // operations...
 
    // Draw the background if there is one
    if ( hasBackground )
    {
        viddriver->draw2DRectangle(
                            background_color,
                            AbsoluteRect,
                            &AbsoluteClippingRect
                            );
    }
 
    // Draw the axis if desired
 
    if ( showXaxis )
    {
        drawToGUI(
            irr::core::line2df(
                window.UpperLeftCorner.X,
                0.0f,
                window.LowerRightCorner.X,
                0.0f
                ),
            xaxis_color
            );
    }
 
    if ( showYaxis )
    {
        drawToGUI(
            irr::core::line2df(
                0.0f,
                window.UpperLeftCorner.Y,
                0.0f,
                window.LowerRightCorner.Y
                ),
            yaxis_color
            );
    }
 
    // Draw the markers/lines if desired
    if ( UseMarkers )
    {
            // Y-axis
        if ( showYaxisMarks )
        {
            /* Set the offset for making the lines appear to be drawn
            from the center outward */
            markerIter.setMin( window.UpperLeftCorner.Y );
            markerIter.setMax( window.LowerRightCorner.Y );
            markerIter.setStep( markYgap );
            markerIter.setVal( 0.0f ); // start in the center
 
            // Set up the marker line
 
                // Left side of the line
            if ( UseTicks )
                marker.start.X = -window.getWidth() / 20.0f; // for 10% window width
            else
                marker.start.X = window.UpperLeftCorner.X;
 
                // Right side of the line
            if ( UseTicks )
                marker.end.X = window.getWidth() / 20.0f; // for 10% window width
            else
                marker.end.X = window.LowerRightCorner.X;
 
            // Draw each marker
            while ( !++markerIter ) // go until past the max
            {
                // Assign the position to the line to draw
                marker.start.Y = marker.end.Y = markerIter.Val();
 
                // Draw the marker to the GUI
                drawToGUI( marker, ymark_color );
            }
 
            // Restart at the center
            markerIter = 0.0f;
 
            // Draw each marker
            while ( !--markerIter ) // go until past the min
            {
                // Assign the position to the line to draw
                marker.start.Y = markerIter.Val();
                marker.end.Y = markerIter.Val();
 
                // Draw the marker to the GUI
                drawToGUI( marker, ymark_color );
            }
        }
 
            // X-axis
        if ( showXaxisMarks )
        {
            /* Set the offset for making the lines appear to be drawn
            from the center outward */
            markerIter.setMin( window.UpperLeftCorner.X );
            markerIter.setMax( window.LowerRightCorner.X );
            markerIter.setStep( markXgap );
            markerIter.setVal( 0.0f ); // start in the center
 
            // Set up the marker line
 
                // Top of the line - Below the x-axis in terms of irrlicht drawing
            if ( UseTicks )
                marker.start.Y = window.getHeight() / 20.0f; // for 10% window height
            else
                marker.start.Y = window.UpperLeftCorner.Y;
 
                // Bottom of the line - Above the x-axis in terms of irrlicht drawing
            if ( UseTicks )
                marker.end.Y = -window.getHeight() / 20.0f; // for 10% window height
            else
                marker.end.Y = window.LowerRightCorner.Y;
 
            // Draw each marker
            while ( !++markerIter ) // go until past the max
            {
                // Assign the position to the line to draw
                marker.start.X = marker.end.X = markerIter.Val();
 
                // Draw the marker to the GUI
                drawToGUI( marker, xmark_color );
            }
 
            // Restart at the center
            markerIter = 0.0f;
 
            // Draw each marker
            while ( !--markerIter ) // go until past the min
            {
                // Assign the position to the line to draw
                marker.start.X = markerIter.Val();
                marker.end.X = markerIter.Val();
 
                // Draw the marker to the GUI
                drawToGUI( marker, xmark_color );
            }
        }
    }
 
    // Display each points on screen
    for (
        irr::s32 pt = 0;
        pt < (irr::s32)graphImage.size();
        pt++
        )
    {
        /* Note that when drawing the graph in the GUI element,
        we need to shift their stored values because the bounds of the
        graph window are independent of the actual GUI element size. */
 
        /*
        point.X = (irr::s32)(graphImage[pt].Pos.X - window.UpperLeftCorner.X)
                    * AbsoluteRect.getWidth();
        */
 
        point.X = (irr::s32)graphImage[pt].Pos.X;
 
        point.Y = (irr::s32)graphImage[pt].Pos.Y;
            /* Note the y-axis value is negative in order have it drawn
            in the orientation the GUI environment is drawn. */
 
        drawToGUI( point, graphImage[pt].Color );
    }
}
 
void irr::gui::SGraph2D::clearGraph()
{
    graphImage.clear();
}
 
void irr::gui::SGraph2D::useBackground( bool use )
{
    hasBackground = use;
}
 
void irr::gui::SGraph2D::setBackgroundColor( irr::video::SColor color )
{
    background_color = color;
}
 
void irr::gui::SGraph2D::setPointColor( irr::video::SColor color )
{
    point_color = color;
}
 
void irr::gui::SGraph2D::setXAxisColor( irr::video::SColor color )
{
    xaxis_color = color;
}
 
void irr::gui::SGraph2D::setYAxisColor( irr::video::SColor color )
{
    yaxis_color = color;
}
 
void irr::gui::SGraph2D::setShowXAxis( bool show )
{
    showXaxis = show;
}
 
void irr::gui::SGraph2D::setShowYAxis( bool show )
{
    showYaxis = show;
}
 
void irr::gui::SGraph2D::useTicks()
{
    UseMarkers = true;
    UseTicks = true;
 
    showXaxisMarks = true;
    showYaxisMarks = true;
}
 
void irr::gui::SGraph2D::useLines()
{
    UseMarkers = true;
    UseTicks = false;
 
    showXaxisMarks = true;
    showYaxisMarks = true;
}
 
void irr::gui::SGraph2D::useNoMarkers()
{
    UseMarkers = false;
}
 
void irr::gui::SGraph2D::showXAxisMarkers( bool show )
{
    showXaxisMarks = show;
    if (show) UseMarkers = true;
}
 
void irr::gui::SGraph2D::showYAxisMarkers( bool show )
{
    showYaxisMarks = show;
    if (show) UseMarkers = true;
}
 
void irr::gui::SGraph2D::setXAxisMarkerColor( irr::video::SColor color )
{
    xmark_color = color;
}
 
void irr::gui::SGraph2D::setYAxisMarkerColor( irr::video::SColor color )
{
    ymark_color = color;
}
 
void irr::gui::SGraph2D::serializeAttributes(
    irr::io::IAttributes *out,
    irr::io::SAttributeReadWriteOptions *options
    )
{
    irr::core::recti win;
    win.UpperLeftCorner.X = (irr::s32)(window.UpperLeftCorner.X);
    win.UpperLeftCorner.Y = (irr::s32)(window.UpperLeftCorner.Y);
    win.LowerRightCorner.X = (irr::s32)(window.LowerRightCorner.X);
    win.LowerRightCorner.Y = (irr::s32)(window.LowerRightCorner.Y);
 
    out->addRect( "Window", win );
 
    out->addBool( "FillBackground", hasBackground );
    out->addColor( "BGColor", background_color );
    out->addColor( "XAxisColor", xaxis_color );
    out->addColor( "YAxisColor", yaxis_color );
    out->addColor( "PointColor", point_color );
    out->addColor( "XAxisTickColor", xmark_color );
    out->addColor( "YAxisTickColor", ymark_color );
 
    out->addBool( "UseMarkers", UseMarkers );
    out->addBool( "UseTicks", UseTicks );
 
    out->addBool( "ShowXAxis", showXaxis );
    out->addBool( "ShowYAxis", showYaxis );
}
 
void irr::gui::SGraph2D::deserializeAttributes(
    irr::io::IAttributes *in,
    irr::io::SAttributeReadWriteOptions *options
    )
{
    irr::core::recti win = in->getAttributeAsRect( "Window" );
    window.UpperLeftCorner.X = (irr::f32)(win.UpperLeftCorner.X);
    window.UpperLeftCorner.Y = (irr::f32)(win.UpperLeftCorner.Y);
    window.LowerRightCorner.X = (irr::f32)(win.LowerRightCorner.X);
    window.LowerRightCorner.Y = (irr::f32)(win.LowerRightCorner.Y);
 
    hasBackground       =   in->getAttributeAsBool( "FillBackground" );
    background_color    =   in->getAttributeAsColor( "BGColor" );
    xaxis_color         =   in->getAttributeAsColor( "XAxisColor" );
    yaxis_color         =   in->getAttributeAsColor( "YAxisColor" );
    point_color         =   in->getAttributeAsColor( "PointColor" );
    xmark_color         =   in->getAttributeAsColor( "XAxisTickColor" );
    ymark_color         =   in->getAttributeAsColor( "YAxisTickColor" );
 
    UseMarkers          =   in->getAttributeAsBool( "UseMarkers" );
    UseTicks            =   in->getAttributeAsBool( "UseTicks" );
 
    showXaxis           =   in->getAttributeAsBool( "ShowXAxis" );
    showYaxis           =   in->getAttributeAsBool( "ShowYAxis" );
}
 
void irr::gui::SGraph2D::drawOnGraph(
    irr::core::vector2df point, irr::video::SColor color
    )
{
    // Shift the origin to the corner
    point.X -= window.UpperLeftCorner.X;
    point.Y -= window.UpperLeftCorner.Y;
 
    // Convert to the actual GUI window's coordinate system
    point.X *= ((irr::f32)AbsoluteRect.getWidth()) / window.getWidth();
    point.Y *= ((irr::f32)AbsoluteRect.getHeight()) / window.getHeight();
 
    // Save
    graphImage.push_back(
        irr::video::S3DVertex( point.X, point.Y, 0,0,0,0, color, 0,0)
        );
}
 
void irr::gui::SGraph2D::drawRawPoint(
    irr::core::vector2df point,
    irr::video::SColor color
    )
{
    // Shift the origin to the corner
    point.X -= window.UpperLeftCorner.X
         // conversion of shift to GUI element size
        * ((irr::f32)AbsoluteRect.getWidth()) / window.getWidth();
 
    point.Y -= window.UpperLeftCorner.Y
        // conversion of shift to GUI element size
        * ((irr::f32)AbsoluteRect.getHeight()) / window.getHeight();
 
    // Save
    graphImage.push_back(
        irr::video::S3DVertex( point.X, point.Y, 0,0,0,0, color, 0,0)
        );
}
 
void irr::gui::SGraph2D::drawToGUI(
                        irr::core::vector2di point,
                        irr::video::SColor color
                        )
{
    // Flip for drawing on the GUI
    point.Y = AbsoluteRect.getHeight() - point.Y;
 
    /* This function has been passed a value that is already prepared to
    be drawn to screen and simply needs to be offset. */
    point.X += AbsoluteRect.UpperLeftCorner.X;
    point.Y += AbsoluteRect.UpperLeftCorner.Y;
 
    // Do nothing if the window isn't even visible
    if ( window.getArea() == 0.0f )
        return;
 
    // Draw the point as a pixel - might be very small and hard to see
    /* - Drawn faster than a polygon and may create a smooth line (if MathFunc
    returns values of a smooth function) */
    viddriver->drawPixel( point.X, point.Y, point_color );
 
    // Attempt to draw the point as a polygon (to make it more visible)
 
    /*
    viddriver->draw2DPolygon(
                    point,          // position
                    1.5f,           // radius
                    point_color,    // color
                    4               // roundness of the point
                    );
                    */
 
}
 
void irr::gui::SGraph2D::drawToGUI(
                        irr::core::line2df line,
                        irr::video::SColor color
                        )
{
    // Do nothing if the window isn't even visible
    // - saves time and prevents divide-by-zero errors
    if ( window.getArea() == 0.0f )
        return;
 
    /* This function has been passed a value that needs to be prepared
    to fit in the window in addition to it being offset. */
    
    // Line that will be drawn - initialized to begin within the GUI element
    irr::core::line2di drawline(
        AbsoluteRect.UpperLeftCorner.X,
        AbsoluteRect.UpperLeftCorner.Y,
        AbsoluteRect.UpperLeftCorner.X,
        AbsoluteRect.UpperLeftCorner.Y
        );
 
    /* Tranform the line to graph coordinates. */
    line.start.X -= window.UpperLeftCorner.X;
    line.start.Y -= window.UpperLeftCorner.Y;
    line.end.X -= window.UpperLeftCorner.X;
    line.end.Y -= window.UpperLeftCorner.Y;
 
    // starting x
    drawline.start.X += (irr::s32) ( line.start.X
        * AbsoluteRect.getWidth() / window.getWidth() // position conversion
        );
 
    // starting y
    drawline.start.Y += (irr::s32) ( line.start.Y
        * AbsoluteRect.getHeight() / window.getHeight() // position conversion
        );
 
    // ending x
    drawline.end.X += (irr::s32) ( line.end.X
        * AbsoluteRect.getWidth() / window.getWidth() // position conversion
        );
 
    // ending y
    drawline.end.Y += (irr::s32) ( line.end.Y
        * AbsoluteRect.getHeight() / window.getHeight() // position conversion
        );
 
 
    // Draw the line
    viddriver->draw2DLine( drawline.start, drawline.end, color );
}
 
 
#endif // define __SIMPLEGRAPH2D_CPP__
Sample image
Image

Example usage:

Code: Select all

 
#include <irrlicht.h>
//... then include library
 
using namespace irr;
using namespace gui;
 
void plotsine( SGraph2D* );
 
void plotsine( SGraph2D* win )
{
Inc<f32> dis;
core::vector2df pt;
 
dis.copy( win->getIterableXRange() );
dis.setStep( 1.0f/1000.0f );
 
do {
pt.X = dis.Val();
pt.Y = 10 * sin( dis.Val() );
 
win->drawOnGraph( pt, video::SColor(255,255,0,0) );
} while ( !++dis );
}
 
void main()
{
IrrlichtDevice* device = createDevice();
video::IVideoDriver* vid = device->getVideoDriver();
IGUIEnvironment* envir = device->getGUIEnvironment();
 
SGraph2D* graph = new SGraph2D(
envir, // GUI environment
envir->getRootGUIElement(), // parent
0, // id
irr::core::recti(0,0,600,400), // GUI element boundaries
irr::core::rectf( -10.0f, -10.0f, 20.0f, 10.0f ), // graph window
true, // use marks or lines?
true // use tick marks?
);
 
graph->setBackgroundColor( video::SColor(255,150,150,150) );
 
plotsine( graph );
 
graph->drop();
graph = 0;
 
while( device->run() )
{
vid->beginScene();
envir->drawAll();
vid->endScene();
}
 
device->drop();
}
 
The output looks like the image posted above (but without the line, which I added later).
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Graph2D

Post by chronologicaldot »

BUGFIX:
I had my y-axis values of the axis lines flipped. There was nothing wrong with the point plotting - just the line drawing. I've fixed that now.

Scale corrections - I've now made it so you can call setGraphSize(), setGraphSizeX(), and setGraphSizeY() AFTER adding points if you want. The same is true for setScale(), but I've changed it's name to setGraphScale().

FEATURE ADDITION:
>> Drawing with polygons - (I just use IVideoDriver::draw2DPolygon() ) for the points is optional. It makes things show up clearer. You can set the radius and roundness of the points.
>> Auto-adjust!! Now you can draw any number of points on the graph, in or outside of the graph window, call the function autoAdjust(), and voila! - The graph window will be rescaled to show every data point. (The points may overflow if polygons are used, so just follow it with setGraphScale( irr::core::rectf(1.05f,1.05f,1.05f,1.05f) ) to make everything fit nicely.)
>> Numbers on axis - Optionally, you can display numbers on the axis. I'm debating on the number of significant figures to keep (anyone have any ideas on what they'd like?).

I will upload it shortly.
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Graph2D

Post by chronologicaldot »

Alright, I uploaded it to my website.
You can find it here.

Latest sample image:
Image
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Graph2D

Post by CuteAlien »

Thanks, very nice! Please PM hybrid if you want access to the irrExt project so you can put your code some place online where other people using Irrlicht can find it easy.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Re: Graph2D

Post by hybrid »

Yeah, would be quite useful to have it in irrExt, even though the project may be not too active. But it's safer to keep things there instead of losing the sources eventually, or in your case not easily finding your contribution within the forum.
BTW: Seems to be the wrong forum here, I move it to Code snippets, where it probably belongs to.
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Graph2D

Post by chronologicaldot »

Okay, thanks. I wasn't sure where to put the thread.
netpipe
Posts: 670
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Re: Graph2D

Post by netpipe »

awesome, thanke
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Tweak!

Post by chronologicaldot »

Okay, so minor tweak:
In serializeAttributes() and deserializeAttributes(), I forgot to add the lines:
IGUIElement::serializeAttributes()
and
IGUIElement::deserializeAttributes()
(calling of the parent functions to serialize/deserialize the rest of the IGUIElement attributes)

but you probably won't have figured that out until you tried to serialize and deserialize them.

I've made the fix and uploaded it to my website (same url as above).
netpipe
Posts: 670
Joined: Fri Jun 06, 2008 12:50 pm
Location: Edmonton, Alberta, Canada
Contact:

Re: Graph2D

Post by netpipe »

http://www.xup.in/dl,89175520/SGraph2D.tar.gz/ compiles good, thanks- not sure if it has the extra changes you mentioned which may have something to do with dis.copy( win->getIterableXRange() ); giving errors during compile.
Last edited by netpipe on Mon Mar 21, 2016 7:09 pm, edited 2 times in total.
Live long and phosphor!
-- https://github.com/netpipe/Luna Game Engine Status 95%
chronologicaldot
Competition winner
Posts: 688
Joined: Mon Sep 10, 2012 8:51 am

Re: Graph2D

Post by chronologicaldot »

I'd like to help, but you're link seems to be broken at the moment.

Edit: The template issue may have to do with the Incrementer class and the Range class. You need both of them.
At the moment, my old website is down. I'll probably be relocating as I get tired of monitoring a free host.
Post Reply