KNOW-HOW.GRAF
(C) Stepan Vartanov, 1993 - 1996

1. Features.

	Business and Scientific Diagrams of different types. Available as C++ DLL 
(tested with Borland 4.52), or sources. Library is based on KNOW-HOW.GDI, 
and therefore has an access to all its features, like zooming, scrolling or 
rotation of the vector image. 


2. Usage.

	The following example illustrates most aspects of programming KH.GRAF.  
See "Classes" chapter for details. 

 

First you should include header file:

*	Include file:
*	#include "kh_graf\graf.h"

As any class library, KH.GRAF could be used in a few different ways. The 
following code uses class inherited from Graf class of the library. In the most 
cases you will use code that is much simpler, this example is designed to show all 
or almost all features.

*    class Demo : public Graf
*	     {
*	     public:
*	// Not optimized !!! Main drawing function
* 	      void graf_demo();  
* // Draw stack bar graf
*	void draw_stacked(double* xar, double* bar, 
*	      double* car, rect r); 
*	};

The following code was developed using SLANG and only after testing translated 
to C++. SLANG is data processing tool based on KH.GRAF, it should be released 
in September 1996. 

First we created Demo class based on Graf. Now we add functionality:

*	void Demo::graf_demo()
*	 {
*	 rotate(0, 0, 0);    // Turn off rotation
*	// Draw filled rectangle (to erase background of window). Constants 
SOLID_FILL and so on are added to WINDOWS set of constants (like 
..._SOLID). You could use Windows constants as well. See BGIPAINT.H for 
list of constants.
*	 setfillstyle(SOLID_FILL, BLACK);     
*	// If fill is on, polygons and fonts are filled, otherwise it is outlines only.
*	 set_fill(ON);
*	 rectangle(0, 0, 1000, 1000);

*	// Declare some variables - remember, this is just an example
*	// We suppose to use this array for bar grafs shifts. This array is used if more 
than one series appears on the graf. If we plot data for x = 10, then first bar is 
plotted on ten. For bar of the second graf, however it should be 10 + width of 
first bar (to avoid overlapping). Screen coordinates.
*      int shifts[20]; 
*	 memset(shifts, 0, 20 * sizeof(int));
*	Arrays for data. In real application you will pass this data to drawing functions 
from somewhere else.
*	 double xar[5];
*	 double yar[5];
*	// Deltas - if we plot x +- deltax...
*	 double dar[5];
*	// Ticks - if we want to specify their position instead of using auto scaling
*	 int tar[6];
*	// Create array of data to be plotted on a first graf, 6 points
*	 for(int i = 1; i < 6; i++)
*	{
*	xar[i - 1] = i;
*	yar[i - 1] = (double)i * i - 10;
*	dar[i - 1] = (double)i * i / 2;
*	tar[i - 1] = log10((double)i) * 200;      // Tick for axes, if we use Manual mode
*	}
*	   tar[5] = log10(6) * 200;  // We want extra tick on the axes (usually we do 
auto scaling instead)

*	// Set area on screen to draw graf, pixels	
*	   set_graf_clip(30, 10, 200, 200);
*	// Size of graph marker, pixels, Do it before calc_scale() in the case of bar 
graph
*	  set_marker_size(8);  
We are ready now to call calc_scale() functions. 
	Arguments: double* ar - array to be plotted against this axe, 
		int axe (X-0, Y-1), 
		int is_first - we call this function few times if there are few data sets,
		int n - resize flag, int num - fit to scale: see "Classes" for details;
*	// Be careful with the sequence of calls: calc_scale / set_axe
*	   calc_scale(xar, 0, 1, 5, -1);	     // x-axe, first data set, ...
*	   calc_scale(dar, 1, 1, 5, -1);          // y-scale, first, resize
*	   calc_scale(yar, 1, 0, 5, -1);          // y-scale, not first, resize
*	   calc_scale(yar, 1, 0, 5, 1);	   // and fit to nice-looking scale
*	// I do not use symbolic names for colors to show that it is translation
*	// from SLANG. This method is much more effective than direct C++ 
programming
*	// You can use BLACK (0), BLUE (1) and so on, or RGB(R, G, B) or any other 
method.
*	// See KH.GDI file BGIPAINT.H for constants
*	   setcolor(12); setfillstyle(1, 3);
Manual axe setup (example only, usually AUTO mode is used). This function 
specifies the number / position of labels and ticks, ticks text and so on.
	Arguments: int which_axe (HORIZ1=1, VERT1=2, HORIZ2=4, VERT2 = 8) 
	int axe_len, pixels
	double start = 0, double end = 0, - used for auto (if 0,0) or manual 
		calculation of ticks position
	int tick_no = 0, number of ticks on axe
	int* ticks_on_axe = NULL, if not NULL - used for manual ticks setup. 
		Contains screen coordinates of ticks.
	int s_tick_no = 0, Same for sub-ticks
	int* sub_ticks_on_axe = NULL, -//-
	char** legends_on_axe = NULL, text on the axe
	int text_direction = HORIZ_AXE - text could be horizontal or vertical,
		on left or right related to vertical axe or above or below horizontal
		axe;
