/*

    Bist: a chemical drawing tool
    Copyright (C) 2008 Valerio Benfante

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <global.hpp>

#include <cstdio>


#include <cairo/cairo.h>
#include <pango/pangocairo.h>
#include <cairo_t_singleton.hpp>
#include <glib.h>

#include <FL/fl_draw.H>
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Scroll.H>
#include <FL/Fl_Image.H>
#include <FL/Fl_Pixmap.H>

#include <interfacce.hpp>
#include <legame.hpp>
#include <etichetta.hpp>
#include <multiline_label.hpp>
#include <multifont_label.hpp>
#include <paragraph_text.hpp>
#include <atomo.hpp>

#include <procedura.hpp>
#include <gruppo.hpp>

#include <immagine.hpp>
#include <bist_plugin.hpp>
#include <mol_canvas.hpp>
#include <finestra_pr.hpp>
#include <prefs.hpp>
#include <util.hpp>

extern finestra_pr* MainWindow;
extern Preferences  __pref;




/**procedura*****************/

 /**
  *\return true se altro ha lo stesso id di quest'istanza
  **/

bool procedura::operator==(procedura* altro){
  //cout << "IDENT" <<id() <<"-->"<<altro->id()<< endl;
  if(id()==altro->id()){
    return true;
  }else{
    return false;
  }
}

procedura::~procedura(){

}


procedura::procedura(const procedura& altra)
  :_tipo(altra._tipo)
{
  _il_genitore=altra._il_genitore;
}


procedura::procedura(const procedura* other)
  :_tipo(other->_tipo)
{
  _il_genitore=other->_il_genitore;
}


int procedura::id_gruppo(){
  gruppo* grp=dynamic_cast<gruppo*>(_il_genitore);
  if(grp){
    return grp->id();
  }else{
#ifdef DEBUG
    cout << "ppp gruppo indirizzo invalido " //<< typeid(*_il_genitore).name() 
	 << " " <<_il_genitore << endl;
#endif
    return -1;
  }

}



const float procedura::_tolerance_hit_control_point=5;

/*************************proc_arc***********************/






/**
 *Costruttore di default.
 */

proc_arc::proc_arc()
  :procedura(PROC_ARC)
{

}


proc_arc::proc_arc(const proc_arc* altro)
  :procedura(*altro),
   _id(altro->_id),
   _xstart(altro->_xstart),
   _ystart(altro->_ystart),
   _xend(altro->_xend),
   _yend(altro->_yend),
   _x1(altro->_x1),
   _y1(altro->_y1),
   _x2(altro->_x2),
   _y2(altro->_y2),
   _x3(altro->_x3),
   _y3(altro->_y3),
   _x4(altro->_x4),
   _y4(altro->_y4),
   _cr(altro->_cr),
   _cb(altro->_cb),
   _cg(altro->_cg),
   _xpivot(altro->_xpivot),
   _ypivot(altro->_ypivot),
   _angolorot(altro->_angolorot),
   _spessore(altro->_spessore),
   _dash(altro->_dash),
   _edited_cp(altro->_edited_cp)

{
  /*
  cout << "zoom: " << __pref.getZoom() << endl;
  cout << "copiata proc_arc " << phys_xstart() << endl;
  cout << "copiata proc_arc " << xstart() << endl;
  */
}


/**
 *Costruisce loggetto arco.
 *\param id id della procedura la identifica univocamente
 *\param posx ascissa dell arco
 *\param posy ordinata dell arco
 *
 *\param w larghezza dell'arco
 *\param h altezza dell'arco
 *
 *\param startangl angolo (in gradi) da cui partire per disegnare l'arco
 *(partendo da ore 3).
 *
 *\param endangl angolo (in gradi) a cui arrivare per disegnare l'arco
 *\param cr componente rossa del colore della procedura
 *\param cg componente verde del colore della procedura
 *\param cb componente blu del colore della procedura
 *\param xpiv ascissa dell'asse di rotazione.
 *\param ypiv ordinata dell'asse di rotazione
 *\param spess spessore in px della "penna"
 *\param tratt lunghezza del tratteggio (nota: 0 nessun tratteggio).
 *
 */


proc_arc::proc_arc(int id, float xst, float yst,
	 float xen, float yen,
	 float x1, float y1,
	 float x2, float y2,
	 float x3, float y3,
	 float x4, float y4,
	 int cr, int cb, int cg ,
	 float xpiv, float ypiv, float anglrot,
	 int spess, int tratt)
  :procedura(PROC_ARC),
   _id(id),
   _xstart(xst),
   _ystart(yst),
   _xend(xen),
   _yend(yen),
   _x1(x1),
   _y1(y1),
   _x2(x2),
   _y2(y2),
   _x3(x3),
   _y3(y3),
   _x4(x4),
   _y4(y4),
   _cr(cr),
   _cb(cb),
   _cg(cg),
   _xpivot(xpiv),
   _ypivot(ypiv),
   _angolorot(anglrot),
   _spessore(spess),
   _dash(tratt),
   _edited_cp(none)


{
  init();
}

proc_arc::~proc_arc(){

}


void proc_arc::init(){
  ruota(xpivot(),ypivot(),angolorot());

}

  /*ritorna i valori*/

int proc_arc::id(){
  return _id;
}




float proc_arc::posx(){
  if(cairo_t_singleton::can_export()){
    return phys_posx();
  }else{
    return visual_posx();
    
  }
  /*
  float lung=sqrt( pow(x4()-x1(),2) + pow(y4()-y1(),2)  );
  float angl=atan2(y4()-y1(),x4()-x1());

  return (lung/2.0)*cos(angl)+x1()-w()/2;
  */
}

float proc_arc::visual_posx(){
  return __pref.getZoom() * phys_posx();

}

float proc_arc::phys_posx(){
  
  // float lung=sqrt( pow(phys_x4()-phys_x1(),2) + pow(phys_y4()-phys_y1(),2)  );
  // float angl=atan2(phys_y4()-phys_y1(),phys_x4()-phys_x1());

  // return (lung/2.0)*cos(angl)+phys_x1()-phys_w()/2;


  std::pair<float,float> ld;
  std::pair<float,float> ru;

  get_phys_bounding_box(ld,ru);

  return ld.first;

}



float proc_arc::posy(){
  if(cairo_t_singleton::can_export()){
    return phys_posy();
  }else{
    return visual_posy();
  }
  /*
  float lung=sqrt( pow(x4()-x1(),2) + pow(y4()-y1(),2)  );
  float angl=atan2(y4()-y1(),x4()-x1());

  return (lung/2.0)*sin(angl)+y1()-h()/2;
  */
}

float proc_arc::visual_posy(){
  return __pref.getZoom() * phys_posy();

}

float proc_arc::phys_posy(){
  // float lung=sqrt( pow(phys_x4()-phys_x1(),2) + pow(phys_y4()-phys_y1(),2)  );
  // float angl=atan2(phys_y4()-phys_y1(),phys_x4()-phys_x1());

  // return (lung/2.0)*sin(angl)+phys_y1()-phys_h()/2;

  std::pair<float,float> ld;
  std::pair<float,float> ru;

  get_phys_bounding_box(ld,ru);

  return ld.second;
}


float proc_arc::w(){
  vector<float> xtmp;
  xtmp.push_back(x1());
  xtmp.push_back(x2());
  xtmp.push_back(x3());
  xtmp.push_back(x4());
  xtmp.push_back(xstart());
  xtmp.push_back(xend());

  float wtmp=(*max_element(xtmp.begin(),xtmp.end())) - (*min_element(xtmp.begin(),xtmp.end()));
  return wtmp;
}

float proc_arc::visual_w(){
  vector<float> xtmp;
  xtmp.push_back(visual_x1());
  xtmp.push_back(visual_x2());
  xtmp.push_back(visual_x3());
  xtmp.push_back(visual_x4());
  xtmp.push_back(visual_xstart());
  xtmp.push_back(visual_xend());

  float wtmp=(*max_element(xtmp.begin(),xtmp.end())) - (*min_element(xtmp.begin(),xtmp.end()));
  return wtmp;
}

float proc_arc::phys_w(){
  vector<float> xtmp;
  xtmp.push_back(phys_x1());
  xtmp.push_back(phys_x2());
  xtmp.push_back(phys_x3());
  xtmp.push_back(phys_x4());
  xtmp.push_back(phys_xstart());
  xtmp.push_back(phys_xend());

  float wtmp=(*max_element(xtmp.begin(),xtmp.end())) - (*min_element(xtmp.begin(),xtmp.end()));
  return wtmp;
}


float proc_arc::visual_h(){

  vector<float> ytmp;
  ytmp.push_back(visual_y1());
  ytmp.push_back(visual_y2());
  ytmp.push_back(visual_y3());
  ytmp.push_back(visual_y4());
  ytmp.push_back(visual_ystart());
  ytmp.push_back(visual_yend());

  float htmp= (*max_element(ytmp.begin(),ytmp.end())) - (*min_element(ytmp.begin(),ytmp.end()));
  return htmp;
}


float proc_arc::h(){

  vector<float> ytmp;
  ytmp.push_back(y1());
  ytmp.push_back(y2());
  ytmp.push_back(y3());
  ytmp.push_back(y4());
  ytmp.push_back(ystart());
  ytmp.push_back(yend());

  float htmp= (*max_element(ytmp.begin(),ytmp.end())) - (*min_element(ytmp.begin(),ytmp.end()));
  return htmp;
}

float proc_arc::phys_h(){

  vector<float> ytmp;
  ytmp.push_back(phys_y1());
  ytmp.push_back(phys_y2());
  ytmp.push_back(phys_y3());
  ytmp.push_back(phys_y4());
  ytmp.push_back(phys_ystart());
  ytmp.push_back(phys_yend());

  float htmp= (*max_element(ytmp.begin(),ytmp.end())) - (*min_element(ytmp.begin(),ytmp.end()));
  return htmp;
}



float proc_arc::xstart(){
  if(cairo_t_singleton::can_export()){
    return phys_xstart();
  }else{
    return visual_xstart();
  }
}

float proc_arc::visual_xstart(){
  return phys_xstart() * __pref.getZoom();
}

float proc_arc::phys_xstart(){
  return _xstart;
}


float proc_arc::ystart(){
  if(cairo_t_singleton::can_export()){
    return phys_ystart();
  }else{
    return visual_ystart();
  }
}

float proc_arc::visual_ystart(){
  return phys_ystart() * __pref.getZoom();
}

float proc_arc::phys_ystart(){
  return _ystart;
}


float proc_arc::xend(){
  if(cairo_t_singleton::can_export()){
    return phys_xend();
  }else{
    return visual_xend();
  }
}

float proc_arc::visual_xend(){
  return phys_xend() * __pref.getZoom();
}

float proc_arc::phys_xend(){
  return _xend;
}


float proc_arc::yend(){
  if(cairo_t_singleton::can_export()){
    return phys_yend();
  }else{
    return visual_yend();
  }
}

float proc_arc::visual_yend(){
  return phys_yend() * __pref.getZoom();
}


float proc_arc::phys_yend(){
  return _yend;
}

float proc_arc::x1(){
  if(cairo_t_singleton::can_export()){
    return phys_x1();
  }else{
    return visual_x1();
  }
}

float proc_arc::visual_x1(){
  return phys_x1() * __pref.getZoom();
}

float proc_arc::phys_x1(){
  return _x1;
}


float proc_arc::y1(){
  if(cairo_t_singleton::can_export()){
    return phys_y1();
  }else{
    return visual_y1();
  }
}

float proc_arc::visual_y1(){
  return phys_y1() * __pref.getZoom();
}

float proc_arc::phys_y1(){
  return _y1;
}


float proc_arc::x2(){
  if(cairo_t_singleton::can_export()){
    return phys_x2();
  }else{
    return visual_x2();
  }

}

float proc_arc::visual_x2(){
  return phys_x2() * __pref.getZoom();
}

float proc_arc::phys_x2(){
  return _x2;
}

float proc_arc::y2(){
  if(cairo_t_singleton::can_export()){
    return phys_y2();
  }else{
    return visual_y2();
  }
}

float proc_arc::visual_y2(){
  return phys_y2() * __pref.getZoom();
}

float proc_arc::phys_y2(){
  return _y2;
}


float proc_arc::x3(){
  if(cairo_t_singleton::can_export()){
    return phys_x3();
  }else{
    return visual_x3();
  }
}

float proc_arc::visual_x3(){
  return phys_x3() * __pref.getZoom();
}

float proc_arc::phys_x3(){
  return _x3;
}



float proc_arc::y3(){
  if(cairo_t_singleton::can_export()){
    return phys_y3();
  }else{
    return visual_y3();
  }
}

float proc_arc::visual_y3(){
  return phys_y3() * __pref.getZoom();
}

float proc_arc::phys_y3(){
  return _y3;
}


float proc_arc::x4(){
  if(cairo_t_singleton::can_export()){
    return phys_x4();
  }else{
    return visual_x4();
  }
}

