#include "frame.h"
#include "exc.H"
#include "graph.h"
#include "fgraph.h"
#include "graph_drawer.h"
#include "epad.h"
#include "warning.h"
#include "global.h"
#include <cstdio>
#include <algorithm>
#include <vector>
namespace blop
{
length frame::default_linewidth_ = LW;
length frame::default_gridwidth_ = LW;
length frame::default_minor_gridwidth_ = 0.7*LW;
length frame::default_gridcut_ = EX;
color frame::default_gridcolor_ = color(0.7,0.7,0.7);
color frame::default_minor_gridcolor_ = color(0.85,0.85,0.85);
sym::linestyle frame::default_gridstyle_ = sym::solid;
sym::linestyle frame::default_minor_gridstyle_ = sym::solid;
frame::frame()
TRY
{
name("frame");
layer("frame");
title_ = 0;
nodistort_ = false;
frame::all().push_back(this);
marginobjectsep_ = default_marginobjectsep_;
for(int i=0; i<4; ++i)
{
marginboxes_[i] = 0;
owns_marginboxes_[i] = true;
}
legendbox_ = new legendbox;
add(legendbox_);
owns_legendbox_ = true;
draw_frame_ = default_draw_frame_;
draw_axes_ = default_draw_axes_;
foreground_ = default_foreground_;
grid_foreground_ = default_grid_foreground_;
framecolor_ = default_framecolor_;
mirror_x1_ = true;
mirror_x2_ = true;
mirror_y1_ = true;
mirror_y2_ = true;
grid_ = default_grid_;
grid_at_minor_tics_ = default_grid_at_minor_tics_;
gridcolor_ = default_gridcolor_;
minor_gridcolor_ = default_minor_gridcolor_;
gridstyle_ = default_gridstyle_;
minor_gridstyle_ = default_minor_gridstyle_;
gridwidth_ = default_gridwidth_;
minor_gridwidth_ = default_minor_gridwidth_;
gridcut_ = default_gridcut_;
linewidth_ = default_linewidth_;
x1axis_ = new axis(axis::x1); owns_x1axis_ = true;
y1axis_ = new axis(axis::y1); owns_y1axis_ = true;
x2axis_ = new axis(axis::x2); owns_x2axis_ = true;
y2axis_ = new axis(axis::y2); owns_y2axis_ = true;
x1axis_->pos(0.,0.,!cwidth());
x2axis_->pos(!cheight(),0.,!cwidth());
y1axis_->pos(0.,0.,!cheight());
y2axis_->pos(!cwidth(),0.,!cheight());
x1axis_->axiscolor(framecolor_);
x2axis_->axiscolor(framecolor_);
y1axis_->axiscolor(framecolor_);
y2axis_->axiscolor(framecolor_);
left(0.5*EX);
right(!parent_width_ - 0.5*EX);
bottom(0.5*blop::height("X"));
top(!parent_height_ - 0.5*blop::height("X"));
bmargin(!x1axis_->scriptsize());
tmargin(!x2axis_->scriptsize());
lmargin(!y1axis_->scriptsize());
rmargin(!y2axis_->scriptsize());
legend_xalign_ = default_legend_xalign_;
legend_yalign_ = default_legend_yalign_;
legendpos(legend_xalign_, legend_yalign_);
}
CATCH("frame::frame()")
frame::~frame()
{
{
std::vector<frame*>::iterator i=std::find(frame::all().begin(),
frame::all().end(),
this);
if(i==frame::all().end())
err("Unregistered frame (programming error, please report)");
frame::all().erase(i);
}
if(owns_legendbox_) delete legendbox_;
if(owns_x1axis_) delete x1axis_;
if(owns_x2axis_) delete x2axis_;
if(owns_y1axis_) delete y1axis_;
if(owns_y2axis_) delete y2axis_;
if(current_ == this) current_ = 0;
delete title_;
for(int i=0; i<4; ++i)
{
if(owns_marginboxes_[i] && marginboxes_[i] != 0)
delete marginboxes_[i];
}
for(unsigned int i=0; i<graphs_.size(); ++i)
{
if(graphs_[i]->autodel()) delete graphs_[i];
}
}
frame::frame(const frame &)
{
err("frame::frame(const frame &) should not be called");
}
void frame::operator=(const frame &)
{
err("frame::operator=(const frame &) should not be called");
}
void frame::remove_from_all(plottable *p)
{
for(unsigned int i=0; i<all().size(); ++i)
{
all()[i]->remove(p);
}
}
std::vector<frame*> &frame::all()
{
static std::vector<frame*> *f = new std::vector<frame*>;
return *f;
}
frame *frame::current_ = 0;
sym::position frame::default_legend_xalign_ = sym::right;
sym::position frame::default_legend_yalign_ = sym::top;
void frame::default_legendpos(sym::position x, sym::position y) { default_legend_xalign_ = x; default_legend_yalign_ = y; }
bool frame::default_draw_frame_ = true;
int frame::default_draw_axes_ = axis::x1|axis::x2|axis::y1|axis::y2;
bool frame::default_foreground_ = false;
void frame::default_foreground(bool b) { default_foreground_ = b; }
bool frame::default_grid_foreground_ = false;
int frame::default_grid_ = 0;
int frame::default_grid_at_minor_tics_ = 0;
void frame::default_grid(int i) { default_grid_ = i; }
void frame::default_grid(bool i) { if(i) default_grid_ = axis::x1|axis::y1; else default_grid_ = 0; }
void frame::default_grid_at_minor_tics(int i) { default_grid_at_minor_tics_ = i; }
void frame::default_grid_at_minor_tics(bool i) { if(i) default_grid_at_minor_tics_ = axis::x1|axis::y1; else default_grid_at_minor_tics_ = 0; }
color frame::default_framecolor_ = black;
void frame::default_framecolor(const color &c) { default_framecolor_ = c; }
length frame::default_marginobjectsep_(new length::base_id_t(terminal::EX));
frame &frame::nodistort(bool f)
{
nodistort_ = f;
if(nodistort_) container::caspect(-1);
return *this;
}
frame &frame::caspect(double s)
{
if(s>0) nodistort_ = false;
bmargin(!x1axis_->scriptsize());
tmargin(!x2axis_->scriptsize());
container::caspect(s);
return *this;
}
frame &frame::cxlock(sym::position a)
{
container::cxlock(a);
return *this;
}
frame &frame::cylock(sym::position a)
{
container::cylock(a);
return *this;
}
frame &frame::lmarginbox(epad *p)
{
if(marginboxes_[Left] != 0 && owns_marginboxes_[Left])
delete marginboxes_[Left];
owns_marginboxes_[Left] = false;
marginboxes_[Left] = p;
lmargin(!y1axis_->scriptsize()+!marginobjectsep_+!p->width());
modified_ = true;
return *this;
}
epad *frame::lmarginbox() const { return marginboxes_[Left]; }
frame &frame::rmarginbox(epad *p)
{
if(marginboxes_[Right] != 0 && owns_marginboxes_[Right])
delete marginboxes_[Right];
owns_marginboxes_[Right] = false;
marginboxes_[Right] = p;
lmargin(!y2axis_->scriptsize()+!marginobjectsep_+!p->width());
modified_ = true;
return *this;
}
epad *frame::rmarginbox() const { return marginboxes_[Right]; }
frame &frame::bmarginbox(epad *p)
{
if(marginboxes_[Bottom] != 0 && owns_marginboxes_[Bottom])
delete marginboxes_[Bottom];
owns_marginboxes_[Bottom] = false;
marginboxes_[Bottom] = p;
lmargin(!x1axis_->scriptsize()+!marginobjectsep_+!p->height());
modified_ = true;
return *this;
}
epad *frame::bmarginbox() const { return marginboxes_[Bottom]; }
frame &frame::tmarginbox(epad *p)
{
if(marginboxes_[Top] != 0 && owns_marginboxes_[Top])
delete marginboxes_[Top];
owns_marginboxes_[Top] = false;
marginboxes_[Top] = p;
lmargin(!x2axis_->scriptsize()+!marginobjectsep_+!p->height());
modified_ = true;
return *this;
}
epad *frame::tmarginbox() const { return marginboxes_[Top]; }
frame &frame::lmarginobject(box *b)
{
if(marginboxes_[Left] == 0)
{
owns_marginboxes_[Left] = true;
marginboxes_[Left] = new epad;
marginboxes_[Left]->autodel(false);
marginboxes_[Left]->right(-!y1axis_->scriptsize()-!marginobjectsep_);
marginboxes_[Left]->width(!b->width());
marginboxes_[Left]->bottom(0.0);
marginboxes_[Left]->top(1.0);
marginboxes_[Left]->fix_height(true);
marginboxes_[Left]->borderwidth(0.0);
add(marginboxes_[Left]);
lmargin(!y1axis_->scriptsize()+!marginobjectsep_+!marginboxes_[Left]->width());
}
marginboxes_[Left]->add(b);
modified_ = true;
return *this;
}
frame &frame::rmarginobject(box *b)
{
if(marginboxes_[Right] == 0)
{
owns_marginboxes_[Right] = true;
marginboxes_[Right] = new epad;
marginboxes_[Right]->autodel(false);
marginboxes_[Right]->left(1.0+!y2axis_->scriptsize()+!marginobjectsep_);
marginboxes_[Right]->width(!b->width());
marginboxes_[Right]->bottom(0.0);
marginboxes_[Right]->top(1.0);
marginboxes_[Right]->fix_height(true);
marginboxes_[Right]->borderwidth(0.0);
add(marginboxes_[Right]);
rmargin(!y2axis_->scriptsize()+!marginobjectsep_+!marginboxes_[Right]->width());
}
marginboxes_[Right]->add(b);
modified_ = true;
return *this;
}
frame &frame::bmarginobject(box *b)
{
if(marginboxes_[Bottom] == 0)
{
owns_marginboxes_[Bottom] = true;
marginboxes_[Bottom] = new epad;
marginboxes_[Bottom]->autodel(false);
marginboxes_[Bottom]->left(0.0);
marginboxes_[Bottom]->right(1.0);
marginboxes_[Bottom]->fix_width(true);
marginboxes_[Bottom]->top(-!x1axis_->scriptsize()-!marginobjectsep_);
marginboxes_[Bottom]->height(!b->height());
marginboxes_[Bottom]->borderwidth(0.0);
add(marginboxes_[Bottom]);
bmargin(!x1axis_->scriptsize()+!marginobjectsep_+!marginboxes_[Bottom]->height());
}
marginboxes_[Bottom]->add(b);
modified_ = true;
return *this;
}
frame &frame::tmarginobject(box *b)
{
if(marginboxes_[Top] == 0)
{
owns_marginboxes_[Top] = true;
marginboxes_[Top] = new epad;
marginboxes_[Top]->autodel(false);
marginboxes_[Top]->left(0.0);
marginboxes_[Top]->right(1.0);
marginboxes_[Top]->fix_width(true);
marginboxes_[Top]->bottom(1.0+!x2axis_->scriptsize()+!marginobjectsep_);
marginboxes_[Top]->height(!b->height());
marginboxes_[Top]->borderwidth(0.0);
add(marginboxes_[Top]);
tmargin(!x2axis_->scriptsize()+!marginobjectsep_+!marginboxes_[Top]->height());
}
marginboxes_[Top]->add(b);
modified_ = true;
return *this;
}
void frame::cd_specific()
{
current_ = this;
}
frame &frame::legend(legendbox &l)
{
owns_legendbox_ = false;
remove(legendbox_);
delete legendbox_;
legendbox_ = &l;
for(std::vector<plottable*>::iterator i = graphs_.begin();
i != graphs_.end(); ++i)
{
l.add(*i);
}
return *this;
}
frame &frame::own_legend()
{
if(owns_legendbox_) return *this;
legendbox *new_legendbox = new legendbox;
for(std::vector<plottable*>::iterator i = graphs_.begin();
i != graphs_.end(); ++i)
{
if(legendbox_) legendbox_->remove(*i);
new_legendbox->add(*i);
}
add(legendbox_ = new_legendbox);
owns_legendbox_ = true;
return *this;
}
frame &frame::legendpos(sym::position xalign,sym::position yalign)
TRY
{
modified_ = true;
legend_xalign_ = xalign;
legend_yalign_ = yalign;
legendbox_->width(legendbox_->width());
legendbox_->height(legendbox_->height());
if(xalign == sym::right)
{
if(mirror_y1_) legendbox_->right(!cwidth() - 1.3*!y1axis_->ticlength());
else legendbox_->right(!cwidth() - 1.3*!y2axis_->ticlength());
}
else if(xalign == sym::left) legendbox_->left(1.3*!y1axis_->ticlength());
else legendbox_->xcenter(0.5*!cwidth());
if(yalign == sym::top)
{
if(mirror_x1_) legendbox_->top(!cheight()- 1.3*!x1axis_->ticlength());
else legendbox_->top(!cheight()- 1.3*!x2axis_->ticlength());
}
else if(yalign == sym::bottom) legendbox_->bottom(1.3*!x1axis_->ticlength());
else legendbox_->ycenter(0.5*!cheight());
return *this;
}
CATCH("frame::legend(int,int)")
frame &frame::title(const var &t)
{
if(t.str() == "")
{
if(title_) delete title_;
title_ = 0;
return *this;
}
if(!title_)
{
title_ = new label(t);
tmarginobject(title_);
}
else title_->text(t);
title_->x(0.5,sym::center).y(0.5,sym::center);
return *this;
}
frame &frame::loffset(const length &l)
{
modified_ = true;
left(l);
return *this;
}
frame &frame::roffset(const length &l)
{
modified_ = true;
right(!parent_width_ - l);
return *this;
}
frame &frame::boffset(const length &l)
{
modified_ = true;
bottom(l);
return *this;
}
frame &frame::toffset(const length &l)
{
modified_ = true;
top(!parent_height_ - l);
return *this;
}
frame &frame::offsets(const length &l)
{
modified_ = true;
toffset(l);
boffset(l);
loffset(l);
roffset(l);
return *this;
}
frame &frame::mknew(container &parent)
{
frame *f = new frame;
f->autodel(true);
parent.add(f);
f->cd();
return *f;
}
frame &frame::current()
TRY
{
if(!current_)
{
return mknew();
}
return *current_;
}
CATCH("frame::current()")
bool frame::parent(container *p)
{
grob::parent(p);
parent_width_ = !p->cwidth();
parent_height_ = !p->cheight();
return true;
}
frame &frame::remove(plottable *g)
{
for(unsigned int i=0; i<graphs_.size(); ++i)
{
if(graphs_[i] == g)
{
graphs_[i]->parent(0);
graphs_.erase(graphs_.begin()+i);
modified_ = true;
--i;
}
}
for(unsigned int i=0; i<ordering_.size(); ++i)
{
if(ordering_[i].plottable_ == g)
{
ordering_.erase(ordering_.begin()+i);
--i;
}
}
if(legendbox_) legendbox_->remove(g);
return *this;
}
void frame::add(grob *g)
{
ordering_.push_back(grob_plottable(g,0));
container::add(g);
}
bool frame::remove(grob *g)
{
for(unsigned int i=0; i<ordering_.size(); ++i)
{
if(ordering_[i].grob_ == g)
{
ordering_.erase(ordering_.begin()+i);
--i;
}
}
return container::remove(g);
}
frame &frame::add(plottable *p)
{
if(p == 0) return *this;
graphs_.push_back(p);
legendbox_->add(p);
p->parent(this);
modified_ = true;
ordering_.push_back(grob_plottable(0,p));
return *this;
}
frame &frame::clear_graphs(bool all)
{
modified_ = true;
if(owns_x1axis_) x1axis_->clear_autosettings();
if(owns_x2axis_) x2axis_->clear_autosettings();
if(owns_y1axis_) y1axis_->clear_autosettings();
if(owns_y2axis_) y2axis_->clear_autosettings();
for(int i=0; i<(int)graphs_.size(); ++i)
{
if(!graphs_[i]->permanent() || all==true)
{
plottable *p = graphs_[i];
p->parent(0);
legendbox_->remove(p);
graphs_.erase(graphs_.begin()+i);
if(p->autodel()) delete p;
--i;
for(unsigned int j=0; j<ordering_.size(); ++j)
{
if(ordering_[j].plottable_ == p)
{
ordering_.erase(ordering_.begin()+j);
--j;
}
}
}
}
return *this;
}
frame &frame::clear_graphs_and_autosettings(bool all)
{
clear_graphs(all);
x1axis()->clear_autosettings();
x2axis()->clear_autosettings();
y1axis()->clear_autosettings();
y2axis()->clear_autosettings();
return *this;
}
void frame::clear()
{
container::clear();
for(int i=0; i<4; ++i)
{
if(owns_marginboxes_[i]) add(marginboxes_[i]);
}
if(owns_x1axis_) x1axis_->clear();
if(owns_x2axis_) x2axis_->clear();
if(owns_y1axis_) y1axis_->clear();
if(owns_y2axis_) y2axis_->clear();
if(owns_legendbox_) legendbox_->clear();
else
{
for(unsigned int i=0; i<graphs_.size(); ++i)
{
legendbox_->remove(graphs_[i]);
}
}
modified_ = true;
vector<plottable*> graphs = graphs_;
graphs_.clear();
for(unsigned int i=0; i<graphs.size(); ++i)
{
if(graphs[i]->autodel()) delete graphs[i];
}
for(unsigned int i=0; i<ordering_.size(); ++i)
{
if(ordering_[i].plottable_)
{
ordering_.erase(ordering_.begin()+i);
--i;
}
}
}
static bool length_depends_on_any(const length &l, const length* d[], int n)
{
for(int i=0; i<n; ++i)
{
if(l.depends_on(*(d[i]))) return true;
}
return false;
}
void frame::prepare_for_draw()
{
if(global::debug > 0) cout<<"[blop] [frame] prepare_for_draw starts..."<<endl;
for(int i=0; i<4; ++i)
{
if(marginboxes_[i] && marginboxes_[i]->empty()) marginboxes_[i]->off();
}
{
std::vector<int> n(14,0);
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
if(!graphs_[i]->drawstyle() || !graphs_[i]->drawstyle()->draws_points()) continue;
point_drawer *pt = graphs_[i]->pointtype();
if(dynamic_cast<autopoint*>(pt)) continue;
if(dynamic_cast<fsquare*>(pt)) ++n[0];
if(dynamic_cast<square*>(pt)) ++n[1];
if(dynamic_cast<fdiamond*>(pt)) ++n[2];
if(dynamic_cast<diamond*>(pt)) ++n[3];
if(dynamic_cast<ftriangledown*>(pt)) ++n[4];
if(dynamic_cast<triangledown*>(pt)) ++n[5];
if(dynamic_cast<ftriangle*>(pt)) ++n[6];
if(dynamic_cast<triangle*>(pt)) ++n[7];
if(dynamic_cast<fcircle*>(pt)) ++n[8];
if(dynamic_cast<circle*>(pt)) ++n[9];
if(dynamic_cast<plus*>(pt)) ++n[10];
if(dynamic_cast<cross*>(pt)) ++n[11];
if(dynamic_cast<fstar4*>(pt)) ++n[12];
if(dynamic_cast<star4*>(pt)) ++n[13];
}
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
autopoint *pt = dynamic_cast<autopoint*>(graphs_[i]->pointtype());
if(!pt) continue;
vector<int>::size_type min = 0;
for(vector<int>::size_type p=0; p<n.size(); ++p) if(n[p]<n[min]) min=p;
if(graphs_[i]->drawstyle() && graphs_[i]->drawstyle()->draws_points()) ++n[min];
switch(min) {
case 0: pt->drawer(new fsquare()); break;
case 1: pt->drawer(new square()); break;
case 2: pt->drawer(new fdiamond()); break;
case 3: pt->drawer(new diamond()); break;
case 4: pt->drawer(new ftriangledown()); break;
case 5: pt->drawer(new triangledown()); break;
case 6: pt->drawer(new ftriangle()); break;
case 7: pt->drawer(new triangle()); break;
case 8: pt->drawer(new fcircle()); break;
case 9: pt->drawer(new circle()); break;
case 10: pt->drawer(new plus()); break;
case 11: pt->drawer(new cross()); break;
case 12: pt->drawer(new fstar4()); break;
case 13: pt->drawer(new star4()); break;
default: pt->drawer(new fsquare());
}
}
}
{
std::map<int,int> linecolor, pointcolor;
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
if(graphs_[i]->drawstyle())
{
if(graphs_[i]->drawstyle()->uses_linecolor()) ++linecolor [color::sequence_index(graphs_[i]->linecolor ())];
if(graphs_[i]->drawstyle()->draws_points() ) ++pointcolor[color::sequence_index(graphs_[i]->pointcolor())];
}
}
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
if(!graphs_[i]->drawstyle()) continue;
if(graphs_[i]->drawstyle()->uses_linecolor() && graphs_[i]->linecolor() == autocolor)
{
int min = 0;
for(int c=0; c<(int)color::default_sequence().size(); ++c)
{
if(linecolor[c]<linecolor[min]) min=c;
}
graphs_[i]->linecolor(color::default_sequence()[min]);
++linecolor[min];
}
if(graphs_[i]->drawstyle()->draws_points() && graphs_[i]->pointcolor() == autocolor)
{
int min = 0;
for(int c=1; c<(int)color::default_sequence().size(); ++c)
{
if(pointcolor[c]<pointcolor[min]) min=c;
}
graphs_[i]->pointcolor(color::default_sequence()[min]);
++pointcolor[min];
}
}
}
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
if(dynamic_cast<fgraph*>(graphs_[i]) != 0) continue;
if(global::debug>0) cout<<"[blop] [frame] processing data graph["<<i<<"]"<<endl;
axis *xaxis =
(graphs_[i]->xaxis() == axis::x1 ? x1axis_ : x2axis_);
axis *yaxis =
(graphs_[i]->yaxis() == axis::y1 ? y1axis_ : y2axis_);
graphs_[i]->prepare_for_draw(xaxis,yaxis,this,1);
graph_drawer *drawer = graphs_[i]->drawstyle();
if(drawer == 0) err("No drawer specified");
drawer->set_ranges(graphs_[i],xaxis,yaxis);
}
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
if(dynamic_cast<fgraph*>(graphs_[i]) == 0) continue;
if(global::debug>0) cout<<"[blop] [frame] processing function graphs["<<i<<"]"<<endl;
axis *xaxis =
(graphs_[i]->xaxis() == axis::x1 ? x1axis_ : x2axis_);
axis *yaxis =
(graphs_[i]->yaxis() == axis::y1 ? y1axis_ : y2axis_);
graphs_[i]->prepare_for_draw(xaxis,yaxis,this,1);
graph_drawer *drawer = graphs_[i]->drawstyle();
if(drawer == 0) err("No drawer specified");
drawer->set_ranges(graphs_[i],xaxis,yaxis);
}
for(vector<plottable*>::size_type i=0; i<graphs_.size(); ++i)
{
if(global::debug>0) cout<<"[blop] [frame] reprocessing graph["<<i<<"]"<<endl;
axis *xaxis =
(graphs_[i]->xaxis() == axis::x1 ? x1axis_ : x2axis_);
axis *yaxis =
(graphs_[i]->yaxis() == axis::y1 ? y1axis_ : y2axis_);
graphs_[i]->prepare_for_draw(xaxis,yaxis,this,2);
}
if(owns_x1axis_) x1axis_->calculate_tics();
if(owns_x2axis_) x2axis_->calculate_tics();
if(owns_y1axis_) y1axis_->calculate_tics();
if(owns_y2axis_) y2axis_->calculate_tics();
bool nodistort_used = true;
if(!nodistort_) nodistort_used = false;
else
{
if(x1axis_->logscale() || y1axis_->logscale())
{
warning::print("Can not use nodistort with logscales");
nodistort_used = false;
}
const length *donotdependonthis[] =
{&lmargin(), &rmargin(), &cwidth(), &cleft(), &cright(), &cxcenter(),
&bmargin(), &tmargin(), &cheight(), &cbottom(), &ctop(), &cycenter()};
if(length_depends_on_any(lmargin(),donotdependonthis,12) ||
length_depends_on_any(rmargin(),donotdependonthis,12) ||
length_depends_on_any(bmargin(),donotdependonthis,12) ||
length_depends_on_any(tmargin(),donotdependonthis,12))
{
warning::print("Some nontrivial length-dependencies detected "
"for the margins of this frame, nodistort will not be used");
nodistort_used = false;
}
}
if(nodistort_used)
{
container::caspect((y1axis_->max()-y1axis_->min())/(x1axis_->max()-x1axis_->min()));
}
container::prepare_for_draw();
if(owns_x1axis_) x1axis_->prepare_for_draw();
if(owns_x2axis_) x2axis_->prepare_for_draw();
if(owns_y1axis_) y1axis_->prepare_for_draw();
if(owns_y2axis_) y2axis_->prepare_for_draw();
legendbox_->update();
legendbox_->prepare_for_draw();
if(mirror_x1_) cheight().register_me();
if(mirror_y1_) cwidth().register_me();
if(grid_)
{
if(grid_) gridwidth_.register_me();
if(grid_at_minor_tics_) minor_gridwidth_.register_me();
if(!x1axis_->cuts_.empty() ||
!x2axis_->cuts_.empty() ||
!y1axis_->cuts_.empty() ||
!y2axis_->cuts_.empty()) gridcut_.register_me();
}
linewidth_.register_me();
if(nodistort_used)
{
container::caspect(-1);
}
if(global::debug>0) cout<<"[blop] [frame] prepare_for_draw finished"<<endl;
}
void frame::draw_frame(terminal *term)
{
term->set_linewidth(linewidth_.termspecific_id());
term->set_color(framecolor_);
term->set_linestyle(sym::solid);
vector<terminal::coord> c;
c.push_back(terminal::coord(terminal::id(0,1),terminal::id(0,2)));
c.push_back(terminal::coord(terminal::id(1,1),terminal::id(0,2)));
c.push_back(terminal::coord(terminal::id(1,1),terminal::id(1,2)));
c.push_back(terminal::coord(terminal::id(0,1),terminal::id(1,2)));
c.push_back(terminal::coord(terminal::id(0,1),terminal::id(0,2)));
term->draw_lines(c);
}
void frame::draw_axes(terminal *term)
{
term->set_linewidth(linewidth_.termspecific_id());
term->set_color(framecolor_);
term->set_linestyle(sym::solid);
if(draw_axes_ & axis::x1)
{
if(owns_x1axis_)
{
x1axis_->print(term,
(x1axis_->pos_changed()||!draw_frame_)&&!x1axis_->tics_.empty());
if(mirror_x1_ && !x1axis_->pos_changed() && draw_frame_)
x1axis_->print_tics(term,0.,!cwidth(),!cheight(),true);
}
else
{
x1axis_->print_tics(term,0.,!cwidth(),0.);
if(mirror_x1_) x1axis_->print_tics(term,0.,!cwidth(),!cheight(),true);
}
}
if(draw_axes_ & axis::y1)
{
if(owns_y1axis_)
{
y1axis_->print(term,
(y1axis_->pos_changed()||!draw_frame_)&&!y1axis_->tics_.empty());
if(mirror_y1_ && !y1axis_->pos_changed() && draw_frame_)
y1axis_->print_tics(term,0.,!cheight(),!cwidth(),true);
}
else
{
y1axis_->print_tics(term,0.,!cheight(),0.);
if(mirror_y1_) y1axis_->print_tics(term,0.,!cheight(),!cwidth(),true);
}
}
if(draw_axes_ & axis::x2)
{
if(owns_x2axis_)
{
x2axis_->print(term,
(x2axis_->pos_changed()||!draw_frame_)&&!x2axis_->tics_.empty());
if(mirror_x2_ && !x2axis_->pos_changed() && draw_frame_)
x2axis_->print_tics(term,0.,!cwidth(),0.,true);
}
else
{
x2axis_->print_tics(term,0.,!cwidth(),!cheight());
if(mirror_x2_) x2axis_->print_tics(term,0.,!cwidth(),0.,true);
}
}
if(draw_axes_ & axis::y2)
{
if(owns_y2axis_)
{
y2axis_->print(term,
(y2axis_->pos_changed()||!draw_frame_)&&!y2axis_->tics_.empty());
if(mirror_y2_ && !y2axis_->pos_changed() && draw_frame_)
y2axis_->print_tics(term,0.,!cheight(),0.,true);
}
else
{
y2axis_->print_tics(term,0.,!cheight(),!cwidth());
if(mirror_y2_) y2axis_->print_tics(term,0.,!cheight(),0.,true);
}
}
}
void frame::draw_grid(terminal *term)
{
term->open_layer("grid");
if(grid_ & axis::x1)
{
term->set_linewidth(gridwidth_.termspecific_id());
term->set_linestyle(gridstyle_);
term->set_color(gridcolor_);
for(unsigned int i=0; i<x1axis_->tics_.size(); ++i)
{
double v = x1axis_->map_point(x1axis_->tics_[i].value());
if(v == unset) continue;
if(y1axis_->cuts_.empty())
{
term->draw_line(terminal::coord(terminal::id(v,1),terminal::id(0.0,2)),
terminal::coord(terminal::id(v,1),terminal::id(1.0,2)));
}
else
{
double start = 0.0;
for(unsigned int c=0; c<y1axis_->cuts_.size(); ++c)
{
int start_id = terminal::ZERO;
if(start != 0.0)
{
start_id = term->lincombi(1,terminal::id(start,2),
0.5,gridcut_.termspecific_id());
}
double end = y1axis_->map_point(y1axis_->cuts_[c].first);
int end_id = term->lincombi(1,terminal::id(end,2),
-0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(terminal::id(v,1),start_id),
terminal::coord(terminal::id(v,1), end_id));
start = y1axis_->map_point(y1axis_->cuts_[c].second);
}
int start_id = term->lincombi(1,terminal::id(start,2),
0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(terminal::id(v,1),start_id),
terminal::coord(terminal::id(v,1),terminal::id(1.0,2)));
}
}
if(grid_at_minor_tics_&axis::x1)
{
term->set_linewidth(minor_gridwidth_.termspecific_id());
term->set_linestyle(minor_gridstyle_);
term->set_color(minor_gridcolor_);
for(unsigned int i=0; i<x1axis_->minor_tics_.size(); ++i)
{
double v = x1axis_->map_point(x1axis_->minor_tics_[i].value());
if(v == unset) continue;
if(y1axis_->cuts_.empty())
{
term->draw_line(terminal::coord(terminal::id(v,1),terminal::id(0.0,2)),
terminal::coord(terminal::id(v,1),terminal::id(1.0,2)));
}
else
{
double start = 0.0;
for(unsigned int c=0; c<y1axis_->cuts_.size(); ++c)
{
int start_id = terminal::ZERO;
if(start != 0.0)
{
start_id = term->lincombi(1,terminal::id(start,2),
0.5,gridcut_.termspecific_id());
}
double end = y1axis_->map_point(y1axis_->cuts_[c].first);
int end_id = term->lincombi(1,terminal::id(end,2),
-0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(terminal::id(v,1),start_id),
terminal::coord(terminal::id(v,1), end_id));
start = y1axis_->map_point(y1axis_->cuts_[c].second);
}
int start_id = term->lincombi(1,terminal::id(start,2),
0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(terminal::id(v,1),start_id),
terminal::coord(terminal::id(v,1),terminal::id(1.0,2)));
}
}
}
}
if(grid_ & axis::y1)
{
term->set_linewidth(gridwidth_.termspecific_id());
term->set_linestyle(gridstyle_);
term->set_color(gridcolor_);
for(unsigned int i=0; i<y1axis_->tics_.size(); ++i)
{
double v = y1axis_->map_point(y1axis_->tics_[i].value());
if(v == unset) continue;
if(x1axis_->cuts_.empty())
{
term->draw_line(terminal::coord(terminal::id(0.0,1),terminal::id(v,2)),
terminal::coord(terminal::id(1.0,1),terminal::id(v,2)));
}
else
{
double start = 0.0;
for(unsigned int c=0; c<x1axis_->cuts_.size(); ++c)
{
int start_id = terminal::ZERO;
if(start != 0.0)
{
start_id = term->lincombi(1,terminal::id(start,1),
0.5,gridcut_.termspecific_id());
}
double end = x1axis_->map_point(x1axis_->cuts_[c].first);
int end_id = term->lincombi(1,terminal::id(end,1),
-0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(start_id,terminal::id(v,2)),
terminal::coord(end_id, terminal::id(v,2)));
start = x1axis_->map_point(x1axis_->cuts_[c].second);
}
int start_id = term->lincombi(1,terminal::id(start,1),
0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(start_id,terminal::id(v,2)),
terminal::coord(terminal::id(1.0,1),terminal::id(v,2)));
}
}
if(grid_at_minor_tics_&axis::y1)
{
term->set_linewidth(minor_gridwidth_.termspecific_id());
term->set_linestyle(minor_gridstyle_);
term->set_color(minor_gridcolor_);
for(unsigned int i=0; i<y1axis_->minor_tics_.size(); ++i)
{
double v = y1axis_->map_point(y1axis_->minor_tics_[i].value());
if(v == unset) continue;
if(x1axis_->cuts_.empty())
{
term->draw_line(terminal::coord(terminal::id(0.0,1),terminal::id(v,2)),
terminal::coord(terminal::id(1.0,1),terminal::id(v,2)));
}
else
{
double start = 0.0;
for(unsigned int c=0; c<x1axis_->cuts_.size(); ++c)
{
int start_id = terminal::ZERO;
if(start != 0.0)
{
start_id = term->lincombi(1,terminal::id(start,1),
0.5,gridcut_.termspecific_id());
}
double end = x1axis_->map_point(x1axis_->cuts_[c].first);
int end_id = term->lincombi(1,terminal::id(end,1),
-0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(start_id,terminal::id(v,2)),
terminal::coord(end_id, terminal::id(v,2)));
start = x1axis_->map_point(x1axis_->cuts_[c].second);
}
int start_id = term->lincombi(1,terminal::id(start,1),
0.5,gridcut_.termspecific_id());
term->draw_line(terminal::coord(start_id,terminal::id(v,2)),
terminal::coord(terminal::id(1.0,1),terminal::id(v,2)));
}
}
}
}
if(grid_ & axis::x2)
{
term->set_linewidth(gridwidth_.termspecific_id());
term->set_linestyle(gridstyle_);
term->set_color(gridcolor_);
for(unsigned int i=0; i<x2axis_->tics_.size(); ++i)
{
double v = x2axis_->map_point(x2axis_->tics_[i].value());
if(v == unset) continue;
term->draw_line(terminal::coord(terminal::id(v,1),terminal::id(0.0,2)),
terminal::coord(terminal::id(v,1),terminal::id(1.0,2)));
}
if(grid_at_minor_tics_&axis::x2)
{
term->set_linewidth(minor_gridwidth_.termspecific_id());
term->set_linestyle(minor_gridstyle_);
term->set_color(minor_gridcolor_);
for(unsigned int i=0; i<x2axis_->minor_tics_.size(); ++i)
{
double v = x2axis_->map_point(x2axis_->minor_tics_[i].value());
if(v == unset) continue;
term->draw_line(terminal::coord(terminal::id(v,1),terminal::id(0.0,2)),
terminal::coord(terminal::id(v,1),terminal::id(1.0,2)));
}
}
}
if(grid_ & axis::y2)
{
term->set_linewidth(gridwidth_.termspecific_id());
term->set_linestyle(gridstyle_);
term->set_color(gridcolor_);
for(unsigned int i=0; i<y2axis_->tics_.size(); ++i)
{
double v = y2axis_->map_point(y2axis_->tics_[i].value());
if(v == unset) continue;
term->draw_line(terminal::coord(terminal::id(0.0,1),terminal::id(v,2)),
terminal::coord(terminal::id(1.0,1),terminal::id(v,2)));
}
if(grid_at_minor_tics_&axis::y2)
{
term->set_linewidth(minor_gridwidth_.termspecific_id());
term->set_linestyle(minor_gridstyle_);
term->set_color(minor_gridcolor_);
for(unsigned int i=0; i<y2axis_->minor_tics_.size(); ++i)
{
double v = y2axis_->map_point(y2axis_->minor_tics_[i].value());
if(v == unset) continue;
term->draw_line(terminal::coord(terminal::id(0.0,1),terminal::id(v,2)),
terminal::coord(terminal::id(1.0,1),terminal::id(v,2)));
}
}
}
term->set_linestyle(sym::solid);
term->close_layer("grid");
}
class compare_graphs_by_level
{
public:
bool operator()(plottable *g1, plottable *g2) { return g1->level()<g2->level(); }
};
void frame::print_graph_(plottable *p, terminal *term)
{
graph_drawer *d = p->drawstyle();
if(d == 0)
{
warning::print("No drawer specified for graph","frame::print_graph_(plottable *,terminal *)");
}
else
{
if(p->columns() < d->req_components())
{
warning::print(var("Graph has too few columns (") & p->columns() & ")",
"frame::print_graph_(plottable *,terminal *)");
}
else
{
term->open_layer(p->layer());
d->draw(p,this,term);
term->close_layer(p->layer());
}
}
}
void frame::print(terminal *term)
TRY
{
if(global::debug>0) cout<<"[blop] [frame] print starts..."<<endl;
if(print_me_ < 2)
{
if(global::debug>0)
{
cout<<"[blop] [frame] this frame is switched off."<<endl;
cout<<"[blop] [frame] print finished."<<endl;
}
return;
}
term->open_layer(layer_);
term->subpicture_begin(terminal::coord(cleft().termspecific_id(),
cbottom().termspecific_id()),
terminal::coord(cright().termspecific_id(),
ctop().termspecific_id()));
if(!grid_foreground_) draw_grid(term);
term->set_color(black);
if(!foreground_)
{
if(draw_frame_) draw_frame(term);
if(draw_axes_ ) draw_axes(term);
}
term->set_color(black);
std::vector<blop::plottable *> graphs(graphs_);
std::sort(graphs.begin(), graphs.end(), compare_graphs_by_level());
unsigned int graph_index = 0;
for(; graph_index<graphs.size() && graphs[graph_index]->level()<0; ++graph_index)
{
print_graph_(graphs[graph_index], term);
}
for(unsigned int i=0; i<ordering_.size(); ++i)
{
if(ordering_[i].plottable_ && ordering_[i].plottable_->level()==0)
{
print_graph_(ordering_[i].plottable_, term);
}
if(ordering_[i].grob_ && ordering_[i].grob_ != legendbox_)
{
ordering_[i].grob_->print(term);
}
}
for(; graph_index<graphs.size(); ++graph_index)
{
if(graphs[graph_index]->level()>0) print_graph_(graphs[graph_index],term);
}
if(owns_legendbox_) legendbox_->print(term);
if(grid_foreground_) draw_grid(term);
if(foreground_)
{
if(draw_frame_) draw_frame(term);
if(draw_axes_ ) draw_axes(term);
}
term->subpicture_end();
term->close_layer(layer_);
if(global::debug>0) cout<<"[blop] [frame] print finished."<<endl;
}
CATCH("frame::print(terminal *)")
frame& frame::grid(int g)
{
if(g != grid_) modified_ = true;
grid_ = g;
return *this;
}
frame &frame::grid(bool i)
{
if(i)
{
int new_grid = grid_ | (axis::x1|axis::y1);
if(new_grid != grid_) modified_ = true;
grid_ = new_grid;
}
else
{
if(grid_ != 0) modified_ = true;
grid_ = 0;
}
return *this;
}
frame &frame::grid_at_minor_tics(int g)
{
if(g != grid_at_minor_tics_) modified_ = true;
grid_at_minor_tics_ = g;
return *this;
}
frame& frame::gridcolor(const color &c)
{
modified_ = true;
gridcolor_ = c;
return *this;
}
frame &frame::minor_gridcolor(const color &c)
{
modified_ = true;
minor_gridcolor_ = c;
return *this;
}
frame& frame::framecolor(const color &c)
{
modified_ = true;
framecolor_ = c;
return *this;
}
const color &frame::framecolor() const {return framecolor_; }
frame& frame::gridstyle(sym::linestyle s)
{
modified_ = true;
gridstyle_ = s;
return *this;
}
frame& frame::minor_gridstyle(sym::linestyle s)
{
modified_ = true;
minor_gridstyle_ = s;
return *this;
}
frame &frame::linewidth(const length &l)
{
modified_ = true;
linewidth_ = l;
return *this;
}
const length &frame::linewidth() const { return linewidth_; }
frame &frame::ticlength(const length &l)
{
if(x1axis_) x1axis_->ticlength(l);
if(y1axis_) y1axis_->ticlength(l);
if(x2axis_) x2axis_->ticlength(l);
if(y2axis_) y2axis_->ticlength(l);
return *this;
}
frame &frame::minor_ticlength(const length &l)
{
if(x1axis_) x1axis_->minor_ticlength(l);
if(y1axis_) y1axis_->minor_ticlength(l);
if(x2axis_) x2axis_->minor_ticlength(l);
if(y2axis_) y2axis_->minor_ticlength(l);
return *this;
}
frame &frame::draw_tics(bool f)
{
if(x1axis_) x1axis_->draw_tics(f);
if(y1axis_) y1axis_->draw_tics(f);
if(x2axis_) x2axis_->draw_tics(f);
if(y2axis_) y2axis_->draw_tics(f);
return *this;
}
frame& frame::gridwidth(const length &l)
{
modified_ = true;
gridwidth_ = l;
return *this;
}
frame &frame::minor_gridwidth(const length &l)
{
modified_ = true;
minor_gridwidth_ = l;
return *this;
}
frame& frame::gridcut(const length &l)
{
modified_ = true;
gridcut_ = l;
return *this;
}
const length &frame::gridcut() const {return gridcut_;}
frame &frame::foreground(bool b)
{
modified_ = true;
foreground_ = b;
return *this;
}
bool frame::foreground() const { return foreground_; }
dgraph *frame::lastd()
{
for(unsigned int i=0; i<graphs_.size(); ++i)
{
if(dgraph *p = dynamic_cast<dgraph *>(graphs_[i])) return p;
}
return 0;
}
fgraph *frame::lastf()
{
for(unsigned int i=0; i<graphs_.size(); ++i)
{
if(fgraph *p = dynamic_cast<fgraph *>(graphs_[i])) return p;
}
return 0;
}
plottable *frame::last()
{
if(graphs_.empty()) return 0;
return graphs_.back();
}
plottable *frame::get_graph(int n)
{
if(n<0 || (int)graphs_.size() <= n)
{
warning::print(var("graph index [") & n & "] is out of range",
"frame::get_graph(int)");
return 0;
}
return graphs_[n];
}
bool frame::modified() const
{
if(container::modified()) return true;
for(unsigned int i=0; i<graphs_.size(); ++i)
{
if(graphs_[i]->modified()) return true;
}
if(x1axis_->modified()) return true;
if(y1axis_->modified()) return true;
if(x2axis_->modified()) return true;
if(y2axis_->modified()) return true;
return false;
}
void frame::modified(bool f)
{
container::modified(f);
for(unsigned int i=0; i<graphs_.size(); ++i)
{
graphs_[i]->modified(f);
}
x1axis_->modified(f);
y1axis_->modified(f);
x2axis_->modified(f);
y2axis_->modified(f);
}
}