// Here we specify ticks labels manually:
*	 char* s[] = { "One", "Two", "Three", "Four", "Five", "Six" };
*	 set_axe(HORIZ1, clip.width(), 0, 0, 6, tar, 5, tar, s, 1);

*	//Automatic setup for Y:
*	   set_axe(VERT1, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);

Function to draw axe on screen
	Prototype: void show_axes(int ax_color, int legends_color,
	int grid_style, int grid_color, int width, int ticks_width, 
	int set_of_axes_to_show);
*	   show_axes(14, 9, 1, 2, 3, 1, HORIZ1 + VERT1);

*	   setcolor(14); setfillstyle(5, 11);
*	  cross();                       // Draw beginning of axes (0,0)

Plot the graph.
	Arguments: xar, dar - data to plot
		5 - type of marker
		BAR_GRAF - type of graf
		1, shifts - see "Classes"
*	   plot_data(xar, dar, 5, BAR_GRAF, 1, shifts);
*	   setcolor(15); setfillstyle(6, 14);
*	// Plot another line on the same axes
*	   plot_data(xar, yar, 5, BAR_GRAF, 1, shifts);   // Plot second dataset
*	   set_marker_size(4);
*	   setcolor(9); setfillstyle(1, 7);
*	// And another one...
*	   plot_data(xar, yar, 5, COMBINED_GRAF, 1, shifts);
*	   set_marker_size(8);
*	///////////////////////////////////////////////////////////////////////////
The following code draws few more graphs with different settings:
*	// Prepare data for the second graf
*	   for(i = 0; i < 20; i++)
*	shifts[i] = 0;
*	 for(i = 1; i < 6; i++)
*	{
*	yar[i - 1] = (double)i * i - 10;
*	dar[i - 1] = (double)i * i / 2 - 5;
*	}

*	   set_graf_clip(230, 20, 380, 210);       // Rectangle on screen
*	   calc_scale(xar, 0, 1, 5, 0);
*	   calc_scale(dar, 1, 1, 5, -1);           // y-scale, first, resize
*	   calc_scale(yar, 1, 0, 5, -1);           // y-scale, not first, resize
*	   calc_scale(yar, 1, 0, 5, 1);
*	   calc_scale(xar, 0, 0, 5, 1);

