]> git.donarmstrong.com Git - lilypond.git/blob - lily/stencil.cc
*** empty log message ***
[lilypond.git] / lily / stencil.cc
1 /*
2   stencil.cc -- implement Stencil
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include <math.h>
10 #include <libc-extension.hh>    // isinf
11
12 #include "font-metric.hh" 
13 #include "dimensions.hh"
14 #include "interval.hh"
15 #include "string.hh"
16 #include "stencil.hh"
17 #include "warn.hh"
18
19 #include "ly-smobs.icc"
20
21 SCM
22 Stencil::smobbed_copy () const
23 {
24   Stencil *s = new Stencil (*this);
25   return s->smobbed_self ();
26 }
27
28 Offset
29 Stencil::origin () const
30 {
31   return origin_;
32 }
33
34 Interval
35 Stencil::extent (Axis a) const
36 {
37   return dim_[a];
38 }
39
40 Stencil::Stencil (Box b, SCM func)
41 {
42   expr_ = func;
43   dim_ = b;
44 }
45
46 Stencil::Stencil ()
47 {
48   expr_ = SCM_EOL;
49   set_empty (true);
50 }
51
52 void
53 Stencil::translate (Offset o)
54 {
55   Axis a = X_AXIS;
56   while (a < NO_AXES)
57     {
58       if (abs (o[a]) > 100 CM
59           || isinf (o[a]) || isnan (o[a]))
60         {
61           programming_error ("Improbable offset for translation: setting to zero");
62           o[a] =  0.0;
63         }
64       incr (a);
65     }
66
67   expr_ = scm_list_n (ly_symbol2scm ("translate-stencil"),
68                    ly_offset2scm (o),
69                    expr_, SCM_UNDEFINED);
70   if (!is_empty ())
71     dim_.translate (o);
72   origin_ += o;
73 }
74   
75 void
76 Stencil::translate_axis (Real x, Axis a)
77 {
78   Offset o (0,0);
79   o[a] = x;
80   translate (o);
81 }
82
83 void
84 Stencil::add_stencil (Stencil const &s)
85 {
86   expr_ = scm_list_n (ly_symbol2scm ("combine-stencil"),
87                       s.expr_, expr_, SCM_UNDEFINED);
88   dim_.unite (s.dim_);
89 }
90
91 void
92 Stencil::set_empty (bool e)
93 {
94   if (e)
95     {
96       dim_[X_AXIS].set_empty ();
97       dim_[Y_AXIS].set_empty ();
98     }
99   else
100     {
101       dim_[X_AXIS] = Interval (0,0);
102       dim_[Y_AXIS] = Interval (0,0);
103     }
104 }
105
106 void
107 Stencil::align_to (Axis a, Real x)
108 {
109   if (is_empty ())
110     return ;
111
112   Interval i (extent (a));
113   translate_axis (-i.linear_combination (x), a);
114 }
115
116 /*
117   TODO: unintuitive naming, you would expect *this to be moved.  Kept
118   API for compat with add_at_edge ().
119 */
120 Stencil
121 Stencil::moved_to_edge (Axis a, Direction d, Stencil const &s, Real padding,
122                         Real minimum) const
123 {
124   Real my_extent= is_empty () ? 0.0 : dim_[a][d];
125   Interval i (s.extent (a));
126   Real his_extent;
127   if (i.is_empty ())
128     {
129       programming_error ("Stencil::move_to_edge: adding empty stencil.");
130       his_extent = 0.0;
131     }
132   else
133     his_extent = i[-d];
134
135   Real offset = (my_extent -  his_extent) + d * padding;
136
137   Stencil toadd (s);
138   toadd.translate_axis (offset,a);
139
140   if (minimum > 0
141       && d *(- origin ()[a] + toadd.origin ()[a]) < minimum)
142     toadd.translate_axis ( -toadd.origin ()[a]
143                            + origin ()[a] + d* minimum, a);
144     
145   return toadd;
146 }
147
148 /*  See scheme Function.  */
149 void
150 Stencil::add_at_edge (Axis a, Direction d, Stencil const &s, Real padding,
151                        Real minimum)
152 {
153   add_stencil (moved_to_edge (a,d,s,padding, minimum));
154 }
155
156 /* Hmm... maybe this is not such a good idea ; stuff can be empty,
157    while expr_ == '()  */
158 bool
159 Stencil::is_empty () const
160 {
161   return expr_ == SCM_EOL;
162 }
163
164 SCM
165 Stencil::get_expr () const
166 {
167   return expr_;
168 }
169
170 Box
171 Stencil::extent_box () const
172 {
173   return dim_;
174 }
175
176 int
177 Stencil::print_smob (SCM , SCM port, scm_print_state *)
178 {
179   scm_puts ("#<Stencil ", port);
180   scm_puts (" >", port);
181   return 1;
182 }
183
184 SCM
185 Stencil::mark_smob (SCM s)
186 {
187   Stencil  *r = (Stencil *) ly_cdr (s);
188   return r->expr_;
189 }
190
191 IMPLEMENT_SIMPLE_SMOBS (Stencil);
192 IMPLEMENT_TYPE_P (Stencil, "ly:stencil?");
193 IMPLEMENT_DEFAULT_EQUAL_P (Stencil);