float proc_arc::visual_x4(){
  return phys_x4() * __pref.getZoom();
}

float proc_arc::phys_x4(){
  return _x4;
}



float proc_arc::y4(){
  if(cairo_t_singleton::can_export()){
    return phys_y4();
  }else{
    return visual_y4();
  }
}

float proc_arc::visual_y4(){
  return phys_y4() * __pref.getZoom();
}

float proc_arc::phys_y4(){
  return _y4;
}


int proc_arc::cr(){
  return _cr;
}
int proc_arc:: cg(){
  return _cg;
}
int proc_arc::cb(){
  return _cb;
}


float proc_arc::xpivot(){
  return _xpivot;
}


float proc_arc::ypivot(){
  return _ypivot;
}


float proc_arc::angolorot(){
  return _angolorot;
}

int proc_arc::spessore(){
  return _spessore;
}

int proc_arc::dash(){
  return _dash;
}


  /*setta i valori*/

void proc_arc::id(int nw){
  _id=nw;
}

void proc_arc::posx(float nw){
  trasla(nw-phys_posx(),0);
}

void proc_arc::posy(float nw){
  trasla(0,nw-phys_posy());
}

void proc_arc::w(float nw){
  xend(phys_xend()*nw);
  x2(phys_x2()*nw);
  x4(phys_x4()*nw);
}

void proc_arc::h(float nw){
  ystart(phys_ystart()*nw);
  yend(phys_yend()*nw);
  y1(phys_y1()*nw);
  y2(phys_y2()*nw);
}



void proc_arc::xstart(float nw){
  _xstart=nw;
}
void proc_arc::ystart(float nw){
  _ystart=nw;
}


void proc_arc::xend(float nw){
  _xend=nw;
}

void proc_arc::yend(float nw){
  _yend=nw;
}

void proc_arc::x1(float nw){
  _x1=nw;
}
void proc_arc::y1(float nw){
  _y1=nw;
}

void proc_arc::x2(float nw){
  _x2=nw;
}
void proc_arc::y2(float nw){
_y2=nw;
}

void proc_arc::x3(float nw){
_x3=nw;
}

void proc_arc::y3(float nw){
_y3=nw;
}


void proc_arc::x4(float nw){
_x4=nw;
}
void proc_arc::y4(float nw){
_y4=nw;
}




void proc_arc::cr(int nw){
  _cr=nw;
}

void proc_arc::cg(int nw){
  _cg=nw;
}

void proc_arc::cb(int nw){
  _cb=nw;
}


void proc_arc::xpivot(float nw){
  _xpivot=nw;
}

void proc_arc::ypivot(float nw){
  _ypivot=nw;
}

void proc_arc::angolorot(float nw){
  _angolorot=nw;
}

void proc_arc::spessore(int nw){
  _spessore=nw;
}


void proc_arc::dash(int nw){
  _dash=nw;
}




int proc_arc::sotto_mouse(int posx_m, int posy_m){
  
  // float ics_e=posx()  + ( (w() - w()/scala_bb)/2   );
  // float ips_e=posy()  +  ( (h() - h()/scala_bb)/2   );
  // float w_e=(w() - w()/scala_bb);
  // float h_e= (h() - h()/scala_bb);



  pair<float,float> ld;
  pair<float,float> ru;



  get_bounding_box(ld, ru);

  if(posx_m > ld.first && posx_m < ru.first &&
     posy_m > ld.second && posy_m < ru.second){
    return id();
  }else{
    return -1;
  }

}