*	// We draw four axes on this graph
*	   set_axe(HORIZ1, clip.width(), xmin, xmax, -1, NULL, 2, NULL, NULL, 0);
*	   set_axe(VERT1, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	   set_axe(HORIZ2, clip.width(), xmin, xmax, -1, NULL, 5, NULL, NULL, 0);
*	   set_axe(VERT2, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	//Axes numeration: HORIZ1= 1, VERIT1 = 2, HORIZ2 = 4, VERT2 = 8
*	// Prototype: void show_axes(int ax_color, int legends_color,
*	//    int grid_style, int grid_color, int width, int ticks_width, int set);
*	   show_axes(14, 12, 0, 7, 3, 1, 1 + 2 + 4 + 8);
*	   setcolor(11); setfillstyle(1, 3);
*	   cross();
*	   set_fill(ON);
*	   plot_data(xar, yar, 5, BAR_3D_GRAF, 1, shifts);
*	   setcolor(8); setfillstyle(1, 2);
*	   plot_data(xar, dar, 5, BAR_3D_GRAF, 1, shifts);
*	   for(i = 0; i < 20; i++)
*	shifts[i] = 0;
*	/////////////////////////////////////////////////////////////////////////////
*	// Third graf: prepare data
*	   double rar[100];
*	 double sar[100];
*	 for(i = 1; i < 101; i++)
*	{
*	rar[i - 1] = i;
*	sar[i - 1] = (double)sin(3.6 * i) / 1000;  // sin() overloaded!
*	}
*	// Specify size
*	   set_graf_clip(420, 20, 600, 210);
*	// Specify scale, if we do not need auto scaling
*	   set_graf_scale(0, -1, 100, 2);                 // Manual scale ajustment

*	   set_axe(HORIZ1, clip.width(), xmin, xmax, -1, NULL, 2, NULL, NULL, 0);
*	   set_axe(VERT1, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	   set_axe(HORIZ2, clip.width(), xmin, xmax, -1, NULL, 2, NULL, NULL, 0);
*	   set_axe(VERT2, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	   show_axes(14, 12, 3, 7, 3, 1, 1 + 2 + 4 + 8);
*	   cross();
*	   setcolor(10); setfillstyle(1, 2); To_Paint::setlinestyle(3, 0);
*	   plot_data(rar, sar, 100, LINE_GRAF, 1, shifts);
*	   To_Paint::setlinestyle(1, 1);
*	//''''''''''''''''''''''''''''''''' Add small graph at the corner of big one
*	//'''''''''''''''''''''''''''''''''
*	   for(i = 1; i < 101; i++)
*	sar[i - 1] = 100 * sar[i - 1];

*	   set_graf_clip(510, 35, 595, 90);
*	   setfillstyle(1, 0);
*	   rectangle(480, 20, 600, 120);
*	   calc_scale(rar, 0, 1, 100, 0);
*	 calc_scale(sar, 1, 1, 100, 0);

*	   set_axe(HORIZ1, clip.width(), xmin, xmax, -1, NULL, 2, NULL, NULL, 1);
*	   set_axe(VERT1, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	   show_axes(14, 12, -1, 7, 3, 1, 1 + 2);
*	   cross();
*	   setcolor(10); setfillstyle(1, 2); To_Paint::setlinestyle(3, 0);
*	   plot_data(rar, sar, 100, LINE_GRAF, 1, shifts);
*	/////////////////////////////////////////////////////////////////////////////
*	// Now we need stacked bar graph. It accept two arrays - actual data AND 
previous data to plot
*	// current data on.
*	   set_marker_size(16);
*	   double zar[20];
*	//                We set zar[] manually. The rules are:
*	//              zar[4*i] keep ystart < 0;
*	//	 zar[4*i+1] keep ystart >= 0;
*	//	 zar[4*i+2] keep yend < 0;
*	//	 zar[4*i+3] keep yend >= 0;
*	zar[0] = 0; zar[1] = 0; zar[2] = 0; zar[3] = 10;
*	zar[4] = 0; zar[5] = 0; zar[6] = 0; zar[7] = 24;
*	zar[8] = 0; zar[9] = 0; zar[10] = 0; zar[11] = 15;
*	zar[12] = 0; zar[13] = 0; zar[14] = 0; zar[15] = 10;
*	zar[16] = 0; zar[17] = 0; zar[18] = 0; zar[19] = 5;

*	   double aar[20];

*	aar[0] = 0;    aar[1] = 10; aar[2] = 0;     aar[3] = 12;
*	aar[4] = 0;    aar[5] = 24; aar[8] = 0;     aar[7] = 25;
*	aar[8] = 0;    aar[9] = 15; aar[10] = 0;    aar[11] = 25;
*	aar[12] = 0;   aar[13] = 10; aar[14] = 0;   aar[15] = 15;
*	aar[16] = 0;   aar[17] = 5; aar[18] = 0;    aar[19] = 7;

*	   set_graf_clip(20, 230, 240, 400);
*	   calc_scale(xar, 0, 1, 5, 0);
*	   calc_scale(zar, 1, 1, 20, 0);
*	   calc_scale(aar, 1, 0, 20, -1);

*	   set_graf_scale(xmin, ymin * 1.2, xmax, ymax * 1.2);
*	 calc_scale(xar, 0, 0, 5, 1);

*	   set_axe(HORIZ1, clip.width(), xmin, xmax, -1, NULL, 5, NULL, NULL, 0);
*	   set_axe(VERT1, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	   set_axe(HORIZ2, clip.width(), xmin, xmax, -1, NULL, 5, NULL, NULL, 0);
*	   set_axe(VERT2, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);

*	   show_axes(14, 12, 0, 7, 3, 1, 1 + 2 + 4 + 8);
*	   setcolor(8); setfillstyle(1, 2);
*	   cross();
*	   plot_data(xar, zar, 5, STACKED_BAR_GRAF, 3);
*	   setcolor(14); setfillstyle(1, 9);
*	   plot_data(xar, aar, 5, STACKED_BAR_GRAF, 3);
*	////////////////////////////////////////////////////////////////////////////
*	// Now we combine manual and automatic approaches: first two arrays are
*	// composed manually, third is added with call to get_stacked()
*	double bar[20];
*	bar[0] = 0;      bar[1] = 0;      bar[2] = -10;    bar[3] = 10;
*	bar[4] = 0;      bar[5] = 0;      bar[6] = -20;    bar[7] = 10;
*	bar[8] = 0;      bar[9] = 0;     bar[10] = 0;     bar[11] = 10;
*	bar[12] = 0;     bar[13] = 0;     bar[14] = 0;     bar[15] = 20;
*	bar[16] = 0;     bar[17] = 0;     bar[18] = 0;     bar[19] = 2;

*	double car[20];
*	car[0] = -10;   car[1] = 10;    car[2] = -15;   car[3] = 20;
*	car[4] = -20;   car[5] = 10;    car[6] = -25;   car[7] = 15;
*	car[8] = 0;     car[9] = 10;    car[10] = 0;    car[11] = 17;
*	car[12] = 0;    car[13] = 20;   car[14] = 0;    car[15] = 22;
*	car[16] = 0;    car[17] = 2;    car[18] = 0;    car[19] = 12;

*	setcolor(9); setfillstyle(1, 1);

*	// We suppose to draw the same (almost) graf with and without rotation
*	draw_stacked(xar, bar, car, rect(310, 250, 550, 450));
*	// Preparations
*	rotate(250, 250, 45);   // See KH.GDI
*	set_marker_size(8);

*	setfillstyle(SOLID_FILL, BLACK);
*	KH_Paint::rectangle(120, 120, 330, 330);

*	draw_stacked(xar, bar, car, rect(150, 150, 300, 300));
*	 }

*	void Demo::draw_stacked(double* xar, double* bar, double* car, rect r)
*	 {
*	double ear[20];
*	for(int i = 0; i < 20; i++)
*	   ear[i] = car[i];

*	set_graf_clip(r.origin.X, r.origin.Y, r.corner.X, r.corner.Y);
*	calc_scale(xar, 0, 1, 5, 0);
*	get_stacked(xar, ear, 5);                // ear scale is enought
*	calc_scale(ear, 1, 1, 20, -1);             // y-scale, first, resize
*	// We have xmin, xmax, ymin, ymax. Now we want change scale.
*	set_graf_scale(xmin, ymin * 1.2, xmax, ymax * 1.2);
*	calc_scale(xar, 0, 0, 5, 1);              // Fit to "nice-looking" numbers
*	calc_scale(ear, 1, 0, 20, 1);             // Fit to "nice-looking" numbers
*	// Axes numeration: HORIZ1 = 1, VERT1 = 2, HORIZ2 = 4, VERT2 = 8
*	set_axe(HORIZ1, clip.width(), xmin, xmax, -1, NULL, 5, NULL, NULL, 0);
*	set_axe(VERT1, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);
*	set_axe(HORIZ2, clip.width(), xmin, xmax, -1, NULL, 5, NULL, NULL, 0);
*	set_axe(VERT2, clip.height(), ymin, ymax, -1, NULL, 2, NULL, NULL, 0);

*	show_axes(14, 12, 0, 7, 3, 1, 1 + 2 + 4 + 8);
*	cross();
*	setcolor(9); setfillstyle(1, 1);
*	plot_data(xar, bar, 5, STACKED_BAR_GRAF, 3);
*	setcolor(11); setfillstyle(1, 6);
*	plot_data(xar, car, 5, STACKED_BAR_GRAF, 3);
*	setcolor(10); setfillstyle(1, 12);
*	plot_data(xar, ear, 5, STACKED_BAR_GRAF, 3);
*	 }
*	//////////////////////////////////////////////////////////////
*	void gdi_demoWindow::Paint (TDC& dc, bool erase, TRect& rect)
*	{
*	 TWindow::Paint(dc, erase, rect);

*	 // INSERT>> Your code here.
*	 Demo* demo = new Demo();
*	 demo->DC = dc;
*	 demo->graf_demo();
*	 delete demo;

*	}



Classes in KNOW-HOW.GRAF

Important: KNOW-HOW.GRAF is based on KNOW-HOW.GDI. KNOW-
HOW.GDI functions are not listed here. See KNOW-HOW.GDI manual for 
details.

File AXE.H

This class encapsulate attributes of an AXE : length, 
ticks, sub-ticks and so on.

#ifndef __AXE_H_
#define __AXE_H_

#include "kh_gdi\geom.h"
#include <string.h>


#define MAXLABELS 40

struct _export Axe
	{
	int len_scr;       // Length on screen, pixels
	int* ticks;        // Ticks offset from axe 
				 // beginning, pixels
	int* sub_ticks;    // Sub-ticks, -//-
	char** labels;     // Ticks labels
	int ticks_no;      // Total number of ticks
	int sub_ticks_no;  // Total number of sub ticks

// Constructor. 
// If you do not want to use automatic ticks 
// calculation, use start == end
// and pass array of ticks coordinates.
	Axe(int len_on_screen, double start_of_axe = 0,
	   double end_of_axe = 0, int total_tick_no = 5,
	   int* tick_offsets = NULL, 
	   int total_sub_tick_no = 0,
	   int* sub_ticks_offset = NULL, 
	   char** label_legends = NULL);

	 ~Axe();
// loc, structure for LOCATION (point) is defined in 
// GEOM.H of KNOW-HOW.GDI
// The following is an abstract function and should be 
// owerloaded in descendants
	 virtual loc get_label_pos(loc, int )  
		{ return loc(0, 0); }
// Create nice-looking labels for an axe
	 int calc_labels(double start, double end, 
	    int s = 0);
// Reason why this function is here: AXE.H does not 
// include WINDOWS.H. It will make compilation faster 
// and some conflicts could be avoided. It also make 
// code platform-independent. setcolor() will be 
// overloaded in derived classes
	 void setcolor(int lab_col);
// Adjust length of an axe 
	 double ajust_axe(double stars, double end);
	 };

#endif __AXE_H_

File H_V_AXES.H

This class extends Axe to specialized Horizontal or Vertical axe.


#ifndef __HORIZ_VERT_AXES_H_
#define __HORIZ_VERT_AXES_H_

#include "kh_graf\axe.h"

enum axes_dir  { HORIZ_AXE, VERT_AXE };
enum axes_type { NORMAL_AXE, REVERSE_AXE };

class _export HV_Axes : public Axe
    {
    public:
// Type of axe - left-top or right-bottom pair
	int type;
// Type of axe - horiz or vert
	int dir;
// Direction of ticks labels text 
	int text_dir;
    public:

/* l - length; start/end specify minimum and maximum 
values to be plotted. If we have few data sets, use 
min and max for all set, or auto mode. Tick_no - 
number of ticks on axe, t - coordinates (pixels, axes-
related) of ticks if manual mode is used; s_tick_no 
and s - same for sub-ticks in manual mode (auto mode 
could use some of this variables if you want), lab - 
text of ticks labels for manual mode.
*/
	HV_Axes(int l, double start = 0, double end = 0,
	    int tick_no = 5, int* t = NULL,
	    int s_tick_no = 0, int* s = NULL,
	    char** lab = NULL);

// Draw labels for axes
	void show_labels(loc pos);
// Change / set axe type
	void set_type(int t, int d, int td = HORIZ_AXE);
// Label position
	virtual loc get_label_pos(loc, int );
// Draw axe(s)
	void show_axe(loc pos, int color, int width, int 
         tick_width);
// Show both axe and labels
	void draw_axe(loc lt, int ax_col, int lab_col, 
         int width, int tick_width);     	

// Few drawing functions
      virtual void load(char* s);
	virtual void settextjustify(int hor_j, int 
         ver_j);
	virtual int gettextwidth(char* s);
	virtual void outtextxy(int x, int y, char* s, int 
         dir);
	virtual int getheight();
	virtual void setlinestyle(int w, int s);
	virtual void line(int l, int t, int r, int b);
    };

#endif __HORIZ_VERT_AXES_H_

File AXES2.H

KNOW-HOW.GRAF supports up to four axes: two vertical and two horizontal. 
Class Axes2 incapsulates this 'set' of axes with some related operations.


#ifndef __AXES2_H_
#define  __AXES2_H_

#include "kh_graf\h_v_axes.h"

// Four possible axes could be ORed as HORIZ1|VERT1... 

enum { HORIZ1 = 1, VERT1 = 2, HORIZ2 = 4, VERT2 = 8 };

class _export Axes2
    {
    protected:
// Class includes axes pointers as data members. NULL 
// if not used

	HV_Axes* horiz_axe;
	HV_Axes* vert_axe;
	HV_Axes* horiz_axe_2;
	HV_Axes* vert_axe_2;

// Ticks-based grid could be used with axes, even with 
// user-defined ticks:

	int grid_style;

    public:
	Axes2();
	~Axes2()
	    {
	    delete horiz_axe; delete vert_axe;
	    delete horiz_axe_2; delete vert_axe_2;
	    }

/*  This function calculates ticks coordinates and 
labels (in auto mode) or just copies this values if we 
use manual mode (start <> end). In the case of manual 
axe setup, you could provide ticks / subticks with 
labels and so on. Manual here means that library 
expects values from outside (your function, user input 
and so on).
*/
	void set_axe(int which_axe, int axe_len,
	    double start = 0, double end = 0,
	    int tick_no = 0, int* ticks_on_axe = NULL,
	    int s_tick_no = 0, 
          int* sub_ticks_on_axe = NULL,
	    char** legends_on_axe = NULL, 
          int text_direction = HORIZ_AXE);

// Draw set of axes, given coordinates, color, color
// for legends, width for axes and ticks and set of
// axes to be drawn

	void show(loc left_top, int ax_color, 
          int legends_color,
	    int w, int tw, int set);

// Again, we do not have WINDOWS.H included yet, so we 
// need templates for drawing functions

	virtual void setlinestyle(int w, int s);
	virtual void line(int l, int t, int r, int b);
    };

#endif __AXES2_H_


File GRAF.H 

Class for drawing X-Y dependences on screen. Usually main class from the 
user's point of view

#ifndef __GRAF_H_
#define __GRAF_H_

#include "kh_graf\axes2.h"
#include "kh_gdi\drawtool.h"

/*    There are few types of graphics. Line graf could 
be used for drawing splines (no markers). Marker graf 
looks nice for the set of few (up to 20 - 40) points. 
Combined graf is the combination of line and marker 
grafs (data with spline). Bar and 3 dimensional bar
presents data as bars drawn from 0(Y) to y(Y). Stacked 
bar graf draws 3-d bars not from zero, but from the 
top of previous bar.
*/

// Type of graf
enum { NO_GRAF, LINE_GRAF, MARKER_GRAF, COMBINED_GRAF, 
    BAR_GRAF, BAR_3D_GRAF, STACKED_BAR_GRAF };

// Type of marker, some types ignore it
enum { NON, BAR, CIRCLE, TRIANGLE, STAR5, STAR6, 
    R_CROSS, X_CROSS, DIAMOND, TRIANGLE2, BAR2, 
    CIRCLE2, ARROW_UP, ARROW_DN };

/* This class has full access to KH_Paint class 
drawing features. It could zoom / scroll / rotate / 
reflect and so on. KH_Paint is part of KNOW-HOW.GDI 
library.
*/

class _export Graf : public KH_Paint, public Axes2
    {
    public:
// Minimum and maximum values to plot
	double xmin, ymin, xmax, ymax;
// Screen coordinates of the graf
	rect clip;
// Size of marker
	int marker_size;

    public:
        Graf();
        ~Graf();

// Some functions, like this one will never be used 
// directly by the user.
	void show_marker(int type, loc pos);

/* Array of shifts is two times larger than x and y 
arrays. It contains information about shifts of bars 
in BAR_GRAF or BAR_3D_GRAF. s[2*i] contain negative 
and s[2*i +1] - positive shifts.
After every call to this function shifts[] will be 
modified. Initial values of array element at first 
call should be 0. See example in the prev. chapter.
*/
	void plot_data(double* x, double* y1, 
        int no, int type, int mark,
	    int* shifts = NULL, double* y_dv = NULL, 
          double* x_dv = NULL);

// Draw the two lines throught (0, 0)
	void cross();

// Compute axes settings. See explaination in prev. 
// section.
	void calc_scale(double* ar, int axe, int 
        is_first, int n, int num,
 	  double* dv = NULL);

// Modify 'base' array after adding 'add' array
	  void get_stacked(double* add, double* base, int 
            n);

// Set screen coordinates of the graf
	void set_graf_clip(int x1, int y1, int x2, int 
        y2);

// Sometimes we want to adjust graf (mostly make scale 
// smaller. You can see example in prev. chapter
	void set_graf_scale(double xmi, double ymi, 
		double xma, double yma);

// Change the size of marker
	void set_marker_size(int m) { marker_size = m; }


// Draw axes / ticks / labels / grid
	void show_axes(int ax_color, int legends_color,
	  int grid_style, int grid_color, int w, int 
        tw, int set);
    };

#endif __GRAF_H_



