📄 fl_cartesian.cpp
字号:
// 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 "Fl_Cartesian.H"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.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(min_ +(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), 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 a, b, l1, l2, m1, m2, l ,_y,_w,_h; //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_);
a=y()+Fl::box_dh(box())+border_;
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;
default:
m1=0;
m2=0;
l=0;
l1=0;
l2=0;
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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -