tioga 1.9 → 1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -55,15 +55,23 @@ DECLARE_SYMBOL(void, Dvector_Push_Double, (VALUE ary, double val));
55
55
 
56
56
 
57
57
  /* functions for interpolation */
58
- DECLARE_SYMBOL(double, c_dvector_spline_interpolate,
59
- (double x, int n_pts_data, double *Xs, double *Ys,
60
- double *Bs, double *Cs, double *Ds));
61
- DECLARE_SYMBOL(double, c_dvector_linear_interpolate,
62
- (int num_pts, double *xs, double *ys, double x));
63
58
  DECLARE_SYMBOL(void, c_dvector_create_spline_interpolant,
64
59
  (int n_pts_data, double *Xs, double *Ys,
65
60
  bool start_clamped, double start_slope,
66
61
  bool end_clamped, double end_slope,
67
62
  double *As, double *Bs, double *Cs));
63
+ DECLARE_SYMBOL(double, c_dvector_spline_interpolate,
64
+ (double x, int n_pts_data, double *Xs, double *Ys,
65
+ double *Bs, double *Cs, double *Ds));
66
+
67
+ DECLARE_SYMBOL(void, c_dvector_create_pm_cubic_interpolant,
68
+ (int n_pts_data, double *Xs, double *Ys,
69
+ double *As, double *Bs, double *Cs));
70
+ DECLARE_SYMBOL(double, c_dvector_pm_cubic_interpolate,
71
+ (double x, int n_pts_data, double *Xs, double *Ys,
72
+ double *Bs, double *Cs, double *Ds));
73
+
74
+ DECLARE_SYMBOL(double, c_dvector_linear_interpolate,
75
+ (int num_pts, double *xs, double *ys, double x));
68
76
  #endif /* __Dvector_H__ */
69
77
 
@@ -49,6 +49,9 @@
49
49
  #ifndef MIN
50
50
  #define MIN(a,b) (((a) < (b)) ? (a) : (b))
51
51
  #endif
52
+ #ifndef SIGN
53
+ #define SIGN(a) (((a) > 0) ? 1 : -1)
54
+ #endif
52
55
 
53
56
 
54
57
 
@@ -1068,7 +1071,8 @@ PRIVATE
1068
1071
  * call-seq:
1069
1072
  * dvector.min_gt(val) -> float or nil
1070
1073
  *
