Reset parser in grace_set_project().
[grace.git] / src / drawticks.c
blob1f79bfda8644b620b12d51215942f3bb2fdeea6c
1 /*
2 * Grace - GRaphing, Advanced Computation and Exploration of data
3 *
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
5 *
6 * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7 * Copyright (c) 1996-2004 Grace Development Team
8 *
9 * Maintained by Evgeny Stambulchik
12 * All Rights Reserved
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 /*
30 * Draw axis bars, axis labels, ticks and tick labels
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
39 #include "utils.h"
40 #include "core_utils.h"
41 #include "plotone.h"
42 #include "parser.h"
44 static void drawgrid(Canvas *canvas, Quark *q)
46 Quark *gr;
47 tickmarks *t;
48 tickprops tprops;
49 int ttype;
50 world w;
51 view v;
52 double wtpos;
53 WPoint wp_grid_start, wp_grid_stop;
54 VPoint vp_grid_start, vp_grid_stop;
55 VPoint vpc, vp1, vp2;
56 double phi_start, phi_stop, rho;
57 double wc_start, wc_stop; /* world coordinates */
58 int ittype_loop, itick;
60 t = axis_get_data(q);
61 if (!t) {
62 return;
65 gr = get_parent_graph(q);
67 setclipping(canvas, TRUE);
69 /* TODO: add Pen to ticks and remove the following */
70 setpattern(canvas, 1);
72 graph_get_viewport(gr, &v);
73 graph_get_world(gr, &w);
75 /* graph center; for polar plots */
76 vpc.x = (v.xv1 + v.xv2)/2.0;
77 vpc.y = (v.yv1 + v.yv2)/2.0;
79 if (axis_is_x(q)) { /* an X-axis */
80 wc_start = w.xg1;
81 wc_stop = w.xg2;
82 wp_grid_start.y = w.yg1;
83 wp_grid_stop.y = w.yg2;
84 } else { /* a Y-axis */
85 wc_start = w.yg1;
86 wc_stop = w.yg2;
87 wp_grid_start.x = w.xg1;
88 wp_grid_stop.x = w.xg2;
91 for (ittype_loop = 0; ittype_loop < 2; ittype_loop++) {
92 if (ittype_loop == 0) { /* minor ticks */
93 ttype = TICK_TYPE_MINOR;
94 tprops = t->mprops;
95 } else { /* major ticks */
96 ttype = TICK_TYPE_MAJOR;
97 tprops = t->props;
99 if (tprops.gridflag == 0) {
100 continue;
103 setcolor(canvas, tprops.color);
104 setlinewidth(canvas, tprops.linew);
105 setlinestyle(canvas, tprops.lines);
107 for (itick = 0; itick < t->nticks; itick++) {
108 if (t->tloc[itick].type != ttype) {
109 continue;
112 wtpos = t->tloc[itick].wtpos;
114 if ((wtpos < wc_start) || (wtpos > wc_stop)) {
115 continue;
118 if (axis_is_x(q)) { /* an X-axis */
119 wp_grid_start.x = wtpos;
120 wp_grid_stop.x = wtpos;
121 } else { /* a Y-axis */
122 wp_grid_start.y = wtpos;
123 wp_grid_stop.y = wtpos;
126 Wpoint2Vpoint(gr, &wp_grid_start, &vp_grid_start);
127 Wpoint2Vpoint(gr, &wp_grid_stop, &vp_grid_stop);
130 if (!axis_is_x(q) && graph_get_type(gr) == GRAPH_POLAR) {
131 xy2polar(vp_grid_start.x - vpc.x, vp_grid_start.y - vpc.y,
132 &phi_start, &rho);
133 xy2polar(vp_grid_stop.x - vpc.x, vp_grid_stop.y - vpc.y,
134 &phi_stop, &rho);
135 vp1.x = vpc.x - rho;
136 vp1.y = vpc.y + rho;
137 vp2.x = vpc.x + rho;
138 vp2.y = vpc.y - rho;
139 if (graph_is_xinvert(gr) == TRUE) {
140 fswap(&phi_start, &phi_stop);
142 if (phi_stop < phi_start) {
143 phi_stop += 2*M_PI;
145 DrawArc(canvas, &vp1, &vp2, 180.0/M_PI*phi_start,
146 180.0/M_PI*(phi_stop - phi_start));
147 } else {
148 DrawLine(canvas, &vp_grid_start, &vp_grid_stop);
154 static void drawaxis(Canvas *canvas, Quark *q)
156 Quark *gr;
157 tickmarks *t;
158 tickprops tprops;
159 world w;
160 view v, bb;
161 double vbase1, vbase2, vbase1_start, vbase1_stop, vbase2_start, vbase2_stop;
162 double vbase_tlabel, vbase_tlabel1, vbase_tlabel2;
163 double tsize, tlsize, wtpos, vtpos;
164 double tl_offset, tl_trans;
165 WPoint wp1_start, wp1_stop, wp2_start, wp2_stop;
166 VPoint vp1_start, vp1_stop, vp2_start, vp2_stop;
167 VPoint vp_tick1_start, vp_tick1_stop, vp_tick2_start, vp_tick2_stop;
168 VPoint vp_tlabel, vp_label, vp_label_offset1, vp_label_offset2;
169 VPoint vpc, vp1, vp2;
170 double phi_start, phi_stop, rho;
171 VVector ort_para, ort_perp;
172 double wc_start, wc_stop, wc_start_labels, wc_stop_labels; /* world
173 coordinates */
174 int ittype_loop, itick, itcur;
175 int ttype;
176 char tlabel[MAX_STRING_LENGTH];
177 int tlabel1_just, tlabel2_just, label1_just, label2_just;
178 int langle;
180 int tick_dir_sign;
182 double (*coord_conv) (const Quark *gr, double wx);
184 t = axis_get_data(q);
185 if (!t) {
186 return;
189 setclipping(canvas, FALSE);
191 /* TODO: add Pen to ticks and remove the following */
192 setpattern(canvas, 1);
194 gr = get_parent_graph(q);
196 graph_get_viewport(gr, &v);
197 graph_get_world(gr, &w);
199 /* graph center; for polar plots */
200 vpc.x = (v.xv1 + v.xv2)/2.0;
201 vpc.y = (v.yv1 + v.yv2)/2.0;
204 if (t->zero == FALSE) {
205 tick_dir_sign = +1;
206 } else {
207 tick_dir_sign = -1;
210 if (axis_is_x(q)) { /* an X-axis */
211 ort_para.x = 1.0;
212 ort_para.y = 0.0;
213 ort_perp.x = 0.0;
214 ort_perp.y = 1.0;
216 coord_conv = xy_xconv;
218 wc_start = w.xg1;
219 wc_stop = w.xg2;
221 wp1_start.x = w.xg1;
222 wp1_stop.x = w.xg2;
223 wp2_start.x = w.xg1;
224 wp2_stop.x = w.xg2;
225 if (t->zero == TRUE) {
226 if (w.yg1 <= 0.0 && w.yg2 >= 0.0) {
227 wp1_start.y = 0.0;
228 wp1_stop.y = 0.0;
229 wp2_start.y = 0.0;
230 wp2_stop.y = 0.0;
231 } else {
232 return;
234 } else {
235 wp1_start.y = w.yg1;
236 wp1_stop.y = w.yg1;
237 wp2_start.y = w.yg2;
238 wp2_stop.y = w.yg2;
241 Wpoint2Vpoint(gr, &wp1_start, &vp1_start);
242 Wpoint2Vpoint(gr, &wp1_stop, &vp1_stop);
243 Wpoint2Vpoint(gr, &wp2_start, &vp2_start);
244 Wpoint2Vpoint(gr, &wp2_stop, &vp2_stop);
246 if (graph_is_yinvert(gr) == TRUE) {
247 vpswap(&vp1_start, &vp2_start);
248 vpswap(&vp1_stop, &vp2_stop);
251 /* TODO axis offset for polar plots */
252 if (graph_get_type(gr) != GRAPH_POLAR) {
253 vp1_start.y -= t->offsx;
254 vp1_stop.y -= t->offsx;
255 vp2_start.y += t->offsy;
256 vp2_stop.y += t->offsy;
259 vbase1 = vp1_start.y;
260 vbase2 = vp2_start.y;
262 tlabel1_just = JUST_CENTER|JUST_TOP;
263 tlabel2_just = JUST_CENTER|JUST_BOTTOM;
265 switch (t->label_layout) {
266 case LAYOUT_PARALLEL:
267 langle = 0;
268 break;
269 case LAYOUT_PERPENDICULAR:
270 langle = 90;
271 break;
272 default:
273 errmsg("Internal error in drawaxis()");
274 return;
276 } else { /* a Y-axis */
277 ort_para.x = 0.0;
278 ort_para.y = 1.0;
279 ort_perp.x = 1.0;
280 ort_perp.y = 0.0;
282 coord_conv = xy_yconv;
284 wc_start = w.yg1;
285 wc_stop = w.yg2;
287 wp1_start.y = w.yg1;
288 wp1_stop.y = w.yg2;
289 wp2_start.y = w.yg1;
290 wp2_stop.y = w.yg2;
292 if (t->zero == TRUE) {
293 if (w.xg1 <= 0.0 && w.xg2 >= 0.0) {
294 wp1_start.x = 0.0;
295 wp1_stop.x = 0.0;
296 wp2_start.x = 0.0;
297 wp2_stop.x = 0.0;
298 } else {
299 return;
301 } else {
302 wp1_start.x = w.xg1;
303 wp1_stop.x = w.xg1;
304 wp2_start.x = w.xg2;
305 wp2_stop.x = w.xg2;
308 Wpoint2Vpoint(gr, &wp1_start, &vp1_start);
309 Wpoint2Vpoint(gr, &wp1_stop, &vp1_stop);
310 Wpoint2Vpoint(gr, &wp2_start, &vp2_start);
311 Wpoint2Vpoint(gr, &wp2_stop, &vp2_stop);
313 if (graph_is_xinvert(gr) == TRUE) {
314 vpswap(&vp1_start, &vp2_start);
315 vpswap(&vp1_stop, &vp2_stop);
318 if (graph_get_type(gr) != GRAPH_POLAR) {
319 vp1_start.x -= t->offsx;
320 vp1_stop.x -= t->offsx;
321 vp2_start.x += t->offsy;
322 vp2_stop.x += t->offsy;
325 vbase1 = vp1_start.x;
326 vbase2 = vp2_start.x;
328 tlabel1_just = JUST_RIGHT|JUST_MIDDLE;
329 tlabel2_just = JUST_LEFT|JUST_MIDDLE;
331 switch (t->label_layout) {
332 case LAYOUT_PARALLEL:
333 langle = 90;
334 break;
335 case LAYOUT_PERPENDICULAR:
336 langle = 0;
337 break;
338 default:
339 errmsg("Internal error in drawaxis()");
340 return;
344 /* Begin axis bar stuff */
345 if (t->t_drawbar) {
346 setcolor(canvas, t->t_drawbarcolor);
347 setlinewidth(canvas, t->t_drawbarlinew);
348 setlinestyle(canvas, t->t_drawbarlines);
349 if (t->t_op == PLACEMENT_NORMAL || t->t_op == PLACEMENT_BOTH) {
350 if (axis_is_x(q) && graph_get_type(gr) == GRAPH_POLAR) {
351 xy2polar(vp1_start.x - vpc.x, vp1_start.y - vpc.y,
352 &phi_start, &rho);
353 xy2polar(vp1_stop.x - vpc.x, vp1_stop.y - vpc.y,
354 &phi_stop, &rho);
355 vp1.x = vpc.x - rho;
356 vp1.y = vpc.y + rho;
357 vp2.x = vpc.x + rho;
358 vp2.y = vpc.y - rho;
359 if (graph_is_xinvert(gr) == TRUE) {
360 fswap(&phi_start, &phi_stop);
362 if (phi_stop < phi_start) {
363 phi_stop += 2*M_PI;
365 DrawArc(canvas, &vp1, &vp2, 180.0/M_PI*phi_start,
366 180.0/M_PI*(phi_stop - phi_start));
367 } else {
368 DrawLine(canvas, &vp1_start, &vp1_stop);
371 if (t->t_op == PLACEMENT_OPPOSITE || t->t_op == PLACEMENT_BOTH) {
372 if (axis_is_x(q) && graph_get_type(gr) == GRAPH_POLAR) {
373 xy2polar(vp2_start.x - vpc.x, vp2_start.y - vpc.y,
374 &phi_start, &rho);
375 xy2polar(vp2_stop.x - vpc.x, vp2_stop.y - vpc.y,
376 &phi_stop, &rho);
377 vp1.x = vpc.x - rho;
378 vp1.y = vpc.y + rho;
379 vp2.x = vpc.x + rho;
380 vp2.y = vpc.y - rho;
381 if (graph_is_xinvert(gr) == TRUE) {
382 fswap(&phi_start, &phi_stop);
384 if (phi_stop < phi_start) {
385 phi_stop += 2*M_PI;
387 DrawArc(canvas, &vp1, &vp2, 180.0/M_PI*phi_start,
388 180.0/M_PI*(phi_stop - phi_start));
389 } else {
390 DrawLine(canvas, &vp2_start, &vp2_stop);
394 /* End axis bar stuff*/
397 /* TODO ticks, labels and axis labels for polar plots */
398 if (graph_get_type(gr) == GRAPH_POLAR) {
399 return;
402 activate_bbox(canvas, BBOX_TYPE_TEMP, TRUE);
403 reset_bbox(canvas, BBOX_TYPE_TEMP);
405 /* Begin axis tick stuff */
406 if (t->t_flag) {
407 for (ittype_loop = 0; ittype_loop < 2; ittype_loop++) {
409 if (ittype_loop == 0) { /* minor ticks */
410 ttype = TICK_TYPE_MINOR;
411 tprops = t->mprops;
412 } else { /* major ticks */
413 ttype = TICK_TYPE_MAJOR;
414 tprops = t->props;
416 tsize = 0.02 * tprops.size;
418 switch (tprops.inout) {
419 case TICKS_IN:
420 vbase1_start = vbase1;
421 vbase1_stop = vbase1 + tick_dir_sign*tsize;
422 vbase2_start = vbase2;
423 vbase2_stop = vbase2 - tick_dir_sign*tsize;
424 break;
425 case TICKS_OUT:
426 vbase1_start = vbase1;
427 vbase1_stop = vbase1 - tick_dir_sign*tsize;
428 vbase2_start = vbase2;
429 vbase2_stop = vbase2 + tick_dir_sign*tsize;
430 break;
431 case TICKS_BOTH:
432 vbase1_start = vbase1 - tsize;
433 vbase1_stop = vbase1 + tsize;
434 vbase2_start = vbase2 + tsize;
435 vbase2_stop = vbase2 - tsize;
436 break;
437 default:
438 errmsg("Internal error in drawaxis()");
439 return;
442 setcolor(canvas, tprops.color);
443 setlinewidth(canvas, tprops.linew);
444 setlinestyle(canvas, tprops.lines);
446 itcur = 0;
447 for (itick = 0; itick < t->nticks; itick++) {
448 if (t->tloc[itick].type != ttype) {
449 continue;
452 wtpos = t->tloc[itick].wtpos;
454 if ((wtpos < wc_start) || (wtpos > wc_stop)) {
455 continue;
458 vtpos = coord_conv(gr, wtpos);
459 if (t->t_op == PLACEMENT_NORMAL ||
460 t->t_op == PLACEMENT_BOTH) {
461 vp_tick1_start.x = vtpos*ort_para.x + vbase1_start*ort_perp.x;
462 vp_tick1_start.y = vtpos*ort_para.y + vbase1_start*ort_perp.y;
463 vp_tick1_stop.x = vtpos*ort_para.x + vbase1_stop*ort_perp.x;
464 vp_tick1_stop.y = vtpos*ort_para.y + vbase1_stop*ort_perp.y;
465 DrawLine(canvas, &vp_tick1_start, &vp_tick1_stop);
467 if (t->t_op == PLACEMENT_OPPOSITE ||
468 t->t_op == PLACEMENT_BOTH) {
469 vp_tick2_start.x = vtpos*ort_para.x + vbase2_start*ort_perp.x;
470 vp_tick2_start.y = vtpos*ort_para.y + vbase2_start*ort_perp.y;
471 vp_tick2_stop.x = vtpos*ort_para.x + vbase2_stop*ort_perp.x;
472 vp_tick2_stop.y = vtpos*ort_para.y + vbase2_stop*ort_perp.y;
473 DrawLine(canvas, &vp_tick2_start, &vp_tick2_stop);
475 itcur++;
479 /* End axis ticks stuff */
481 /* Make sure we don't end up with an empty BBox if no ticks have
482 been drawn */
483 vp1.x = v.xv1;
484 vp1.y = v.yv1;
485 vp2.x = v.xv2;
486 vp2.y = v.yv2;
487 update_bbox(canvas, BBOX_TYPE_TEMP, &vp1);
488 update_bbox(canvas, BBOX_TYPE_TEMP, &vp2);
490 /* Begin tick label stuff */
492 if(t->tl_gaptype==TYPE_AUTO) {
493 /* hard coded offsets for autoplacement of tick labels */
494 tl_trans=0.0; /* parallel */
495 tl_offset=0.01; /* perpendicular */
496 } else{
497 tl_trans = t->tl_gap.x;
498 tl_offset = t->tl_gap.y;
501 if (t->tl_flag) {
502 if (t->tl_starttype == TYPE_SPEC) {
503 wc_start_labels = t->tl_start;
504 } else {
505 wc_start_labels = wc_start;
508 if (t->tl_stoptype == TYPE_SPEC) {
509 wc_stop_labels = t->tl_stop;
510 } else {
511 wc_stop_labels = wc_stop;
514 tlsize = 0.02*t->tl_tprops.charsize;
516 tsize = 0.02*t->props.size;
518 switch (t->props.inout) {
519 case TICKS_IN:
520 vbase_tlabel1 = vbase1 - (1 - tick_dir_sign)/2*tsize - tl_offset;
521 vbase_tlabel2 = vbase2 + (1 - tick_dir_sign)/2*tsize + tl_offset;
522 break;
523 case TICKS_OUT:
524 vbase_tlabel1 = vbase1 - (1 + tick_dir_sign)/2*tsize - tl_offset;
525 vbase_tlabel2 = vbase2 + (1 + tick_dir_sign)/2*tsize + tl_offset;
526 break;
527 case TICKS_BOTH:
528 vbase_tlabel1 = vbase1 - tsize - tl_offset;
529 vbase_tlabel2 = vbase2 + tsize + tl_offset;
530 break;
531 default:
532 errmsg("Internal error in drawaxis()");
533 return;
536 itcur = 0;
537 for (itick = 0; itick < t->nticks; itick++) {
538 if (t->tloc[itick].type != TICK_TYPE_MAJOR) {
539 continue;
542 wtpos = t->tloc[itick].wtpos;
544 if ((wtpos < wc_start_labels) || (wtpos > wc_stop_labels)) {
545 continue;
548 if (t->tl_prestr[0]) {
549 strcpy(tlabel, t->tl_prestr);
550 } else {
551 tlabel[0] = '\0';
553 if (t->tloc[itick].label != NULL) {
554 strcat(tlabel, t->tloc[itick].label);
556 if (t->tl_appstr[0]) {
557 strcat(tlabel, t->tl_appstr);
560 vtpos = coord_conv(gr, wtpos);
562 if (itcur % (t->tl_skip + 1) == 0) {
563 TextProps tprops = t->tl_tprops;
564 /* Tick labels on normal side */
565 if (t->tl_op == PLACEMENT_NORMAL ||
566 t->tl_op == PLACEMENT_BOTH) {
567 vbase_tlabel = vbase_tlabel1 - (tl_offset + tlsize)*
568 (itcur % (t->tl_staggered + 1));
569 vp_tlabel.x = (vtpos + tl_trans)*ort_para.x +
570 vbase_tlabel*ort_perp.x;
571 vp_tlabel.y = (vtpos + tl_trans)*ort_para.y +
572 vbase_tlabel*ort_perp.y;
573 tprops.just = tlabel1_just;
574 drawtext(canvas, &vp_tlabel, &tprops, tlabel);
576 /* Tick labels on opposite side */
577 if (t->tl_op == PLACEMENT_OPPOSITE ||
578 t->tl_op == PLACEMENT_BOTH) {
579 vbase_tlabel = vbase_tlabel2 + (tl_offset + tlsize)*
580 (itcur % (t->tl_staggered + 1));
581 vp_tlabel.x = (vtpos + tl_trans)*ort_para.x +
582 vbase_tlabel*ort_perp.x;
583 vp_tlabel.y = (vtpos + tl_trans)*ort_para.y +
584 vbase_tlabel*ort_perp.y;
585 tprops.just = tlabel2_just;
586 drawtext(canvas, &vp_tlabel, &tprops, tlabel);
589 itcur++;
593 /* End tick label stuff */
595 get_bbox(canvas, BBOX_TYPE_TEMP, &bb);
597 /* Begin axis label stuff */
599 if (t->label_place == TYPE_SPEC) {
600 vp_label_offset1 = t->label_offset;
601 vp_label_offset2 = t->label_offset;
603 /* These settings are for backward compatibility */
604 label1_just = JUST_CENTER|JUST_MIDDLE;
605 label2_just = JUST_CENTER|JUST_MIDDLE;
606 } else {
607 /* parallel is trivial ;-) */
608 vp_label_offset1.x = 0.00;
609 vp_label_offset2.x = 0.00;
611 /* perpendicular */
612 if (axis_is_x(q)) {
613 vp_label_offset1.y = vbase1 - bb.yv1;
614 vp_label_offset2.y = bb.yv2 - vbase2;
615 } else {
616 vp_label_offset1.y = vbase1 - bb.xv1;
617 vp_label_offset2.y = bb.xv2 - vbase2;
620 vp_label_offset1.y += tl_offset;
621 vp_label_offset2.y += tl_offset;
623 label1_just = tlabel1_just;
624 label2_just = tlabel2_just;
627 if (!is_empty_string(t->label)) {
629 setcharsize(canvas, t->label_tprops.charsize);
630 setfont(canvas, t->label_tprops.font);
631 setcolor(canvas, t->label_tprops.color);
633 /* Axis label on normal side */
634 if (t->label_op == PLACEMENT_NORMAL ||
635 t->label_op == PLACEMENT_BOTH) {
637 vp_label.x = (vp1_start.x + vp1_stop.x)/2
638 + vp_label_offset1.x*ort_para.x
639 - vp_label_offset1.y*ort_perp.x;
640 vp_label.y = (vp1_start.y + vp1_stop.y)/2
641 + vp_label_offset1.x*ort_para.y
642 - vp_label_offset1.y*ort_perp.y;
644 WriteString(canvas, &vp_label, (double) langle, label1_just, t->label);
647 /* Axis label on opposite side */
648 if (t->label_op == PLACEMENT_OPPOSITE ||
649 t->label_op == PLACEMENT_BOTH) {
651 vp_label.x = (vp2_start.x + vp2_stop.x)/2
652 + vp_label_offset2.x*ort_para.x
653 + vp_label_offset2.y*ort_perp.x ;
654 vp_label.y = (vp2_start.y + vp2_stop.y)/2
655 + vp_label_offset2.x*ort_para.y
656 + vp_label_offset2.y*ort_perp.y ;
658 WriteString(canvas, &vp_label, (double) langle, label2_just, t->label);
662 /* End axis label stuff */
665 static void calculate_tickgrid(Quark *q)
667 Quark *gr;
668 int itick, imtick, itmaj;
669 int nmajor;
670 double swc_start, swc_stop, stmajor;
671 int scale;
672 double wtmaj;
673 world w;
674 tickmarks *t;
675 int res, len;
676 grarr *tvar;
677 double *tt;
679 t = axis_get_data(q);
681 if (!t) {
682 return;
685 gr = get_parent_graph(q);
687 graph_get_world(gr, &w);
689 reenter:
690 if (t->t_spec == TICKS_SPEC_NONE) {
691 if (axis_is_x(q)) {
692 scale = graph_get_xscale(gr);
693 if (scale == SCALE_LOG) {
694 swc_start = fscale(w.xg1, scale);
695 swc_stop = fscale(w.xg2, scale);
696 } else {
697 swc_start = w.xg1;
698 swc_stop = w.xg2;
700 } else {
701 scale = graph_get_yscale(gr);
702 if (scale == SCALE_LOG) {
703 swc_start = fscale(w.yg1, scale);
704 swc_stop = fscale(w.yg2, scale);
705 } else {
706 swc_start = w.yg1;
707 swc_stop = w.yg2;
710 if (scale == SCALE_LOG) {
711 stmajor = fscale(t->tmajor, scale);
712 } else {
713 stmajor = t->tmajor;
716 if (stmajor <= 0.0) {
717 errmsg("Invalid major tick spacing, autoticking");
718 axis_autotick(q);
719 goto reenter;
722 if (t->t_round == TRUE) {
723 swc_start = floor(swc_start/stmajor)*stmajor;
726 nmajor = (int) ceil((swc_stop - swc_start) / stmajor + 1);
727 t->nticks = (nmajor - 1)*(t->nminor + 1) + 1;
729 if (t->nticks > MAX_TICKS) {
730 errmsg("Too many ticks ( > MAX_TICKS ), autoticking");
731 axis_autotick(q);
732 goto reenter;
736 * if (t->nticks > MAX_TICKS) {
737 * t->nticks = MAX_TICKS;
741 itick = 0;
742 itmaj = 0;
743 while (itick < t->nticks) {
744 if (scale == SCALE_LOG) {
745 wtmaj = ifscale(swc_start + itmaj*stmajor, scale);
746 } else {
747 wtmaj = swc_start + itmaj*stmajor;
748 if (t->tl_format == FORMAT_GENERAL && fabs(wtmaj) < 1.0e-6*stmajor) {
749 wtmaj = 0.0;
752 t->tloc[itick].wtpos = wtmaj;
753 t->tloc[itick].type = TICK_TYPE_MAJOR;
755 itick++;
756 for (imtick = 0; imtick < t->nminor && itick < t->nticks; imtick++) {
757 if (scale == SCALE_LOG) {
758 t->tloc[itick].wtpos = wtmaj * (imtick + 2);
759 } else {
760 t->tloc[itick].wtpos = wtmaj + (imtick + 1)*stmajor/(t->nminor + 1);
762 t->tloc[itick].type = TICK_TYPE_MINOR;
763 XCFREE(t->tloc[itick].label);
764 itick++;
766 itmaj++;
770 if (t->t_spec != TICKS_SPEC_BOTH) {
771 nmajor = 0;
772 for (itick = 0; itick < t->nticks; itick++) {
773 if (t->tloc[itick].type == TICK_TYPE_MAJOR) {
774 nmajor++;
777 if (!is_empty_string(t->tl_formula)) {
779 tvar = get_parser_arr_by_name("$t");
780 if (tvar == NULL) {
781 tvar = define_parser_arr("$t");
782 if (tvar == NULL) {
783 errmsg("Internal error");
784 return;
788 if (tvar->length != 0) {
789 xfree(tvar->data);
790 tvar->length = 0;
792 tvar->data = xmalloc(nmajor*SIZEOF_DOUBLE);
793 if (tvar->data == NULL) {
794 return;
796 tvar->length = nmajor;
798 itmaj = 0;
799 for (itick = 0; itick < t->nticks; itick++) {
800 if (t->tloc[itick].type == TICK_TYPE_MAJOR) {
801 tvar->data[itmaj] = t->tloc[itick].wtpos;
802 itmaj++;
806 res = v_scanner(t->tl_formula, &len, &tt);
807 XCFREE(tvar->data);
808 tvar->length = 0;
809 if (res != RETURN_SUCCESS || len != nmajor) {
810 errmsg("Error in tick transformation formula");
811 return;
814 itmaj = 0;
815 for (itick = 0; itick < t->nticks; itick++) {
816 if (t->tloc[itick].type == TICK_TYPE_MAJOR) {
817 t->tloc[itick].label = copy_string(t->tloc[itick].label,
818 create_fstring(get_parent_project(q),
819 t->tl_format, t->tl_prec,
820 tt[itmaj], LFORMAT_TYPE_EXTENDED));
821 itmaj++;
824 xfree(tt);
825 } else {
826 for (itick = 0; itick < t->nticks; itick++) {
827 if (t->tloc[itick].type == TICK_TYPE_MAJOR) {
828 t->tloc[itick].label = copy_string(t->tloc[itick].label,
829 create_fstring(get_parent_project(q),
830 t->tl_format, t->tl_prec,
831 t->tloc[itick].wtpos, LFORMAT_TYPE_EXTENDED));
838 void draw_axis(Canvas *canvas, Quark *q)
840 tickmarks *t = axis_get_data(q);
841 if (t && graph_get_type(get_parent_graph(q)) != GRAPH_PIE) {
842 /* calculate tick mark positions */
843 calculate_tickgrid(q);
845 /* draw grid lines */
846 drawgrid(canvas, q);
848 /* draw the rest */
849 drawaxis(canvas, q);