Update of /project/gsharp/cvsroot/gsharp In directory common-lisp.net:/tmp/cvs-serv17460
Modified Files: drawing.lisp Log Message: Added comments and documentation strings to explain a bit more about the new spacing algorithm.
Date: Wed Nov 30 06:52:47 2005 Author: rstrandh
Index: gsharp/drawing.lisp diff -u gsharp/drawing.lisp:1.39 gsharp/drawing.lisp:1.40 --- gsharp/drawing.lisp:1.39 Wed Nov 30 03:37:05 2005 +++ gsharp/drawing.lisp Wed Nov 30 06:52:47 2005 @@ -96,6 +96,14 @@ collect (/ (nat-width method (measure-coeff measure) min-dist) compress))))
+;;; Compute the elasticity of each timeline in each measure of the +;;; measures of a system (line) by taking its duration to the power of +;;; the spaceing style. This metric is arbitrarily normalized to the +;;; duration of a whole note, which means that the force to apply to a +;;; line is not comparable between two different lines. All we know +;;; is that timelines with the same elasticity will grow and shrink in +;;; parallel, and that proportions between two timelines of different +;;; durations will be preserved. (defun compute-elasticities (measures method) (loop for measure in measures do (loop with timelines = (timelines measure) @@ -104,8 +112,29 @@ do (setf (elasticity timeline) (expt (duration timeline) (spacing-style method))))))
-(defgeneric left-bulge (element pane)) -(defgeneric right-bulge (element pane)) +;;; FIXME: there should be an :around method that adds the value +;;; return by the main method to the explicit horizontal offset that +;;; the user wants to impose on an element, and the existence of this +;;; around method should be documented. +;;; FIXME: we should probably also allow for the user to introduce +;;; explicit (positive or negative) bulges that will be added in by +;;; the :around method, thus allowing the user to explicitly move two +;;; adjacent elements further apart, or to bring them closer together. +(defgeneric left-bulge (element pane) + (:documentation "The amount by which an element sticks out to the +left of the center of its timeline")) + +;;; FIXME: there should be an :around method that adds the value +;;; return by the main method to the explicit horizontal offset that +;;; the user wants to impose on an element, and the existence of this +;;; around method should be documented. +;;; FIXME: we should probably also allow for the user to introduce +;;; explicit (positive or negative) bulges that will be added in by +;;; the :around method, thus allowing the user to explicitly move two +;;; adjacent elements further apart, or to bring them closer together. +(defgeneric right-bulge (element pane) + (:documentation "The amount by which an element sticks out to the +right of the center of its timeline"))
(defmethod left-bulge ((element element) pane) (score-pane:staff-step 1)) @@ -121,6 +150,15 @@ (+ (score-pane:staff-step 0.5) (/ (text-size pane (map 'string 'code-char (text element))) 2)))
+;;; As it turns out, the spacing algorithm would be very complicated +;;; if we were to take into account exactly how elements with +;;; arbitrarily many timelines between them might influence the +;;; overall layout. Instead we apprixmate by obtaining a closest gap +;;; only between adjacent timelines as follows: first, we consider +;;; adjacent elements whose timelines are also adjacent (and there is +;;; a special case for the last element of a layer), and set the +;;; smallest gap between the timelines to the closest possible +;;; distance between the two elements... (defun compute-gaps-adjacent-timelines (bars method pane) (declare (ignore method)) (loop for bar in bars @@ -138,6 +176,27 @@ (+ (right-bulge e1 pane) (left-bulge e2 pane)))))))))
+;;; ... Then we consider adjacent elements whose timelines are +;;; separated by at least one other timeline. If the sum of the +;;; distances between individual timelines is greater than or equal to +;;; the closest distance between the adjacent elements (which is +;;; likely if we are talking melody), then there is nothing to do, +;;; since the individual distances are more restrictive than that +;;; imposed by the adjacent elements. If not, we try to distribute +;;; the closest distance between the two adjacent elements over the +;;; individual timelines proportionally to the elasticity of the +;;; timlines. If in doing so, we find that some timeline already has +;;; a smallest gap that is larger than the fraction of the closest +;;; distance between adjacent elements that we attribute to it, then +;;; that smallest gap is subtracted from the distance we need to +;;; distribute, the timeline is removed from consideration, and we +;;; start over. This process must terminate (or else, the sum of the +;;; closest gaps must have been larger than the distance to distribute +;;; in the first place) with at least one timeline to distribute over. +;;; There is a special case here, which occurs when all the +;;; elasticites of the timelines to be considered is zero. In this +;;; case, instead of distributing proportionally to the elasticities +;;; of individual timelies, we distribute evenly between the timelines. (defun compute-gaps-separated-timelines (bars method pane) (declare (ignore method)) (flet ((handle-timelines (timelines element-gap) @@ -198,6 +257,11 @@ ;; whose corresponding timeline is not the last one in the meaure do (compute-gaps-separated-timelines (measure-bars measure) method pane)))
+;;; When this function is called, each timeline has an elasticity and +;;; a smallest gap to the next adjacent timline (or to the end of the +;;; measure). These values, together with an elasticity function at +;;; the beginning of a measure, are used to compute the total +;;; elasticity function of a measure. (defun compute-elasticity-functions (measures method) (loop for measure in measures do (loop with result = (make-elementary-elasticity (min-width method) 0.0001) @@ -272,8 +336,11 @@ (compute-elasticities measures method) (compute-gaps measures method pane) (let* ((e-fun (compute-elasticity-functions measures method)) + ;; FIXME: it would be much better to compress the system + ;; proportionally, so that every smallest gap gets shrunk + ;; by the same percentage (force (if (> (zero-force-size e-fun) (line-width method)) - 0 + 0 (force-at-size e-fun (line-width method))))) nil) (let ((widths (compute-widths measures method)))