Index: lily/grob.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/grob.cc,v
retrieving revision 1.168
diff -p -u -r1.168 grob.cc
--- lily/grob.cc	11 Feb 2006 11:35:18 -0000	1.168
+++ lily/grob.cc	8 May 2006 09:47:09 -0000
@@ -120,6 +120,15 @@ Grob::get_print_stencil () const
 
 	  retval = Stencil (m->extent_box (), expr);
 	}
+      SCM rot = get_property ("rotation");
+      if (rot != SCM_EOL)
+	{
+	  Real angle = scm_to_double (scm_car (rot));
+	  Real x = scm_to_double (scm_cadr (rot));
+	  Real y = scm_to_double (scm_caddr (rot));
+
+	  retval.rotate (angle, x, y);
+	}
 
       /* color support... see interpret_stencil_expression () for more... */
       SCM color = get_property ("color");
@@ -522,6 +531,7 @@ ADD_INTERFACE (Grob, "grob-interface",
 	       "meta "
 	       "minimum-X-extent "
 	       "minimum-Y-extent "
+	       "rotation "
 	       "springs-and-rods "
 	       "staff-symbol "
 	       "stencil "
Index: lily/stencil.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/stencil.cc,v
retrieving revision 1.51
diff -p -u -r1.51 stencil.cc
--- lily/stencil.cc	19 Feb 2006 12:38:02 -0000	1.51
+++ lily/stencil.cc	8 May 2006 09:47:09 -0000
@@ -78,6 +78,41 @@ Stencil::origin () const
   return origin_;
 }
 