int proc_arc::control_point_under_mouse(int posx_m, int posy_m){

  if(similar_to(xstart(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(ystart(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=start;
    return id();
  }else if(similar_to(xend(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(yend(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=end;
    return id();
  }else if(similar_to(x1(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(y1(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=lb;
    return id();
  }else if(similar_to(x2(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(y2(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=rb;
    return id();
  }else if(similar_to(x3(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(y3(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=lu;
    return id();
  }else if(similar_to(x4(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(y4(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=ru;
    return id();
  }else{
    return -1;
  }
  
}

void proc_arc::unset_edit_control_point(){ 

  _edited_cp=none;

}

void proc_arc::control_point_transl(float dx, float dy){

  if(_edited_cp==start){
    xstart(descale(xstart() +dx));
    ystart(descale(ystart() +dy));
  }else if(_edited_cp==end){
    xend(descale(xend() +dx));
    yend(descale(yend() +dy));
  }else if(_edited_cp==ru){
    x4(descale(x4() +dx));
    y4(descale(y4() +dy));
  }else if(_edited_cp==lu){
    x3(descale(x3() +dx));
    y3(descale(y3() +dy));
  }else if(_edited_cp==lb){
    x1(descale(x1() +dx));
    y1(descale(y1() +dy));
  }else if(_edited_cp==rb){
    x2(descale(x2() +dx));
    y2(descale(y2() +dy));
  }


}

bool proc_arc::dentro_bb(float x, float y, float w , float h){

  float xcent=xstart()+((xend()-xstart())/2);
  float ycent=ystart()+((yend()-ystart())/2);

  if(xcent>x && xcent<x+w &&
     ycent>y && ycent<y+h){
      return true;
    }else{
      return false;
    }


}


void proc_arc::get_bounding_box(std::pair<float,float>& ld,
                                std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(x1());
  x.push_back(x2());
  x.push_back(x3());
  x.push_back(x4());
  x.push_back(xstart());
  x.push_back(xend());

  y.push_back(y1());
  y.push_back(y2());
  y.push_back(y3());
  y.push_back(y4());
  y.push_back(ystart());
  y.push_back(yend());

  calc_bb_gen(x,y,ld,ru);


}


void proc_arc::get_visual_bounding_box(std::pair<float,float>& ld,
                                       std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(visual_x1());
  x.push_back(visual_x2());
  x.push_back(visual_x3());
  x.push_back(visual_x4());
  x.push_back(visual_xstart());
  x.push_back(visual_xend());

  y.push_back(visual_y1());
  y.push_back(visual_y2());
  y.push_back(visual_y3());
  y.push_back(visual_y4());
  y.push_back(visual_ystart());
  y.push_back(visual_yend());

  calc_bb_gen(x,y,ld,ru);


}


void proc_arc::get_phys_bounding_box(std::pair<float,float>& ld,
                                       std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(phys_x1());
  x.push_back(phys_x2());
  x.push_back(phys_x3());
  x.push_back(phys_x4());
  x.push_back(phys_xstart());
  x.push_back(phys_xend());

  y.push_back(phys_y1());
  y.push_back(phys_y2());
  y.push_back(phys_y3());
  y.push_back(phys_y4());
  y.push_back(phys_ystart());
  y.push_back(phys_yend());

  calc_bb_gen(x,y,ld,ru);


}




void proc_arc::disegna(){
  //  fl_color(255, 0, 0);

  //  ( (w() - w()/scala_bb)/2   )
  /*
  fl_rect( static_cast<int>(rintf(posx()  - ( (w() - w()/scala_bb)/2   ) )),
	   static_cast<int>(rintf(posy()-  ( (h() - h()/scala_bb)/2   )       )),
	   static_cast<int>(rintf(   (w() - w()/scala_bb)   )) ,
	   static_cast<int>(rintf(   (h() - h()/scala_bb)     ))) ;

  fl_pie( static_cast<int>(rintf(x1())),
	  static_cast<int>(rintf(y1())),
	  4,4,0,360);

  fl_pie( static_cast<int>(rintf(x2())),
	  static_cast<int>(rintf(y2())),
	  4,4,0,360);
  fl_pie( static_cast<int>(rintf(x3())),
	  static_cast<int>(rintf(y3())),
	  4,4,0,360);
  fl_pie( static_cast<int>(rintf(x4())),
	  static_cast<int>(rintf(y4())),
	  4,4,0,360);
  */


  if(cairo_t_singleton::can_export()){
    cairo_t* cn=cairo_t_singleton::get_context();
    cairo_save(cn);


    if(dash()>0){
      const double dash_gap[1]={dash()};
      cairo_set_dash(cn,dash_gap,1,0);
    }
    cairo_set_line_width(cn,spessore());
    cairo_set_source_rgb(cn,remap_color_1(cr()),
                         remap_color_1(cg()),
                         remap_color_1(cb())
                         );
    
    cairo_move_to(cn,xstart(),ystart());
    cairo_curve_to(cn,x1(),y1(),
                   x2(),y2(),
                   xend(),yend());
    cairo_stroke(cn);
    //context->clear_path();
    
    cairo_move_to(cn,xend(),yend());
    cairo_curve_to(cn,x4(),y4(),
                   x3(),y3(),
                   xstart(),ystart());
    cairo_stroke(cn);
    //context->clear_path();
    //context->set_line_width(1);
    cairo_restore(cn);
    

  }else{
    int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
    int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
    float the_zoom=__pref.getZoom();
    int vero_spessore=static_cast<int>(rintf(spessore()*the_zoom));
    //float dx_sc=posx()+w()/2;
    //float dy_sc=posy()+h()/2;

    if(vero_spessore<=0){
      vero_spessore=1;
    }

    //fl_color(255, 0, 0);
    //fl_pie((int)posx()+dx_scroll,(int)posy()+dy_scroll,3,3,0,360);
    //fl_color(0, 0, 255);
    //fl_pie((int)visual_posx()+dx_scroll,(int)visual_posy()+dy_scroll,3,3,0,360);

    /*
    float v_xstart=xstart()*the_zoom;
    float v_ystart=ystart()*the_zoom;
    float v_xend=xend()*the_zoom;
    float v_yend=yend()*the_zoom;
    float v_x1=x1()*the_zoom;
    float v_y1=y1()*the_zoom;
    float v_x2=x2()*the_zoom;
    float v_y2=y2()*the_zoom;
    float v_x3=x3()*the_zoom;
    float v_y3=y3()*the_zoom;
    float v_x4=x4()*the_zoom;
    float v_y4=y4()*the_zoom;
    */
    fl_color(cr(), cg(), cb());

    char gap_dash[2]={dash(),0};
    
    fl_line_style(FL_SOLID, vero_spessore,gap_dash);
    fl_begin_line();
    
    fl_curve(xstart()+dx_scroll, ystart()+dy_scroll, 
	     x1()+dx_scroll, y1()+dy_scroll, 
	     x2()+dx_scroll,y2()+dy_scroll,
	     xend()+dx_scroll, yend()+dy_scroll);
    fl_end_line();
    
    fl_begin_line();
    fl_curve(xstart()+dx_scroll, ystart()+dy_scroll, 
	     x3()+dx_scroll, y3()+dy_scroll, 
	     x4()+dx_scroll,y4()+dy_scroll,
	     xend()+dx_scroll, yend()+dy_scroll);
    fl_end_line();

    fl_line_style(0);
    
    draw_shadowed_point(x1()+dx_scroll, y1()+dy_scroll,255,0,0);
    draw_shadowed_point(x2()+dx_scroll, y2()+dy_scroll,255,0,0);
    draw_shadowed_point(x3()+dx_scroll, y3()+dy_scroll,255,0,0);
    draw_shadowed_point(x4()+dx_scroll, y4()+dy_scroll,255,0,0);


  }

}



void proc_arc::trasla(float dx, float dy){
  
  //cout << "TRTRT" << endl;
  xstart(descale(xstart()+dx));
  ystart(descale(ystart()+dy));

  xend(descale(xend()+dx));
  yend(descale(yend()+dy));

  x1(descale(x1()+dx));
  y1(descale(y1()+dy));

  x2(descale(x2()+dx));
  y2(descale(y2()+dy));

  x3(descale(x3()+dx));
  y3(descale(y3()+dy));

  x4(descale(x4()+dx));
  y4(descale(y4()+dy));
}



void proc_arc::phys_translate(float dx, float dy){
  xstart(phys_xstart()+dx);
  ystart(phys_ystart()+dy);

  xend(phys_xend()+dx);
  yend(phys_yend()+dy);

  x1(phys_x1()+dx);
  y1(phys_y1()+dy);

  x2(phys_x2()+dx);
  y2(phys_y2()+dy);

  x3(phys_x3()+dx);
  y3(phys_y3()+dy);

  x4(phys_x4()+dx);
  y4(phys_y4()+dy);
}


/**
 *Scala l'oggetto
 *
 *\param sc il fattore di scala
 */

void proc_arc::scale(float sc){
  xstart(phys_xstart()*sc);
  ystart(phys_ystart()*sc);

  xend(phys_xend()*sc);
  yend(phys_yend()*sc);

  x1(phys_x1()*sc);
  y1(phys_y1()*sc);

  x2(phys_x2()*sc);
  y2(phys_y2()*sc);

  x3(phys_x3()*sc);
  y3(phys_y3()*sc);

  x4(phys_x4()*sc);
  y4(phys_y4()*sc);

}

/**
 *Ruota l'oggetto in senso orario.
 *
 *\param angl l'angolo di rotazione in radianti
 */

void proc_arc::ruota(float xpiv, float ypiv, float angl){


  xpivot(xpiv/__pref.getZoom());
  ypivot(ypiv/__pref.getZoom());
  angolorot(angl);
  //cout << "RUOTA: " <<angl <<" " <<  angolorot() << endl;

  float x=phys_xstart()-xpivot();
  float y=phys_ystart()-ypivot();
  float xp=x*cos(angolorot())+y*sin(angolorot());
  float yp=y*cos(angolorot())-x*sin(angolorot());
  xstart(xp+xpivot());
  ystart(yp+ypivot());

  x=phys_xend()-xpivot();
  y=phys_yend()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  xend(xp+xpivot());
  yend(yp+ypivot());

  x=phys_x1()-xpivot();
  y=phys_y1()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  x1(xp+xpivot());
  y1(yp+ypivot());

  
  x=phys_x2()-xpivot();
  y=phys_y2()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  x2(xp+xpivot());
  y2(yp+ypivot());


  x=phys_x3()-xpivot();
  y=phys_y3()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  x3(xp+xpivot());
  y3(yp+ypivot());


  x=phys_x4()-xpivot();
  y=phys_y4()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  x4(xp+xpivot());
  y4(yp+ypivot());

  angolorot(0);
}


float proc_arc::minima_x(){

 vector<float> xtmp;
  xtmp.push_back(x1());
  xtmp.push_back(x2());
  xtmp.push_back(x3());
  xtmp.push_back(x4());
  xtmp.push_back(xstart());
  xtmp.push_back(xend());


  return (*min_element(xtmp.begin(),xtmp.end()));


}

float proc_arc::minima_y(){
 vector<float> ytmp;
  ytmp.push_back(y1());
  ytmp.push_back(y2());
  ytmp.push_back(y3());
  ytmp.push_back(y4());
  ytmp.push_back(ystart());
  ytmp.push_back(yend());


  return (*min_element(ytmp.begin(),ytmp.end()));
}


void proc_arc::write_native_format(std::ostream& stream, std::string indent){
  stream << indent << ETIC_ARC << " " << APRI 
         << indent << "\t" << id() << SEP << phys_xstart() << std::endl
         << indent << "\t" << SEP << phys_ystart()  << SEP << phys_xend() << std::endl
         << indent << "\t" << SEP << phys_yend()  << SEP << phys_x1() << std::endl
         << indent << "\t" << SEP << phys_y1() << SEP << phys_x2() << std::endl
         << indent << "\t" << SEP << phys_y2()  << SEP << phys_x3() << std::endl
         << indent << "\t" << SEP << phys_y3()  << SEP << phys_x4() << std::endl
         << indent << "\t" << SEP << phys_y4() << SEP << cr() << std::endl
         << indent << "\t" << SEP << cg()  << SEP << cb() << std::endl
         << indent << "\t" << SEP << xpivot() << SEP << ypivot() << std::endl
         << indent << "\t" << SEP << angolorot() << SEP << spessore() << std::endl
         << indent << "\t" << SEP << dash() 
         << CHIUDI << std::endl;
}         
const float proc_arc::scala_bb=2;

/*********************proc_arrow*******************/



proc_arrow::proc_arrow()
  :procedura(PROC_ARROW),
   _arr_w(__pref.get_arr_w()),
   _arr_h(__pref.get_arr_h()),
   _arr_gap(__pref.get_arr_gap()),
   _edited_cp(none)
{

}


proc_arrow::proc_arrow(const proc_arrow* altro)
  :procedura(*altro),
   _id(altro->_id),
   _posx(altro->_posx),
   _posy(altro->_posy),
   _eposx(altro->_eposx),
   _eposy(altro->_eposy),
   _cr(altro->_cr),
   _cb(altro->_cb),
   _cg(altro->_cg),
   _xpivot(altro->_xpivot),
   _ypivot(altro->_ypivot),
   _angolorot(altro->_angolorot),
   _spessore(altro->_spessore),
   _dash(altro->_dash),
   _punte(altro->_punte),
   _arr_w(altro->_arr_w),
   _arr_h(altro->_arr_h),
   _arr_gap(altro->_arr_gap),
   _edited_cp(altro->_edited_cp)

{

}

proc_arrow::proc_arrow(int id,float posx, float posy,
		       float eposx,float eposy,
		       int cr, int cb, int cg ,
		       float xpiv, float ypiv, float anglrot,
		       int spess, int tratt, int punte,
		       float arr_w, float arr_h, float arr_gap)
   :procedura(PROC_ARROW),
    _id(id),
    _posx(posx),
    _posy(posy),
    _eposx(eposx),
    _eposy(eposy),
    _cr(cr),
    _cb(cb),
    _cg(cg),
    _xpivot(xpiv),
    _ypivot(ypiv),
    _angolorot(anglrot),
    _spessore(spess),
    _dash(tratt),
    _punte(punte),
    _arr_w(arr_w),
    _arr_h(arr_h),
    _arr_gap(arr_gap),
    _edited_cp(none)
{

}

proc_arrow::~proc_arrow(){
#ifdef DEBUG
 cout << "distruzione arrow" << endl;
#endif
}


void proc_arrow::init(){
  ruota(xpivot(),ypivot(),angolorot());
}

  /*ritorna i valori*/

int proc_arrow::id(){
  return _id;
}

float proc_arrow::posx(){
  if(cairo_t_singleton::can_export()){
    return phys_posx();
  }else{
    return visual_posx();
  }
}

float proc_arrow::visual_posx(){
  return phys_posx() * __pref.getZoom();
}

float proc_arrow::phys_posx(){
  return _posx;
}


float proc_arrow::posy(){
  if(cairo_t_singleton::can_export()){
    return phys_posy();
  }else{
    return visual_posy();
  }
}

float proc_arrow::visual_posy(){
  return phys_posy() * __pref.getZoom();
}

float proc_arrow::phys_posy(){
  return _posy;
}


float proc_arrow::eposx(){
  if(cairo_t_singleton::can_export()){
    return phys_eposx();
  }else{
    return visual_eposx();
  }
}

float proc_arrow::visual_eposx(){
  return phys_eposx() * __pref.getZoom();
}

float proc_arrow::phys_eposx(){
  return _eposx;
}


float proc_arrow::eposy(){
  if(cairo_t_singleton::can_export()){
    return phys_eposy();
  }else{
    return visual_eposy();
  }
}

float proc_arrow::visual_eposy(){
  return phys_eposy() * __pref.getZoom();
}

float proc_arrow::phys_eposy(){
  return _eposy;
}

float proc_arrow::w(){
  if(cairo_t_singleton::can_export()){
    return phys_w();
  }else{
    return visual_w();
  }
}

float proc_arrow::visual_w(){
  return visual_eposx() - visual_posx();
}

float proc_arrow::phys_w(){
  return phys_eposx() - phys_posx();
}


void proc_arrow::arrows_points(std::vector<float>& x,
                               std::vector<float>& y){


  switch(punte()){

  case ARR_OMOL_PUNT:
    
      calculate_arrow_points(posx(),posy(),
                             eposx(),eposy(),spessore(),arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y );

      break;
  case ARR_ETEROL_PUNT:

      calculate_arrow_points(posx(),posy(),
                             eposx(),eposy(),spessore(),
                             arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y,
                             true);
      calculate_arrow_points(posx(),posy(),
                             eposx(),eposy(),spessore(),
                             arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y,
                             false);
      
    break;
  case ARR_EQ:
    calculate_equilibrium_arrows(x,y);
    break;
  case ARR_DOUBLE:

    
      calculate_arrow_points(posx(),posy(),
		      eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                      true);
      calculate_arrow_points(posx(),posy(),
		      eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                      false);
    
      calculate_arrow_points(eposx(),eposy(),
		      posx(),posy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                      true);
    
      calculate_arrow_points(eposx(),eposy(),
		      posx(),posy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                      false);
      

    break;


  case ARR_BLOC:
    {


      calculate_arrow_points(posx(),posy(),eposx(),eposy(),spessore(),
                             arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                             true);
      calculate_arrow_points(posx(),posy(),eposx(),eposy(),spessore(),
                             arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                             false);
    }
    break;
    
  default:
    break;

  }


}

float proc_arrow::h(){
  if(cairo_t_singleton::can_export()){
    return phys_h();
  }else{
    return visual_h();
  }
}

float proc_arrow::visual_h(){
  return visual_eposy() - visual_posy();
}

float proc_arrow::phys_h(){
  return phys_eposy() - phys_posy();
}

int proc_arrow::cr(){
  return _cr;
}

int proc_arrow::cb(){
  return _cb;
}

int proc_arrow::cg(){
  return _cg;
}

float proc_arrow::xpivot(){
  return _xpivot;
}

float proc_arrow::ypivot(){
  return _ypivot;
}

float proc_arrow::angolorot(){
  return _angolorot;
}

int proc_arrow::spessore(){
  return _spessore;
}


int proc_arrow::dash(){
  return _dash;
}

int proc_arrow::punte(){
  return _punte;
}

float proc_arrow::arr_w(){
  return _arr_w;
}

float proc_arrow::arr_h(){
  return _arr_h;
}

float proc_arrow::arr_gap(){
  return _arr_gap;
}


  /*setta i valori*/

void proc_arrow::id(int nw){
  _id=nw;
}

void proc_arrow::posx(float nw){
  _posx=nw;
}

void proc_arrow::posy(float nw){
  _posy=nw;
}

void proc_arrow::eposx(float nw){
  _eposx=nw;
}

void proc_arrow::eposy(float nw){
  _eposy=nw;
}

void proc_arrow::cr(int nw){
  _cr=nw;
}

void proc_arrow::cb(int nw){
  _cb=nw;
}

void proc_arrow::cg(int nw){
  _cg=nw;
}


void proc_arrow::xpivot(float nw){
  _xpivot=nw;
}

void proc_arrow:: ypivot(float nw){
  _ypivot=nw;
}

void proc_arrow::angolorot(float nw){
  _angolorot=nw;
}


void proc_arrow::spessore(int nw){
  _spessore=nw;
}


void proc_arrow::dash(int nw){
  _dash=nw;
}

void proc_arrow::punte(int nw){
  _punte=nw;
}




void proc_arrow::w(float nw){

}


void proc_arrow::h(float nw){

}


void proc_arrow::arr_w(float nw){
   _arr_w=nw;
}

void proc_arrow::arr_h(float nw){
   _arr_h=nw;
}

void proc_arrow::arr_gap(float nw){
  if(nw<0){
    nw=0;
  }

  if(nw>1){
    nw=1;
  }

  _arr_gap=nw;
}


int proc_arrow::sotto_mouse(int posx_m, int posy_m){
  
  int sensleg=__pref.get_sensib_leg();
  bool res=line_belongs(posx_m, posy_m, 
			    posx(),posy(),
			    eposx(),eposy(),
			    sensleg+spessore());
  
  if(res){
    return id();
  }else{
    return -1;
  }

}


bool proc_arrow::dentro_bb(float x, float y, float w , float h){
    if(posx()>x && posx()<x+w   &&
       posy()>y && posy()<y+h   &&
       eposx()>x && eposx()<x+w &&
       eposy()>y && eposy()<y+h   ){
      return true;
    }else{
      return false;
    }
  }


void proc_arrow::get_bounding_box(std::pair<float,float>& ld,
                                std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(posx());
  x.push_back(eposx());

  y.push_back(posy());
  y.push_back(eposy());

  calc_bb_gen(x,y,ld,ru);


}



void proc_arrow::get_visual_bounding_box(std::pair<float,float>& ld,
                                std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(visual_posx());
  x.push_back(visual_eposx());

  y.push_back(visual_posy());
  y.push_back(visual_eposy());

  calc_bb_gen(x,y,ld,ru);


}



void proc_arrow::get_phys_bounding_box(std::pair<float,float>& ld,
                                       std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(phys_posx());
  x.push_back(phys_eposx());

  y.push_back(phys_posy());
  y.push_back(phys_eposy());
  /*
    for(unsigned int i=0;i<x.size();i++){
    std::cerr << "arrow::"<<__FUNCTION__ << x[i] << " " << y[i] << std::endl;
    }
  */

  calc_bb_gen(x,y,ld,ru);
  /*
  std::cerr << "ld" << ld.first << " " << ld.second << std::endl;
  std::cerr << "ru" << ru.first << " " << ru.second << std::endl;
  */
}




int proc_arrow::control_point_under_mouse(int posx_m, int posy_m){

  if(similar_to(posx(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(posy(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=beg;
    return id();
  }else if(similar_to(eposx(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
	   similar_to(eposy(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=end;
    return id();
  }else{
    return -1;
  }

}




void proc_arrow::unset_edit_control_point(){ 

  _edited_cp=none;

}

void proc_arrow::control_point_transl(float dx, float dy){

  if(_edited_cp==beg){
    posx(descale(posx()+dx));
    posy(descale(posy()+dy));
  }else if(_edited_cp==end){
    eposx(descale(eposx()+dx));
    eposy(descale(eposy()+dy));
  }

}

void proc_arrow::disegna(){
  
  char gap_dash[2]={dash(),0};
  float the_zoom=__pref.getZoom();
  int vero_spessore=static_cast<int>(rintf(spessore()*the_zoom));

  if(cairo_t_singleton::can_export()){

    cairo_t* cn=cairo_t_singleton::get_context();
    cairo_save(cn);
    cairo_set_source_rgb(cn,
                         remap_color_1(cr()),
                         remap_color_1(cg()),
                         remap_color_1(cb())
                         );
    cairo_set_line_width(cn,spessore());
    
    if(dash()>0){
      const double dash_gap[1]={dash()};
      cairo_set_dash(cn,dash_gap,1,0);
    }
    

    cairo_move_to(cn,posx(),posy());
    cairo_line_to(cn,eposx(),eposy());
    cairo_stroke(cn);
    cairo_restore(cn);
          
  }else{

    //float dx_sc=posx()+w()/2;
    //float dy_sc=posy()+h()/2;
    
    if(vero_spessore<=0){
      vero_spessore=1;
    }

    //trasla(-dx_sc,-dy_sc);
    //trasla(dx_sc,dy_sc);
    int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
    int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
    fl_color(cr(), cg(), cb());
    fl_line_style(FL_SOLID, vero_spessore,gap_dash);
    float v_posx=posx();//*the_zoom;
    float v_posy=posy();//*the_zoom;
    float v_eposx=eposx();//*the_zoom;
    float v_eposy=eposy();//*the_zoom;


    fl_line(static_cast<int>( rintf( v_posx+dx_scroll ) ),
	    static_cast<int>( rintf( v_posy+dy_scroll ) ),
	    static_cast<int>( rintf( v_eposx+dx_scroll ) ),
	    static_cast<int>( rintf( v_eposy+dy_scroll ) )
	    );

    
    fl_line_style(0);

  }
  switch(punte()){

  case ARR_OMOL_PUNT:
    
      draw_arrow(posx(),posy(),
		      eposx(),eposy(),spessore(),arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb()
                      );

    break;
  case ARR_ETEROL_PUNT:

      draw_arrow(posx(),posy(),
		      eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb(),
                      true);
      draw_arrow(posx(),posy(),
		      eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb(),
                      false);

    break;
  case ARR_EQ:
    disegna_equilibrio();
    break;
  case ARR_DOUBLE:

    
      draw_arrow(posx(),posy(),
		      eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);
      draw_arrow(posx(),posy(),
		      eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);
    
      draw_arrow(eposx(),eposy(),
		      posx(),posy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);
    
      draw_arrow(eposx(),eposy(),
		      posx(),posy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);
      

    break;


  case ARR_BLOC:
    {
      fl_line_style(FL_SOLID, vero_spessore,gap_dash);


      draw_arrow(posx(),posy(),eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);
      draw_arrow(posx(),posy(),eposx(),eposy(),spessore(),
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);
      fl_line_style(FL_SOLID, vero_spessore);

      float xmezzo=(eposx()-posx())/2.0;
      float ymezzo=(eposy()-posy())/2.0;
      float lungfr=sqrt( pow(eposx()-posx(),2.0f) +
			 pow(eposy()-posy(),2.0f)
			 );
      float angl=atan2(eposy()-posy(),eposx()-posx())+M_PI/4.0;


      for(int i=0;i<4;i++,angl+=M_PI/2){
        if(cairo_t_singleton::can_export()){
          cairo_t* cn=cairo_t_singleton::get_context();
          cairo_save(cn);
          cairo_set_source_rgb(cn,
                               remap_color_1(cr()),
                               remap_color_1(cg()),
                               remap_color_1(cb())
                               );
          cairo_set_line_width(cn,spessore());
	
          cairo_move_to(cn,xmezzo+posx(),ymezzo+posy());
          cairo_line_to(cn,(lungfr/4.0) * cos(angl) + xmezzo +posx(), 
                        (lungfr/4.0) * sin(angl) + ymezzo +posy());
          cairo_stroke(cn);
          cairo_restore(cn);
        }else{
	  int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
	  int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
	  float p1x=xmezzo;
	  float p1y=ymezzo;
	  float p2x=(lungfr/4.0) * cos(angl) + xmezzo;
	  float p2y=(lungfr/4.0) * sin(angl) + ymezzo;


	  fl_line(static_cast<int>(rintf((p1x+posx())))+dx_scroll,
		  static_cast<int>(rintf((p1y+posy())))+dy_scroll,
		  static_cast<int>(rintf((p2x+posx())))+dx_scroll,
		  static_cast<int>(rintf((p2y+posy())))+dy_scroll);
	  
	}
      }
      break;
    }
  default:
    break;

  }

  if(!cairo_t_singleton::can_export()){
    fl_line_style(0);
  }
}


void proc_arrow::disegna_equilibrio(){
  char gap_dash[2]={dash(),0};
  float the_zoom=__pref.getZoom();
  int vero_spessore= cairo_t_singleton::can_export()? spessore() : 
    static_cast<int>(rintf(spessore()*the_zoom));
  float eq_spacing=cairo_t_singleton::can_export() ? EQU_SPACING : EQU_SPACING *the_zoom;

  if(vero_spessore<=0){
    vero_spessore=1;
  }

  fl_line_style(FL_SOLID,vero_spessore,gap_dash);
  float m;
  float q;

  bool risultato=rett_eqn(0,0,
			  eposx()-posx(),eposy()-posy(),
			  m,q);

  if(risultato){
    m=-1/m;

    float disx=eq_spacing*cos(atan(m));
    float disy=eq_spacing*sin(atan(m));


    if(cairo_t_singleton::get_context()){

      cairo_t* cn=cairo_t_singleton::get_context();
      cairo_save(cn);
      cairo_set_source_rgb(cn,
                              remap_color_1(cr()),
                              remap_color_1(cg()),
                              remap_color_1(cb())
                              );
      cairo_set_line_width(cn,spessore());
    
      if(dash()>0){
        double dash_gap[1]={dash()};
        cairo_set_dash(cn,dash_gap,1,0);
      }
      
      cairo_move_to(cn,posx() + disx, posy() + disy);
      cairo_line_to(cn,eposx() + disx, eposy() + disy);
      cairo_stroke(cn);
      cairo_restore(cn);
      
      draw_arrow(posx(),posy(),eposx(),eposy(),vero_spessore,
                      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);

      draw_arrow(posx(),posy(),eposx(),eposy(),vero_spessore,
                      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);


      draw_arrow(eposx()+ disx,eposy()+disy,posx()+ disx,
                      posy()+disy,vero_spessore,
                      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);   


      draw_arrow(eposx()+ disx,eposy()+disy,posx()+ disx,
                      posy()+disy,vero_spessore,
                      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);   

      
    }else{
      int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
      int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
     
      float p1x=posx() + disx;
      float p1y=posy() + disy;
      float p2x=eposx() + disx;
      float p2y=eposy() + disy;
      fl_line(static_cast<int>( rintf(p1x)+dx_scroll),
	      static_cast<int>( rintf(p1y)+dy_scroll),
	      static_cast<int>( rintf(p2x)+dx_scroll),
	      static_cast<int>( rintf(p2y)+dy_scroll));
      
      draw_arrow(posx(),posy(),
		      eposx(),eposy(),
		      vero_spessore,
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);
      draw_arrow(posx(),posy(),
		      eposx(),eposy(),
		      vero_spessore,
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);

      draw_arrow(p2x,p2y,
		      p1x,p1y,
		      vero_spessore,
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      true);

      draw_arrow(p2x,p2y,
		      p1x,p1y,
		      vero_spessore,
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                      false);

     
    }


  }else{ //if(risultato) == false
    if(cairo_t_singleton::get_context()){
      cairo_t* cn=cairo_t_singleton::get_context();
      
      cairo_save(cn);
      cairo_set_source_rgb(cn,
                              remap_color_1(cr()),
                              remap_color_1(cg()),
                              remap_color_1(cb())
                              );
      cairo_set_line_width(cn,spessore());
      
      if(dash()>0){
        double dash_gap[1]={dash()};
        cairo_set_dash(cn,dash_gap,1,0);
      }
      
      cairo_move_to(cn,posx() + eq_spacing , posy());
      cairo_line_to(cn,eposx() + eq_spacing , eposy());
      cairo_stroke(cn);
      cairo_restore(cn);

    }else{
      int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
      int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();
      
      fl_line(static_cast<int>( rintf( posx()+dx_scroll+ eq_spacing) ),
	      static_cast<int>( rintf( posy()+dy_scroll ) ),
	      static_cast<int>( rintf( eposx()+dx_scroll + eq_spacing) ),
	      static_cast<int>( rintf( eposy()+dy_scroll ) )
	      );

    }
    if(posy()>eposy()){
	draw_arrow(posx(),posy(),
			eposx(),eposy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                        true);

	draw_arrow(posx(),posy(),
			eposx(),eposy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                        false);

	draw_arrow(eposx()+ eq_spacing  ,eposy(),
		   posx()+ eq_spacing ,posy(),vero_spessore,
		   arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),true);


	draw_arrow(eposx()+ eq_spacing  ,eposy(),
			posx()+ eq_spacing ,posy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),false);

    }else{
	draw_arrow(posx(),posy(),
			eposx(),eposy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                        true);
	draw_arrow(posx(),posy(),
			eposx(),eposy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                        false);


	draw_arrow(eposx()+ eq_spacing  ,eposy(),
			posx()+ eq_spacing  ,posy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),true);

	draw_arrow(eposx()+ eq_spacing  ,eposy(),
			posx()+ eq_spacing  ,posy(),vero_spessore,
			arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),false);

    }
  }


  if(! cairo_t_singleton::can_export()){
    fl_line_style(0);
  }



}

////////

void proc_arrow::calculate_equilibrium_arrows(vector<float>& x, vector<float>& y){
  char gap_dash[2]={dash(),0};
  float the_zoom=__pref.getZoom();
  int vero_spessore= cairo_t_singleton::can_export()? spessore() : 
    static_cast<int>(rintf(spessore()*the_zoom));
  float eq_spacing=cairo_t_singleton::can_export() ? EQU_SPACING : EQU_SPACING *the_zoom;

  if(vero_spessore<=0){
    vero_spessore=1;
  }

  fl_line_style(FL_SOLID,vero_spessore,gap_dash);
  float m;
  float q;

  bool risultato=rett_eqn(0,0,
			  eposx()-posx(),eposy()-posy(),
			  m,q);

  if(risultato){
    m=-1/m;

    float disx=eq_spacing*cos(atan(m));
    float disy=eq_spacing*sin(atan(m));
    
    float p1x=posx() + disx;
    float p1y=posy() + disy;
    float p2x=eposx() + disx;
    float p2y=eposy() + disy;
    calculate_arrow_points(posx(),posy(),
                           eposx(),eposy(),
                           vero_spessore,
                           arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                           x,y,
                           true);

    calculate_arrow_points(posx(),posy(),
                           eposx(),eposy(),
                           vero_spessore,
                           arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                           x,y,
                           false);


    calculate_arrow_points(p2x,p2y,
                           p1x,p1y,
                           vero_spessore,
                           arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                           x,y,
                           true);


    calculate_arrow_points(p2x,p2y,
                           p1x,p1y,
                           vero_spessore,
                           arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                           x,y,
                           false);

     
  


  }else{ //if(risultato) == false
    
    if(posy()>eposy()){
	calculate_arrow_points(posx(),posy(),
                               eposx(),eposy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                               x,y,
                               true);

	calculate_arrow_points(posx(),posy(),
                               eposx(),eposy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),
                               x,y,
                               false);


	calculate_arrow_points(eposx()+ eq_spacing  ,eposy(),
                               posx()+ eq_spacing ,posy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,true);


	calculate_arrow_points(eposx()+ eq_spacing  ,eposy(),
                               posx()+ eq_spacing ,posy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,false);

    }else{
	calculate_arrow_points(posx(),posy(),
                               eposx(),eposy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                               true);

	calculate_arrow_points(posx(),posy(),
                               eposx(),eposy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,
                               false);


	calculate_arrow_points(eposx()+ eq_spacing  ,eposy(),
                               posx()+ eq_spacing  ,posy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,true);

	calculate_arrow_points(eposx()+ eq_spacing  ,eposy(),
                               posx()+ eq_spacing  ,posy(),vero_spessore,
                               arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y,false);



    }
  }

}






void proc_arrow::trasla(float dx, float dy){
  posx(descale(posx()+dx));
  posy(descale(posy()+dy));
  eposx(descale(eposx()+dx));
  eposy(descale(eposy()+dy));
}


void proc_arrow::phys_translate(float dx, float dy){
  posx(phys_posx()+dx);
  posy(phys_posy()+dy);
  eposx(phys_eposx()+dx);
  eposy(phys_eposy()+dy);
}


/**
 *Scala l'oggetto
 *
 *\param sc il fattore di scala
 */

void proc_arrow::scale(float sc){

 posx(phys_posx()*sc);
 posy(phys_posy()*sc);
 eposx(phys_eposx()*sc);
 eposy(phys_eposy()*sc);

}

/**
 *Ruota l'oggetto in senso orario.
 *
 *\param angl l'angolo di rotazione in radianti
 */

void proc_arrow::ruota(float xpiv, float ypiv, float angl){

  
  xpivot(xpiv/__pref.getZoom());
  ypivot(ypiv/__pref.getZoom());
  angolorot(angl);
  
  //cout << "RUOTA: " <<angl <<" " <<  angolorot() << endl;

  float x=phys_posx()-xpivot();
  float y=phys_posy()-ypivot();
  float xp=x*cos(angolorot())+y*sin(angolorot());
  float yp=y*cos(angolorot())-x*sin(angolorot());
  posx(xp+xpivot());
  posy(yp+ypivot());
  x=phys_eposx()-xpivot();
  y=phys_eposy()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  eposx(xp+xpivot());
  eposy(yp+ypivot());

  angolorot(0);

}


void proc_arrow::write_native_format(std::ostream& stream, std::string indent){
  stream << indent << ETIC_ARROW << " " << APRI << id() << SEP << phys_posx() << std::endl
         << indent << "\t" << SEP << phys_posy()  << SEP << phys_eposx() << std::endl
         << indent << "\t" << SEP << phys_eposy()	<< SEP << cr() << std::endl
         << indent << "\t" << SEP << cg()  << SEP << cb() << std::endl
         << indent << "\t" << SEP << xpivot() << SEP << ypivot() << std::endl
         << indent << "\t" << SEP << angolorot() << SEP << spessore() << std::endl
         << indent << "\t" << SEP << dash() << SEP << punte() << std::endl
         << indent << "\t" << SEP << arr_w() << SEP << arr_h() << std::endl
         << indent << "\t" << SEP << arr_gap()  << std::endl
         << indent << CHIUDI << std::endl;

}



/****************************bezier**********************/


const float proc_bezier::scala_bb=4;

/**
 * Costruttore di default riempie i membri con spazzatura
 */

proc_bezier::proc_bezier()
  :procedura(PROC_BEZIER),
   _arr_w(__pref.get_arr_w()),
   _arr_h(__pref.get_arr_h()),
   _arr_gap(__pref.get_arr_gap()),
   _edited_cp(none)
{

}


proc_bezier::proc_bezier(const proc_bezier* altro)
  :procedura(*altro),
   _id(altro->_id),
   _ix(altro->_ix),
   _iy(altro->_iy),
   _tan1x(altro->_tan1x),
   _tan1y(altro->_tan1y),
   _tan2x(altro->_tan2x),
   _tan2y(altro->_tan2y),
   _ex(altro->_ex),
   _ey(altro->_ey),
   _cr(altro->_cr),
   _cb(altro->_cb),
   _cg(altro->_cg),
   _xpivot(altro->_xpivot),
   _ypivot(altro->_ypivot),
   _angolorot(altro->_angolorot),
   _spessore(altro->_spessore),
   _dash(altro->_dash),
   _punte(altro->_punte),
   _arr_w(altro->_arr_w),
   _arr_h(altro->_arr_h),
   _arr_gap(altro->_arr_gap),
   _edited_cp(altro->_edited_cp)
   
{

}


  /**
   *
   *Costruisce l'oggetto freccia.
   *\param id id della procedura, la identifica univocamente
   *\param ix ascissa del punto di partenza della curva
   *\param iy ordinata del punto di partenza della curva
   *
   *\param tan1x ascissa della prima tangente.
   *\param tan1y ordinata della prima tangente.
   *
   *\param tan2x ascissa della seconda tangente.
   *\param tan2y ordinata della seconda tangente.
   *
   *\param ex ascissa del punto di arrivo della curva
   *\param ex ordinata del punto di arrivo della curva
   *
   *\param cr componente rossa del colore della procedura
   *\param cg componente verde del colore della procedura
   *\param cb componente blu del colore della procedura
   *\param xpiv ascissa dell'asse di rotazione.
   *\param ypiv ordinata dell'asse di rotazione
   *\param anglrot l'angolo di rotazione in radianti ed in senso orario
   *\param spess spessore in px della "penna"
   *\param tratt lunghezza del tratteggio (nota: 0 nessun tratteggio).
   *\param punte numero di punte delle freccie, puo' assumere i valori:
   *
   *<ul>
   *
   *<li> ARR_NO_PUNT nessuna punta
   *
   *<li> ARR_OMOL_PUNT  scissione omolitica
   *
   *<li> ARR_ETEROL_PUNT   scissione eterolitica
   *
   *</ul>
   *
   */

proc_bezier::proc_bezier(int id,float ix, float iy,
			 float tang1x, float tang1y,
			 float tang2x, float tang2y,
			 float ex, float ey,
			 int cr, int cb, int cg ,
			 float xpiv, float ypiv, float anglrot,
			 int spess, int tratt, int punte,
			 float arr_w, float arr_h, float arr_gap)
  :procedura(PROC_BEZIER),
   _id(id),
   _ix(ix),
   _iy(iy),
   _tan1x(tang1x),
   _tan1y(tang1y),
   _tan2x(tang2x),
   _tan2y(tang2y),
   _ex(ex),
   _ey(ey),
   _cr(cr),
   _cb(cb),
   _cg(cg),
   _xpivot(xpiv),
   _ypivot(ypiv),
   _angolorot(anglrot),
   _spessore(spess),
   _dash(tratt),
   _punte(punte),
   _arr_w(arr_w),
   _arr_h(arr_h),
   _arr_gap(arr_gap),
   _edited_cp(none)
{

}

  /**
   *Distruttore
   */


proc_bezier::~proc_bezier(){
  //cout << "eliminata bezier" << endl;
}


void proc_bezier::init(){
  ruota(xpivot(),ypivot(),angolorot());
}

  /*ritorna i valori*/

int proc_bezier::id(){

  return _id;
}

float proc_bezier::ix(){
  if(cairo_t_singleton::can_export()){
    return phys_ix();
  }else{
    return visual_ix();
  }
}

float proc_bezier::visual_ix(){
  return phys_ix() * __pref.getZoom();
}

float proc_bezier::phys_ix(){
  return _ix;
}


float proc_bezier::iy(){
  if(cairo_t_singleton::can_export()){
    return phys_iy();
  }else{
    return visual_iy();
  }
}

float proc_bezier::visual_iy(){
  return phys_iy() * __pref.getZoom();
}

float proc_bezier::phys_iy(){
  return _iy;
}


float proc_bezier::tan1x(){
  if(cairo_t_singleton::can_export()){
    return phys_tan1x();
  }else{
    return visual_tan1x();
  }

}

float proc_bezier::visual_tan1x(){
  return phys_tan1x() * __pref.getZoom();
}

float proc_bezier::phys_tan1x(){
  return _tan1x;

}



float proc_bezier::tan1y(){
  if(cairo_t_singleton::can_export()){
    return phys_tan1y();
  }else{
    return visual_tan1y();
  }
}

float proc_bezier::visual_tan1y(){
  return phys_tan1y() * __pref.getZoom();
}


float proc_bezier::phys_tan1y(){
  return _tan1y;
}


float proc_bezier::tan2x(){
  if(cairo_t_singleton::can_export()){
    return phys_tan2x();
  }else{
    return visual_tan2x();
  }
}

float proc_bezier::visual_tan2x(){
  return phys_tan2x() * __pref.getZoom();
}

float proc_bezier::phys_tan2x(){
  return _tan2x;
}

float proc_bezier::tan2y(){
  if(cairo_t_singleton::can_export()){
    return phys_tan2y();
  }else{
    return visual_tan2y();
  }
}

float proc_bezier::visual_tan2y(){
  return phys_tan2y() * __pref.getZoom();
}

float proc_bezier::phys_tan2y(){
  return _tan2y;
}


float proc_bezier::ex(){
  if(cairo_t_singleton::can_export()){
    return phys_ex();
  }else{
    return visual_ex();
  }

}

float proc_bezier::visual_ex(){
  return phys_ex() * __pref.getZoom();
}

float proc_bezier::phys_ex(){
  return _ex;
}


float proc_bezier::ey(){
  if(cairo_t_singleton::can_export()){
    return phys_ey();
  }else{
    return visual_ey();
  }
}

float proc_bezier::visual_ey(){
  return phys_ey() * __pref.getZoom();
}


float proc_bezier::phys_ey(){
  return _ey;
}

float proc_bezier::w(){
 vector<float> xtmp;
  xtmp.push_back(ix());
  xtmp.push_back(ex());
  xtmp.push_back(tan1x());
  xtmp.push_back(tan2x());

  float wtmp=(*max_element(xtmp.begin(),xtmp.end())) - (*min_element(xtmp.begin(),xtmp.end()));
  return wtmp;


}

float proc_bezier::visual_w(){
 vector<float> xtmp;
  xtmp.push_back(visual_ix());
  xtmp.push_back(visual_ex());
  xtmp.push_back(visual_tan1x());
  xtmp.push_back(visual_tan2x());

  float wtmp=(*max_element(xtmp.begin(),xtmp.end())) - (*min_element(xtmp.begin(),xtmp.end()));
  return wtmp;
}


float proc_bezier::phys_w(){
 vector<float> xtmp;
  xtmp.push_back(phys_ix());
  xtmp.push_back(phys_ex());
  xtmp.push_back(phys_tan1x());
  xtmp.push_back(phys_tan2x());

  float wtmp=(*max_element(xtmp.begin(),xtmp.end())) - (*min_element(xtmp.begin(),xtmp.end()));
  return wtmp;
}

float proc_bezier::h(){
  vector<float> ytmp;
  ytmp.push_back(visual_iy());
  ytmp.push_back(visual_ey());
  ytmp.push_back(visual_tan1y());
  ytmp.push_back(visual_tan2y());

  float wtmp=(*max_element(ytmp.begin(),ytmp.end())) - (*min_element(ytmp.begin(),ytmp.end()));
  return wtmp;
}

float proc_bezier::visual_h(){
  vector<float> ytmp;
  ytmp.push_back(visual_iy());
  ytmp.push_back(visual_ey());
  ytmp.push_back(visual_tan1y());
  ytmp.push_back(visual_tan2y());

  float wtmp=(*max_element(ytmp.begin(),ytmp.end())) - (*min_element(ytmp.begin(),ytmp.end()));
  return wtmp;
}

float proc_bezier::phys_h(){
  vector<float> ytmp;
  ytmp.push_back(phys_iy());
  ytmp.push_back(phys_ey());
  ytmp.push_back(phys_tan1y());
  ytmp.push_back(phys_tan2y());

  float wtmp=(*max_element(ytmp.begin(),ytmp.end())) - (*min_element(ytmp.begin(),ytmp.end()));
  return wtmp;
}

int proc_bezier::cr(){
  return _cr;
}

int proc_bezier::cb(){
  return _cb;
}

int proc_bezier::cg(){

  return _cg;
}

float proc_bezier::xpivot(){
  return _xpivot;
}

float proc_bezier::ypivot(){
  return _ypivot;
}

float proc_bezier::angolorot(){
  return _angolorot;
}

int proc_bezier::spessore(){
  return _spessore;
}

int proc_bezier::dash(){
  return _dash;
}

int proc_bezier::punte(){
  return _punte;
}


float proc_bezier::arr_w(){
  return _arr_w;
}

float proc_bezier::arr_h(){
  return _arr_h;
}

float proc_bezier::arr_gap(){
  return _arr_gap;
}




float proc_bezier::posx(){

 vector<float> xtmp;
  xtmp.push_back(ix());
  xtmp.push_back(ex());
  xtmp.push_back(tan1x());
  xtmp.push_back(tan2x());
  return (*min_element(xtmp.begin(),xtmp.end()));
}


float proc_bezier::visual_posx(){

 vector<float> xtmp;
  xtmp.push_back(visual_ix());
  xtmp.push_back(visual_ex());
  xtmp.push_back(visual_tan1x());
  xtmp.push_back(visual_tan2x());
  return (*min_element(xtmp.begin(),xtmp.end()));
}


float proc_bezier::phys_posx(){

 vector<float> xtmp;
  xtmp.push_back(phys_ix());
  xtmp.push_back(phys_ex());
  xtmp.push_back(phys_tan1x());
  xtmp.push_back(phys_tan2x());
  return (*min_element(xtmp.begin(),xtmp.end()));
}

float proc_bezier::posy(){

  vector<float> ytmp;
  ytmp.push_back(iy());
  ytmp.push_back(ey());
  ytmp.push_back(tan1y());
  ytmp.push_back(tan2y());
  return (*min_element(ytmp.begin(),ytmp.end()));
}

float proc_bezier::visual_posy(){

  vector<float> ytmp;
  ytmp.push_back(visual_iy());
  ytmp.push_back(visual_ey());
  ytmp.push_back(visual_tan1y());
  ytmp.push_back(visual_tan2y());
  return (*min_element(ytmp.begin(),ytmp.end()));
}


float proc_bezier::phys_posy(){

  vector<float> ytmp;
  ytmp.push_back(phys_iy());
  ytmp.push_back(phys_ey());
  ytmp.push_back(phys_tan1y());
  ytmp.push_back(phys_tan2y());
  return (*min_element(ytmp.begin(),ytmp.end()));
}

/*set values*/



void proc_bezier::id(int nw){
  _id=nw;
}



void proc_bezier::ix(float nw){
  _ix=nw;
}

void proc_bezier::iy(float nw){
  _iy=nw;
}

void proc_bezier::tan1x(float nw){
  _tan1x=nw;
}

void proc_bezier::tan1y(float nw){
  _tan1y=nw;
}

void proc_bezier::tan2x(float nw){
  _tan2x=nw;
}

void proc_bezier::tan2y(float nw){
  _tan2y=nw;
}

void proc_bezier::ex(float nw){
  _ex=nw;
}

void proc_bezier::ey(float nw){
  _ey=nw;
}

void proc_bezier::cr(int nw){
  _cr=nw;
}

void proc_bezier::cb(int nw){
  _cb=nw;
}

void proc_bezier::cg(int nw){
  _cg=nw;
}

void proc_bezier::xpivot(float nw){
  _xpivot=nw;
}

void proc_bezier::ypivot(float nw){
  _ypivot=nw;
}

void proc_bezier::angolorot(float nw){
  _angolorot=nw;
}

void proc_bezier::spessore(int nw){
  _spessore=nw;
}

void proc_bezier::dash(int nw){
  _dash=nw;
}

void proc_bezier::punte(int nw){
  _punte=nw;
}



void proc_bezier::arr_w(float nw){
   _arr_w=nw;
}

void proc_bezier::arr_h(float nw){
   _arr_h=nw;
}

void proc_bezier::arr_gap(float nw){
  if(nw<0){
    nw=0;
  }

  if(nw>1){
    nw=1;
  }

  _arr_gap=nw;
}


int proc_bezier::sotto_mouse(int posx_m, int posy_m){

 vector<float> xtmp;
  xtmp.push_back(ix());
  xtmp.push_back(ex());
  xtmp.push_back(tan1x());
  xtmp.push_back(tan2x());

  float minx=(*min_element(xtmp.begin(),xtmp.end()));


  vector<float> ytmp;
  ytmp.push_back(iy());
  ytmp.push_back(ey());
  ytmp.push_back(tan1y());
  ytmp.push_back(tan2y());

  float miny=(*min_element(ytmp.begin(),ytmp.end()));

  
  float ics_e= minx +  (w()/(scala_bb*2.0));
  float ips_e=miny + (h()/(scala_bb*2.0));
  float w_e=(w() - w()/scala_bb);
  float h_e= (h() - h()/scala_bb);

  if(posx_m > ics_e && posx_m < ics_e+w_e &&
     posy_m > ips_e && posy_m < ips_e+h_e){
    return id();
  }else{
    return -1;
  }

}


void proc_bezier::control_point_transl(float dx, float dy){

  if(_edited_cp==beg){
    ix(descale(ix()+dx));
    iy(descale(iy()+dy));
  }else if(_edited_cp==tan1){
    tan1x(descale(tan1x()+dx));
    tan1y(descale(tan1y()+dy));
  }else if(_edited_cp==tan2){
    tan2x(descale(tan2x()+dx));
    tan2y(descale(tan2y()+dy));
  }else if(_edited_cp==end){
    ex(descale(ex()+dx));
    ey(descale(ey()+dy));
  }

}
void proc_bezier::unset_edit_control_point(){
  _edited_cp=none;

}

int proc_bezier::control_point_under_mouse(int posx_m, int posy_m){
  
  if(similar_to(ix(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(iy(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=beg;
    return id();
  }else if(similar_to(tan1x(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
	   similar_to(tan1y(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=tan1;
    return id();
  }else if(similar_to(tan2x(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
	   similar_to(tan2y(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=tan2;
    return id();
  }else if(similar_to(ex(),static_cast<float>(posx_m),_tolerance_hit_control_point) && 
	   similar_to(ey(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=end;
    return id();
  }else{
    return -1;
  }

}


bool proc_bezier::dentro_bb(float x, float y, float w , float h){
  
  float xcent=ix()+((ex()-ix())/2);
  float ycent=iy()+((ey()-iy())/2);

  if(xcent>x && xcent<x+w &&
     ycent>y && ycent<y+h){
      return true;
    }else{
      return false;
    }


}




void proc_bezier::get_bounding_box(std::pair<float,float>& ld,
                                   std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(ix());
  x.push_back(tan1x());
  x.push_back(tan2x());
  x.push_back(ex());

  y.push_back(iy());
  y.push_back(tan1y());
  y.push_back(tan2y());
  y.push_back(ey());

  calc_bb_gen(x,y,ld,ru);

}



void proc_bezier::get_visual_bounding_box(std::pair<float,float>& ld,
                                   std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(visual_ix());
  x.push_back(visual_tan1x());
  x.push_back(visual_tan2x());
  x.push_back(visual_ex());

  y.push_back(visual_iy());
  y.push_back(visual_tan1y());
  y.push_back(visual_tan2y());
  y.push_back(visual_ey());

  calc_bb_gen(x,y,ld,ru);

}


void proc_bezier::get_phys_bounding_box(std::pair<float,float>& ld,
                                   std::pair<float,float>& ru){

  std::vector<float> x;
  std::vector<float> y;

  x.push_back(phys_ix());
  x.push_back(phys_tan1x());
  x.push_back(phys_tan2x());
  x.push_back(phys_ex());

  y.push_back(phys_iy());
  y.push_back(phys_tan1y());
  y.push_back(phys_tan2y());
  y.push_back(phys_ey());

  calc_bb_gen(x,y,ld,ru);

}




void proc_bezier::disegna(){

  float the_zoom=__pref.getZoom();
  int vero_spessore= cairo_t_singleton::can_export()? spessore() : 
    static_cast<int>(rintf(spessore()*the_zoom));
  if(vero_spessore<=0){
    vero_spessore=1;
  }



  if(cairo_t_singleton::get_context()){
    cairo_t* cn=cairo_t_singleton::get_context();
    cairo_save(cn);
    cairo_set_source_rgb(cn,
                            remap_color_1(cr()),
                            remap_color_1(cg()),
                            remap_color_1(cb())
                            );
    cairo_set_line_width(cn,spessore());
  
    if(dash()>0){
      double dash_gap[1]={dash()};
      cairo_set_dash(cn,dash_gap,1,0);
    }
    
    cairo_move_to(cn,ix(),iy());
    cairo_curve_to(cn,tan1x(),tan1y(),
                      tan2x(),tan2y(),
                      ex(),ey());
    cairo_stroke(cn);
    cairo_restore(cn);


  }else{
    char gap_dash[2]={dash(),0};
    int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
    int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();

    fl_color(cr(), cg(), cb());
    fl_line_style(FL_SOLID, vero_spessore,gap_dash);
    fl_begin_line();
    
    fl_curve(visual_ix()+dx_scroll, visual_iy()+dy_scroll, 
	     visual_tan1x()+dx_scroll, visual_tan1y()+dy_scroll, 
	     visual_tan2x()+dx_scroll, visual_tan2y()+dy_scroll, 
	     visual_ex()+dx_scroll, visual_ey()+dy_scroll);

    fl_end_line();
    draw_shadowed_point(visual_tan1x()+dx_scroll, visual_tan1y()+dy_scroll,255,0,0);
    draw_shadowed_point(visual_tan2x()+dx_scroll, visual_tan2y()+dy_scroll,255,0,0);
    fl_line_style(0);
    fl_color(cr(), cg(), cb());
  }

  switch(punte()){

  case ARR_OMOL_PUNT:
    {

      if(cairo_t_singleton::can_export()){
        std::pair<float,float> intersection=correct_arrow_ps(true);

        
        draw_arrow(intersection.first,
                        intersection.second,
                        ex(),ey(),spessore(),
                        arr_w(),arr_h(),arr_gap(),
                        cr(),cg(),cb(),
                        false);
        
      }else{


        std::pair<float , float> pt=poly_bezier(visual_ix(), visual_iy(), 
                                                visual_tan1x(), visual_tan1y(), 
                                                visual_tan2x(), visual_tan2y(), 
                                                visual_ex(), visual_ey(),
                                                1-PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW);
        
        
        
        draw_arrow(pt.first,pt.second,
                        visual_ex(),visual_ey(),
                        vero_spessore,
                        arr_w(),arr_h(),arr_gap(),
                        cr(),cg(),cb());
        
      }
      break;
    }
  case ARR_DOUBLE:
    if(cairo_t_singleton::can_export()){
      std::pair<float,float> intersection=correct_arrow_ps(false);
      
      draw_arrow(intersection.first,intersection.second,
		      ix(),iy(),spessore(),arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb(),
		      true);
      draw_arrow(intersection.first,intersection.second,
		      ix(),iy(),spessore(),
                      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb());
      
    }else{

      std::pair<float , float> tan_correct=poly_bezier(visual_ix(), visual_iy(), 
						       visual_tan1x(), visual_tan1y(), 
						       visual_tan2x(), visual_tan2y(), 
						       visual_ex(), visual_ey(),
						       PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW);
      
      draw_arrow(tan_correct.first,tan_correct.second,
		      visual_ix(),visual_iy(),vero_spessore,
		      arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb(),
		      true);
      draw_arrow(tan_correct.first,tan_correct.second,
		      visual_ix(),visual_iy(),vero_spessore,
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb());
      
    }



    
  case ARR_ETEROL_PUNT:
    if(cairo_t_singleton::can_export()){
      std::pair<float,float> intersection=correct_arrow_ps(true);
      
      draw_arrow(intersection.first,
		      intersection.second,
		      ex(),ey(),spessore(),
		      arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb(),
		      true);
      
      
      draw_arrow(intersection.first,
		      intersection.second,
		      ex(),ey(),spessore(),
		      arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb());
      

    }else{

      std::pair<float , float> tan_correct=poly_bezier(visual_ix(), visual_iy(), 
						       visual_tan1x(), visual_tan1y(), 
						       visual_tan2x(), visual_tan2y(), 
						       visual_ex(), visual_ey(),
						       1-PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW);
      
      draw_arrow(tan_correct.first,tan_correct.second,
		      visual_ex(),visual_ey(),vero_spessore,
		      arr_w(),arr_h(),arr_gap(),
                      cr(),cg(),cb(),
		      true);
      draw_arrow(tan_correct.first,tan_correct.second,
		      visual_ex(),visual_ey(),vero_spessore,
		      arr_w(),arr_h(),arr_gap(),cr(),cg(),cb());
      
    }
 
    break;
    

 
  case ARR_BLOC:
      break;

  default:
    break;

  }


  if(!cairo_t_singleton::can_export()){
    fl_line_style(0);
  }

}


void proc_bezier::arrows_points(std::vector<float>& x,
                                std::vector<float>& y){


  switch(punte()){

  case ARR_OMOL_PUNT:
    {

      std::pair<float,float> intersection=correct_arrow_ps(true);

      
      calculate_arrow_points(intersection.first,
                             intersection.second,
                             ex(),ey(),spessore(),
                             arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y,
                             false);
        
    }
      break;
    
  case ARR_DOUBLE:
    {
      std::pair<float,float> intersection=correct_arrow_ps(false);
      calculate_arrow_points(intersection.first,intersection.second,
                             ix(),iy(),spessore(),arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y,
                             true);
      calculate_arrow_points(intersection.first,intersection.second,
                             ix(),iy(),spessore(),
                             arr_w(),arr_h(),arr_gap(),cr(),cg(),cb(),x,y);
    } 
  case ARR_ETEROL_PUNT:
    {
      std::pair<float,float> intersection=correct_arrow_ps(true);
      
      calculate_arrow_points(intersection.first,
                             intersection.second,
                             ex(),ey(),spessore(),
                             arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y,
                             true);
      
      
      calculate_arrow_points(intersection.first,
                             intersection.second,
                             ex(),ey(),spessore(),
                             arr_w(),arr_h(),arr_gap(),
                             cr(),cg(),cb(),x,y);
      
    }
    break;
    

 
  case ARR_BLOC:
      break;

  default:
    break;

  }
  
}


void proc_bezier::trasla(float dx, float dy){

  ix(descale(ix()+dx));
  iy(descale(iy()+dy));

  tan1x(descale(tan1x()+dx));
  tan1y(descale(tan1y()+dy));

  tan2x(descale(tan2x()+dx));
  tan2y(descale(tan2y()+dy));

  ex(descale(ex()+dx));
  ey(descale(ey()+dy));


}


void proc_bezier::phys_translate(float dx, float dy){
  ix(phys_ix()+dx);
  iy(phys_iy()+dy);

  tan1x(phys_tan1x()+dx);
  tan1y(phys_tan1y()+dy);

  tan2x(phys_tan2x()+dx);
  tan2y(phys_tan2y()+dy);

  ex(phys_ex()+dx);
  ey(phys_ey()+dy);

}


/**
 *Scala l'oggetto
 *
 *\param sc il fattore di scala
 */

void proc_bezier::scale(float sc){


  ix(phys_ix()*sc);
  iy(phys_iy()*sc);

  tan1x(phys_tan1x()*sc);
  tan1y(phys_tan1y()*sc);

  tan2x(phys_tan2x()*sc);
  tan2y(phys_tan2y()*sc);

  ex(phys_ex()*sc);
  ey(phys_ey()*sc);


}

/**
 *Ruota l'oggetto in senso orario.
 *
 *\param angl l'angolo di rotazione in radianti
 */

void proc_bezier::ruota(float xpiv, float ypiv, float angl){


  xpivot(xpiv/__pref.getZoom());
  ypivot(ypiv/__pref.getZoom());
  angolorot(angl);
  //cout << "RUOTA: " <<angl <<" " <<  angolorot() << endl;

  float x=phys_ix()-xpivot();
  float y=phys_iy()-ypivot();
  float xp=x*cos(angolorot())+y*sin(angolorot());
  float yp=y*cos(angolorot())-x*sin(angolorot());
  ix(xp+xpivot());
  iy(yp+ypivot());

  x=phys_tan1x()-xpivot();
  y=phys_tan1y()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  tan1x(xp+xpivot());
  tan1y(yp+ypivot());

  x=phys_tan2x()-xpivot();
  y=phys_tan2y()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  tan2x(xp+xpivot());
  tan2y(yp+ypivot());


  x=phys_ex()-xpivot();
  y=phys_ey()-ypivot();
  xp=x*cos(angolorot())+y*sin(angolorot());
  yp=y*cos(angolorot())-x*sin(angolorot());
  ex(xp+xpivot());
  ey(yp+ypivot());

  angolorot(0);

}


/*

  benchmark

  scan 0.2:
  real	0m0.652s
  user	0m0.476s
  sys	0m0.008s
  
  binary 0.2
  
  real	0m0.025s
  user	0m0.020s
  sys	0m0.000s

 */



std::pair<float,float> proc_bezier::correct_arrow_ps(bool end_curve){
  float width_segment_arrow_gap=arr_w() - arr_gap() * arr_w();

  static const float rotation_segment_arrow_rate=1E-2;
  static const float tol_intersect_arrow_seg_bezier=1E-1;
  static const float tol_l_r=0.00001f;
  float trasl_x=end_curve ? ex() : ix();
  float trasl_y=end_curve ? ey() : iy();
  float ix_t=ix()-trasl_x;
  float iy_t=iy()-trasl_y;
  float tan1x_t=tan1x()-trasl_x;
  float tan1y_t=tan1y()-trasl_y;
  float tan2x_t=tan2x()-trasl_x;
  float tan2y_t=tan2y()-trasl_y;
  float ex_t=ex()-trasl_x;
  float ey_t=ey()-trasl_y;
      
  pair<float, float> intersection;
  bool intersection_found=false;

  for(float ang=0;ang<=3*M_PI;ang+=rotation_segment_arrow_rate){
    bool binary_can_run=true;
    std::pair<float,float> rotated_seg_pair=rotate_point(0, 
							 width_segment_arrow_gap, 
							 ang);
    //std::cerr << "ang : " << ang << std::endl;
    
    float l_th=0;
    float r_th=1;
    
    std::pair<float , float> curve_l=poly_bezier(ix_t,iy_t,
                                                 tan1x_t,tan1y_t,
                                                 tan2x_t,tan2y_t,
                                                 ex_t,ey_t,
                                                 l_th);
    std::pair<float , float> curve_r=poly_bezier(ix_t,iy_t,
                                                 tan1x_t,tan1y_t,
                                                 tan2x_t,tan2y_t,
                                                 ex_t,ey_t,
                                                 r_th);
    std::pair<float , float> curve_m;

    while(binary_can_run){
      float m = l_th + ((r_th - l_th)/2.0);
      curve_m=poly_bezier(ix_t,iy_t,
                          tan1x_t,tan1y_t,
                          tan2x_t,tan2y_t,
                          ex_t,ey_t,
                          m);
      /*
      cerr << "curve_m.first=" << curve_m.first << std::endl;
      cerr << "curve_l.first=" << curve_l.first << std::endl;
      cerr << "curve_r.first=" << curve_r.first << std::endl;
      cerr << "m " << m << std::endl;
      cerr << "r_th " << r_th << std::endl;
      cerr << "l_th " << l_th << std::endl;
      */
      if(curve_m.first > rotated_seg_pair.first){
        r_th=m;
        //cerr << "set m= r_th" << std::endl;
      }else{
        //cerr << "set m= l_th" << std::endl;
        l_th=m;
      }
        
        
      curve_l=poly_bezier(ix_t,iy_t,
                          tan1x_t,tan1y_t,
                          tan2x_t,tan2y_t,
                          ex_t,ey_t,
                          l_th);
      curve_r=poly_bezier(ix_t,iy_t,
                          tan1x_t,tan1y_t,
                          tan2x_t,tan2y_t,
                          ex_t,ey_t,
                          r_th);
      
      /*
      std::cerr << "l: " << l_th << " r: " <<r_th 
                << " x actual: " << rotated_seg_pair.first 
                << " x now: " <<  curve_m.first
                << std::endl;
      */
      if(similar_to(rotated_seg_pair.first, 
                    curve_m.first, 
                    tol_intersect_arrow_seg_bezier)){
        //std::cerr << "FINE BINARY" << std::endl;
        binary_can_run=false;
      }else if(similar_to(l_th,r_th,tol_l_r)){
        //std::cerr << "out l==r" << std::endl;
        binary_can_run=false;
      }

    }

    


    if(similar_to(rotated_seg_pair.second, 
                  curve_m.second, 
                  tol_intersect_arrow_seg_bezier) &&
       similar_to(rotated_seg_pair.first, 
                  curve_m.first, 
                  tol_intersect_arrow_seg_bezier)
       ){
      // std::cerr << "FOUND" << std::endl;
      // std::cerr << curve_m.first << "," << rotated_seg_pair.first << std::endl;
      // std::cerr << curve_m.second << "," << rotated_seg_pair.second << std::endl;
      // std::cerr << "---------------" << std::endl;;
      intersection=curve_m;
      intersection_found=true;
      break;
    }
    
  }

  
  


    
    intersection.first+=trasl_x;
    intersection.second+=trasl_y;      
    
    if(!intersection_found){ // intersection  failed using  another method
      // here
      float dt_bez=end_curve? 1-PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW : PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW;
      
      intersection=poly_bezier(ix(), iy(), 
                               tan1x(), tan1y(), 
                               tan2x(), tan2y(), 
                               ex(), ey(),
                               dt_bez);
      //std::cout << "123 non found" << std::endl; 
      //abort();
    }
    
    return intersection;
    
  }



void proc_bezier::write_native_format(std::ostream& stream, std::string indent){
  stream << indent << ETIC_BEZIER << " " << APRI << id() << SEP << phys_ix()  << std::endl
         << indent << "\t" <<  SEP << phys_iy()     << SEP << phys_tan1x() << std::endl
         << indent << "\t" <<  SEP << phys_tan1y()  << SEP << phys_tan2x() << std::endl
         << indent << "\t" <<  SEP << phys_tan2y()  << SEP << phys_ex() << std::endl
         << indent << "\t" <<  SEP << phys_ey()     << SEP << cr() << std::endl
         << indent << "\t" <<  SEP << cg()     << SEP << cb() << std::endl
         << indent << "\t" <<  SEP << xpivot() << SEP << ypivot() << std::endl
         << indent << "\t" <<  SEP << angolorot() << SEP << spessore() << std::endl
         << indent << "\t" <<  SEP << dash() << SEP << punte() << std::endl
         << indent << "\t" <<  SEP << arr_w() << SEP << arr_h() << std::endl
         << indent << "\t" <<  SEP << arr_gap() << std::endl
         << indent << CHIUDI << endl;
         
}        



// std::pair<float,float> proc_bezier::correct_arrow_ps(bool end_curve){
//   //float width_segment_arrow=__pref.get_arr_w();
//   float width_segment_arrow_gap=arr_w() - arr_gap() * arr_w();

//   static const float rotation_segment_arrow_rate=1E-2;
//   static const float tol_intersect_arrow_seg_bezier=1E-1;
//   static const float dt_bezier=1E-4;
//   static const float tol_l_r=0.00001f;
//   float trasl_x=end_curve ? ex() : ix();
//   float trasl_y=end_curve ? ey() : iy();
//   float ix_t=ix()-trasl_x;
//   float iy_t=iy()-trasl_y;
//   float tan1x_t=tan1x()-trasl_x;
//   float tan1y_t=tan1y()-trasl_y;
//   float tan2x_t=tan2x()-trasl_x;
//   float tan2y_t=tan2y()-trasl_y;
//   float ex_t=ex()-trasl_x;
//   float ey_t=ey()-trasl_y;
      
//   pair<float, float> intersection;
//   bool intersection_found=false;

//   for(float ang=0;ang<=3*M_PI;ang+=rotation_segment_arrow_rate){

//     std::pair<float,float> rotated_seg_pair=rotate_point(0, 
// 							 width_segment_arrow_gap, 
// 							 ang);  

//     for(float t=0;t<=1;t+=dt_bezier){
//       std::pair<float , float> curve=poly_bezier(ix_t,iy_t,
// 						 tan1x_t,tan1y_t,
// 						 tan2x_t,tan2y_t,
// 						 ex_t,ey_t,
// 						 t);
//       if(similar_to(rotated_seg_pair.first, 
// 		    curve.first, 
// 		    tol_intersect_arrow_seg_bezier) &&
// 	 similar_to(rotated_seg_pair.second, 
// 		    curve.second, 
// 		    tol_intersect_arrow_seg_bezier)){

// 	intersection=curve;
// 	intersection_found=true;
// 	break;
//       }

//     }
	
//     if(intersection_found){
//       break;
//     }
	
//  }

  


    
//     intersection.first+=trasl_x;
//     intersection.second+=trasl_y;      
    
//     if(!intersection_found){ // intersection  failed using  another method
//       // here
//       float dt_bez=end_curve? 1-PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW : PROC_BEZIER_OFFSETT_TANGENT_FOR_ARROW;
      
//       intersection=poly_bezier(ix(), iy(), 
//                                tan1x(), tan1y(), 
//                                tan2x(), tan2y(), 
//                                ex(), ey(),
//                                dt_bez);
//       //std::cout << "123 non found" << std::endl; 
//       //abort();
//     }
    
//     return intersection;
    
//   }



/******BOX*******/

BoxProc::BoxProc()
  :procedura(PROC_BOX),
   _edited_cp(none)
{

}


BoxProc::BoxProc(const BoxProc* other)
  :procedura::procedura(other),
   _id(other->_id),
   _ld(other->_ld),
   _ru(other->_ru),
   _cr(other->_cr),
   _cg(other->_cg),
   _cb(other->_cb),
   _xpivot(other->_xpivot),
   _ypivot(other->_ypivot),
   _angolorot(other->_angolorot),
   _thickness(other->_thickness),
   _dash(other->_dash),
   _box_type(other->_box_type),
   _edited_cp(other->_edited_cp)
{

}

BoxProc::BoxProc(int id,float ld_x, float ld_y,
                 float ru_x, float ru_y,
                 int cr, int cb, int cg ,
                 float xpiv, float ypiv, float anglrot,
                 int thick, int dash, box_type type)
  :procedura::procedura(PROC_BOX),
   _id(id),
   _cr(cr),
   _cg(cg),
   _cb(cb),
   _xpivot(xpiv),
   _ypivot(ypiv),
   _angolorot(anglrot),
   _thickness(thick),
   _dash(dash),
   _box_type(type)
{

  _ld.first=ld_x;
  _ld.second=ld_y;
  _ru.first=ru_x;
  _ru.second=ru_y;
  
}


BoxProc::~BoxProc(){

}

void BoxProc::init(){
  ruota(xpivot(),ypivot(),angolorot());
}

int BoxProc::id(){
  return _id;
}

float BoxProc::w(){
  if(cairo_t_singleton::can_export()){
    return phys_w();
  }else{
    return visual_w();
  }
}



float BoxProc::visual_w(){
  return phys_w() *  __pref.getZoom();
}

float BoxProc::phys_w(){
  return _ru.first - _ld.first;
}


float BoxProc::h(){
  if(cairo_t_singleton::can_export()){
    return phys_h();
  }else{
    return visual_h();
  }
}

float BoxProc::visual_h(){
  return phys_h() *  __pref.getZoom();
}

float BoxProc::phys_h(){
  return _ru.second - _ld.second;
}

float BoxProc::visual_posx(){
  return phys_posx() * __pref.getZoom();
}

float BoxProc::phys_posx(){
  return _ld.first;
}

float BoxProc::posx(){
  if(cairo_t_singleton::can_export()){
    return phys_posx();
  }else{
    return visual_posx();
  }
}

float BoxProc::posy(){
  if(cairo_t_singleton::can_export()){
    return phys_posy();
  }else{
    return visual_posy();
  }
}

float BoxProc::visual_posy(){
  return phys_posy() * __pref.getZoom();
}

float BoxProc::phys_posy(){
  return _ld.second;
}


float BoxProc::ld_x(){
  if(cairo_t_singleton::can_export()){
    return phys_ld_x();
  }else{
    return visual_ld_x();
  }
}

float BoxProc::ld_y(){
  if(cairo_t_singleton::can_export()){
    return phys_ld_y();
  }else{
    return visual_ld_y();
  }
}

float BoxProc::ru_x(){
  if(cairo_t_singleton::can_export()){
    return phys_ru_x();
  }else{
    return visual_ru_x();
  }
}

float BoxProc::ru_y(){
  if(cairo_t_singleton::can_export()){
    return phys_ru_y();
  }else{
    return visual_ru_y();
  }
}


float BoxProc::phys_ld_x(){
  return _ld.first;
}

float BoxProc::phys_ld_y(){
  return _ld.second;
}

float BoxProc::phys_ru_x(){
  return _ru.first;
}

float BoxProc::phys_ru_y(){
  return _ru.second;
}

float BoxProc::visual_ld_x(){
  return phys_ld_x() * __pref.getZoom();
}

float BoxProc::visual_ld_y(){
  return phys_ld_y() * __pref.getZoom();
}

float BoxProc::visual_ru_x(){
  return phys_ru_x() * __pref.getZoom();
}

float BoxProc::visual_ru_y(){
  return phys_ru_y() * __pref.getZoom();
}


void BoxProc::trasla(float dx, float dy){
  
  ld_x(descale(ld_x()+dx));
  ld_y(descale(ld_y()+dy));

  ru_x(descale(ru_x()+dx));
  ru_y(descale(ru_y()+dy));

}
void BoxProc::phys_translate(float dx, float dy){
  _ld.first+=dx;
  _ld.second+=dy;

  _ru.first+=dx;
  _ru.second+=dy;
}


int BoxProc::cr(){
  return _cr;
}
int BoxProc:: cg(){
  return _cg;
}
int BoxProc::cb(){
  return _cb;
}


float BoxProc::xpivot(){
  return _xpivot;
}


float BoxProc::ypivot(){
  return _ypivot;
}


float BoxProc::angolorot(){
  return _angolorot;
}

int BoxProc::spessore(){
  return _thickness;
}

int BoxProc::dash(){
  return _dash;
}

box_type BoxProc::b_type(){
  return _box_type;
}

bool BoxProc::dentro_bb(float x, float y, float w , float h){
  if(ld_x()>x && ld_x()<x+w &&
     ru_y()>y && ru_y()<y+h){

    return true;
   }else{

    return false;
  }
}


void BoxProc::get_bounding_box(std::pair<float,float>& ld,
                               std::pair<float,float>& ru){
  if(cairo_t_singleton::can_export()){
    get_phys_bounding_box(ld,ru);
  }else{
    get_visual_bounding_box(ld,ru);
  }
}

void BoxProc::get_phys_bounding_box(std::pair<float,float>& ld,
                                    std::pair<float,float>& ru){
  ld=_ld;
  ru=_ru;

  int actual_thickness=spessore();  
  int shadow_thickness=0;
  if(b_type()==SHADOWED){
    shadow_thickness=actual_thickness*BoxProc::shadow_thickness_factor;
  }

  ru.first+=actual_thickness + shadow_thickness;
  ru.second+=actual_thickness + shadow_thickness;
  
}

void BoxProc::get_visual_bounding_box(std::pair<float,float>& ld,
                                      std::pair<float,float>& ru){
  ld.first=visual_ld_x();
  ld.second=visual_ld_y();

  ru.first=visual_ru_x();
  ru.second=visual_ru_y();
}

int BoxProc::sotto_mouse(int posx_m, int posy_m){
  if(posx_m > ld_x()  && posx_m < ru_x() &&
     posy_m > ld_y()  && posy_m < ru_y()){
    return id();
  }else{
    return -1;
  }
}

int BoxProc::control_point_under_mouse(int posx_m, int posy_m){
  int res=-1;

  if(similar_to(ld_x(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
     similar_to(ld_y(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=ld;
    res=id();
  }else if(similar_to(ru_x(),static_cast<float>(posx_m),_tolerance_hit_control_point) &&
	   similar_to(ru_y(),static_cast<float>(posy_m),_tolerance_hit_control_point)){
    _edited_cp=ru;
    res=id();
  }

  return res;
  
}

void BoxProc::unset_edit_control_point(){
  _edited_cp=none;
}

void BoxProc::control_point_transl(float dx, float dy){

  if(_edited_cp==ld){
    ld_x(descale(ld_x()+dx));
    ld_y(descale(ld_y()+dy));
  }else if(_edited_cp==ru){
    ru_x(descale(ru_x()+dx));
    ru_y(descale(ru_y()+dy));
  }


  if(ru_x() <= ld_x()){
    std::pair<float,float> svru=_ru;
    std::pair<float,float> svld=_ld;
    _ld.first=svru.first;
    _ru.first=svld.first;
    _edited_cp=ld;
  }

  if(ld_x() >= ru_x()){
    std::pair<float,float> svru=_ru;
    std::pair<float,float> svld=_ld;
    _ld.first=svru.first;
    _ru.first=svld.first;
    _edited_cp=ru;
  }


  if(ru_y() <= ld_y()){
    std::pair<float,float> svru=_ru;
    std::pair<float,float> svld=_ld;
    _ld.second=svru.second;
    _ru.second=svld.second;
    _edited_cp=ru;
  }


  if(ld_y() >= ru_y()){
    std::pair<float,float> svru=_ru;
    std::pair<float,float> svld=_ld;
    _ld.second=svru.second;
    _ru.second=svld.second;
    _edited_cp=ld;
  }




}



void BoxProc::id(int nw){
  _id=nw;
}


void BoxProc::w(float nw){
  _ru.first=nw;
}

void BoxProc::h(float nw){
  _ru.second=nw;
}


void BoxProc::posx(float nw){
  _ld.first=nw;
}

void BoxProc::posy(float nw){
  _ld.second=nw;
}


void BoxProc::cr(int nw){
  _cr=nw;
}

void BoxProc::cb(int nw){
  _cb=nw;
}

void BoxProc::cg(int nw){
  _cg=nw;
}

void BoxProc::xpivot(float nw){
  _xpivot=nw;
}

void BoxProc::ypivot(float nw){
  _ypivot=nw;
}

void BoxProc::angolorot(float nw){
  _angolorot=nw;
}

void BoxProc::spessore(int nw){
  _thickness=nw;
}

void BoxProc::dash(int nw){
  _dash=nw;
}


void BoxProc::ld_x(float nw){
  _ld.first=nw;
}

void BoxProc::ld_y(float nw){
  _ld.second=nw;
}

void BoxProc::ru_x(float nw){
  _ru.first=nw;
}

void BoxProc::ru_y(float nw){
  _ru.second=nw;
}


void BoxProc::b_type(box_type type){
  _box_type=type;
}


void BoxProc::disegna(){
 
  float the_zoom=__pref.getZoom();
  int actual_thickness= cairo_t_singleton::can_export()? spessore() : 
    static_cast<int>(rintf(spessore()*the_zoom));

  
  if(actual_thickness<=0){
    actual_thickness=1;
  }
  
  int shadow_thickness=actual_thickness*BoxProc::shadow_thickness_factor;

  float weight_col=0.5;
  float weight_col_1=1- weight_col;
  float melting_col=0;
  if(cr()==0 && cg()==0 && cb()==0){
    melting_col=255;
  }

  if(cairo_t_singleton::can_export()){
    cairo_t* cn=cairo_t_singleton::get_context();



    if(b_type()==SHADOWED){
      cairo_save(cn);
      cairo_set_source_rgb(cn,
                           remap_color_1(weight_col* cr() + weight_col_1 * melting_col),
                           remap_color_1(weight_col* cg() + weight_col_1 * melting_col),
                           remap_color_1(weight_col* cb() + weight_col_1 * melting_col)
                           );


      cairo_set_line_width(cn,shadow_thickness);
      cairo_move_to(cn,
                    phys_ru_x()+actual_thickness, 
                    phys_ld_y()+actual_thickness);

      cairo_line_to(cn,
                    phys_ru_x()+actual_thickness, 
                    phys_ru_y()+actual_thickness + (shadow_thickness/2) );

      cairo_move_to(cn,
                    phys_ru_x()+actual_thickness, 
                    phys_ru_y()+actual_thickness);
      cairo_line_to(cn,
                    phys_ld_x()+actual_thickness, 
                    phys_ru_y()+actual_thickness);

      
      cairo_stroke(cn);
      cairo_restore(cn);
    

    }



    cairo_save(cn);
    cairo_set_source_rgb(cn,
                         remap_color_1(cr()),
                         remap_color_1(cg()),
                         remap_color_1(cb())
                         );


    cairo_set_line_width(cn,spessore());
  
    if(dash()>0){
      double dash_gap[1]={dash()};
      cairo_set_dash(cn,dash_gap,1,0);
    }

    cairo_rectangle(cn,
                    phys_ld_x(),
                    phys_ld_y(),
                    phys_w(),
                    phys_h());


    cairo_stroke(cn);
    cairo_restore(cn);





    
  }else{
    char gap_dash[2]={dash(),0};
    int dx_scroll=(MainWindow->ritorna_mol_canvas())->x();
    int dy_scroll=(MainWindow->ritorna_mol_canvas())->y();

    fl_line_style(FL_SOLID, actual_thickness,gap_dash);

    if(b_type()==SHADOWED){

      fl_line_style(FL_SOLID, actual_thickness*BoxProc::shadow_thickness_factor);
      fl_color(weight_col* cr() + weight_col_1 * melting_col, 
               weight_col* cg() + weight_col_1 * melting_col, 
               weight_col* cb() + weight_col_1 * melting_col
               );
      fl_begin_line();

      fl_vertex(ru_x()+actual_thickness+dx_scroll, ld_y()+actual_thickness+dy_scroll);
      fl_vertex(ru_x()+actual_thickness+dx_scroll, ru_y()+actual_thickness+dy_scroll);

      fl_vertex(ru_x()+actual_thickness+dx_scroll, ru_y()+actual_thickness+dy_scroll);
      fl_vertex(ld_x()+actual_thickness+dx_scroll, ru_y()+actual_thickness+dy_scroll);

      fl_end_line();
      fl_line_style(FL_SOLID, actual_thickness,gap_dash);
    }
    fl_color(cr(), cg(), cb());
    fl_begin_line();

    
    fl_rect(ld_x()+dx_scroll,
            ld_y()+dy_scroll,
            w(),
            h());
    fl_end_line();


    draw_shadowed_point(visual_ld_x()+dx_scroll, visual_ld_y()+dy_scroll,255,0,0);
    draw_shadowed_point(visual_ru_x()+dx_scroll, visual_ru_y()+dy_scroll,255,0,0);
    fl_line_style(0);
    fl_color(cr(), cg(), cb());

  }


}

void BoxProc::scale(float sc){
  ld_x(phys_ld_x()*sc);
  ld_y(phys_ld_y()*sc);

  ru_x(phys_ru_x()*sc);
  ru_y(phys_ru_y()*sc);
}

void BoxProc::ruota(float xpiv, float ypiv,float angl){
  // TO DO
}


void BoxProc::write_native_format(std::ostream& stream, std::string indent){
  /*

	     'BOX'   APRI
			ID_PROC SEP LD_X SEP LD_Y SEP RU_X SEP RU_Y
			SEP COLORE SEP COLORE SEP COLORE SEP XPIVOT
			SEP YPIVOT SEP ANGOLOROT SEP SPESSORE SEP
			DASH SEP BOX_TYPE
		      CHIUDI
  */



  stream << indent << ETIC_BOX << " " << APRI << std::endl
         << indent << "\t" << id() << SEP << phys_ld_x() << SEP << phys_ld_y() << SEP <<std::endl
         << indent << "\t" << phys_ru_x() << SEP << phys_ru_y() << SEP  << std::endl
         << indent << "\t" << cr() << SEP << cg() << SEP << cb() << SEP << std::endl
         << indent << "\t" << xpivot() << SEP << ypivot() << SEP << angolorot() << SEP << std::endl
         << indent << "\t" << spessore() << SEP << dash() << SEP << static_cast<int>(b_type()) << std::endl
         << indent << CHIUDI << std::endl; 
  
}

const int BoxProc::shadow_thickness_factor=3;
