2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
23 #include "font-metric.hh"
25 #include "string-convert.hh"
28 #include "ly-smobs.icc"
36 Stencil::Stencil (Box b
, SCM func
)
43 Stencil::print_smob (SCM
, SCM port
, scm_print_state
*)
45 scm_puts ("#<Stencil ", port
);
46 scm_puts (" >", port
);
51 Stencil::mark_smob (SCM smob
)
53 Stencil
*s
= (Stencil
*) SCM_CELL_WORD_1 (smob
);
57 IMPLEMENT_SIMPLE_SMOBS (Stencil
);
58 IMPLEMENT_TYPE_P (Stencil
, "ly:stencil?");
59 IMPLEMENT_DEFAULT_EQUAL_P (Stencil
);
62 Stencil::extent (Axis a
) const
68 Stencil::is_empty () const
70 return (expr_
== SCM_EOL
71 || dim_
[X_AXIS
].is_empty ()
72 || dim_
[Y_AXIS
].is_empty ());
76 Stencil::expr () const
82 Stencil::extent_box () const
88 Stencil::rotate (Real a
, Offset off
)
90 rotate_degrees (a
* 180/M_PI
, off
);
94 Rotate this stencil around the point ABSOLUTE_OFF.
98 Stencil::rotate_degrees_absolute (Real a
, Offset absolute_off
)
100 const Real x
= absolute_off
[X_AXIS
];
101 const Real y
= absolute_off
[Y_AXIS
];
104 * Build scheme expression (processed in stencil-interpret.cc)
106 /* TODO: by hanwenn 2008/09/10 14:38:56:
107 * in effect, this copies the underlying expression. It might be a
108 * little bit nicer to mirror this in the api, ie. make a
110 * and have Stencil::rotate be an abbrev of
114 expr_
= scm_list_n (ly_symbol2scm ("rotate-stencil"),
115 scm_list_2 (scm_from_double (a
),
116 scm_cons (scm_from_double (x
), scm_from_double (y
))),
117 expr_
, SCM_UNDEFINED
);
120 * Calculate the new bounding box
122 Box shifted_box
= extent_box ();
123 shifted_box
.translate (-absolute_off
);
126 pts
.push_back (Offset (shifted_box
.x ().at(LEFT
), shifted_box
.y ().at(DOWN
)));
127 pts
.push_back (Offset (shifted_box
.x ().at(RIGHT
), shifted_box
.y ().at(DOWN
)));
128 pts
.push_back (Offset (shifted_box
.x ().at(RIGHT
), shifted_box
.y ().at(UP
)));
129 pts
.push_back (Offset (shifted_box
.x ().at(LEFT
), shifted_box
.y ().at(UP
)));
131 const Offset rot
= complex_exp (Offset (0, a
* M_PI
/ 180.0));
133 for (vsize i
= 0; i
< pts
.size (); i
++)
134 dim_
.add_point (pts
[i
] * rot
+ absolute_off
);
138 Rotate this stencil around the point RELATIVE_OFF.
140 RELATIVE_OFF is measured in terms of the extent of the stencil, so
141 -1 = LEFT/DOWN edge, 1 = RIGHT/UP edge.
144 Stencil::rotate_degrees (Real a
, Offset relative_off
)
147 * Calculate the center of rotation
149 const Real x
= extent (X_AXIS
).linear_combination (relative_off
[X_AXIS
]);
150 const Real y
= extent (Y_AXIS
).linear_combination (relative_off
[Y_AXIS
]);
151 rotate_degrees_absolute (a
, Offset (x
, y
));
155 Stencil::translate (Offset o
)
164 || fabs (o
[a
]) > 1e6
)
166 programming_error (String_convert::form_string ("Improbable offset for stencil: %f staff space", o
[a
])
168 + "Setting to zero.");
170 if (strict_infinity_checking
)
171 scm_misc_error (__FUNCTION__
, "Improbable offset.", SCM_EOL
);
176 expr_
= scm_list_n (ly_symbol2scm ("translate-stencil"),
178 expr_
, SCM_UNDEFINED
);
184 Stencil::translate_axis (Real x
, Axis a
)
192 Stencil::scale (Real x
, Real y
)
194 expr_
= scm_list_3 (ly_symbol2scm ("scale-stencil"),
195 scm_list_2 (scm_from_double (x
),
196 scm_from_double (y
)),
203 Stencil::add_stencil (Stencil
const &s
)
205 expr_
= scm_list_3 (ly_symbol2scm ("combine-stencil"), s
.expr_
, expr_
);
210 Stencil::set_empty (bool e
)
214 dim_
[X_AXIS
].set_empty ();
215 dim_
[Y_AXIS
].set_empty ();
219 dim_
[X_AXIS
] = Interval (0, 0);
220 dim_
[Y_AXIS
] = Interval (0, 0);
225 Stencil::align_to (Axis a
, Real x
)
230 Interval
i (extent (a
));
231 translate_axis (-i
.linear_combination (x
), a
);
234 /* See scheme Function. */
236 Stencil::add_at_edge (Axis a
, Direction d
, Stencil
const &s
, Real padding
)
238 Interval my_extent
= dim_
[a
];
239 Interval
i (s
.extent (a
));
243 programming_error ("Stencil::add_at_edge: adding empty stencil.");
249 Real offset
= (my_extent
.is_empty () ? 0.0 : my_extent
[d
] - his_extent
)
253 toadd
.translate_axis (offset
, a
);
258 Stencil::in_color (Real r
, Real g
, Real b
) const
260 Stencil
new_stencil (extent_box (),
261 scm_list_3 (ly_symbol2scm ("color"),
262 scm_list_3 (scm_from_double (r
),
264 scm_from_double (b
)),
271 Stencil::translated (Offset z
) const