1071
- * Returns the minimum entry in _dvector_ which is greater than _val_, or <code>nil</code> if no such entry if found.
1074
+ * Returns the minimum entry in _dvector_ which is greater than _val_,
1075
+ * or <code>nil</code> if no such entry if found.
1072
1076
  */ VALUE dvector_min_gt(VALUE ary, VALUE val) {
1073
1077
  Dvector *d = Get_Dvector(ary);
1074
1078
  val = rb_Float(val);
@@ -1092,7 +1096,8 @@ PRIVATE
1092
1096
  * call-seq:
1093
1097
  * dvector.max_lt(val) -> float or nil
1094
1098
  *
1095
- * Returns the maximum entry in _dvector_ which is less than _val_, or <code>nil</code> if no such entry if found.
1099
+ * Returns the maximum entry in _dvector_ which is less than _val_,
1100
+ * or <code>nil</code> if no such entry if found.
1096
1101
  */ VALUE dvector_max_lt(VALUE ary, VALUE val) {
1097
1102
  Dvector *d = Get_Dvector(ary);
1098
1103
  val = rb_Float(val);
@@ -1390,7 +1395,8 @@ PRIVATE
1390
1395
  Dvector *d2 = Get_Dvector(ary2);
1391
1396
  long len = d->len;
1392
1397
  if (len != d2->len) {
1393
- rb_raise(rb_eArgError, "vectors with different lengths (%d vs %d) for reverse_each2_with_index", len, d2->len);
1398
+ rb_raise(rb_eArgError, "vectors with different lengths (%d vs %d) for reverse_each2_with_index",
1399
+ len, d2->len);
1394
1400
  }
1395
1401
  while (len--) {
1396
1402
  rb_yield_values(3, rb_float_new(d->ptr[len]), rb_float_new(d2->ptr[len]), LONG2NUM(len));
@@ -1687,8 +1693,10 @@ PRIVATE
1687
1693
  * call-seq:
1688
1694
  * dvector.dup -> a_dvector
1689
1695
  *
1690
- * Returns a copy of _dvector_. For performance sensitive situations involving a series of vector operations,
1691
- * first make a copy using dup and then do "bang" operations to modify the result without further copying.
1696
+ * Returns a copy of _dvector_.
1697
+ * For performance sensitive situations involving a series of vector operations,
1698
+ * first make a copy using dup and then do "bang" operations to modify the result
1699
+ * without further copying.
1692
1700
  */ VALUE dvector_dup(VALUE ary) {
1693
1701
  Dvector *d = Get_Dvector(ary);
1694
1702
  return dvector_new4_dbl(d->len, d->ptr);
@@ -1700,7 +1708,8 @@ PRIVATE
1700
1708
  * dvector.collect {|x| block } -> a_dvector
1701
1709
  * dvector.map {|x| block } -> a_dvector
1702
1710
  *
1703
- * Invokes <i>block</i> once for each element of _dvector_. Returns a new vector holding the values returned by _block_.
1711
+ * Invokes <i>block</i> once for each element of _dvector_.
1712
+ * Returns a new vector holding the values returned by _block_.
1704
1713
  * Note that for numeric operations on long vectors, it is more efficient to
1705
1714
  * apply the operator directly to the vector rather than using map or collect.
1706
1715
  *
@@ -4896,7 +4905,8 @@ PRIVATE
4896
4905
  * Replaces contents of _dvector_ by control points for Bezier curve.
4897
4906
  * The cubic, y(x), is defined from x0 to x0+delta_x.
4898
4907
  * At location x = x0 + dx, with dx between 0 and delta_x, define y = a*dx^3 + b*dx^2 + c*dx + y0.
4899
- * This routine replaces the contents of _dest_ by [x1, y1, x2, y2, x3, y3], the Bezier control points to match this cubic.
4908
+ * This routine replaces the contents of _dest_ by [x1, y1, x2, y2, x3, y3],
4909
+ * the Bezier control points to match this cubic.
4900
4910
  *
4901
4911
  */
4902
4912
  VALUE dvector_make_bezier_control_points_for_cubic_in_x(VALUE dest, VALUE x0, VALUE y0, VALUE delta_x, VALUE a, VALUE b, VALUE c)
@@ -4911,6 +4921,162 @@ VALUE dvector_make_bezier_control_points_for_cubic_in_x(VALUE dest, VALUE x0, VA
4911
4921
  NUM2DBL(x0), NUM2DBL(y0), NUM2DBL(delta_x), NUM2DBL(a), NUM2DBL(b), NUM2DBL(c));
4912
4922
  }
4913
4923
 
4924
+
4925
+
4926
+
4927
+
4928
+ void c_dvector_create_pm_cubic_interpolant(int nx, double *x, double *f,
4929
+ double *As, double *Bs, double *Cs)
4930
+ {
4931
+ double *h = (double *)ALLOC_N(double, nx);
4932
+ double *s = (double *)ALLOC_N(double, nx);
4933
+ double *p = (double *)ALLOC_N(double, nx);
4934
+ double as00, asm1, ap00, sm1, s00;
4935
+ int n = nx-1, i;
4936
+
4937
+
4938
+ for (i=0; i < n; i++) {
4939
+ h[i] = x[i+1] - x[i];
4940
+ s[i] = (f[i+1] - f[i])/h[i];
4941
+ }
4942
+
4943
+ /* slope at i of parabola through i-1, i, and i+1 */
4944
+ for (i=1; i < n; i++) {
4945
+ p[i] = (s[i-1]*h[i] + s[i]*h[i-1])/(h[i]+h[i-1]);
4946
+ }
4947
+
4948
+ /* "safe" slope at i to ensure monotonic -- see Steffen paper for explanation. */
4949
+ for (i=1; i < n; i++) {
4950
+ asm1 = fabs(s[i-1]);
4951
+ as00 = fabs(s[i]);
4952
+ ap00 = fabs(p[i]);
4953
+ sm1 = (s[i-1] > 0)? 1.0 : -1.0;
4954
+ s00 = (s[i] > 0)? 1.0 : -1.0;
4955
+ Cs[i] = (sm1+s00)*MIN(asm1, MIN(as00, 0.5*ap00));
4956
+ }
4957
+
4958
+ /* slope at 1st point of parabola through 1st 3 points */
4959
+ p[0] = s[0]*(1 + h[0] / (h[0] + h[1])) - s[1] * h[0] / (h[0] + h[1]);
4960
+
4961
+ /* safe slope at 1st point */
4962
+ if (p[0]*s[0] <= 0) {
4963
+ Cs[0] = 0;
4964
+ } else if (fabs(p[0]) > 2.0*fabs(s[0])) {
4965
+ Cs[0] = 2.0*s[0];
4966
+ } else {
4967
+ Cs[0] = p[0];
4968
+ }
4969
+
4970
+ /* slope at last point of parabola through last 3 points */
4971
+ p[n] = s[n-1]*(1 + h[n-1] / (h[n-1] + h[n-2])) - s[n-2]*h[n-1] / (h[n-1] + h[n-2]);
4972
+
4973
+ /* safe slope at last point */
4974
+ if (p[n]*s[n-1] <= 0) {
4975
+ Cs[n] = 0;
4976
+ } else if (fabs(p[n]) > 2.0*fabs(s[n-1])) {
4977
+ Cs[n] = 2.0*s[n-1];
4978
+ } else {
4979
+ Cs[n] = p[n];
4980
+ }
4981
+
4982
+ for (i=0; i < n; i++) {
4983
+ Bs[i] = (3.0*s[i] - 2.0*Cs[i] - Cs[i+1]) / h[i];
4984
+ }
4985
+ Bs[n] = 0;
4986
+
4987
+ for (i=1; i < n; i++) {
4988
+ As[i] = (Cs[i] + Cs[i+1] - 2.0*s[i]) / (h[i]*h[i]);
4989
+ }
4990
+ As[n] = 0;
4991
+
4992
+ free(p); free(s); free(h);
4993
+ }
4994
+
4995
+ PRIVATE
4996
+ /*
4997
+ * call-seq:
4998
+ * Dvector.create_pm_cubic_interpolant(xs, ys) -> interpolant
4999
+ *
5000
+ * Uses Dvectors _xs_ and _ys_ to create a cubic pm_cubic interpolant. The _xs_ must be given in ascending order.
5001
+ * The interpolant is an array of Dvectors: [Xs, Ys, As, Bs, Cs].
5002
+ * For x between Xs[j] and Xs[j+1], let dx = x - Xs[j], and find interpolated y for x by
5003
+ * y = As[j]*dx^3 + Bs[j]*dx^2 + Cs[j]*dx + Ys[j].
5004
+ * pm_cubic algorithms derived from Steffen, M., "A simple method for monotonic interpolation in one dimension",
5005
+ * Astron. Astrophys., (239) 1990, 443-450.
5006
+ *
5007
+ */
5008
+ VALUE dvector_create_pm_cubic_interpolant(int argc, VALUE *argv, VALUE klass) {
5009
+ if (argc != 2)
5010
+ rb_raise(rb_eArgError, "wrong # of arguments(%d) for create_pm_cubic_interpolant", argc);
5011
+ klass = Qnil;
5012
+ VALUE Xs = argv[0], Ys = argv[1];
5013
+ long xdlen, ydlen;
5014
+ double start = 0.0, end = 0.0;
5015
+ double *X_data = Dvector_Data_for_Read(Xs, &xdlen);
5016
+ double *Y_data = Dvector_Data_for_Read(Ys, &ydlen);
5017
+ if (X_data == NULL || Y_data == NULL || xdlen != ydlen)
5018
+ rb_raise(rb_eArgError, "Data for create_pm_cubic_interpolant must be equal length Dvectors");
5019
+ int nx = xdlen;
5020
+ VALUE As = Dvector_Create(), Bs = Dvector_Create(), Cs = Dvector_Create();
5021
+ double *As_data = Dvector_Data_Resize(As, nx);
5022
+ double *Bs_data = Dvector_Data_Resize(Bs, nx);
5023
+ double *Cs_data = Dvector_Data_Resize(Cs, nx);
5024
+ c_dvector_create_pm_cubic_interpolant(nx, X_data, Y_data, As_data, Bs_data, Cs_data);
5025
+ VALUE result = rb_ary_new2(5);
5026
+ rb_ary_store(result, 0, Xs);
5027
+ rb_ary_store(result, 1, Ys);
5028
+ rb_ary_store(result, 2, As);
5029
+ rb_ary_store(result, 3, Bs);
5030
+ rb_ary_store(result, 4, Cs);
5031
+ return result;
5032
+ }
5033
+
5034
+ double c_dvector_pm_cubic_interpolate(double x, int nx,
5035
+ double *Xs, double *Ys, double *As, double *Bs, double *Cs)
5036
+ {
5037
+ int j;
5038
+ for (j = 0; j < nx && x >= Xs[j]; j++);
5039
+ if (j == nx) return Ys[j-1];
5040
+ if (j == 0) return Ys[0];
5041
+ j--;
5042
+ double dx = x - Xs[j];
5043
+ return Ys[j] + dx*(Cs[j] + dx*(Bs[j] + dx*As[j]));
5044
+ }
5045
+
5046
+ PRIVATE
5047
+ /*
5048
+ * call-seq:
5049
+ * Dvector.pm_cubic_interpolate(x, interpolant) -> y
5050
+ *
5051
+ * Returns the _y_ corresponding to _x_ by pm_cubic interpolation using the _interpolant_
5052
+ * which was previously created by calling _create_pm_cubic_interpolant_.
5053
+ *
5054
+ */
5055
+ VALUE dvector_pm_cubic_interpolate(int argc, VALUE *argv, VALUE klass) {
5056
+ if (argc != 2)
5057
+ rb_raise(rb_eArgError, "wrong # of arguments(%d) for pm_cubic_interpolate", argc);
5058
+ klass = Qnil;
5059
+ VALUE x = argv[0];
5060
+ VALUE interpolant = argv[1];
5061
+ x = rb_Float(x);
5062
+ interpolant = rb_Array(interpolant);
5063
+ if (RARRAY(interpolant)->len != 5)
5064
+ rb_raise(rb_eArgError, "interpolant must be array of length 5 from create_pm_cubic_interpolant");
5065
+ Dvector *Xs = Get_Dvector(rb_ary_entry(interpolant,0));
5066
+ Dvector *Ys = Get_Dvector(rb_ary_entry(interpolant,1));
5067
+ Dvector *As = Get_Dvector(rb_ary_entry(interpolant,2));
5068
+ Dvector *Bs = Get_Dvector(rb_ary_entry(interpolant,3));
5069
+ Dvector *Cs = Get_Dvector(rb_ary_entry(interpolant,4));
5070
+ if (Xs->len <= 0 || Xs->len != Ys->len || Xs->len != Bs->len || Xs->len != Cs->len || Xs->len != As->len)
5071
+ rb_raise(rb_eArgError, "interpolant must be from create_pm_cubic_interpolant");
5072
+ double y = c_dvector_pm_cubic_interpolate(NUM2DBL(x), Xs->len, Xs->ptr, Ys->ptr, As->ptr, Bs->ptr, Cs->ptr);
5073
+ return rb_float_new(y);
5074
+ }
5075
+
5076
+
5077
+
5078
+
5079
+
4914
5080
  void c_dvector_create_spline_interpolant(int n_pts_data, double *Xs, double *Ys,
4915
5081
  bool start_clamped, double start_slope, bool end_clamped, double end_slope,
4916
5082
  double *As, double *Bs, double *Cs)
@@ -5319,7 +5485,8 @@ static VALUE dvector_convolve(VALUE self, VALUE kernel, VALUE middle)
5319
5485
  :call-seq:
5320
5486
  Dvector.fast_fancy_read(stream, options) => Array_of_Dvectors
5321
5487
 
5322
- Reads data from an IO stream and separate it into columns of data
5488
+ Reads data from an IO stream (or anything that supports a gets method)
5489
+ and separate it into columns of data
5323
5490
  according to the _options_, a hash holding the following elements
5324
5491
  (compulsory, but you can use FANCY_READ_DEFAULTS):
5325
5492
  * 'sep': a regular expression that separate the entries
@@ -5333,8 +5500,6 @@ static VALUE dvector_convolve(VALUE self, VALUE kernel, VALUE middle)
5333
5500
 
5334
5501
  As a side note, the read time is highly non-linear, which suggests that
5335
5502
  the read is memory-allocation/copying-limited, at least for big files.
5336
- Well, the read time is non-linear for
5337
-
5338
5503
 
5339
5504
  An internal memory allocation with aggressive policy should solve that,
5340
5505
  that is, not using directly Dvectors (and it would be way faster to store
@@ -5534,6 +5699,10 @@ void Init_Dvector() {
5534
5699
  rb_define_singleton_method(cDvector, "read_row", dvector_read_row, -1);
5535
5700
  rb_define_singleton_method(cDvector, "create_spline_interpolant", dvector_create_spline_interpolant, -1);
5536
5701
  rb_define_singleton_method(cDvector, "spline_interpolate", dvector_spline_interpolate, -1);
5702
+
5703
+ rb_define_singleton_method(cDvector, "create_pm_cubic_interpolant", dvector_create_pm_cubic_interpolant, -1);
5704
+ rb_define_singleton_method(cDvector, "pm_cubic_interpolate", dvector_pm_cubic_interpolate, -1);
5705
+
5537
5706
  rb_define_singleton_method(cDvector, "linear_interpolate", dvector_linear_interpolate, -1);
5538
5707
  rb_define_singleton_method(cDvector, "min_of_many", dvector_min_of_many, 1);
5539
5708
  rb_define_singleton_method(cDvector, "max_of_many", dvector_max_of_many, 1);
@@ -135,6 +135,18 @@ PRIVATE double c_dvector_spline_interpolate(double x, int n_pts_data,
135
135
  double *Xs, double *Ys, double *Bs, double *Cs, double *Ds);
136
136
  PRIVATE VALUE dvector_spline_interpolate(int argc, VALUE *argv, VALUE klass);
137
137
 
138
+
139
+
140
+ PRIVATE void c_dvector_create_pm_cubic_interpolant(int n_pts_data, double *Xs, double *Ys,
141
+ double *Bs, double *Cs, double *Ds);
142
+ PRIVATE VALUE dvector_create_pm_cubic_interpolant(int argc, VALUE *argv, VALUE klass);
143
+
144
+ PRIVATE double c_dvector_pm_cubic_interpolate(double x, int n_pts_data,
145
+ double *Xs, double *Ys, double *Bs, double *Cs, double *Ds);
146
+ PRIVATE VALUE dvector_pm_cubic_interpolate(int argc, VALUE *argv, VALUE klass);
147
+
148
+
149
+
138
150
  PRIVATE double c_dvector_linear_interpolate(int num_pts, double *xs, double *ys, double x);
139
151
  PRIVATE VALUE dvector_linear_interpolate(int argc, VALUE *argv, VALUE klass);
140
152
 
@@ -55,15 +55,23 @@ DECLARE_SYMBOL(void, Dvector_Push_Double, (VALUE ary, double val));
55
55
 
56
56
 
57
57
  /* functions for interpolation */
58
- DECLARE_SYMBOL(double, c_dvector_spline_interpolate,
59
- (double x, int n_pts_data, double *Xs, double *Ys,
60
- double *Bs, double *Cs, double *Ds));
61
- DECLARE_SYMBOL(double, c_dvector_linear_interpolate,
62
- (int num_pts, double *xs, double *ys, double x));
63
58
  DECLARE_SYMBOL(void, c_dvector_create_spline_interpolant,
64
59
  (int n_pts_data, double *Xs, double *Ys,
65
60
  bool start_clamped, double start_slope,
66
61
  bool end_clamped, double end_slope,
67
62
  double *As, double *Bs, double *Cs));
63
+ DECLARE_SYMBOL(double, c_dvector_spline_interpolate,
64
+ (double x, int n_pts_data, double *Xs, double *Ys,
65
+ double *Bs, double *Cs, double *Ds));
66
+
67
+ DECLARE_SYMBOL(void, c_dvector_create_pm_cubic_interpolant,
68
+ (int n_pts_data, double *Xs, double *Ys,
69
+ double *As, double *Bs, double *Cs));
70
+ DECLARE_SYMBOL(double, c_dvector_pm_cubic_interpolate,
71
+ (double x, int n_pts_data, double *Xs, double *Ys,
72
+ double *Bs, double *Cs, double *Ds));
73
+
74
+ DECLARE_SYMBOL(double, c_dvector_linear_interpolate,
75
+ (int num_pts, double *xs, double *ys, double x));
68
76
  #endif /* __Dvector_H__ */
69
77
 
@@ -33,9 +33,28 @@ module Dobjects
33
33
  #
34
34
  # e = MathEvaluator.new("x*y", "x,y")
35
35
  # e.compute(1,2) -> 2
36
+ #
37
+ # If an exception arises, NaN is returned. Note that compilation
38
+ # problems will be caught before ;-)...
36
39
  def compute(*args)
40
+ begin
41
+ return compute_unsafe(*args)
42
+ rescue
43
+ return 0.0/0.0
44
+ end
45
+ end
46
+
47
+ # This function does the actual evaluation with the blocks
48
+ # given.
49
+ #
50
+ # e = MathEvaluator.new("x*y", "x,y")
51
+ # e.compute(1,2) -> 2
52
+ #
53
+ # No care is taken to intercept exceptions.
54
+ def compute_unsafe(*args)
37
55
  return @block.call(*args)
38
56
  end
57
+
39
58
  end
40
59
 
41
60
  class Dvector
@@ -55,15 +55,23 @@ DECLARE_SYMBOL(void, Dvector_Push_Double, (VALUE ary, double val));
55
55
 
56
56
 
57
57
  /* functions for interpolation */
58
- DECLARE_SYMBOL(double, c_dvector_spline_interpolate,
59
- (double x, int n_pts_data, double *Xs, double *Ys,
60
- double *Bs, double *Cs, double *Ds));
61
- DECLARE_SYMBOL(double, c_dvector_linear_interpolate,
62
- (int num_pts, double *xs, double *ys, double x));
63
58
  DECLARE_SYMBOL(void, c_dvector_create_spline_interpolant,
64
59
  (int n_pts_data, double *Xs, double *Ys,
65
60
  bool start_clamped, double start_slope,
66
61
  bool end_clamped, double end_slope,
67
62
  double *As, double *Bs, double *Cs));
63
+ DECLARE_SYMBOL(double, c_dvector_spline_interpolate,
64
+ (double x, int n_pts_data, double *Xs, double *Ys,
65
+ double *Bs, double *Cs, double *Ds));
66
+
67
+ DECLARE_SYMBOL(void, c_dvector_create_pm_cubic_interpolant,
68
+ (int n_pts_data, double *Xs, double *Ys,
69
+ double *As, double *Bs, double *Cs));
70
+ DECLARE_SYMBOL(double, c_dvector_pm_cubic_interpolate,
71
+ (double x, int n_pts_data, double *Xs, double *Ys,
72
+ double *Bs, double *Cs, double *Ds));
73
+
74
+ DECLARE_SYMBOL(double, c_dvector_linear_interpolate,
75
+ (int num_pts, double *xs, double *ys, double x));
68
76
  #endif /* __Dvector_H__ */
69
77
 
data/split/Tioga/axes.c CHANGED
@@ -20,19 +20,15 @@
20
20
  along with Tioga; if not, write to the Free Software
21
21
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
22
  */
23
+ #include <math.h>
24
+
23
25
  #include "figures.h"
24
26
  #include "pdfs.h"
25
27
 
28
+
29
+
26
30
  /*
27
31
  Here is my (Vincent) big TODO-list for the axes stuff:
28
- * provide a way to reliably get the location from major/minor
29
- ticks for a given axis, so users can build lines/grids that build on
30
- top of that (or rather under it ;-)...)
31
- -> this is partly done, as you can now get the major ticks position.
32
- * let the users choose between the current way to pick up ticks position
33
- and another, such as the one I'm using in SciYAG, which seems to give
34
- results that are more according to my expectations.
35
-
36
32
  * BUG fix: apparently, two calls to the axes stuff do no return the
37
33
  same thing, so I'll need to have a careful look at that
38
34
  */
@@ -41,9 +37,17 @@ typedef struct {
41
37
  int type;
42
38
  int other_axis_type;
43
39
  double line_width;
40
+
41
+ /* Stroke color... */
44
42
  double stroke_color_R;
45
43
  double stroke_color_G;
46
44
  double stroke_color_B;
45
+
46
+ /* Tick labels color */
47
+ double labels_color_R;
48
+ double labels_color_G;
49
+ double labels_color_B;
50
+
47
51
  double major_tick_width; // same units as line_width
48
52
  double minor_tick_width; // same units as line_width
49
53
  double major_tick_length; // in units of numeric label char heights
@@ -127,6 +131,11 @@ static void Get_xaxis_Specs(OBJ_PTR fmkr, FM *p, PlotAxis *s, int *ierr)
127
131
  s->stroke_color_R = p->xaxis_stroke_color_R; // for axis line and tick marks
128
132
  s->stroke_color_G = p->xaxis_stroke_color_G;
129
133
  s->stroke_color_B = p->xaxis_stroke_color_B;
134
+
135
+ s->labels_color_R = p->xaxis_labels_color_R; // for axis line and tick marks
136
+ s->labels_color_G = p->xaxis_labels_color_G;
137
+ s->labels_color_B = p->xaxis_labels_color_B;
138
+
130
139
  s->major_tick_width = p->xaxis_major_tick_width; // same units as line_width
131
140
  s->minor_tick_width = p->xaxis_minor_tick_width; // same units as line_width
132
141
  s->major_tick_length = p->xaxis_major_tick_length; // in units of numeric label char heights
@@ -163,9 +172,15 @@ static void Get_yaxis_Specs(OBJ_PTR fmkr, FM *p, PlotAxis *s, int *ierr)
163
172
  s->type = p->yaxis_type;
164
173
  s->other_axis_type = p->xaxis_type;
165
174
  s->line_width = p->yaxis_line_width; // for axis line
175
+
166
176
  s->stroke_color_R = p->yaxis_stroke_color_R; // for axis line and tick marks
167
177
  s->stroke_color_G = p->yaxis_stroke_color_G;
168
178
  s->stroke_color_B = p->yaxis_stroke_color_B;
179
+
180
+ s->labels_color_R = p->yaxis_labels_color_R; // for axis line and tick marks
181
+ s->labels_color_G = p->yaxis_labels_color_G;
182
+ s->labels_color_B = p->yaxis_labels_color_B;
183
+
169
184
  s->major_tick_width = p->yaxis_major_tick_width; // same units as line_width
170
185
  s->minor_tick_width = p->yaxis_minor_tick_width; // same units as line_width
171
186
  s->major_tick_length = p->yaxis_major_tick_length; // in units of numeric label char heights
@@ -635,16 +650,21 @@ static double * pick_major_ticks_positions_Vincent(OBJ_PTR fmkr, FM *p,
635
650
  double norm_tick_min = tick_min/factor;
636
651
  int i;
637
652
 
653
+ /* printf("axis_min: %g\taxis_max: %g\n", axis_min, axis_max); */
638
654
  /* We get the one just above tick_min */
639
655
  for(i = 0; i < nb_natural_distances; i++)
640
656
  if(natural_distances[i] >= norm_tick_min)
641
657
  break;
642
658
 
659
+
643
660
  *tick = natural_distances[i] * factor;
661
+ /* printf("norm_tick_min: %g\ttick: %g\ttick_min:%g\n", */
662
+ /* norm_tick_min, *tick, tick_min); */
644
663
  double first_tick = ceil(axis_min /(*tick)) * (*tick);
645
664
  double last_tick = floor(axis_max /(*tick)) * (*tick);
646
665
 
647
- *num_locations = (int)((last_tick - first_tick)/(*tick) + 1);
666
+ *num_locations = (int)round((last_tick - first_tick)/(*tick));
667
+ *num_locations += 1;
648
668
 
649
669
  double *majors = ALLOC_N_double(*num_locations);
650
670
  for (i = 0; i < *num_locations; i++)
@@ -831,6 +851,13 @@ static void draw_minor_ticks(OBJ_PTR fmkr, FM *p, PlotAxis *s, int *ierr)
831
851
  static void show_numeric_label(OBJ_PTR fmkr, FM *p, PlotAxis *s,
832
852
  char *text, int location, double position, double shift, int *ierr)
833
853
  {
854
+ /* We need a buffer to implement the color */
855
+ long len = strlen(text) + 100; /* Should be enough overhead ! */
856
+ char * buffer = ALLOC_N_char(len);
857
+ snprintf(buffer, len, "\\textcolor[rgb]{%0.2f,%0.2f,%0.2f}{%s}",
858
+ s->labels_color_R, s->labels_color_G, s->labels_color_B,
859
+ text);
860
+
834
861
  if(location == AXIS_FREE_LOCATION) {
835
862
  /* We convert the tick position into frame position */
836
863
  double x,y, ft_ht = p->default_text_scale *
@@ -852,7 +879,7 @@ static void show_numeric_label(OBJ_PTR fmkr, FM *p, PlotAxis *s,
852
879
  ft_ht * ENLARGE * shift);
853
880
  }
854
881
 
855
- c_show_rotated_label(fmkr, p, text, x, y,
882
+ c_show_rotated_label(fmkr, p, buffer, x, y,
856
883
  s->numeric_label_scale,
857
884
  s->numeric_label_angle + angle,
858
885
  s->numeric_label_justification,
@@ -862,9 +889,10 @@ static void show_numeric_label(OBJ_PTR fmkr, FM *p, PlotAxis *s,
862
889
  else {
863
890
  // position is in figure coords and must be converted to frame coords
864
891
  double pos = ((!s->reversed)? (position - s->axis_min) : (s->axis_max - position)) / s->length;
865
- c_show_rotated_text(fmkr, p, text, location, shift, pos,
892
+ c_show_rotated_text(fmkr, p, buffer, location, shift, pos,
866
893
  s->numeric_label_scale, s->numeric_label_angle, s->numeric_label_justification, s->numeric_label_alignment, OBJ_NIL, ierr);
867
894
  }
895
+ free(buffer);
868
896
  }
869
897
 
870
898
  static void draw_numeric_labels(OBJ_PTR fmkr, FM *p, int location, PlotAxis *s, int *ierr)
@@ -1168,6 +1196,40 @@ static int prepare_dict_PlotAxis(OBJ_PTR fmkr, FM *p,
1168
1196
  if(Hash_Has_Key(axis_spec, "minor_tick_length"))
1169
1197
  axis->minor_tick_length = Hash_Get_Double(axis_spec, "minor_tick_length");
1170
1198
 
1199
+ /* Stroke color */
1200
+ if(Hash_Has_Key(axis_spec, "stroke_color") ||
1201
+ Hash_Has_Key(axis_spec, "color")) {
1202
+ OBJ_PTR color = (Hash_Has_Key(axis_spec, "stroke_color") ?
1203
+ Hash_Get_Obj(axis_spec, "stroke_color") :
1204
+ Hash_Get_Obj(axis_spec, "color") );
1205
+ int err;
1206
+ axis->stroke_color_R = Array_Entry_double(color, 0, &err);
1207
+ axis->stroke_color_G = Array_Entry_double(color, 1, &err);
1208
+ axis->stroke_color_B = Array_Entry_double(color, 2, &err);
1209
+ }
1210
+
1211
+ /* Labels color */
1212
+ if(Hash_Has_Key(axis_spec, "labels_color") ||
1213
+ Hash_Has_Key(axis_spec, "color")) {
1214
+ OBJ_PTR color = (Hash_Has_Key(axis_spec, "labels_color") ?
1215
+ Hash_Get_Obj(axis_spec, "labels_color") :
1216
+ Hash_Get_Obj(axis_spec, "color") );
1217
+ int err;
1218
+ axis->labels_color_R = Array_Entry_double(color, 0, &err);
1219
+ axis->labels_color_G = Array_Entry_double(color, 1, &err);
1220
+ axis->labels_color_B = Array_Entry_double(color, 2, &err);
1221
+ }
1222
+
1223
+ /* Log scale: */
1224
+ if(Hash_Has_Key(axis_spec, "log")) {
1225
+ OBJ_PTR val = Hash_Get_Obj(axis_spec, "log");
1226
+ if(val == OBJ_NIL || val == OBJ_FALSE)
1227
+ axis->log_vals = 0;
1228
+ else
1229
+ axis->log_vals = 1;
1230
+ }
1231
+
1232
+
1171
1233
  return 1;
1172
1234
  }
1173
1235
 
@@ -1193,7 +1255,8 @@ void c_show_axis_generic(OBJ_PTR fmkr, FM *p, OBJ_PTR axis_spec, int *ierr)
1193
1255
  /*
1194
1256
  This function takes an axis specification (either integer or
1195
1257
  hash) and returns a hash containing the following keys:
1196
- * 'major' : position of all major ticks
1258
+ * 'major_ticks' : position of all major ticks
1259
+ * 'minor_ticks' : position of all major ticks
1197
1260
  * 'labels' : the names of all labels
1198
1261
  * 'vertical' : if the axis is vertical or horizontal
1199
1262
  * 'line_width' : the line width
@@ -1202,8 +1265,9 @@ void c_show_axis_generic(OBJ_PTR fmkr, FM *p, OBJ_PTR axis_spec, int *ierr)
1202
1265
  * 'scale', 'shift' and 'angle': the scale, shift and angle of numeric
1203
1266
  labels
1204
1267
  * 'x0', 'y0', 'x1', 'y1': the position of the axis in figure coordinates
1205
-
1206
- */
1268
+ * 'stroke_color': the color to use for drawing lines.
1269
+ * 'labels_color': the color to use for drawing tick labels.
1270
+ */
1207
1271
  OBJ_PTR c_axis_get_information(OBJ_PTR fmkr, FM *p, OBJ_PTR axis_spec,
1208
1272
  int *ierr)
1209
1273
  {
@@ -1219,14 +1283,15 @@ OBJ_PTR c_axis_get_information(OBJ_PTR fmkr, FM *p, OBJ_PTR axis_spec,
1219
1283
  /* First, major ticks positions */
1220
1284
  prepare_axis_coordinates(fmkr, p, axis.location, &axis, ierr);
1221
1285
  compute_major_ticks(fmkr, p, &axis, ierr);
1222
- Hash_Set_Obj(hash, "major", Vector_New(axis.nmajors, axis.majors));
1286
+ Hash_Set_Obj(hash, "major_ticks", Vector_New(axis.nmajors, axis.majors));
1223
1287
 
1224
1288
  /* Then, minor ticks positions */
1225
1289
  double * minor;
1226
1290
  long count;
1291
+ OBJ_PTR color;
1227
1292
  minor = get_minor_ticks_location(fmkr, p, &axis, &count);
1228
1293
  if(minor) {
1229
- Hash_Set_Obj(hash, "minor", Vector_New(count, minor));
1294
+ Hash_Set_Obj(hash, "minor_ticks", Vector_New(count, minor));
1230
1295
  free(minor);
1231
1296
  }
1232
1297
 
@@ -1259,6 +1324,25 @@ OBJ_PTR c_axis_get_information(OBJ_PTR fmkr, FM *p, OBJ_PTR axis_spec,
1259
1324
  Hash_Set_Double(hash, "y0", axis.y0);
1260
1325
  Hash_Set_Double(hash, "y1", axis.y1);
1261
1326
 
1327
+ /* Log values */
1328
+ Hash_Set_Obj(hash, "log", axis.log_vals ? OBJ_TRUE : OBJ_FALSE);
1329
+
1330
+ /* Stroke color */
1331
+ color = Array_New(3);
1332
+ Array_Store(color, 0, Float_New(axis.stroke_color_R),ierr);
1333
+ Array_Store(color, 1, Float_New(axis.stroke_color_G),ierr);
1334
+ Array_Store(color, 2, Float_New(axis.stroke_color_B),ierr);
1335
+ Hash_Set_Obj(hash, "stroke_color", color);
1336
+
1337
+ /* Tick labels color */
1338
+ color = Array_New(3);
1339
+ Array_Store(color, 0, Float_New(axis.labels_color_R),ierr);
1340
+ Array_Store(color, 1, Float_New(axis.labels_color_G),ierr);
1341
+ Array_Store(color, 2, Float_New(axis.labels_color_B),ierr);
1342
+ Hash_Set_Obj(hash, "labels_color", color);
1343
+
1344
+
1345
+
1262
1346
  free_allocated_memory(&axis);
1263
1347
  return hash;
1264
1348
  }