Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_sg_plots 5 #define tools_sg_plots 6 7 #include "_switch" 8 //#include "head_light" 9 #include "matrix" 10 11 #include "plotter" 12 13 namespace tools { 14 namespace sg { 15 16 class plots : public node { 17 TOOLS_NODE(plots,tools::sg::plots,node) 18 public: 19 sf<float> width; 20 sf<float> height; 21 sf<unsigned int> cols; //must never be 0. 22 sf<unsigned int> rows; //must never be 0. 23 sf<bool> view_border; //current plotter border 24 sf<float> plotter_scale; //scale factor applied to each plotter. 25 26 sf<bool> border_visible; 27 sf<float> border_width; 28 sf<float> border_height; 29 sf<float> border_z; 30 sf<float> border_scale; 31 sf_vec<colorf,float> border_color; 32 33 // for gopaw : 34 sf<float> left_margin; 35 sf<float> right_margin; 36 sf<float> top_margin; 37 sf<float> bottom_margin; 38 sf<float> horizontal_spacing; 39 sf<float> vertical_spacing; 40 public: 41 virtual const desc_fields& node_desc_fields() const { 42 TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::plots) 43 static const desc_fields s_v(parent::node_desc_fields(),18, //WARNING : take care of count. 44 TOOLS_ARG_FIELD_DESC(width), //1 45 TOOLS_ARG_FIELD_DESC(height), 46 TOOLS_ARG_FIELD_DESC(cols), 47 TOOLS_ARG_FIELD_DESC(rows), 48 TOOLS_ARG_FIELD_DESC(view_border), 49 TOOLS_ARG_FIELD_DESC(plotter_scale), 50 TOOLS_ARG_FIELD_DESC(border_visible), 51 TOOLS_ARG_FIELD_DESC(border_width), 52 TOOLS_ARG_FIELD_DESC(border_height), 53 TOOLS_ARG_FIELD_DESC(border_z), //10 54 TOOLS_ARG_FIELD_DESC(border_scale), 55 TOOLS_ARG_FIELD_DESC(border_color), 56 TOOLS_ARG_FIELD_DESC(left_margin), 57 TOOLS_ARG_FIELD_DESC(right_margin), 58 TOOLS_ARG_FIELD_DESC(top_margin), 59 TOOLS_ARG_FIELD_DESC(bottom_margin), 60 TOOLS_ARG_FIELD_DESC(horizontal_spacing), 61 TOOLS_ARG_FIELD_DESC(vertical_spacing) 62 ); 63 return s_v; 64 } 65 virtual bool touched() { 66 if(parent::touched()) return true; 67 68 if(m_sep.empty()) return true; 69 if(m_extras.size()!=m_extras_sep.size()) return true; 70 71 //{size_t _number = m_sep.size(); 72 // for(size_t index=0;index<_number;index++) { 73 // separator* sep = (separator*)m_sep[index]; 74 // plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 75 // if(_plotter->shape.touched()) return true; 76 // }} 77 78 return false; 79 } 80 private: 81 void add_fields(){ 82 add_field(&width); 83 add_field(&height); 84 add_field(&cols); 85 add_field(&rows); 86 add_field(&view_border); 87 add_field(&plotter_scale); 88 add_field(&border_visible); 89 add_field(&border_width); 90 add_field(&border_height); 91 add_field(&border_z); 92 add_field(&border_scale); 93 add_field(&border_color); 94 add_field(&left_margin); 95 add_field(&right_margin); 96 add_field(&top_margin); 97 add_field(&bottom_margin); 98 add_field(&horizontal_spacing); 99 add_field(&vertical_spacing); 100 } 101 private: 102 static unsigned int MATRIX() {return 0;} 103 static unsigned int BORDER() {return 1;} 104 static unsigned int PLOTTER() {return 2;} 105 //static unsigned int TSF() {return xxx;} 106 //static unsigned int LIGHT() {return xxx;} 107 108 typedef std::vector<plottable*> ptbs_t; 109 typedef std::vector<node*> todels_t; 110 typedef std::vector<plotprim*> prims_t; 111 public: 112 /* 113 class updater { 114 public: 115 virtual void update(plots&,size_t) = 0; 116 virtual updater* copy() const = 0; 117 public: 118 virtual ~updater(){} 119 }; 120 */ 121 public: 122 virtual void render(render_action& a_action) { 123 update_if_touched(); 124 m_group.render(a_action); 125 } 126 virtual void pick(pick_action& a_action) { 127 update_if_touched(); 128 nodekit_pick(a_action,m_group,this); 129 //m_group.pick(a_action); 130 } 131 virtual void search(search_action& a_action) { 132 update_if_touched(); 133 parent::search(a_action); 134 if(a_action.done()) return; 135 if(a_action.do_path()) a_action.path_push(this); 136 m_group.search(a_action); 137 if(a_action.done()) return; 138 if(a_action.do_path()) a_action.path_pop(); 139 } 140 virtual void bbox(bbox_action& a_action) { 141 update_if_touched(); 142 m_group.bbox(a_action); 143 } 144 145 virtual void event(event_action& a_action) { 146 update_if_touched(); 147 m_group.event(a_action); 148 if(a_action.done()) return; 149 } 150 virtual bool write(write_action& a_action) { 151 update_if_touched(); 152 return m_group.write(a_action); 153 } 154 public: 155 plots(const base_freetype& a_ttf) 156 :parent() 157 ,width(1) 158 ,height(1) 159 ,cols(1) 160 ,rows(1) 161 ,view_border(true) 162 ,plotter_scale(1) 163 ,border_visible(false) 164 ,border_width(0) 165 ,border_height(0) 166 ,border_z(0) 167 ,border_scale(1) 168 ,border_color(colorf_grey()) 169 ,left_margin(0) 170 ,right_margin(0) 171 ,top_margin(0) 172 ,bottom_margin(0) 173 ,horizontal_spacing(0) 174 ,vertical_spacing(0) 175 176 ,m_ttf(a_ttf) 177 ,m_current(0) 178 ,m_extras() 179 //,m_updater(0) 180 ,m_old_cols(0) 181 ,m_old_rows(0) 182 { 183 add_fields(); 184 init_sg(); 185 } 186 virtual ~plots() { 187 //delete m_updater; 188 } 189 public: 190 plots(const plots& a_from) 191 :parent(a_from) 192 ,width(a_from.width) 193 ,height(a_from.height) 194 ,cols(a_from.cols) 195 ,rows(a_from.rows) 196 ,view_border(a_from.view_border) 197 ,plotter_scale(a_from.plotter_scale) 198 ,border_visible(a_from.border_visible) 199 ,border_width(a_from.border_width) 200 ,border_height(a_from.border_height) 201 ,border_z(a_from.border_z) 202 ,border_scale(a_from.border_scale) 203 ,border_color(a_from.border_color) 204 ,left_margin(a_from.left_margin) 205 ,right_margin(a_from.right_margin) 206 ,top_margin(a_from.top_margin) 207 ,bottom_margin(a_from.bottom_margin) 208 ,horizontal_spacing(a_from.horizontal_spacing) 209 ,vertical_spacing(a_from.vertical_spacing) 210 211 ,m_ttf(a_from.m_ttf) 212 ,m_current(a_from.m_current) 213 ,m_extras(a_from.m_extras) 214 //,m_updater(0) 215 ,m_old_cols(0) 216 ,m_old_rows(0) 217 ,m_origins(a_from.m_origins) 218 ,m_sizes(a_from.m_sizes) 219 ,m_extras_origins(a_from.m_extras_origins) 220 ,m_extras_sizes(a_from.m_extras_sizes) 221 { 222 add_fields(); 223 init_sg(); 224 //m_updater = a_from.m_updater?a_from.m_updater->copy():0; 225 if(!copy_plotters(a_from)) {} 226 } 227 plots& operator=(const plots& a_from){ 228 parent::operator=(a_from); 229 if(&a_from==this) return *this; 230 231 width = a_from.width; 232 height = a_from.height; 233 234 cols = a_from.cols; 235 rows = a_from.rows; 236 view_border = a_from.view_border; 237 plotter_scale = a_from.plotter_scale; 238 239 border_visible = a_from.border_visible; 240 border_width = a_from.border_width; 241 border_height = a_from.border_height; 242 border_z = a_from.border_z; 243 border_scale = a_from.border_scale; 244 border_color = a_from.border_color; 245 246 left_margin = a_from.left_margin; 247 right_margin = a_from.right_margin; 248 top_margin = a_from.top_margin; 249 bottom_margin = a_from.bottom_margin; 250 horizontal_spacing = a_from.horizontal_spacing; 251 vertical_spacing = a_from.vertical_spacing; 252 253 m_old_cols = 0; 254 m_old_rows = 0; 255 m_origins = a_from.m_origins; 256 m_sizes = a_from.m_sizes; 257 m_extras_origins = a_from.m_extras_origins; 258 m_extras_sizes = a_from.m_extras_sizes; 259 260 m_current = a_from.m_current; 261 m_extras = a_from.m_extras; 262 263 if(!copy_plotters(a_from)) {} 264 265 return *this; 266 } 267 public: 268 unsigned int number() const {return cols*rows;} 269 unsigned int current_index() const {return m_current;} 270 271 void adjust_size(unsigned int a_ww,unsigned int a_wh) { 272 if(!a_ww||!a_wh) return; 273 float aspect = float(a_ww)/float(a_wh); 274 width = height * aspect; 275 } 276 277 //void enforce_update() { //used in geant4 plotting. 278 // update_sg(); 279 // reset_touched(); 280 //} 281 282 const base_freetype& ttf() const {return m_ttf;} 283 public: 284 /* 285 void set_updater(updater* a_updater) { 286 //WARNING : we take ownership of a_updater 287 delete m_updater; 288 m_updater = a_updater; 289 } 290 */ 291 void clear() { 292 update_if_touched(); 293 {size_t _number = m_sep.size(); 294 for(size_t index=0;index<_number;index++) { 295 separator* sep = (separator*)m_sep[index]; 296 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 297 _plotter->clear(); 298 }} 299 tools_vforit(extra,m_extras,it) { 300 separator* sep = (*it).m_sep; 301 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 302 _plotter->clear(); 303 } 304 } 305 306 bool has_data() { 307 update_if_touched(); 308 {size_t _number = m_sep.size(); 309 for(size_t index=0;index<_number;index++) { 310 separator* sep = (separator*)m_sep[index]; 311 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 312 if(_plotter->plottables().size()) return true; 313 }} 314 tools_vforit(extra,m_extras,it) { 315 separator* sep = (*it).m_sep; 316 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 317 if(_plotter->plottables().size()) return true; 318 } 319 return false; 320 } 321 322 void touch_plotters() { //used in exlib/geant4/session. 323 update_if_touched(); 324 {size_t _number = m_sep.size(); 325 for(size_t index=0;index<_number;index++) { 326 separator* sep = (separator*)m_sep[index]; 327 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 328 _plotter->touch(); 329 }} 330 tools_vforit(extra,m_extras,it) { 331 separator* sep = (*it).m_sep; 332 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 333 _plotter->touch(); 334 } 335 } 336 337 void next() { 338 update_if_touched(); 339 size_t _number = m_sep.size(); 340 if(m_current>=(uint32(_number)-1)) { 341 m_current = 0; 342 } else { 343 m_current++; 344 } 345 update_current_border(); 346 } 347 348 bool set_current_plotter(unsigned int a_index) { 349 update_if_touched(); 350 if(a_index>=m_sep.size()) return false; 351 m_current = a_index; 352 update_current_border(); 353 return true; 354 } 355 356 bool set_current(plotter* a_plotter) { //for popup. 357 update_if_touched(); 358 size_t _number = m_sep.size(); 359 for(size_t index=0;index<_number;index++) { 360 separator* sep = (separator*)m_sep[index]; 361 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 362 if(_plotter==a_plotter) { 363 m_current = uint32(index); 364 update_current_border(); 365 return true; 366 } 367 } 368 return false; 369 } 370 371 // torche* current_torche() { 372 // update_if_touched(); 373 // separator* sep = (separator*)m_sep[m_current]; 374 // return safe_cast<node,torche>(*((*sep)[LIGHT()])); 375 // } 376 377 /* 378 matrix* current_tsf() { 379 plotter& _plotter = current_plotter(); 380 if(_plotter.shape.value()==plotter::xyz) { 381 return &(_plotter.tsf()); 382 } else { 383 update_if_touched(); 384 separator* sep = (separator*)m_sep[m_current]; 385 return safe_cast<node,matrix>(*((*sep)[TSF()])); 386 } 387 } 388 */ 389 390 plotter& current_plotter() { 391 update_if_touched(); 392 separator* sep = (separator*)m_sep[m_current]; 393 return *((plotter*)(*sep)[PLOTTER()]); 394 } 395 plotter* find_plotter(unsigned int a_index) { 396 update_if_touched(); 397 if(a_index>=m_sep.size()) return 0; 398 separator* sep = (separator*)m_sep[a_index]; 399 return (plotter*)(*sep)[PLOTTER()]; 400 } 401 402 /* 403 bool find_plotter(unsigned int a_ww,unsigned int a_wh, 404 float a_x,float a_y, 405 unsigned int& a_index) { 406 update_if_touched(); 407 408 a_index = 0; 409 410 if(!a_ww) return false; 411 if(!a_wh) return false; 412 413 float aspect = float(a_ww)/float(a_wh); 414 415 // one plotter in pixels : 416 unsigned int rw = (unsigned int)(float(a_ww)/float(cols.value())); 417 unsigned int rh = (unsigned int)(float(a_wh)/float(rows.value())); 418 float ra = float(rw)/float(rh); 419 420 // all window wc : 421 float wh_wc = 1; 422 float ww_wc = wh_wc * aspect; 423 424 // plotter size in window wc : 425 float rh_wc = wh_wc/rows; 426 float rw_wc = rh_wc*ra; 427 428 unsigned int _number = m_sep.size(); 429 for(unsigned int index=0;index<_number;index++) { 430 unsigned int row = index/cols; 431 unsigned int col = index-cols*row; 432 433 float x = -ww_wc*0.5f + col * rw_wc + rw_wc * 0.5f; 434 float y = wh_wc*0.5f - row * rh_wc - rh_wc * 0.5f; 435 436 if( ((x-rw_wc*0.5f)<a_x)&&(a_x<(x+rw_wc*0.5f)) && 437 ((y-rh_wc*0.5f)<a_y)&&(a_y<(y+rh_wc*0.5f)) ){ 438 a_index = index; 439 return true; 440 } 441 } 442 443 return false; 444 } 445 */ 446 447 void set_regions(unsigned int a_cols = 1,unsigned int a_rows = 1,bool a_transfer = false) { 448 unsigned int oldn = cols*rows; 449 450 std::vector<ptbs_t> ptbss; 451 std::vector<prims_t> primss; 452 std::vector<todels_t> tdlss; 453 std::vector<plotter> pls; 454 455 if(a_transfer) { 456 ptbss.resize(oldn); 457 primss.resize(oldn); 458 tdlss.resize(oldn); 459 pls.resize(oldn,plotter(m_ttf)); 460 for(unsigned int index=0;index<oldn;index++) { 461 plotter* p = find_plotter(index); 462 p->transfer_plottables(ptbss[index]); 463 p->transfer_primitives(primss[index]); 464 p->transfer_todels(tdlss[index]); 465 pls[index] = *p; //to copy styles. 466 } 467 } 468 469 cols = a_cols?a_cols:1; 470 rows = a_rows?a_rows:1; 471 if(view_border.value()) {view_border = (number()==1?false:true);} 472 update_sg(); 473 set_current_plotter(0); 474 clear(); 475 if(a_transfer) { 476 //fill new plotters with old data : 477 unsigned int num = min_of(oldn,cols*rows); 478 for(unsigned int index=0;index<num;index++) { 479 plotter* p = find_plotter(index); 480 p->copy_style(pls[index]); //it must not touch p width, height, depth. 481 482 {const ptbs_t& ptbs = ptbss[index]; 483 tools_vforcit(plottable*,ptbs,it) p->add_plottable(*it);} 484 {const prims_t& prims = primss[index]; 485 tools_vforcit(plotprim*,prims,it) p->add_primitive(*it);} 486 {const todels_t& todels = tdlss[index]; 487 tools_vforcit(node*,todels,it) p->add_node_todel(*it);} 488 } 489 } 490 reset_touched(); 491 } 492 493 void current_to_one() { 494 ptbs_t ptbs;current_plotter().transfer_plottables(ptbs); 495 prims_t prims;current_plotter().transfer_primitives(prims); 496 todels_t tdls;current_plotter().transfer_todels(tdls); 497 plotter pl = current_plotter(); //to copy styles. 498 499 set_regions(1,1,false); 500 501 plotter& p = current_plotter(); 502 p.copy_style(pl); //copy styles. 503 504 {tools_vforcit(plottable*,ptbs,it) p.add_plottable(*it);} 505 {tools_vforcit(plotprim*,prims,it) p.add_primitive(*it);} 506 {tools_vforcit(node*,tdls,it) p.add_node_todel(*it);} 507 508 } 509 510 void plotters(std::vector<plotter*>& a_vec) { //a_vec do NOT get ownership of sg::plotter objects. Use in G4Analysis. 511 a_vec.clear(); 512 update_if_touched(); 513 size_t _number = m_sep.size(); 514 for(size_t index=0;index<_number;index++) { 515 separator* sep = (separator*)m_sep[index]; 516 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 517 a_vec.push_back(_plotter); 518 } 519 } 520 521 ////////////////////////////////////////////////////////////////////// 522 //// styling methods : /////////////////////////////////////////////// 523 ////////////////////////////////////////////////////////////////////// 524 void set_line_width(float a_line_width) { 525 update_if_touched(); 526 size_t _number = m_sep.size(); 527 for(size_t index=0;index<_number;index++) { 528 separator* sep = (separator*)m_sep[index]; 529 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 530 531 _plotter->bins_style(0).line_width = a_line_width; 532 _plotter->inner_frame_style().line_width = a_line_width; 533 _plotter->grid_style().line_width = a_line_width; 534 _plotter->x_axis().line_style().width = a_line_width; 535 _plotter->x_axis().ticks_style().width = a_line_width; 536 _plotter->y_axis().line_style().width = a_line_width; 537 _plotter->y_axis().ticks_style().width = a_line_width; 538 _plotter->z_axis().line_style().width = a_line_width; 539 _plotter->z_axis().ticks_style().width = a_line_width; 540 _plotter->colormap_axis().line_style().width = a_line_width; 541 _plotter->colormap_axis().ticks_style().width = a_line_width; 542 543 // needed if font is hershey : 544 _plotter->title_style().line_width = a_line_width; 545 _plotter->infos_style().line_width = a_line_width; 546 _plotter->title_box_style().line_width = a_line_width; 547 548 _plotter->x_axis().labels_style().line_width = a_line_width; 549 _plotter->x_axis().mag_style().line_width = a_line_width; 550 _plotter->x_axis().title_style().line_width = a_line_width; 551 552 _plotter->y_axis().labels_style().line_width = a_line_width; 553 _plotter->y_axis().mag_style().line_width = a_line_width; 554 _plotter->y_axis().title_style().line_width = a_line_width; 555 556 _plotter->z_axis().labels_style().line_width = a_line_width; 557 _plotter->z_axis().mag_style().line_width = a_line_width; 558 _plotter->z_axis().title_style().line_width = a_line_width; 559 560 _plotter->colormap_axis().labels_style().line_width = a_line_width; 561 _plotter->colormap_axis().mag_style().line_width = a_line_width; 562 _plotter->colormap_axis().title_style().line_width = a_line_width; 563 } 564 } 565 566 /* 567 void set_border_style() { 568 update_if_touched(); 569 size_t _number = m_sep.size(); 570 for(size_t index=0;index<_number;index++) { 571 separator* sep = (separator*)m_sep[index]; 572 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 573 _plotter->background_style().visible = true; 574 _plotter->background_style().color = colorf_black(); 575 _plotter->background_style().line_width = 0.003; 576 } 577 border_visible = true; 578 } 579 */ 580 581 void set_grids_visibility(bool a_visible = false) { 582 update_if_touched(); 583 size_t _number = m_sep.size(); 584 for(size_t index=0;index<_number;index++) { 585 separator* sep = (separator*)m_sep[index]; 586 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 587 _plotter->grid_style().visible = a_visible; 588 } 589 border_visible = true; 590 } 591 592 void adjust_scales(float a_plotter_scale = 1) { 593 // Rescale some plotter parameters (for example margins) according to the number of plots. 594 // We assume that these parameters had been set previously according to one plot per page. 595 // Then this function must be applied after all the styles had been applied (because 596 // a plotting style may set these parameters). 597 598 float ww_wc = width.value(); 599 float wh_wc = height.value(); 600 float rw_wc = ww_wc/cols.value(); 601 float rh_wc = wh_wc/rows.value(); 602 603 float cooking = 1.2f; //if increased the data area is diminished. 604 605 float wfac = (rw_wc/ww_wc)*cooking; 606 float hfac = (rh_wc/wh_wc)*cooking; 607 608 float label_cooking = 1.6f; //if increased the labels are bigger. 609 610 if((cols.value()>=4)&&(cols.value()>rows.value())) label_cooking = 0.9f; 611 612 float title_cooking = 1.1f; //extra title cooking. 613 614 plotter_scale = a_plotter_scale; 615 616 update_if_touched(); 617 {size_t _number = m_sep.size(); 618 for(size_t index=0;index<_number;index++) { 619 separator* sep = (separator*)m_sep[index]; 620 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 621 622 _plotter->left_margin = _plotter->left_margin * wfac; 623 _plotter->right_margin = _plotter->right_margin * wfac; 624 _plotter->bottom_margin = _plotter->bottom_margin * hfac; 625 _plotter->top_margin = _plotter->top_margin * hfac; 626 627 _plotter->x_axis().tick_length = _plotter->x_axis().tick_length * wfac; 628 _plotter->y_axis().tick_length = _plotter->y_axis().tick_length * hfac; 629 630 _plotter->title_to_axis = _plotter->title_to_axis * hfac; 631 _plotter->title_height = _plotter->title_height * hfac * title_cooking; 632 633 _plotter->x_axis().label_height = _plotter->x_axis().label_height * hfac * label_cooking; 634 _plotter->y_axis().label_height = _plotter->y_axis().label_height * hfac * label_cooking; 635 }} 636 } 637 638 //gopaw: 639 void configure_grid_PAW(unsigned int a_ww,unsigned int a_wh) { 640 641 m_origins.clear(); 642 m_sizes.clear(); 643 644 float wvp = float(a_ww); //pixels. 645 float hvp = float(a_wh); //pixels. 646 if( (wvp<=0)||(hvp<=0)||(width.value()<=0)||(height.value()<=0) ) return; 647 648 unsigned int _cols = cols.value(); 649 unsigned int _rows = rows.value(); 650 if((!_cols)||(!_rows)) return; 651 652 float wdata = (width.value()-left_margin.value()-right_margin.value()-(_cols-1)*horizontal_spacing.value())/_cols; 653 float hdata = (height.value()-bottom_margin.value()-top_margin.value()-(_rows-1)*vertical_spacing.value())/_rows; 654 655 if((wdata<=0)||(hdata<=0)) return; 656 657 /* 658 // wpix = w * wvp pixels 659 // hpix = h * hvp pixels 660 // wpix/hpix = cst = (w * wvp) / (h * hvp) = width / height 661 float h,w,xo,yo; 662 h = w = xo = yo = 0; 663 float waspect = wvp/hvp; 664 float paspect = width.value()/height.value(); 665 if(waspect>=paspect) { 666 h = 1; 667 w = paspect * h * (hvp/wvp); 668 xo = (1-w)/2; 669 yo = 0; 670 } else { 671 w = 1; 672 h = w * (wvp/hvp)/paspect; 673 xo = 0; 674 yo = (1-h)/2; 675 } 676 float xfac = w / width.value(); 677 float yfac = h / height.value(); 678 */ 679 680 unsigned int _num = number(); 681 for(unsigned int iregion=0;iregion<_num;iregion++) { 682 //iregion = col + row * cols 683 unsigned int row = iregion/_cols; 684 unsigned int col = iregion - row * _cols; 685 686 float wr,hr,x,y,lm,rm,bm,tm; 687 wr = hr = x = y = 0; 688 lm = rm = bm = tm = 0; 689 690 if(_cols==1) { 691 wr = width.value(); 692 x = 0; 693 lm = left_margin.value(); 694 rm = right_margin.value(); 695 } else { 696 float wrl = left_margin.value()+wdata+horizontal_spacing.value()/2; 697 float wrr = right_margin.value()+wdata+horizontal_spacing.value()/2; 698 float wri = wdata+horizontal_spacing.value(); 699 if(col==0) { 700 wr = wrl; 701 x = 0; 702 lm = left_margin.value(); 703 rm = horizontal_spacing.value()/2; 704 } else if(col==(_cols-1)) { 705 wr = wrr; 706 x = width.value() - wrr; 707 lm = horizontal_spacing.value()/2; 708 rm = right_margin.value(); 709 } else { 710 wr = wri; 711 x = wrl + (col-1) * wri; 712 lm = horizontal_spacing.value()/2; 713 rm = horizontal_spacing.value()/2; 714 } 715 } 716 717 if(_rows==1) { 718 hr = height.value(); 719 y = 0; 720 tm = top_margin.value(); 721 bm = bottom_margin.value(); 722 } else { 723 float hrt = top_margin.value()+hdata+vertical_spacing.value()/2; //top 724 float hrb = bottom_margin.value()+hdata+vertical_spacing.value()/2; //bottom 725 float hri = hdata+vertical_spacing.value(); 726 if(row==0) { //top row. 727 hr = hrt; 728 y = height.value()-hrt; 729 tm = top_margin.value(); 730 bm = vertical_spacing.value()/2; 731 } else if(row==(_rows-1)) { 732 hr = hrb; 733 y = 0; 734 tm = vertical_spacing.value()/2; 735 bm = bottom_margin.value(); 736 } else { 737 hr = hri; 738 y = height.value()- (hrt + row * hri); 739 tm = vertical_spacing.value()/2; 740 bm = vertical_spacing.value()/2; 741 } 742 } 743 744 //m_origins.push_back(vec2f(xo/xfac+x,yo/yfac+y)); 745 m_origins.push_back(vec2f(x,y)); 746 m_sizes.push_back(vec2f(wr,hr)); 747 748 separator* sep = (separator*)m_sep[iregion]; 749 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 750 751 //_plotter->width = wr; 752 _plotter->left_margin = lm; 753 _plotter->right_margin = rm; 754 755 //_plotter->height = hr; 756 _plotter->top_margin = tm; 757 _plotter->bottom_margin = bm; 758 759 // ignore margins and spacings : 760 //float wr = w/_cols; 761 //float hr = h/_rows; 762 //float x = xo + col * wr; 763 //float y = yo + (rows-1-row) * hr; 764 //viewportRegion->setPositionPercent(x,y); 765 //viewportRegion->setSizePercent(wr,hr); 766 767 } 768 } 769 770 void configure_extras_PAW(unsigned int a_ww,unsigned int a_wh) { 771 772 m_extras_origins.clear(); 773 m_extras_sizes.clear(); 774 775 float wvp = float(a_ww); //pixels. 776 float hvp = float(a_wh); //pixels. 777 if( (wvp<=0)||(hvp<=0)||(width.value()<=0)||(height.value()<=0) ) return; 778 779 tools_vforcit(extra,m_extras,it) { 780 const extra& _extra = *it; 781 782 unsigned int _cols = _extra.m_cols; 783 unsigned int _rows = _extra.m_rows; 784 if((!_cols)||(!_rows)) continue; 785 786 float wdata = (width.value()-left_margin.value()-right_margin.value()-(_cols-1)*horizontal_spacing.value())/_cols; 787 float hdata = (height.value()-bottom_margin.value()-top_margin.value()-(_rows-1)*vertical_spacing.value())/_rows; 788 789 if((wdata<=0)||(hdata<=0)) continue; 790 791 unsigned int iregion = _extra.m_index; 792 unsigned int row = iregion/_cols; 793 unsigned int col = iregion - row * _cols; 794 795 float wr,hr,x,y,lm,rm,bm,tm; 796 wr = hr = x = y = 0; 797 lm = rm = bm = tm = 0; 798 799 if(_cols==1) { 800 wr = width.value(); 801 x = 0; 802 lm = left_margin.value(); 803 rm = right_margin.value(); 804 } else { 805 float wrl = left_margin.value()+wdata+horizontal_spacing.value()/2; 806 float wrr = right_margin.value()+wdata+horizontal_spacing.value()/2; 807 float wri = wdata+horizontal_spacing.value(); 808 if(col==0) { 809 wr = wrl; 810 x = 0; 811 lm = left_margin.value(); 812 rm = horizontal_spacing.value()/2; 813 } else if(col==(_cols-1)) { 814 wr = wrr; 815 x = width.value() - wrr; 816 lm = horizontal_spacing.value()/2; 817 rm = right_margin.value(); 818 } else { 819 wr = wri; 820 x = wrl + (col-1) * wri; 821 lm = horizontal_spacing.value()/2; 822 rm = horizontal_spacing.value()/2; 823 } 824 } 825 826 if(_rows==1) { 827 hr = height.value(); 828 y = 0; 829 tm = top_margin.value(); 830 bm = bottom_margin.value(); 831 } else { 832 float hrt = top_margin.value()+hdata+vertical_spacing.value()/2; //top 833 float hrb = bottom_margin.value()+hdata+vertical_spacing.value()/2; //bottom 834 float hri = hdata+vertical_spacing.value(); 835 if(row==0) { //top row. 836 hr = hrt; 837 y = height.value()-hrt; 838 tm = top_margin.value(); 839 bm = vertical_spacing.value()/2; 840 } else if(row==(_rows-1)) { 841 hr = hrb; 842 y = 0; 843 tm = vertical_spacing.value()/2; 844 bm = bottom_margin.value(); 845 } else { 846 hr = hri; 847 y = height.value()- (hrt + row * hri); 848 tm = vertical_spacing.value()/2; 849 bm = vertical_spacing.value()/2; 850 } 851 } 852 853 //m_extras_origins.push_back(vec2f(xo/xfac+x,yo/yfac+y)); 854 m_extras_origins.push_back(vec2f(x,y)); 855 m_extras_sizes.push_back(vec2f(wr,hr)); 856 857 separator* sep = _extra.m_sep; 858 plotter* _plotter = (plotter*)(*sep)[PLOTTER()]; 859 860 //_plotter->width = wr; 861 _plotter->left_margin = lm; 862 _plotter->right_margin = rm; 863 864 //_plotter->height = hr; 865 _plotter->top_margin = tm; 866 _plotter->bottom_margin = bm; 867 868 // ignore margins and spacings : 869 //float wr = w/_cols; 870 //float hr = h/_rows; 871 //float x = xo + col * wr; 872 //float y = yo + (rows-1-row) * hr; 873 //viewportRegion->setPositionPercent(x,y); 874 //viewportRegion->setSizePercent(wr,hr); 875 876 } //tools_vforcit 877 } 878 void configure_PAW(unsigned int a_ww,unsigned int a_wh) { 879 configure_grid_PAW(a_ww,a_wh); 880 configure_extras_PAW(a_ww,a_wh); 881 touch(); 882 update_if_touched(); 883 } 884 ////////////////////////////////////////////////////////////////////// 885 ////////////////////////////////////////////////////////////////////// 886 ////////////////////////////////////////////////////////////////////// 887 888 //gopaw: 889 void delete_extras() { 890 m_extras_sep.clear(); 891 m_extras.clear(); 892 } 893 894 plotter* create_extra_plotter(unsigned int a_cols,unsigned int a_rows,unsigned int a_index) { 895 // Create a plotter with size and position as if in a grid of a_colsxa_rows and at position a_index. 896 // The index numbering being for example for a grid of 3x2 : 897 // 0 1 2 898 // 3 4 5 899 m_extras.push_back(extra(a_cols,a_rows,a_index)); 900 update_if_touched(); 901 separator* sep = m_extras.back().m_sep; 902 return (plotter*)(*sep)[PLOTTER()]; 903 } 904 plotter* last_extra_plotter() const { 905 if(m_extras.empty()) return 0; 906 separator* sep = m_extras.back().m_sep; 907 return (plotter*)(*sep)[PLOTTER()]; 908 } 909 public: 910 void init_sg() { // used also in gopaw::base_viewer::clean_gstos(). 911 m_group.clear(); 912 m_sep.clear(); 913 m_border_sep.clear(); 914 m_extras_sep.clear(); 915 m_group.add(new noderef(m_sep)); 916 m_group.add(new noderef(m_border_sep)); 917 m_group.add(new noderef(m_extras_sep)); 918 } 919 void clear_sg() { //used in GL_plots_viewer. 920 m_group.clear(); 921 m_sep.clear(); 922 m_border_sep.clear(); 923 m_extras_sep.clear(); 924 } 925 protected: 926 void update_if_touched() { 927 if(touched()) { 928 update_sg(); 929 reset_touched(); 930 } 931 } 932 void update_sg(){ 933 934 if(m_sep.empty()||(cols.value()!=m_old_cols)||(rows.value()!=m_old_rows)){ 935 936 m_old_cols = cols; 937 m_old_rows = rows; 938 939 m_sep.clear(); 940 941 for(unsigned int irow=0;irow<rows;irow++) { 942 for(unsigned int icol=0;icol<cols;icol++) { 943 separator* sep = new separator; 944 m_sep.add(sep); 945 946 sep->add(new sg::matrix); //MATRIX() 947 948 //head_light* light = new head_light; 949 //light->direction = vec3f(1,-1,-10); 950 //light->on = false; 951 //sep->add(light); //LIGHT() 952 953 _switch* border = new _switch; 954 sep->add(border); //BORDER() 955 956 //matrix* tsf = new matrix; 957 //sep->add(tsf); //TSF() 958 959 sep->add(new plotter(m_ttf)); //PLOTTER() 960 } 961 } 962 963 if(m_current>=m_sep.size()) m_current = 0; 964 } 965 966 update_current_border(); 967 update_border(); 968 969 if((width.value()>0)&&(height.value()>0)) { 970 size_t _number = m_sep.size(); 971 972 bool configure = (m_origins.size()==_number)&&(m_sizes.size()==_number)?true:false; 973 974 // all window wc : 975 float ww_wc = width; 976 float wh_wc = height; 977 978 // plotter size in window wc : 979 //float rw_wc = ww_wc/cols; 980 //float rh_wc = wh_wc/rows; 981 982 for(size_t index=0;index<_number;index++) { 983 separator* sep = (separator*)m_sep[index]; 984 set_plotter_layout(*sep,index,configure,cols.value(),rows.value(), 985 ww_wc,wh_wc,m_origins,m_sizes,plotter_scale.value()); 986 } 987 } 988 989 update_extras(); 990 } 991 992 bool copy_plotters(const plots& a_from) { 993 update_if_touched(); 994 if(m_sep.size()==a_from.m_sep.size()) { 995 size_t _number = m_sep.size(); 996 for(size_t index=0;index<_number;index++) { 997 separator* _from_sep = (separator*)a_from.m_sep[index]; 998 matrix* _from_matrix = (matrix*)(*_from_sep)[MATRIX()]; 999 //_switch* _border = (_switch*)(*_sep)[BORDER()]; 1000 plotter* _from_plotter = (plotter*)(*_from_sep)[PLOTTER()]; 1001 1002 separator* _sep = (separator*)m_sep[index]; 1003 matrix* _matrix = (matrix*)(*_sep)[MATRIX()]; 1004 plotter* _plotter = (plotter*)(*_sep)[PLOTTER()]; 1005 1006 _matrix->operator=(*_from_matrix); 1007 _plotter->operator=(*_from_plotter); 1008 } 1009 } 1010 if(m_extras_sep.size()==a_from.m_extras_sep.size()) { 1011 size_t _number = m_extras_sep.size(); 1012 for(size_t index=0;index<_number;index++) { 1013 separator* _from_sep = (separator*)a_from.m_extras_sep[index]; 1014 matrix* _from_matrix = (matrix*)(*_from_sep)[MATRIX()]; 1015 plotter* _from_plotter = (plotter*)(*_from_sep)[PLOTTER()]; 1016 1017 separator* _sep = (separator*)m_extras_sep[index]; 1018 matrix* _matrix = (matrix*)(*_sep)[MATRIX()]; 1019 plotter* _plotter = (plotter*)(*_sep)[PLOTTER()]; 1020 1021 _matrix->operator=(*_from_matrix); 1022 _plotter->operator=(*_from_plotter); 1023 } 1024 } 1025 return true; 1026 } 1027 1028 static void create_plotter_border(_switch& a_parent,float a_w,float a_h) { 1029 a_parent.clear(); 1030 1031 group* sep = new group; 1032 a_parent.add(sep); 1033 1034 a_parent.add(new group()); //empty 1035 1036 rgba* mat = new rgba(); 1037 mat->color = colorf_red(); 1038 sep->add(mat); 1039 1040 draw_style* ds = new draw_style; 1041 ds->style = draw_lines; 1042 ds->line_width = 4; 1043 sep->add(ds); 1044 1045 vertices* vtxs = new vertices; 1046 vtxs->mode = gl::line_strip(); 1047 sep->add(vtxs); 1048 1049 float dw = a_w*0.5f; 1050 float dh = a_h*0.5f; 1051 vtxs->add(-dw,-dh,0); 1052 vtxs->add( dw,-dh,0); 1053 vtxs->add( dw, dh,0); 1054 vtxs->add(-dw, dh,0); 1055 vtxs->add(-dw,-dh,0); 1056 } 1057 1058 void update_current_border() { 1059 size_t _number = m_sep.size(); 1060 for(size_t index=0;index<_number;index++) { 1061 separator* sep = (separator*)m_sep[index]; 1062 _switch* _border = (_switch*)(*sep)[BORDER()]; 1063 if(index==m_current) { 1064 _border->which = view_border.value()?0:1; 1065 //if(m_updater) m_updater->update(*this,index); 1066 } else { 1067 _border->which = 1; 1068 } 1069 } 1070 } 1071 1072 void update_border() { 1073 m_border_sep.clear(); 1074 1075 if(!border_visible.value()) return; 1076 1077 if(width.value()<=0) return; 1078 if(height.value()<=0) return; 1079 if(border_width.value()<=0) return; 1080 if(border_height.value()<=0) return; 1081 1082 // border_scale could be used as an offscreen (inzb_[ps,png,jpeg], gl2s_pdf) 1083 // cooking to avoid seeing a one pixel line at some side (in general left) 1084 // coming from the border. 1085 if(border_scale.value()!=1) { 1086 matrix* _m = new matrix; 1087 _m->set_scale(border_scale.value(),border_scale.value(),1); 1088 m_border_sep.add(_m); 1089 } 1090 1091 float bw = border_width; 1092 float bh = border_height; 1093 1094 // do it with four externals back_area. 1095 1096 float zz = border_z.value(); 1097 1098 // top : 1099 {separator* sep = new separator; 1100 m_border_sep.add(sep); 1101 1102 float wba = width+2*bw; 1103 float hba = bh; 1104 float x = 0; 1105 float y = height*0.5f+bh*0.5f; 1106 1107 matrix* _m = new matrix; 1108 _m->set_translate(x,y,zz); 1109 sep->add(_m); 1110 1111 back_area* b = new back_area; 1112 b->border_visible = false; 1113 b->color = border_color; 1114 b->width = wba; 1115 b->height = hba; 1116 sep->add(b);} 1117 1118 // bottom : 1119 {separator* sep = new separator; 1120 m_border_sep.add(sep); 1121 1122 float wba = width+2*bw; 1123 float hba = bh; 1124 float x = 0; 1125 float y = -height*0.5f-bh*0.5f; 1126 1127 matrix* _m = new matrix; 1128 _m->set_translate(x,y,zz); 1129 sep->add(_m); 1130 1131 back_area* b = new back_area; 1132 b->border_visible = false; 1133 b->color = border_color; 1134 b->width = wba; 1135 b->height = hba; 1136 sep->add(b);} 1137 1138 // left : 1139 {separator* sep = new separator; 1140 m_border_sep.add(sep); 1141 1142 float wba = bw; 1143 float hba = height+2*bh; 1144 float x = -width*0.5f-bw*0.5f; 1145 float y = 0; 1146 1147 matrix* _m = new matrix; 1148 _m->set_translate(x,y,zz); 1149 sep->add(_m); 1150 1151 back_area* b = new back_area; 1152 b->border_visible = false; 1153 b->color = border_color; 1154 b->width = wba; 1155 b->height = hba; 1156 sep->add(b);} 1157 1158 // right : 1159 {separator* sep = new separator; 1160 m_border_sep.add(sep); 1161 1162 float wba = bw; 1163 float hba = height+2*bh; 1164 float x = width*0.5f+bw*0.5f; 1165 float y = 0; 1166 1167 matrix* _m = new matrix; 1168 _m->set_translate(x,y,zz); 1169 sep->add(_m); 1170 1171 back_area* b = new back_area; 1172 b->border_visible = false; 1173 b->color = border_color; 1174 b->width = wba; 1175 b->height = hba; 1176 sep->add(b);} 1177 1178 } 1179 protected: 1180 class extra { 1181 public: 1182 extra(unsigned int a_cols,unsigned int a_rows,unsigned int a_index) 1183 :m_cols(a_cols),m_rows(a_rows),m_index(a_index),m_sep(0){} 1184 virtual ~extra(){} 1185 public: 1186 extra(const extra& a_from):m_cols(a_from.m_cols),m_rows(a_from.m_rows),m_index(a_from.m_index),m_sep(0){} 1187 extra& operator=(const extra& a_from) { 1188 m_cols = a_from.m_cols; 1189 m_rows = a_from.m_rows; 1190 m_index = a_from.m_index; 1191 m_sep = a_from.m_sep; 1192 return *this; 1193 } 1194 public: 1195 unsigned int m_cols; 1196 unsigned int m_rows; 1197 unsigned int m_index; 1198 separator* m_sep; 1199 }; 1200 1201 void update_extras() { 1202 if(m_extras.size()!=m_extras_sep.size()) { 1203 m_extras_sep.clear(); 1204 tools_vforit(extra,m_extras,it) { // same sg layout than grid plotters. 1205 separator* sep = new separator; 1206 m_extras_sep.add(sep); 1207 (*it).m_sep = sep; //*it does not get ownership. 1208 1209 sep->add(new sg::matrix); //MATRIX() 1210 1211 //head_light* light = new head_light; 1212 //light->direction = vec3f(1,-1,-10); 1213 //light->on = false; 1214 //sep->add(light); //LIGHT() 1215 1216 _switch* border = new _switch; 1217 sep->add(border); //BORDER() 1218 1219 //matrix* tsf = new matrix; 1220 //sep->add(tsf); //TSF() 1221 1222 sep->add(new plotter(m_ttf)); //PLOTTER() 1223 } 1224 } 1225 1226 if(width.value()<=0) return; 1227 if(height.value()<=0) return; 1228 1229 // all window wc : 1230 float ww_wc = width; 1231 float wh_wc = height; 1232 1233 size_t _number = m_extras.size(); 1234 1235 bool configure = (m_extras_origins.size()==_number)&&(m_extras_sizes.size()==_number)?true:false; 1236 1237 tools_vforcit(extra,m_extras,it) { 1238 const extra& _extra = *it; 1239 unsigned int index = _extra.m_index; 1240 if(index>=(m_extras_sep.size())) index = 0; 1241 1242 separator* sep = _extra.m_sep; 1243 set_plotter_layout(*sep,index,configure,_extra.m_cols,_extra.m_rows, 1244 ww_wc,wh_wc,m_extras_origins,m_extras_sizes,plotter_scale.value()); 1245 } 1246 1247 } 1248 protected: 1249 static void set_plotter_layout(separator& a_sep,size_t a_index,bool a_configure, 1250 unsigned int a_cols,unsigned int a_rows, 1251 float a_ww_wc,float a_wh_wc, 1252 const std::vector<vec2f>& a_origins,const std::vector<vec2f>& a_sizes,float a_scale) { 1253 size_t row = a_index/a_cols; 1254 size_t col = a_index-a_cols*row; 1255 1256 float rw_wc = a_ww_wc/a_cols; 1257 float rh_wc = a_wh_wc/a_rows; 1258 1259 matrix* _matrix = (matrix*)(a_sep)[MATRIX()]; 1260 plotter* _plotter = (plotter*)(a_sep)[PLOTTER()]; 1261 1262 if(a_configure) { 1263 _plotter->width = a_sizes[a_index].x(); 1264 _plotter->height = a_sizes[a_index].y(); 1265 float x = -a_ww_wc*0.5f + a_origins[a_index].x() + _plotter->width*0.5f; 1266 float y = -a_wh_wc*0.5f + a_origins[a_index].y() + _plotter->height*0.5f; 1267 _matrix->set_translate(x,y,0); 1268 } else { 1269 float x = -a_ww_wc*0.5f + col * rw_wc + rw_wc * 0.5f; 1270 float y = a_wh_wc*0.5f - row * rh_wc - rh_wc * 0.5f; 1271 _matrix->set_translate(x,y,0); 1272 } 1273 _matrix->mul_scale(a_scale,a_scale,1); //applied first. 1274 1275 {_switch* _border = (_switch*)(a_sep)[BORDER()]; 1276 create_plotter_border(*_border,rw_wc,rh_wc); 1277 //_border->which = view_border.value()?(a_index==m_current?0:1):1; 1278 _border->which = 1; 1279 } 1280 1281 if(_plotter->shape.value()==plotter::xy) { 1282 _plotter->depth = min_of(rw_wc,rh_wc); 1283 } else { 1284 //if((rw_wc/rh_wc)>=1.0f) { 1285 // _plotter->depth = rh_wc; 1286 //} else { 1287 // _plotter->depth = rh_wc; 1288 //} 1289 _plotter->depth = rh_wc; 1290 } 1291 1292 if(a_configure) { 1293 } else { 1294 if(_plotter->shape.value()==plotter::xy) { 1295 _plotter->width = rw_wc; 1296 _plotter->height = rh_wc; 1297 } else { 1298 if((rw_wc/rh_wc)>=1.0f) { 1299 _plotter->width = rh_wc; 1300 _plotter->height = rh_wc; 1301 } else { 1302 _plotter->width = rw_wc; 1303 _plotter->height = rw_wc; 1304 } 1305 } 1306 } 1307 } 1308 protected: 1309 const base_freetype& m_ttf; 1310 1311 group m_group; 1312 separator m_sep; 1313 separator m_border_sep; 1314 separator m_extras_sep; 1315 unsigned int m_current; 1316 1317 std::vector<extra> m_extras; 1318 1319 //updater* m_updater; 1320 unsigned int m_old_cols; 1321 unsigned int m_old_rows; 1322 1323 std::vector<vec2f> m_origins; 1324 std::vector<vec2f> m_sizes; 1325 std::vector<vec2f> m_extras_origins; 1326 std::vector<vec2f> m_extras_sizes; 1327 1328 }; 1329 1330 }} 1331 1332 #endif