#include "warning.h"
#include "line.h"
#include "length.h"
#include "frame.h"
#include "canvas.h"
namespace blop
{
bool line::default_arrow_fore_ = false;
bool line::default_arrow_back_ = false;
bool line::default_clip_ = true;
length &line::default_arrowlength_()
{
static length l = 4*MM;
return l;
}
double line::default_arrowangle_ = 30;
sym::linestyle line::default_linestyle_ = sym::solid;
color line::default_linecolor_(0,0,0);
bool line::default_draw_line_ = true;
color line::default_fillcolor_(0,0,0);
bool line::default_fill_ = false;
length &line::default_linewidth_()
{
static length l = LW;
return l;
}
line::line()
{
name("line");
linecolor_ = default_linecolor_;
draw_line_ = default_draw_line_;
fillcolor_ = default_fillcolor_;
fill_ = default_fill_;
linewidth_ = default_linewidth_();
linestyle_ = default_linestyle_;
arrow_length_fore_ = default_arrowlength_();
arrow_length_back_ = default_arrowlength_();
arrow_angle_fore_ = default_arrowangle_;
arrow_angle_back_ = default_arrowangle_;
arrow_width_fore_ = ::tan(arrow_angle_fore_/2*3.1415/180) * !arrow_length_fore_;
arrow_width_back_ = ::tan(arrow_angle_back_/2*3.1415/180) * !arrow_length_back_;
arrow_fore_ = default_arrow_fore_;
arrow_back_ = default_arrow_back_;
clip_ = default_clip_;
}
line &line::arrowangle(double d)
{
arrow_angle_fore_ = d;
arrow_width_fore_ = ::tan(d/2*3.1415/180) * !arrow_length_fore_;
arrow_fore_ = true;
return *this;
}
line &line::arrowangle_back(double d)
{
arrow_angle_back_ = d;
arrow_width_back_ = ::tan(d/2*3.1415/180) * !arrow_length_back_;
arrow_back_ = true;
return *this;
}
int line::npoints() const
{
return x_.size();
}
length &line::x(int i)
{
if(x_.empty())
{
static length dummy;
return dummy;
}
if(i < 0 || i >= (int)x_.size()) i = x_.size()-1;
return x_[i];
}
length &line::y(int i)
{
if(y_.empty())
{
static length dummy;
return dummy;
}
if(i < 0 || i >= (int)y_.size()) i = y_.size()-1;
return y_[i];
}
line &line::operator()(const length &x, const length &y)
{
to(x,y);
return *this;
}
line &line::to (length x, length y)
{
x_.push_back(x);
y_.push_back(y);
return *this;
}
line &line::rto(length x, length y)
{
if(x_.empty())
{
x_.push_back(x);
y_.push_back(y);
return *this;
}
x_.push_back(x_.back() + x);
y_.push_back(y_.back() + y);
return *this;
}
line &line::hto(length x)
{
if(x_.empty())
{
x_.push_back(x);
y_.push_back(terminal::ZERO);
return *this;
}
x_.push_back(x);
y_.push_back(y_.back());
return *this;
}
line &line::vto(length y)
{
if(x_.empty())
{
x_.push_back(terminal::ZERO);
y_.push_back(y);
return *this;
}
x_.push_back(x_.back());
y_.push_back(y);
return *this;
}
line &line::close()
{
if(x_.empty())
{
warning::print("Line has no points, can't close it",
"line::close()");
return *this;
}
x_.push_back(x_[0]);
y_.push_back(y_[0]);
return *this;
}
line &line::draw(container *parent)
{
line *l = new line;
l->autodel(true);
parent->add(l);
return *l;
}
line &line::fdraw(const length &x, const length &y)
{
return line::draw(&frame::current())(x,y);
}
line &line::pdraw(const length &x, const length &y)
{
return line::draw(&pad::current())(x,y);
}
line &line::cdraw(const length &x, const length &y)
{
return line::draw(&canvas::current())(x,y);
}
void line::prepare_for_draw()
{
if(print_me_ == 0) return;
if(parent() == 0)
{
warning::print("Strange: no parent of line");
return;
}
for(vector<length>::size_type i=0; i<x_.size(); ++i)
{
x_[i].set_scale(x_unit());
y_[i].set_scale(y_unit());
x_[i].register_me();
y_[i].register_me();
}
if(!fill_) linewidth_.register_me();
if(arrow_fore_)
{
arrow_length_fore_.register_me();
arrow_width_fore_.register_me();
}
if(arrow_back_)
{
arrow_length_back_.register_me();
arrow_width_back_.register_me();
}
}
void line::print(terminal *t)
{
if(print_me_ != 2) return;
int n = x_.size();
if(n < 2) return;
t->open_layer(layer_);
vector<terminal::coord> cc(n);
for(int i=0; i<n; ++i)
{
cc[i].x = x_[i].termspecific_id();
cc[i].y = y_[i].termspecific_id();
}
if(clip_)
{
if(!t->clip(terminal::coord(terminal::id(0,1),terminal::id(0,2)),
terminal::coord(terminal::id(1,1),terminal::id(1,2))))
{
warning::print("This terminal doesn't support clipping","line::draw(...)");
}
}
if(fill_)
{
t->set_color(fillcolor_);
t->fill_polygon(cc);
}
if(draw_line_)
{
t->set_linestyle(linestyle_);
t->set_linewidth(linewidth_.termspecific_id());
t->set_color(linecolor_);
t->draw_lines(cc);
}
if(arrow_fore_)
draw_arrow(cc[n-2].x, cc[n-2].y, cc[n-1].x, cc[n-1].y,
arrow_length_fore_, arrow_width_fore_,t);
if(arrow_back_)
draw_arrow(cc[1].x, cc[1].y, cc[0].x, cc[0].y,
arrow_length_back_, arrow_width_back_,t);
if(clip_) t->noclip();
t->close_layer(layer_);
}
void line::draw_arrow(terminal::id x1,terminal::id y1,
terminal::id x2,terminal::id y2,
const length &l, const length &w,terminal *t)
{
int dx_id = t->lincombi(1,x1,-1,x2);
int dy_id = t->lincombi(1,y1,-1,y2);
length w_minus = -1*w;
w_minus.specialize(t);
t->rotate(dx_id,dy_id);
t->translate(x2,y2);
vector<terminal::coord> cc;
cc.push_back(terminal::coord(l.termspecific_id(), w.termspecific_id()));
cc.push_back(terminal::coord(terminal::id(0,1),terminal::id(0,2)));
cc.push_back(terminal::coord(l.termspecific_id(), w_minus.termspecific_id()));
t->draw_lines(cc);
t->reset_transformation();
}
}