+/*
+ * Rotate this stencil around the point [x, y]
+ */
+void
+Stencil::rotate (Real a, Real x_off, Real y_off)
+{
+  Real x = extent (X_AXIS).center ();
+  Real y = extent (Y_AXIS).center ();
+  Real x_len = extent (X_AXIS).length ();
+  Real y_len = extent (Y_AXIS).length ();
+
+  /*
+   * Calculate center of rotation
+   */
+  x += x_off * x_len / 2.0;
+  y += y_off * y_len / 2.0;
+
+  SCM offset = ly_offset2scm (Offset (x, y));
+
+  expr_ = scm_list_n (ly_symbol2scm ("rotate-stencil"),
+		      scm_list_2 (scm_from_double (a), offset),
+		      expr_, SCM_UNDEFINED);
+
+  /*
+   * Calculate the new bounding box
+   */
+  const double DEG_TO_RAD = M_PI / 180.0;
+  const double abs_sin_a = fabs (sin (a * DEG_TO_RAD));
+  const double abs_cos_a = fabs (cos (a * DEG_TO_RAD));
+  Real x_new = abs_sin_a * y_len + abs_cos_a * x_len;
+  Real y_new = abs_sin_a * x_len + abs_cos_a * y_len;
+
+  dim_.widen ((x_new - x_len) / 2.0, (y_new - y_len) / 2.0);
+}
+
 void
 Stencil::translate (Offset o)
 {
Index: lily/stencil-interpret.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/stencil-interpret.cc,v
retrieving revision 1.5
diff -p -u -r1.5 stencil-interpret.cc
--- lily/stencil-interpret.cc	6 Jan 2006 09:13:24 -0000	1.5
+++ lily/stencil-interpret.cc	8 May 2006 09:47:09 -0000
@@ -56,6 +56,22 @@ interpret_stencil_expression (SCM expr,
 
 	  return;
 	}
+      else if (head == ly_symbol2scm ("rotate-stencil"))
+	{
+	  SCM args = scm_cadr (expr);
+	  double angle = scm_to_double (scm_car (args));
+	  Offset tmp = o + robust_scm2offset (scm_cadr (args), Offset (0.0, 0.0));
+
+	  SCM offset = ly_offset2scm (tmp);
+	  SCM x = scm_car (offset);
+	  SCM y = scm_cdr (offset);
+
+	  (*func) (func_arg, scm_list_4 (ly_symbol2scm ("rotate"), scm_from_double (angle), x, y));
+	  interpret_stencil_expression (scm_caddr (expr), func, func_arg, o);
+	  (*func) (func_arg, scm_list_4 (ly_symbol2scm ("rotate"), scm_from_double (-angle), x, y));
+
+	  return;
+	}
       else
 	{
 	  (*func) (func_arg,
Index: lily/stencil-scheme.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/stencil-scheme.cc,v
retrieving revision 1.53
diff -p -u -r1.53 stencil-scheme.cc
--- lily/stencil-scheme.cc	6 Jan 2006 09:13:24 -0000	1.53
+++ lily/stencil-scheme.cc	8 May 2006 09:47:09 -0000
@@ -319,6 +319,22 @@ LY_DEFINE (ly_bracket, "ly:bracket",
 			  0.95 * scm_to_double (t)).smobbed_copy ();
 }
 
+LY_DEFINE (ly_rotate_stencil, "ly:stencil-rotate",
+	   2, 0, 0, (SCM stil, SCM angle),
+	   "Return a @var{stil}, "
+	   "but rotated by @var{angle} degrees.")
+{
+  Stencil *s = unsmob_stencil (stil);
+  SCM_ASSERT_TYPE (s, stil, SCM_ARG1, __FUNCTION__, "stencil");
+  SCM_ASSERT_TYPE (scm_is_number (angle), angle, SCM_ARG2, __FUNCTION__, "number");
+  Real a = scm_to_double (angle);
+
+  SCM new_s = s->smobbed_copy ();
+  Stencil *q = unsmob_stencil (new_s);
+  q->rotate (a, 0.0, 0.0);
+  return new_s;
+}
+
 LY_DEFINE (ly_filled_box, "ly:round-filled-box",
 	   3, 0, 0,
 	   (SCM xext, SCM yext, SCM blot),
Index: lily/include/stencil.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/stencil.hh,v
retrieving revision 1.24
diff -p -u -r1.24 stencil.hh
--- lily/include/stencil.hh	6 Jan 2006 09:13:24 -0000	1.24
+++ lily/include/stencil.hh	8 May 2006 09:47:09 -0000
@@ -73,6 +73,7 @@ public:
 		    Real minimum);
   void add_stencil (Stencil const &m);
   void translate (Offset);
+  void rotate (Real, Real, Real);
   void align_to (Axis a, Real x);
   void translate_axis (Real, Axis);
 
Index: scm/define-grob-properties.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/define-grob-properties.scm,v
retrieving revision 1.161
diff -p -u -r1.161 define-grob-properties.scm
--- scm/define-grob-properties.scm	7 May 2006 19:51:12 -0000	1.161
+++ scm/define-grob-properties.scm	8 May 2006 09:47:10 -0000
@@ -344,6 +344,8 @@ quicker the slur attains it @code{height
      (remove-first ,boolean? "Remove the first staff of a orchestral score?")
      (right-padding ,ly:dimension? "Space to insert between note and
 accidentals.")
+     (rotation ,list? "Number of degrees to rotate this object, and what point
+to rotate around. #'(45 0 0) means rotate 45 degrees around the center of this object.")
      (same-direction-correction ,number? "Optical correction amount
 for stems that are placed in tight configurations. This amount is used
 for stems with the same direction to compensate for note-head to stem distance.")
Index: scm/define-markup-commands.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/define-markup-commands.scm,v
retrieving revision 1.146
diff -p -u -r1.146 define-markup-commands.scm
--- scm/define-markup-commands.scm	5 May 2006 22:56:06 -0000	1.146
+++ scm/define-markup-commands.scm	8 May 2006 09:47:10 -0000
@@ -118,6 +118,12 @@ circle of diameter 0 (ie sharp corners).
   (ly:round-filled-box
    xext yext blot))
 
+(define-markup-command (rotate layout props ang arg) (number? markup?)
+  "Rotate object with @var{ang} degrees."
+  (let* ((stil (interpret-markup layout props arg)))
+    (ly:stencil-rotate stil ang)))
+
+
 (define-markup-command (whiteout layout props arg) (markup?)
   "Provide a white underground for @var{arg}"
   (let* ((stil (interpret-markup layout props
Index: scm/output-ps.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/output-ps.scm,v
retrieving revision 1.168
diff -p -u -r1.168 output-ps.scm
--- scm/output-ps.scm	4 Apr 2006 10:18:59 -0000	1.168
+++ scm/output-ps.scm	8 May 2006 09:47:10 -0000
@@ -18,26 +18,26 @@
 
   ;; JUNK this -- see lily.scm: ly:all-output-backend-commands
   #:export (unknown
-	    blank
+	    bezier-sandwich
+	    char
 	    circle
-	    dot
+	    comment
+	    dashed-line
 	    dashed-slur
-	    char
-	    setcolor
-	    resetcolor
+	    dot
+	    draw-line
+	    embedded-ps
 	    named-glyph
-	    dashed-line
-	    zigzag-line
-	    comment
-	    repeat-slash
+	    no-origin
 	    placebox
-	    bezier-sandwich
-	    embedded-ps
+	    polygon
+	    repeat-slash
+	    resetcolor
+	    rotate
 	    round-filled-box
+	    setcolor
 	    text
-	    polygon
-	    draw-line
-	    no-origin))
+	    zigzag-line))
 
 
 (use-modules (guile)
@@ -247,6 +247,14 @@
 ;; restore color from stack
 (define (resetcolor) "setrgbcolor\n")
 
+;; rotate around [x,y]
+(define (rotate ang x y)
+;; FIXME: This is probably not good PS code
+  (format "~a translate ~a rotate ~a translate\n"
+    (numbers->string4 (list x y))
+    (number->string ang)
+    (numbers->string4 (list (* -1 x) (* -1 y)))))
+
 (define (round-filled-box left right bottom top blotdiam)
   (let* ((halfblot (/ blotdiam 2))
 	 (x (- halfblot left))
