fltk_test_11
// Cartesian.H,v 1.0
//
// Copyright 2000-2005 by Roman Kantor.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License
// version 2 as published by the Free Software Foundation.
//
// This library is distributed WITHOUT ANY WARRANTY;
// without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
#ifndef _Cartesian_h_
#define _Cartesian_h_
#include <FL/Fl_Box.H>
#define DEFAULT_POINT_SIZE 4
#define CA_DEFAULT_LABEL_SIZE 12
enum Ca_Damage {CA_DAMAGE_ALL=1, CA_DAMAGE_ADD=2};
enum Ca_When{CA_WHEN_MIN=1,CA_WHEN_MAX=2};
enum Ca_AxisAlign{CA_LEFT=0, CA_RIGHT=1, CA_BOTTOM=CA_LEFT, CA_TOP=CA_RIGHT,
CA_CENTER=3,CA_ALIGNMENT=3,CA_NO_LABELS=32, CA_NO_TICS=64, CA_LINE=128};
enum Ca_PointStyle{CA_SIMPLE=0,CA_ROUND=1,CA_SQUARE=2,CA_UP_TRIANGLE=3, CA_DOWN_TRIANGLE=4,
CA_DIAMOND=5,CA_NO_POINT=6, CA_POINT_STYLE=127, CA_BORDER=128};
enum Ca_GridVisible{
CA_MINOR_GRID=0xF,CA_LEFT_MINOR_TICK=0x1, CA_BOTTOM_MINOR_TICK=CA_LEFT_MINOR_TICK,CA_RIGHT_MINOR_TICK=0x2, CA_TOP_MINOR_TICK=CA_RIGHT_MINOR_TICK, CA_MINOR_TICK=0x3,
CA_MAJOR_GRID=0xF0, CA_LEFT_MAJOR_TICK=0x10, CA_BOTTOM_MAJOR_TICK=CA_LEFT_MAJOR_TICK,CA_RIGHT_MAJOR_TICK=0x20, CA_TOP_MAJOR_TICK=CA_RIGHT_MAJOR_TICK,CA_MAJOR_TICK=0x30,
CA_LABEL_GRID=0xF00,CA_LEFT_LABEL_TICK=0x100,CA_BOTTOM_LABEL_TICK=CA_LEFT_LABEL_TICK,CA_RIGHT_LABEL_TICK=0x200, CA_TOP_LABEL_TICK=CA_RIGHT_LABEL_TICK, CA_LABEL_TICK=0x300,
CA_ALWAYS_VISIBLE=0x1000,CA_FRONT=0x2000};
enum Ca_AxisType{CA_LIN=0, CA_LOG=1, CA_REV=2};
class Ca_Canvas;
class Ca_Axis_;
class Ca_Object_;
class Ca_ObjectChain;
//class Cartesian;
///////////////////////////////////////////////////////////////////////////
class Ca_ObjectChain{
public:
Ca_Object_ *object;
Ca_ObjectChain *next;
};
///////////////////////////////////////////////////////////////////////////
class Ca_Canvas:public Fl_Box{
friend class Ca_Axis_;
friend class Ca_X_Axis;
friend class Ca_Y_Axis;
friend class Ca_Object_;
static Ca_Canvas *current_;
int replot_;
Ca_Axis_ * last_axis_;
int border_;
Ca_Axis_ *current_x_;
Ca_Axis_ *current_y_;
Ca_ObjectChain * first_object_;
Ca_ObjectChain * last_object_;
Ca_ObjectChain * last_plotted_;
void add_object(Ca_Object_ *object);
/* No function body - prevents copy construction/assignment */
Ca_Canvas(const Ca_Canvas &);
const Ca_Canvas & operator=(const Ca_Canvas &);
int dx_, dy_, dw_, dh_;
protected:
void draw();
public:
static Ca_Canvas * current(){return current_;};
static void current(Ca_Canvas * _current){current_=_current;}
void current_x(Ca_Axis_ * axis){current_x_=axis;};
void current_y(Ca_Axis_ * axis){current_y_=axis;};
Ca_Axis_ * current_x(){return current_x_;};
Ca_Axis_ * current_y(){return current_y_;};
void clear();
int border(){return border_;};
void border(int border);
void clip_border(int dx, int dy, int dw, int dh){ dx_ = dx; dy_ = dy; dw_ = dw; dh_ = dh;}
void clip_border(int * dx, int * dy, int *dw, int *dh){ *dx = dx_; *dy = dy_; *dw = dw_; *dh = dh_;}
Ca_ObjectChain * objects(){return first_object_;};
Ca_Canvas(int x, int y, int w, int h, const char *label=0);
~Ca_Canvas();
};
///////////////////////////////////////////////////////////////////////////
class Ca_Axis_:public Fl_Box{
friend class Ca_Canvas;
Ca_Axis_ *previous_axis_;
protected:
int scale_;
int next_tick(int &tick_index, double &tick_value, int &tick_order, double &interval_);
bool valid_;
double k_;
double q_;
const char *label_format_;
Fl_Color minor_grid_color_;
Fl_Color major_grid_color_;
Fl_Color label_grid_color_;
int minor_grid_style_;
int major_grid_style_;
int label_grid_style_;
int minor_grid_width_;
int major_grid_width_;
int label_grid_width_;
char * minor_grid_dashes_;
char * major_grid_dashes_;
char * label_grid_dashes_;
int grid_visible_;
double tick_interval_;
int tick_separation_;
int tick_length_;
int tick_width_;
int major_step_;
int label_step_;
Ca_Canvas * canvas_;
unsigned char axis_align_;
Fl_Font label_font_face_;
int label_font_size_;
double min_;
double max_;
int min_pos_;
int max_pos_;
int border_;
Fl_Color axis_color_;
virtual int min_pos()=0;
virtual int max_pos()=0;
int update();
virtual void draw_grid()=0;
public:
virtual void current()=0;
double position(double);
double value(double);
Ca_Canvas * canvas(){return canvas_;};
int border(){return border_;};
void border(int border){border_=border;damage(CA_DAMAGE_ALL);}
double minimum(){return min_;};
double maximum(){return max_;};
void minimum(double x);
void maximum(double x);
void clear(){valid_=0;};
int cleared(){return !valid_;};
void rescale(int when, double x);
void rescale_move(int when, double x);
void tick_interval(double interval) {tick_interval_=interval; damage(CA_DAMAGE_ALL);};
double tick_interval(){return tick_interval_;};
void tick_separation(int separation) {tick_separation_=separation; damage(CA_DAMAGE_ALL);};
int tick_separation(){return tick_separation_;};
void tick_length(int length){tick_length_=length; damage(CA_DAMAGE_ALL);};
int tick_length(){return tick_length_;};
void tick_width(int width){tick_width_=width; damage(CA_DAMAGE_ALL);};
int tick_width(){return tick_width_;};
void major_step(int step){major_step_=step;damage(CA_DAMAGE_ALL);};
int major_step(){return major_step_;};
void label_step(int step){label_step_=step;damage(CA_DAMAGE_ALL);};
int label_step(){return label_step_;};
void label_format(const char *format){label_format_=format; damage(CA_DAMAGE_ALL);};
const char* label_format(){return label_format_;};
void label_font(Fl_Font face){label_font_face_=face; damage(CA_DAMAGE_ALL);};
Fl_Font label_font(){return label_font_face_;};
void label_size(int size){label_font_size_=size; damage(CA_DAMAGE_ALL);};
int label_size(){return label_font_size_;};
void axis_color(Fl_Color _axis_color){axis_color_=_axis_color; damage(CA_DAMAGE_ALL);};
Fl_Color axis_color(){ return axis_color_;};
void minor_grid_color(Fl_Color color){minor_grid_color_=color; canvas_->damage(CA_DAMAGE_ALL);};
Fl_Color minor_grid_color(){return minor_grid_color_;};
void minor_grid_style(int style, int width=0, char * dashes=0){minor_grid_style_=style;minor_grid_width_=width;minor_grid_dashes_=dashes; canvas_->damage(CA_DAMAGE_ALL);};
void minor_grid_style(int * style, int * width=0, char ** dashes=0){
if (style) *style=minor_grid_style_;
if (width) *width=minor_grid_width_;
if (dashes) *dashes=minor_grid_dashes_;
};
void major_grid_color(Fl_Color color){major_grid_color_=color; canvas_->damage(CA_DAMAGE_ALL);};
Fl_Color major_grid_color(){return major_grid_color_;};
void major_grid_style(int style, int width=0, char * dashes=0){major_grid_style_=style; major_grid_width_=width; major_grid_dashes_=dashes; canvas_->damage(CA_DAMAGE_ALL);};
void major_grid_style(int * style, int * width=0, char ** dashes=0){
if (style) *style=major_grid_style_;
if (width) *width=major_grid_width_;
if (dashes) *dashes=major_grid_dashes_;
};
void label_grid_color(Fl_Color color){label_grid_color_=color; canvas_->damage(CA_DAMAGE_ALL);};
Fl_Color label_grid_color(){return label_grid_color_;};
void label_grid_style(int style, int width=0, char * dashes=0){label_grid_style_=style; label_grid_width_=width; label_grid_dashes_=dashes; canvas_->damage(CA_DAMAGE_ALL);};
void label_grid_style(int * style, int * width=0, char ** dashes=0){
if (style) *style=label_grid_style_;
if (width) *width=label_grid_width_;
if (dashes) *dashes=label_grid_dashes_;
};
void grid_visible(int visible){grid_visible_=visible;canvas_->damage(CA_DAMAGE_ALL);};
int grid_visible(){return grid_visible_;};
void axis_align(unsigned char align){axis_align_=align; damage(CA_DAMAGE_ALL);};
unsigned char axis_align(){return axis_align_;};
void scale(int s){if(s!=scale_){redraw(); canvas_->redraw();} scale_=s;};
int scale(){return scale_;};
Ca_Axis_(int x, int y, int w, int h, const char * label=0);
~Ca_Axis_();
};
//////////////////////////////////////////////////////////////////////
class Ca_X_Axis: public Ca_Axis_{
protected:
int min_pos();
int max_pos();
void draw();
void draw_grid();
public:
void current();
Ca_X_Axis(int x, int y, int w, int h, const char * label=0);
~Ca_X_Axis();
};
///////////////////////////////////////////////////////////////////////////
class Ca_Y_Axis: public Ca_Axis_{
int min_pos();
int max_pos();
void draw();
void draw_grid();
public:
void current();
Ca_Y_Axis(int x, int y, int w, int h, const char * label=0);
~Ca_Y_Axis();
};
///////////////////////////////////////////////////////////////////////////
class Ca_Object_{
friend class Ca_Canvas;
friend class Ca_Axis_;
friend class Ca_Y_Axis;
friend class Ca_X_Axis;
// No function body - prevents copy construction/assignment
Ca_Object_(const Ca_Object_ &);
const Ca_Object_ & operator=(const Ca_Object_ &);
protected:
Ca_Canvas *canvas_;
Ca_Axis_ *x_axis_;
Ca_Axis_ *y_axis_;
virtual void draw()=0;
public:
Ca_Object_(Ca_Canvas * canvas=0);
virtual ~Ca_Object_();
};
///////////////////////////////////////////////////////////////////////////
class Ca_Point:public Ca_Object_{
protected:
void draw();
public:
double x;
double y;
int style;
int size;
Fl_Color color;
Fl_Color border_color;
int border_width;
Ca_Point(double _x, double _y, Fl_Color color=FL_BLACK, int style=CA_SIMPLE, int size=DEFAULT_POINT_SIZE, Fl_Color border_color=FL_BLACK, int border_width=0);
};
///////////////////////////////////////////////////////////////////////////
class Ca_LinePoint:public Ca_Point{
protected:
void draw();
public:
Ca_LinePoint *previous;
int line_width;
Ca_LinePoint(Ca_LinePoint *_previous, double _x, double _y, int line_width, Fl_Color color=FL_BLACK, int style=CA_SIMPLE, int size=DEFAULT_POINT_SIZE, Fl_Color border_color=FL_BLACK, int border_width=0);
Ca_LinePoint(Ca_LinePoint *_previous, double _x, double _y);
};
///////////////////////////////////////////////////////////////////////////
class Ca_PolyLine:public Ca_LinePoint{
protected:
void draw();
public:
int line_style;
Ca_PolyLine * next;
Ca_PolyLine(Ca_PolyLine *_previous, double _x, double _y,int line_style, int line_width=0, Fl_Color color=FL_BLACK, int style=CA_SIMPLE, int size=DEFAULT_POINT_SIZE, Fl_Color border_color=FL_BLACK, int border_width=0);
Ca_PolyLine(Ca_PolyLine *_previous, double _x, double _y);
};
///////////////////////////////////////////////////////////////////////////
class Ca_Line:protected Ca_Point{
protected:
void draw();
public:
Ca_Point::style; //just making public usefull data
Ca_Point::size;
Ca_Point::color;
Ca_Point::border_color;
Ca_Point::border_width;
int line_style;
int line_width;
int n;
double * data;
double * data_2;
Ca_Line(int _n, double *_data, double *_data_2, int _line_style, int _line_width=0, Fl_Color color=FL_BLACK, int style=CA_SIMPLE, int size=DEFAULT_POINT_SIZE, Fl_Color border_color=FL_BLACK, int border_width=0);
Ca_Line(int _n, double *_data, int _line_style, int _line_width=0, Fl_Color _color=FL_BLACK, int style=CA_SIMPLE, int size=DEFAULT_POINT_SIZE, Fl_Color border_color=FL_BLACK, int border_width=0);
};
///////////////////////////////////////////////////////////////////////////
class Ca_Text:public Ca_Object_{
protected:
void draw();
public:
double x1,x2,y1,y2;
char * label;
uchar align;
Fl_Color label_color;
Fl_Font label_font;
int label_size;
Ca_Text(double _x1, double _x2, double _y1, double _y2, char *_label, uchar _align=FL_ALIGN_CENTER, Fl_Font _label_font=FL_HELVETICA, int _label_size=CA_DEFAULT_LABEL_SIZE, Fl_Color _label_color=FL_BLACK);
Ca_Text(double x, double y, char *_label=0, uchar _align=FL_ALIGN_CENTER, Fl_Font _label_font=FL_HELVETICA, int _label_size=CA_DEFAULT_LABEL_SIZE, Fl_Color _label_color=FL_BLACK);
};
///////////////////////////////////////////////////////////////////////////
class Ca_Bar:public Ca_Text{
protected:
void draw();
public:
Fl_Color color;
Fl_Color border_color;
int border_width;
Ca_Bar(double _x1, double _x2, double _y1, double _y2, Fl_Color _color=FL_RED, Fl_Color _border_color=FL_BLACK, int _border_width=0, char *_label=0, uchar _align=FL_ALIGN_CENTER, Fl_Font _label_font=FL_HELVETICA, int _label_size=CA_DEFAULT_LABEL_SIZE, Fl_Color _label_color=FL_BLACK);
};
#endif
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Cartesian.cpp,v 1.0
//
// Copyright 2000-2005 by Roman Kantor.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License
// version 2 as published by the Free Software Foundation.
//
// This library is distributed WITHOUT ANY WARRANTY;
// WITHOUT even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
#include "Cartesian.H"
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <FL/fl_draw.H>
#include <FL/Fl.H>
#include <FL/Fl_Group.H>
static const int CANVAS_BORDER = 0; //gap between the graphics and surrounding"box"
static const int AXIS_BORDER = 0; //gap between axis drawing(i.e.axis line) and its "box"
static const int MINOR_INTERVAL = 0; //0 stands for automatic choice in default_*_intervals array
static const int MINOR_SEPARATION = 18;
static const int MAJOR_STEP = 5;
static const int LABEL_STEP = 10;
static const int LABEL_SIZE = CA_DEFAULT_LABEL_SIZE;
static const Fl_Font LABEL_FONT = FL_HELVETICA;
static const int MAX_LABEL_FORMAT = 16;
static const int MAX_LABEL_LENGTH = 32;
static const int NO_LIN_DEFAULTS=3;
static const double default_lin_intervals[NO_LIN_DEFAULTS] = {1, 2, 5};
static const int default_lin_major_steps[NO_LIN_DEFAULTS] = {5, 5, 2};
static const int default_lin_label_steps[NO_LIN_DEFAULTS] = {10, 5, 4};
static const int NO_LOG_DEFAULTS = 3;
static const double default_log_intervals[NO_LOG_DEFAULTS] = {1, 2, 5};
static const int default_log_major_steps[NO_LOG_DEFAULTS] = {5, 5, 2};
static const int default_log_label_steps[NO_LOG_DEFAULTS] = {10, 5, 2};
/// float drawings for more precise placement (especialy for PS output for Fl_Device!) /////
static inline void ca_rect(double x, double y, double w, double h){
fl_begin_loop();
fl_vertex(x,y);
fl_vertex(x+w,y);
fl_vertex(x+w,y+h);
fl_vertex(x,y+h);
fl_end_loop();
};
static inline void ca_rectf(double x, double y, double w, double h){
fl_begin_polygon();
fl_vertex(x,y);
fl_vertex(x+w,y);
fl_vertex(x+w,y+h);
fl_vertex(x,y+h);
fl_end_polygon();
};
static inline void ca_loop(double x1, double y1, double x2, double y2, double x3, double y3){
fl_begin_loop();
fl_vertex(x1,y1); fl_vertex(x2,y2); fl_vertex(x3,y3);
fl_end_loop();
};
static inline void ca_polygon(double x1, double y1, double x2, double y2, double x3, double y3){
fl_begin_polygon();
fl_vertex(x1,y1); fl_vertex(x2,y2); fl_vertex(x3,y3);
fl_end_polygon();
};
static inline void ca_loop(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4){
fl_begin_loop();
fl_vertex(x1,y1); fl_vertex(x2,y2); fl_vertex(x3,y3); fl_vertex(x4,y4);
fl_end_loop();
};
static inline void ca_polygon(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4){
fl_begin_polygon();
fl_vertex(x1,y1); fl_vertex(x2,y2); fl_vertex(x3,y3); fl_vertex(x4,y4);
fl_end_polygon();
};
static inline void ca_text(const char *label, double x, double y){
fl_draw(label,(int)(x+.5),(int)(y+.5));
};
static inline void ca_point(double x, double y){
fl_point((int)(x+.5),(int)(y+.5));
};
/*
static inline void ca_pie(double x, double y, double w, double h, double a1, double a2){
fl_pie((int)(x+.5), (int)(y+.5),(int)(w+.5),(int)(h+.5),0,270.0);
};
*/
static inline void ca_filled_circle(double x, double y, double r){
fl_begin_polygon();
//fl_arc(x,y,r,0,360);
fl_circle(x,y,r);
fl_end_polygon();
};
static inline void ca_text(const char *label, double x, double y, double w, double h, Fl_Align align){
fl_draw(label, (int)(x+.5), (int)(y+.5), (int)(w+.5), (int)(h+.5), align);
};
//////////////////// Ca_Axis_ ////////////////////////////
void Ca_Axis_::minimum(double x){
min_=x;
if(!valid_){
max_=x;
valid_=1;
}
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
update();
};
void Ca_Axis_::maximum(double x){
max_=x;
if(!valid_){
min_=x;
valid_=1;
}
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
update();
};
int Ca_Axis_::update(){
double _k=k_;
double _q=q_;
min_pos_=min_pos();
max_pos_=max_pos();
if (min_==max_)
k_=0;
else
if(scale_ & CA_LOG){
k_=(max_pos_-min_pos_)/(log(max_)-log(min_));
q_=min_pos_-k_*log(min_);
}else{
k_=(max_pos_-min_pos_)/(max_-min_);
q_=min_pos_;
}
if((_k!=k_)||(_q!=q_))
return 1;
else
return 0;
};
void Ca_Axis_::rescale_move(int when, double x){
if((when&CA_WHEN_MAX)&&(x>max_)){
if(scale_ & CA_LOG)
min_ *=x/max_;
else
min_ += x-max_;
max_=x;
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
}
if((when&CA_WHEN_MIN)&&(x<min_)){
if(scale_ & CA_LOG)
max_ *=x/min_;
else
max_ -= min_-x;
min_=x;
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
}
valid_=1;
};
double Ca_Axis_::position(double value){
if (k_==0) return (min_pos_+max_pos_)/2;
if(scale_ & CA_LOG)
return (int)(q_+k_*log(value));
else
return min_pos_+k_*(value-min_);
};
double Ca_Axis_::value(double pos){
if (max_==min_)
return min_;
if(scale_ & CA_LOG)
return exp((pos-q_)/k_);
else
return (min_ +(pos-min_pos_)/k_);
};
int Ca_Axis_::next_tick(int &tick_index, double &tick_value, int &tick_order, double &interval ){
////////// I know snakes are evil creatures, but sometimes they work so there is such a serpent....
////////// How many if...else can be in in a function? this is going to be a record in the G. book of r.
static int number_per_order;
double _tick_interval;
double minor_number_;
if(scale_ & CA_LOG){ ///////////// begin logarithmic /////////////////
if (!interval){
tick_order=(int)(floor(log10(min_)));
if (tick_interval_!=0){
interval=fabs(tick_interval_);
number_per_order=(int)floor(10/interval+0.5);
}else{
number_per_order=(int)(abs(min_pos_-max_pos_)/(tick_separation_*log10(max_/min_)));
if(number_per_order<=1){
label_step_=major_step_=3;
tick_order = 3*(tick_order/3);
interval=1;
number_per_order=0;
}else{
int _no_per_o=number_per_order;
for(int i=NO_LOG_DEFAULTS-1;i>=0;i--){
major_step_=default_log_major_steps[i];
label_step_=default_log_label_steps[i];
interval=default_log_intervals[i];
number_per_order=(int)floor(10/interval+0.5);
if((10/interval)>=_no_per_o)
break;
}
}
}
tick_index=number_per_order;
tick_order--;
tick_value=pow(10,tick_order);
interval*=tick_value;
if(!number_per_order){
tick_order--;
tick_value /=10;
tick_index=1;
}else
tick_value *=10;
return 1;
}else{
if (tick_value>(max_)){
tick_index-=1;
return 0;
}else{
if(number_per_order){
if(tick_index==number_per_order){
tick_order++;
interval*=10;
if(number_per_order<10){
tick_index=1;
tick_value=interval;
}else{
tick_index=2;
tick_value=2*interval;
}
}else{
tick_value +=interval;
tick_index++;
}
}else{
tick_order++;
tick_index++;
tick_value *=10;
}
return 1;
}
}
}else{ /////////////// begin linear //////////////////////
if (!interval){
minor_number_= (double)abs(min_pos_-max_pos_)/(double)tick_separation_;
_tick_interval=tick_interval_;
if (tick_interval_<0){
interval=_tick_interval=-_tick_interval;
tick_order=(int)floor(log10(_tick_interval));
}else{
if(_tick_interval!=0){
tick_order=(int)floor(log10(fabs(max_-min_)/minor_number_));
interval= pow(10,tick_order) * _tick_interval;
}else
for(int i=NO_LIN_DEFAULTS-1;i>=0;i--){
tick_order=(int)floor(log10(fabs(max_-min_)/minor_number_));
interval= pow(10,tick_order)*(_tick_interval=default_lin_intervals[i]);
major_step_=default_lin_major_steps[i];
label_step_=default_lin_label_steps[i];
if(((max_-min_)/interval)>=minor_number_)
break;
}
}
tick_value = floor(minimum()/interval);
tick_value *= interval;
tick_index=(int) floor((tick_value /interval)+0.5);
return 1;
}else{
if (tick_value>(max_)){
tick_index=-1;
return 0;
}else{
tick_value +=interval;
tick_index++;
return 1;
}
}
} ///// Uf, this is the end of the leg-less beast! //////
};
void Ca_Axis_::rescale(int when, double x){
if(!valid_){
max_=x;
min_=x;
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
valid_=1;
return;
}
if((when&CA_WHEN_MAX)&&(x>max_)){
max_=x;
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
}
if((when&CA_WHEN_MIN)&&(x<min_)){
min_=x;
damage(CA_DAMAGE_ALL);
canvas_->damage(CA_DAMAGE_ALL);
}
};
Ca_Axis_::Ca_Axis_(int x, int y, int w, int h, const char * label)
:Fl_Box(x,y,w,h,label),
scale_(CA_LIN), valid_(0), k_(0), q_(0), label_format_(0),
minor_grid_color_(FL_BLACK), major_grid_color_(FL_BLACK), label_grid_color_(FL_BLACK),
minor_grid_style_(FL_SOLID), major_grid_style_(FL_SOLID), label_grid_style_(FL_SOLID),
minor_grid_width_(0), major_grid_width_(0), label_grid_width_(0),
minor_grid_dashes_(0), major_grid_dashes_(0),label_grid_dashes_(0),
grid_visible_(0), tick_interval_(MINOR_INTERVAL), tick_separation_(MINOR_SEPARATION),
tick_length_(0), tick_width_(0), major_step_(MAJOR_STEP),label_step_(LABEL_STEP),
axis_align_(CA_BOTTOM),label_font_face_(FL_HELVETICA), label_font_size_(LABEL_SIZE),
min_(0),max_(0),min_pos_(0),max_pos_(0),border_(AXIS_BORDER),axis_color_(FL_BLACK)
{
box(FL_NO_BOX);
canvas_=Ca_Canvas::current();
previous_axis_=canvas_->last_axis_;
canvas_->last_axis_=this;
labelsize(LABEL_SIZE);
};
Ca_Axis_::~Ca_Axis_(){
if(!canvas_)return;
if (canvas_->last_axis_==this)
canvas_->last_axis_=previous_axis_;
else{
Ca_Axis_ *axis=canvas_->last_axis_;
while(axis){
if(axis->previous_axis_==this){
axis->previous_axis_=previous_axis_;
break;
}
axis=axis->previous_axis_;
}
};
};
/////////////////////// Ca_X_Axis ///////////////////////////////////////////////
int Ca_X_Axis::min_pos(){
if(scale_&CA_REV)
return canvas_->x()+canvas_->w()-canvas_->border()+Fl::box_dx(canvas_->box())-Fl::box_dw(canvas_->box());
else
return canvas_->x()+canvas_->border()+Fl::box_dx(canvas_->box());
};
int Ca_X_Axis::max_pos(){
if(scale_&CA_REV)
return canvas_->x()+canvas_->border()+Fl::box_dx(canvas_->box());
else
return canvas_->x()+canvas_->w()-canvas_->border()+Fl::box_dx(canvas_->box())-Fl::box_dw(canvas_->box());
};
void Ca_X_Axis::draw(){
int tick_index=-1;
double tick_value;
int tick_order;//, tick_number;
double _interval=0;
const char * label_format=label_format_;
if(damage()|FL_DAMAGE_ALL)
draw_label();
if (damage()&(FL_DAMAGE_ALL|CA_DAMAGE_ALL)){
update();
if (box()==FL_NO_BOX){
fl_color(parent()->color());
fl_rectf(x(),y(),w(),h());
}else
draw_box();
if(!valid_) return;
fl_font(label_font_face_,label_font_size_);
int l1=0;
int l2=0;
int m1=0;
int m2=0;
int l=0;
int _y=0;
int _w=0;
int _h=0; //temporary coordinates for ticks
double _pos,_x;
fl_clip(x()+Fl::box_dx(box()),y()+Fl::box_dy(box()),w()-Fl::box_dw(box()),h()-Fl::box_dh(box()));
fl_color(axis_color_);
int a=y()+Fl::box_dh(box())+border_;
int b=a+h()-Fl::box_dh(box())-2*border_;
switch(axis_align_ & CA_ALIGNMENT){
case CA_BOTTOM:
l=l1=m1=a;
if(axis_align_&CA_NO_TICS)
m2=m1;
else
if (tick_length_)
m2=m1+tick_length_;
else
m2=m1+label_font_size_;
l2=(m1+m2)/2;
break;
case CA_TOP:
l=l2=m2=b-1;
if(axis_align_&CA_NO_TICS)
m1=m2;
else
if (tick_length_)
m1=m2-tick_length_;
else
m1=m2-label_font_size_;
l1=(m1+m2)/2;
break;
case CA_CENTER:
m1=a;
m2=b;
l=(a+b)/2;
l1=(a+l)/2;
l2=(l+b)/2;
break;
}
fl_line_style(FL_SOLID|FL_CAP_FLAT,tick_width_);
if(axis_align_ & CA_LINE){
fl_begin_line();
fl_vertex(min_pos(),l);
fl_vertex(max_pos(),l);
fl_vertex(canvas_->x()+Fl::box_dx(canvas_->box()),l);
fl_vertex(canvas_->x()+canvas_->w()+Fl::box_dx(canvas_->box())-Fl::box_dw(canvas_->box()),l);
//fl_vertex(x()+border_,l);
//fl_vertex(x()+w()-border_,l);
fl_end_line();
}
while(next_tick(tick_index, tick_value, tick_order, _interval)){
_pos=position(tick_value);
if(scale_&CA_REV){
if(_pos<max_pos_-canvas_->border()) break;
if(_pos>min_pos_+canvas_->border()) continue;
}else{
if(_pos<min_pos_-canvas_->border()) continue;
if(_pos>max_pos_+canvas_->border()) break;
}
if(!(axis_align_&CA_NO_TICS)){
if(tick_index % major_step_){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l2);
fl_end_loop();
}else{
fl_begin_loop();
fl_vertex(_pos,m1);
fl_vertex(_pos,m2);
fl_end_loop();
}
}
if(!((tick_index % label_step_)|(axis_align_&CA_NO_LABELS))){
char label[MAX_LABEL_LENGTH];
char _label_format[MAX_LABEL_FORMAT];
if(!label_format){
int _tick_order;
if (tick_order>=0)
_tick_order=0;
else
_tick_order=-tick_order;
sprintf(_label_format,"%s.%if","%",_tick_order);
}
else
strcpy(_label_format,label_format);
sprintf(label, _label_format,tick_value);
fl_measure(label,_w,_h);
_x=_pos-_w/double(2);
switch (axis_align_ & CA_ALIGNMENT){
case CA_TOP:
_y=m1-_h/3;
break;
case CA_BOTTOM:
_y=m2+_h;
break;
case CA_CENTER:
_y=l+_h/3;
Fl_Color _color=fl_color();
fl_color(color());
ca_rectf(_x-_h/6,l-_h/2,_w+_h/3,_h);
fl_color(_color);
break;
}
ca_text(label,_x,_y);
}
}
fl_line_style(0,0);
fl_pop_clip();
}
};
void Ca_X_Axis::current(){
canvas_->current_x(this);
};
void Ca_X_Axis::draw_grid(){
if(!valid_)return;
int tick_index=-1;
double tick_value;
int tick_order;
double _interval=0;
int l1,l2;
double _pos;
l1=canvas_->y()+Fl::box_dy(canvas_->box());
l2=canvas_->y()+canvas_->h()+Fl::box_dy(canvas_->box())-Fl::box_dh(canvas_->box());
int tcl;
if(!(tcl=tick_length_))
tcl=label_font_size_;
while(next_tick(tick_index, tick_value, tick_order, _interval)){
_pos=position(tick_value);
if(scale_&CA_REV){
if(_pos<max_pos_-canvas_->border()) break;
if(_pos>min_pos_+canvas_->border()) continue;
}else{
if(_pos<min_pos_-canvas_->border()) continue;
if(_pos>max_pos_+canvas_->border()) break;
}
int grt;
if((grt=grid_visible_ & CA_LABEL_GRID) && !(tick_index % label_step_)){
fl_color(label_grid_color_);
fl_line_style(label_grid_style_,label_grid_width_);
if(grt==CA_LABEL_GRID){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l2);
fl_end_loop();
}else{
if(grt&CA_LEFT_LABEL_TICK){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l1+tcl);
fl_end_loop();
}
if(grt&CA_RIGHT_LABEL_TICK){
fl_begin_loop();
fl_vertex(_pos,l2-tcl);
fl_vertex(_pos,l2);
fl_end_loop();
}
}
}else if((grt=grid_visible_ & CA_MAJOR_GRID) && !(tick_index % major_step_)){
fl_color(major_grid_color_);
fl_line_style(major_grid_style_,major_grid_width_);
if(grt==CA_MAJOR_GRID){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l2);
fl_end_loop();
}else{
if(grt&CA_LEFT_MAJOR_TICK){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l1+tcl);
fl_end_loop();
}
if(grt&CA_RIGHT_MAJOR_TICK){
fl_begin_loop();
fl_vertex(_pos,l2-tcl);
fl_vertex(_pos,l2);
fl_end_loop();
}
}
}else if((grt=grid_visible_&CA_MINOR_GRID)){
fl_color(minor_grid_color_);
fl_line_style(minor_grid_style_,minor_grid_width_);
if(grt==CA_MINOR_GRID){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l2);
fl_end_loop();
}else{
if(grt&CA_LEFT_MINOR_TICK){
fl_begin_loop();
fl_vertex(_pos,l1);
fl_vertex(_pos,l1+tcl/2);
fl_end_loop();
}
if(grt&CA_RIGHT_MINOR_TICK){
fl_begin_loop();
fl_vertex(_pos,l2-tcl/2);
fl_vertex(_pos,l2);
fl_end_loop();
}
}
}
}
fl_line_style(0,0);
fl_color(FL_BLACK);
};
Ca_X_Axis::Ca_X_Axis(int x, int y, int w, int h, const char *label):Ca_Axis_(x, y, w, h, label){
if(!(canvas_->current_x()))
current();
};
Ca_X_Axis::~Ca_X_Axis(){
if(canvas_){
Ca_ObjectChain *ochain=canvas_->first_object_;
Ca_ObjectChain *next;
Ca_ObjectChain *previous=0;
while (ochain){
next=ochain->next;
if(ochain->object->x_axis_==this){
delete ochain->object;
if(previous)
previous->next=next;
else
canvas_->first_object_=next;
delete ochain;
}
ochain=next;
}
}
}
//////////////////////////// Ca_Y_Axis //////////////////////////////////////////////////////
int Ca_Y_Axis::min_pos(){
if (scale_&CA_REV)
return canvas_->y()+canvas_->border()+Fl::box_dy(canvas_->box());
else
return canvas_->y()+canvas_->h()-canvas_->border()+Fl::box_dy(canvas_->box())-Fl::box_dh(canvas_->box());
};
int Ca_Y_Axis::max_pos(){
if (scale_&CA_REV)
return canvas_->y()+canvas_->h()-canvas_->border()+Fl::box_dy(canvas_->box())-Fl::box_dh(canvas_->box());
else
return canvas_->y()+canvas_->border()+Fl::box_dy(canvas_->box());
};
void Ca_Y_Axis::draw(){
int tick_index=-1;
double tick_value;
int tick_order;//,tick_number;
double _interval=0;
const char * label_format=label_format_;
// if(damage()|FL_DAMAGE_ALL)
// draw_label();
if (damage()&(FL_DAMAGE_ALL|CA_DAMAGE_ALL)){
update();
if (box()==FL_NO_BOX){
fl_color(parent()->color());
fl_rectf(x(),y(),w(),h());
}else
draw_box();
if(!valid_) return;
fl_font(label_font_face_,label_font_size_);
int l1=0; int l2=0; int m1=0; int m2=0; int l=0; int _x=0; int _w,_h; //temporary coordinates for ticks
double _pos,_y;
fl_clip(x()+Fl::box_dx(box()),y()+Fl::box_dy(box()),w()-Fl::box_dw(box()),h()-Fl::box_dh(box()));
fl_color(axis_color_);
int a=x()+Fl::box_dx(box())+border_;
int b=a+w()-Fl::box_dw(box())-2*border_;
switch(axis_align_ & CA_ALIGNMENT){
case CA_RIGHT:
l=l1=m1=a;
if(axis_align_&CA_NO_TICS)
m2=m1;
else
if (tick_length_)
m2=m1+tick_length_;
else
m2=m1+label_font_size_;
l2=(l1+m2)/2;
break;
case CA_LEFT:
l=l2=m2=b-1;
if(axis_align_&CA_NO_TICS)
m1=m2;
else
if (tick_length_)
m1=m2-tick_length_;
else
m1=m2-label_font_size_;
l1=(m1+m2)/2;
break;
case CA_CENTER:
m1=a;
m2=b;
l=(a+b)/2;
l1=(a+l)/2;
l2=(l+b)/2;
break;
}
fl_line_style(FL_SOLID|FL_CAP_FLAT,tick_width_);
// double minp,maxp;
if(axis_align_ & CA_LINE){
fl_begin_line();
fl_vertex(l,canvas_->y()+Fl::box_dy(canvas_->box()));
fl_vertex(l,canvas_->y()+canvas_->h()+Fl::box_dy(canvas_->box())-Fl::box_dh(canvas_->box()));
//fl_vertex(x()+border_,l);
//fl_vertex(x()+w()-border_,l);
fl_end_line();
}
while(next_tick(tick_index, tick_value, tick_order, _interval)){
_pos=position(tick_value);
if(scale_&CA_REV){
if(_pos<min_pos_-canvas_->border()) continue;
if(_pos>max_pos_+canvas_->border()) break;
}else{
if(_pos<max_pos_-canvas_->border()) break;
if(_pos>min_pos_+canvas_->border()) continue;
}
if(!(axis_align_&CA_NO_TICS)){
fl_begin_loop();
if(tick_index % major_step_){
fl_vertex(l1,_pos);
fl_vertex(l2,_pos);
}else{
fl_vertex(m1,_pos);
fl_vertex(m2,_pos);
}
fl_end_loop();
}
if(!((tick_index % label_step_)|(axis_align_&CA_NO_LABELS))){
char label[MAX_LABEL_LENGTH];
char _label_format[MAX_LABEL_FORMAT];
if(!label_format){
int _tick_order;
if (tick_order>=0)
_tick_order=0;
else
_tick_order=-tick_order;
sprintf(_label_format,"%s.%if","%",_tick_order);
}
else
strcpy(_label_format,label_format);
sprintf(label, _label_format,tick_value);
fl_measure(label,_w,_h);
_y=_pos+_h/3;
switch (axis_align_ & CA_ALIGNMENT){
case CA_LEFT:
_x=m1-_h/3-_w;
break;
case CA_RIGHT:
_x=m2+_h/3;
break;
case CA_CENTER:
_x=(m1+m2)/2-_w/2;
Fl_Color _color=fl_color();
fl_color(color());
ca_rectf(_x-_h/6,_pos-_h/2,_w+_h/3,_h);
fl_color(_color);
break;
}
ca_text(label,_x,_y);
}
}
fl_line_style(0);
fl_pop_clip();
}
};
void Ca_Y_Axis::current(){
canvas_->current_y(this);
};
void Ca_Y_Axis::draw_grid(){
if(!valid_)return;
int tick_index=-1;
double tick_value;
int tick_order;
double _interval=0;
int l1,l2;
l1=canvas_->x()+Fl::box_dx(canvas_->box());
l2=canvas_->x()+canvas_->w()+Fl::box_dx(canvas_->box())-Fl::box_dw(canvas_->box());
int tcl;
if(!(tcl=tick_length_))
tcl=label_font_size_;
while(next_tick(tick_index, tick_value, tick_order,_interval)){
double _pos=position(tick_value);
if(scale_&CA_REV){
if(_pos<min_pos_-canvas_->border()) continue;
if(_pos>max_pos_+canvas_->border()) break;
}else{
if(_pos<max_pos_-canvas_->border()) break;
if(_pos>min_pos_+canvas_->border()) continue;
}
int grt;
if((grt=grid_visible_&CA_LABEL_GRID) && !(tick_index % label_step_)){
fl_color(label_grid_color_);
fl_line_style(label_grid_style_,label_grid_width_);
if(grt==CA_LABEL_GRID){
fl_begin_loop();
fl_vertex(l1,_pos);
fl_vertex(l2,_pos);
fl_end_loop();
}else{
if(grt&CA_LEFT_LABEL_TICK){
fl_begin_loop();
fl_vertex(l1,_pos);
fl_vertex(l1+tcl,_pos);
fl_end_loop();
}
if(grt&CA_RIGHT_LABEL_TICK){
fl_begin_loop();
fl_vertex(l2-tcl,_pos);
fl_vertex(l2,_pos);
fl_end_loop();
}
}
}else if((grt=grid_visible_&CA_MAJOR_GRID) && !(tick_index % major_step_)){
fl_color(major_grid_color_);
fl_line_style(major_grid_style_,major_grid_width_);
if(grt==CA_MAJOR_GRID){
fl_begin_loop();
fl_vertex(l1,_pos);
fl_vertex(l2,_pos);
fl_end_loop();
}else{
if(grt&CA_LEFT_MAJOR_TICK){
fl_begin_loop();
fl_vertex(l1,_pos);
fl_vertex(l1+tcl,_pos);
fl_end_loop();
}
if(grt&CA_RIGHT_MAJOR_TICK){
fl_begin_loop();
fl_vertex(l2-tcl,_pos);
fl_vertex(l2,_pos);
fl_end_loop();
}
}
}else if((grt=(grid_visible_&CA_MINOR_GRID))){
fl_color(minor_grid_color_);
fl_line_style(minor_grid_style_,minor_grid_width_);
if(grt==CA_MINOR_GRID){
fl_begin_loop();
fl_vertex(l1,_pos);
fl_vertex(l2,_pos);
fl_end_loop();
}else{
if(grt&CA_LEFT_MINOR_TICK){
fl_begin_loop();
fl_vertex(l1,_pos);
fl_vertex(l1+tcl/2,_pos);
fl_end_loop();
}
if(grt&CA_RIGHT_MINOR_TICK){
fl_begin_loop();
fl_vertex(l2-tcl/2,_pos);
fl_vertex(l2,_pos);
fl_end_loop();
}
}
}
}
fl_line_style(0,0);
fl_color(FL_BLACK);
};
Ca_Y_Axis::Ca_Y_Axis(int x, int y, int w, int h, const char * label):Ca_Axis_(x, y, w, h, label){
if(!(canvas_->current_y()))
current();
axis_align(CA_LEFT|CA_LINE);
};
Ca_Y_Axis::~Ca_Y_Axis(){
if(canvas_){
Ca_ObjectChain *ochain=canvas_->first_object_;
Ca_ObjectChain *next;
Ca_ObjectChain *previous=0;
while (ochain){
next=ochain->next;
if(ochain->object->y_axis_==this){
delete ochain->object;
if(previous)
previous->next=next;
else
canvas_->first_object_=next;
delete ochain;
}
ochain=next;
}
}
}
/////////////////////////////// Ca_Canvas ////////////////////////////////////////////
Ca_Canvas *Ca_Canvas::current_=0;
void Ca_Canvas::draw(){
uchar damage_= damage();
// int _b=border_/2;
// int _x=x()+_b;
// int _y=y()+_b;
// int _w=w()-2*_b;
// int _h=h()-2*_b;
int replot=0;
Ca_Axis_ *axis = last_axis_;
/// something similar will go in the future into the lauout layer...
while (axis){
replot |= axis->update();
axis=axis->previous_axis_;
}
///
if(damage_!=CA_DAMAGE_ADD)
draw_box();
if((damage_!=CA_DAMAGE_ADD)||replot){
last_plotted_=0;
axis=last_axis_;
while(axis){
if(!(axis->grid_visible()&CA_FRONT)&&(axis->visible()||(axis->grid_visible()&CA_ALWAYS_VISIBLE)))
axis->draw_grid();
axis=axis->previous_axis_;
}
}
fl_clip(x()+Fl::box_dx(box())+dx_, y()+Fl::box_dy(box())+border_+dy_, w()-Fl::box_dw(box()) - dw_, h()-Fl::box_dh(box()) - dh_);
if (last_plotted_)
last_plotted_=last_plotted_->next;
else
last_plotted_=first_object_;
while(last_plotted_){
last_plotted_->object->draw();
last_plotted_=last_plotted_->next;
}
last_plotted_=last_object_;
fl_pop_clip();
axis=last_axis_;
while(axis){
if((axis->grid_visible()&CA_FRONT)&&(axis->visible()||(axis->grid_visible()&CA_ALWAYS_VISIBLE)))
axis->draw_grid();
axis=axis->previous_axis_;
}
if (damage_&FL_DAMAGE_ALL)
draw_label();
};
void Ca_Canvas::add_object(Ca_Object_ * object){
last_object_=last_object_->next=new Ca_ObjectChain();
last_object_->object=object;
};
void Ca_Canvas::clear(){
while(first_object_)
delete first_object_->object;
damage(CA_DAMAGE_ALL);
};
Ca_Canvas::Ca_Canvas(int x, int y, int w, int h, const char *label)
:Fl_Box(x,y,w,h,label),
last_axis_(0),border_(CANVAS_BORDER), current_x_(0), current_y_(0),
first_object_(0),last_object_(0),last_plotted_(0), dx_(0), dy_(0), dw_(0), dh_(0)
{
current(this);
};
void Ca_Canvas::border(int border){
border_=border;
damage(CA_DAMAGE_ALL);
Ca_Axis_ *axis=last_axis_;
while(axis){
axis->damage(CA_DAMAGE_ALL);
axis=axis->previous_axis_;
}
};
Ca_Canvas::~Ca_Canvas(){
clear();
Ca_Axis_ *axis=last_axis_;
while(axis){
last_axis_=axis->previous_axis_;
axis->canvas_=0;
axis = last_axis_;
}
};
//////////////////////// Ca_Object //////////////////////
Ca_Object_::Ca_Object_(Ca_Canvas * canvas)
:canvas_(canvas)
{
if(!canvas_)
canvas_=Ca_Canvas::current();
Ca_ObjectChain *objectchain=new(Ca_ObjectChain);
objectchain->object=this;
objectchain->next=0;
if(canvas_->last_object_)
canvas_->last_object_=canvas_->last_object_->next=objectchain;
else
canvas_->last_object_=canvas_->first_object_=objectchain;
x_axis_=canvas_->current_x();
y_axis_=canvas_->current_y();
canvas_->damage(CA_DAMAGE_ADD);
};
Ca_Object_::~Ca_Object_(){
Ca_ObjectChain * objectchain=canvas_->first_object_;
Ca_ObjectChain * previouschain=0;
while(objectchain->object!=this){
previouschain=objectchain;
objectchain=objectchain->next;
}
if(previouschain)
previouschain->next=objectchain->next;
else
canvas_->first_object_=objectchain->next;
if(canvas_->last_object_==objectchain)
canvas_->last_object_=previouschain;
delete objectchain;
canvas_->last_plotted_=0;
canvas_->damage(CA_DAMAGE_ALL);
};
///////////////////////// Ca_Point //////////////////////////////////////////////////////
void Ca_Point::draw(){
fl_color(color);
double s,t;
double _x=x_axis_->position(x);
double _y=y_axis_->position(y);
switch(style & CA_POINT_STYLE){
case CA_NO_POINT:
break;
case CA_SIMPLE:
ca_point(_x,_y);
break;
case CA_ROUND:
ca_filled_circle(_x,_y,size);
//ca_pie(_x-size,_y-size,2*size,2*size,0,360);
if (style & CA_BORDER){
fl_color(border_color);
fl_line_style(0,border_width);
fl_begin_loop();
fl_circle(_x,_y,size);
fl_end_loop();
fl_line_style(0,0);
}
break;
case CA_SQUARE:
ca_rectf(_x-size,_y-size,2*size,2*size);
if (style & CA_BORDER){
fl_color(border_color);
fl_line_style(0,border_width);
ca_rect(_x-size,_y-size,2*size,2*size);
fl_line_style(0,0);
}
break;
case CA_UP_TRIANGLE:
s=(int)(1.12*size+0.5);
t=_y+size/3;
ca_polygon(_x,t-2*size,_x-s,t,_x+s,t);
if (style & CA_BORDER){
fl_color(border_color);
fl_line_style(0,border_width);
ca_loop(_x,t-2*size,_x-s,t,_x+s,t);
fl_line_style(0,0);
}
break;
case CA_DOWN_TRIANGLE:
s=(int)(1.12*size+0.5);
t=_y-size/3;
ca_polygon(_x,t+2*size,_x-s,t,_x+s,t);
if (style & CA_BORDER){
fl_color(border_color);
fl_line_style(0,border_width);
ca_loop(_x,t+2*size,_x-s,t,_x+s,t);
fl_line_style(0,0);
}
break;
case CA_DIAMOND:
s=(int)(1.3*size+0.5);
ca_polygon(_x,_y-s,_x-s,_y,_x,_y+s,_x+s,_y);
if (style & CA_BORDER){
fl_color(border_color);
fl_line_style(0,border_width);
ca_loop(_x,_y-s,_x-s,_y,_x,_y+s,_x+s,_y);
fl_line_style(0,0);
}
break;
}
};
Ca_Point::Ca_Point(double _x, double _y, Fl_Color _color, int _style, int _size, Fl_Color _border_color, int _border_width)
:Ca_Object_(0),
x(_x),
y(_y),
style(_style),
size(_size),
color(_color),
border_color(_border_color),
border_width(_border_width)
{
};
//////////////////////////// Ca_LinePoint ////////////////////////////////////////////////////////
void Ca_LinePoint::draw(){
Ca_Point::draw();
if(previous){
fl_color(color);
fl_line_style(0,line_width);
fl_begin_line();
fl_vertex(previous->x_axis_->position(previous->x),previous->y_axis_->position(previous->y));
fl_vertex(x_axis_->position(x),y_axis_->position(y));
fl_end_line();
fl_line_style(0,0);
}
};
Ca_LinePoint::Ca_LinePoint( Ca_LinePoint *_previous, double _x, double _y,int _line_width, Fl_Color color, int style, int size, Fl_Color border_color, int _border_width):Ca_Point(_x, _y, color, style, size, border_color, _border_width){
previous=_previous;
line_width=_line_width;
};
Ca_LinePoint::Ca_LinePoint(Ca_LinePoint *_previous, double _x, double _y)
:Ca_Point(_x, _y, previous->color, previous->style, previous->size,previous->border_color, previous->border_width),
previous(_previous)
{
if(_previous)
line_width=_previous->line_width;
else
line_width=0;
};
//////////////////////////// Ca_PolyLine ////////////////////////////////////////////////////////
Ca_PolyLine::Ca_PolyLine(Ca_PolyLine *_previous, double _x, double _y,int _line_style, int _line_width, Fl_Color color, int style, int size, Fl_Color border_color,int _border_width)
:Ca_LinePoint(_previous, _x, _y, _line_width, color, style, size, border_color, _border_width),
line_style(_line_style)
{
next=0;
if(_previous) _previous->next=this;
canvas_->damage(CA_DAMAGE_ALL);
};
Ca_PolyLine::Ca_PolyLine(Ca_PolyLine *_previous, double _x, double _y):Ca_LinePoint(_previous,x,y){
next=0;
if(_previous){
line_style=_previous->line_style;
_previous->next=this;
}
canvas_->damage(CA_DAMAGE_ALL);
};
void Ca_PolyLine::draw(){
Ca_Point::draw();
if(next) return;
Ca_PolyLine * temp;
int c=color;
int style=line_style;
int size=line_width;
fl_color(c);
fl_line_style(style,size);
fl_begin_line();
fl_vertex(x_axis_->position(x),y_axis_->position(y));
temp=(Ca_PolyLine *)previous;
while(temp){
fl_vertex(temp->x_axis_->position(temp->x),temp->y_axis_->position(temp->y));
if((temp->line_style != style)||(temp->color!=c)||(temp->line_width!=size)){
fl_end_line();
c=temp->color;
style=temp->line_style;
size=temp->line_width;
fl_color(c);
fl_line_style(style,size);
fl_begin_line();
fl_vertex(temp->x_axis_->position(x),temp->y_axis_->position(y));
}
temp=(Ca_PolyLine *)(temp->previous);
}
fl_end_line();
fl_line_style(0,0);
};
Ca_Line::Ca_Line(int _n, double *_data, double *_data_2, int _line_style, int _line_width, Fl_Color color, int style, int size, Fl_Color border_color, int border_width)
:Ca_Point(0, 0, color, style, size, border_color, border_width),
line_style(_line_style),
line_width(_line_width),
n(_n),
data(_data),
data_2(_data_2)
{};
Ca_Line::Ca_Line(int _n, double *_data, int _line_style, int _line_width, Fl_Color color, int style, int size, Fl_Color border_color, int border_width)
:Ca_Point(0, 0, color, style, size, border_color, border_width),
line_style(_line_style),
line_width(_line_width),
n(_n),
data(_data),
data_2(0)
{};
void Ca_Line::draw(){
fl_color(color);
fl_line_style(line_style,line_width);
fl_begin_line();
int i;
if(data_2){
for(i=0;i<n;i++)
fl_vertex(x_axis_->position(data[i]),y_axis_->position(data_2[i]));
fl_end_line();
fl_line_style(0,0);
for(i=0;i<n;i++){
x=data[i];
y=data_2[i];
Ca_Point::draw();
}
}else{
for(i=0;i<n;i++)
fl_vertex(x_axis_->position(data[2*i]),y_axis_->position(data[2*i+1]));
fl_end_line();
for(i=0;i<n;i++){
x=data[2*i];
y=data[2*i+1];
Ca_Point::draw();
}
fl_line_style(0,0);
}
};
void Ca_Text::draw(){
uchar align_=align;
double X,Y,W,H;
double X1,Y1;
X = x_axis_->position(x1);
X1 = x_axis_->position(x2);
if(X1>X)
W=X1-X;
else{
W=X-X1;
X=X1;
}
Y = y_axis_->position(y1);
Y1 = y_axis_->position(y2);
if(Y1>Y)
H = Y1-Y;
else{
H = Y-Y1;
Y = Y1;
}
fl_color(label_color);
fl_font(label_font,label_size);
ca_text(label,X,Y,W,H,(Fl_Align)align_);
};
Ca_Text::Ca_Text(double _x1, double _x2, double _y1, double _y2, char *_label, uchar _align, Fl_Font _label_font, int _label_size, Fl_Color _label_color)
:Ca_Object_(0),
x1(_x1), x2(_x2), y1(_y1), y2(_y2),
label(_label),
align(_align),
label_color(_label_color),
label_font(_label_font),
label_size(_label_size)
{};
Ca_Text::Ca_Text(double x, double y,char *_label, uchar _align, Fl_Font _label_font, int _label_size, Fl_Color _label_color)
:Ca_Object_(0),
x1(x), x2(x), y1(y), y2(y),
label(_label),
align(_align),
label_color(_label_color),
label_font(_label_font),
label_size(_label_size)
{};
void Ca_Bar::draw(){
uchar align_=align;
double X,Y,W,H;
double X1,Y1;
X = x_axis_->position(x1);
X1 = x_axis_->position(x2);
if(X1>X)
W=X1-X;
else{
W=X-X1;
X=X1;
}
Y = y_axis_->position(y1);
Y1 = y_axis_->position(y2);
if(Y1>Y)
H = Y1-Y;
else{
H = Y-Y1;
Y = Y1;
}
fl_color(color);
ca_rectf(X,Y,W,H);
if(border_width>=0){
fl_color(border_color);
fl_line_style(FL_SOLID|FL_CAP_SQUARE, border_width);
ca_rect(X,Y,W,H);
}
fl_line_style(0,0);
if(!(align_&15)||(align_&FL_ALIGN_INSIDE)){
X += border_width/2;
W -= border_width;
Y += border_width/2;
H -= border_width;
}else{
X -= border_width/2;
W += border_width;
Y -= border_width/2;
H += border_width;
if (align_ & FL_ALIGN_TOP){
align_ ^= (FL_ALIGN_BOTTOM|FL_ALIGN_TOP);
H=Y;
Y=canvas_->y()+Fl::box_dy(canvas_->box());
H-=Y;
}else if(align_ & FL_ALIGN_BOTTOM){
align_^=(FL_ALIGN_BOTTOM|FL_ALIGN_TOP);
Y=Y+H;
H=canvas_->y()+canvas_->h()+Fl::box_dy(canvas_->box())-Fl::box_dh(canvas_->box())-Y;
}else if(align_ & FL_ALIGN_LEFT){
align_^=(FL_ALIGN_LEFT|FL_ALIGN_RIGHT);
W=X;
X=canvas_->x()+Fl::box_dx(canvas_->box());
W=W-X-3;
}else if(align_ & FL_ALIGN_RIGHT){
align_ ^=(FL_ALIGN_LEFT|FL_ALIGN_RIGHT);
X=X+W+3;
W=canvas_->x()+Fl::box_dx(canvas_->box())+canvas_->w()-Fl::box_dw(canvas_->box())-X;
}
}
fl_color(label_color);
fl_font(label_font,label_size);
ca_text(label,X,Y,W,H,(Fl_Align)align_);
};
Ca_Bar::Ca_Bar(double _x1, double _x2, double _y1, double _y2, Fl_Color _color, Fl_Color _border_color, int _border_width, char *_label, uchar _align, Fl_Font _label_font, int _label_size, Fl_Color _label_color)
:Ca_Text(_x1, _x2, _y1, _y2, _label, _align, _label_font, _label_size, _label_color),
color(_color),
border_color(_border_color),
border_width(_border_width)
{
};
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
// Cartesian.H,v 0.9
//
// Copyright 2000 by Roman Kantor.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License
// version 2 as published by the Free Software Foundation.
//
// This library is distributed WITHOUT ANY WARRANTY;
// WITHOUT even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
#include <math.h>
#include <FL/Fl.H>
#include <FL/Fl_Overlay_Window.H>
#include <FL/Fl_Light_Button.H>
#include "Cartesian.H"
#include <FL/fl_draw.H>
#ifdef FL_DEVICE // this is for printing using Fl_Device patch
#include <FL/Fl_Printer.H>
#include <FL/Fl_PostScript.H>
#include <FL/fl_file_chooser.H>
void print(Fl_Widget *, void *w) {
Fl_Widget * g = (Fl_Widget *)w;
char * filename = fl_file_chooser("Print to file...","*.ps","*.ps");
if(!filename) return;
FILE * f = fopen(filename,"w");
if(!f) return;
Fl_Printer * p = new Fl_PostScript(f, 3, Fl_Printer::A4, Fl_Printer::PORTRAIT);
p->page();
p->fit(g, FL_ALIGN_CENTER);
p->draw(g);
delete p;
};
void print2(Fl_Widget *, void *w) {
Fl_Widget * g = (Fl_Widget *)w;
Fl_Printer * p = fl_gdi_printer_chooser();
if(!p) return;
p->page();
p->fit(g, FL_ALIGN_CENTER);
p->draw(g);
delete p;
};
#endif
const double PI=3.1416;
const double MIN_FREQ=90;
const double MAX_FREQ=25000;
const double FREQ_COEF=1.15;
Ca_X_Axis* frequency;
Ca_Y_Axis* current;
Ca_Y_Axis* power;
Ca_Y_Axis* phase;
Fl_Light_Button *logarithmic;
Fl_Light_Button *reversed;
double R=600;
double L=0.16;
double C=1.6e-7;
double U=1;
Ca_Canvas *canvas;
void type_callback(Fl_Widget *, void *){
power->scale((CA_LOG*logarithmic->value())|CA_REV*reversed->value());
}
void next_freq(void *){
static double f=MIN_FREQ;
static Ca_LinePoint *P_I=0;
static Ca_PolyLine *P_P=0;
double XL=2*PI*f*L;
double XC=1/(2*PI*f*C);
double I,P,fi;
I=U/sqrt(R*R+(XL-XC)*(XL-XC));
P=I*I*R;
fi=atan((XL-XC)/R);
phase->current(); //setting coordinate
new Ca_Point(f,fi,FL_YELLOW,CA_DIAMOND|CA_BORDER);current->current(); //setting coordinate
current->rescale(CA_WHEN_MAX,I*1100); //different rescalling for max and min just to get some extra gap
current->rescale(CA_WHEN_MIN,I*1000); //above maximum
P_I=new Ca_LinePoint(P_I,f,I*1000,0,FL_BLUE,CA_ROUND|CA_BORDER);
power->current(); //setting coordinate
power->rescale(CA_WHEN_MIN|CA_WHEN_MAX,P*1000);
P_P=new Ca_PolyLine(P_P,f,P*1000,FL_DASHDOT,2,FL_RED,CA_NO_POINT);
f =f* FREQ_COEF;
if(f<=MAX_FREQ)
Fl::add_timeout(.1,next_freq);
else{
power->current();
//new Ca_Text(1000,1,"Text\ntest!");
}
};
int main(int argc, char ** argv) {
Fl_Double_Window *w= new Fl_Double_Window(580, 380, "Cartesian graphics example");
w->size_range(450,250);
Fl_Group *c =new Fl_Group(0, 35, 580, 345 );
c->box(FL_DOWN_BOX);
c->align(FL_ALIGN_TOP|FL_ALIGN_INSIDE);
canvas = new Ca_Canvas(180, 75, 300, 225, "RLC resonance circuit");
canvas->box(FL_DOWN_BOX);
canvas->color(7);
canvas->align(FL_ALIGN_TOP);
Fl_Group::current()->resizable(canvas);
// w->resizable(canvas);
canvas->border(15);
frequency = new Ca_X_Axis(180, 305, 300, 30, "Frequency [Hz]");
frequency->align(FL_ALIGN_BOTTOM);
frequency->scale(CA_LOG);
frequency->minimum(MIN_FREQ);
frequency->maximum(MAX_FREQ);
frequency->label_format("%g");
frequency->minor_grid_color(fl_gray_ramp(20));
frequency->major_grid_color(fl_gray_ramp(15));
frequency->label_grid_color(fl_gray_ramp(10));
frequency->grid_visible(CA_MINOR_GRID|CA_MAJOR_GRID|CA_LABEL_GRID);
frequency->major_step(10);
frequency->label_step(10);
frequency->axis_color(FL_BLACK);
frequency->axis_align(CA_BOTTOM|CA_LINE);
current = new Ca_Y_Axis(100, 70, 78, 235, "I [mA]");
current->align(FL_ALIGN_TOP_RIGHT);
current->minor_grid_style(FL_DASH);
current->axis_align(CA_LEFT);
current->axis_color(FL_BLACK);
power = new Ca_Y_Axis(10, 70, 75, 235, "P [mW]");
power->box(FL_DOWN_BOX);
power->align(FL_ALIGN_TOP);
power->grid_visible(CA_MINOR_TICK|CA_MAJOR_TICK|CA_LABEL_GRID|CA_ALWAYS_VISIBLE);
//power->minor_grid_style(FL_DOT);
power->minor_grid_color(FL_RED);
power->major_grid_color(FL_RED);
power->label_grid_color(FL_RED);
power->minimum(0.01); //setting beggining range
power->maximum(1);
//power->hide();
phase = new Ca_Y_Axis(480, 70, 60, 235, "Phase [rad]");
phase->align(FL_ALIGN_TOP_LEFT);
phase->minimum(-PI);
phase->maximum(PI);
phase->axis_align(CA_RIGHT);
phase->tick_interval(-PI/4); //fixed ticks setting
phase->major_step(2);
phase->label_step(4);
phase->label_format("%.2f");
power->current();
//double d1[]={100,300,1000,3000,10000};
//double d2[]={.2,1,0.5,0.7,0.2};
//double d3[]={100,.2,300,1,1000,.5,3000,.7,10000,.2};
//new Ca_Line(5, d3, FL_DOT,0,FL_RED,CA_ROUND|CA_BORDER);
new Ca_Bar(7000, 12000, 0.0011, 0.9, FL_RED, FL_BLACK, 4, "Bar", FL_ALIGN_TOP, FL_HELVETICA);
new Ca_Bar(5000, 10000, 0.0011, 0.4, FL_GREEN, FL_BLACK, 4, "Sec.\nbar", FL_ALIGN_TOP|FL_ALIGN_INSIDE, FL_HELVETICA);
logarithmic=new Fl_Light_Button(10,310, 75, 25, "Log");
logarithmic->callback(&type_callback);
reversed= new Fl_Light_Button(10,340, 75, 25, "Rev");
reversed->callback(&type_callback);
c->end();
#ifdef FL_DEVICE
Fl_Button *b2 = new Fl_Button(5,5, 90, 25, "Print to file");
b2->callback(print,c);
Fl_Button *b3 = new Fl_Button(105,5, 90, 25, "Print");
b3->callback(print2,c);
#endif
Fl_Group::current()->resizable(c);
w->end();
w->show();
Fl::add_timeout(0,next_freq);
Fl::run();
return 0;
};