package com.xenoage.zong.musiclayout.layouter; import static com.xenoage.utils.collections.CollectionUtils.alist; import static com.xenoage.utils.kernel.Range.range; import static com.xenoage.utils.log.Log.log; import static com.xenoage.utils.log.Report.warning; import static com.xenoage.zong.musiclayout.layouter.scoreframelayout.ScoreFrameLayouter.scoreFrameLayouter; import static com.xenoage.zong.musiclayout.notator.Notator.notator; import static com.xenoage.zong.musiclayout.spacer.BeamsSpacer.beamsSpacer; import static com.xenoage.zong.musiclayout.spacer.ColumnsSpacer.columnsSpacer; import static com.xenoage.zong.musiclayout.spacer.FramesSpacer.framesSpacer; import java.util.ArrayList; import java.util.List; import java.util.Map; import com.xenoage.zong.core.Score; import com.xenoage.zong.core.music.beam.Beam; import com.xenoage.zong.documents.ScoreDoc; import com.xenoage.zong.layout.LayoutDefaults; import com.xenoage.zong.musiclayout.ScoreFrameLayout; import com.xenoage.zong.musiclayout.ScoreLayout; import com.xenoage.zong.musiclayout.continued.ContinuedElement; import com.xenoage.zong.musiclayout.notation.Notations; import com.xenoage.zong.musiclayout.spacer.frame.fill.FrameFiller; import com.xenoage.zong.musiclayout.spacer.system.fill.SystemFiller; import com.xenoage.zong.musiclayout.spacing.BeamSpacing; import com.xenoage.zong.musiclayout.spacing.ColumnSpacing; import com.xenoage.zong.musiclayout.spacing.FrameSpacing; import com.xenoage.zong.musiclayout.spacing.FramesSpacing; import com.xenoage.zong.musiclayout.spacing.SystemSpacing; /** * A score layouter creates the content for * score frames from a given score. * * @author Andreas Wenger */ public class ScoreLayouter { //input private Context context; private Target target; //output private ScoreLayout layout = null; /** * Creates a {@link ScoreLayouter} for the given score document and target. */ public ScoreLayouter(ScoreDoc doc, Target target) { LayoutDefaults defaults = doc.getLayout().getDefaults(); this.context = new Context(doc.getScore(), defaults.getSymbolPool(), defaults.getLayoutSettings()); this.target = target; } public ScoreLayouter(Context context, Target target) { this.context = context; this.target = target; } /** * Creates the {@link ScoreLayout}. If an error occurs, an error layout * is returned. */ public ScoreLayout createScoreLayout() { try { layout = createLayoutWithExceptions(); } catch (Exception ex) { //exception during the layouting process. show error page log(warning("Layouting failed", ex)); layout = ScoreLayout.createErrorLayout(context.score, context.symbols); } return layout; } /** * Computes the whole layout and returns it. * If something fails, an exception is thrown. */ public ScoreLayout createLayoutWithExceptions() { //notations of elements Notations notations = notator.computeAll(context); //compute optimal measure column spacings List<ColumnSpacing> columns = columnsSpacer.compute(notations, context); //break columns into systems and frames FramesSpacing frames = framesSpacer.compute(columns, target, context, notations); //system stretching (horizontal) fillSystemsHorizontally(frames, target); //frame filling (vertical) fillFramesVertically(frames, target, context.score); //compute beam spacings. these are computed only now, after the horizontal //and vertical spacing of the score is fixed, since the beam slants depend on the //exact spacings Map<Beam, BeamSpacing> beams = beamsSpacer.compute(context.score, notations, frames); //create score frame layouts from the collected information List<ScoreFrameLayout> scoreFrameLayouts = createScoreFrameLayouts(frames, notations, context, beams); //create score layout return new ScoreLayout(context.score, scoreFrameLayouts, context.symbols, context.settings); } /** * Fills the systems horizontally according to the {@link SystemFiller} * of the frame. */ void fillSystemsHorizontally(FramesSpacing frames, Target target) { for (int iFrame : range(frames.size())) { FrameSpacing frameArr = frames.get(iFrame); SystemFiller hFill = target.getArea(iFrame).hFill; //apply strategy for (SystemSpacing oldSystemArr : frameArr.getSystems()) { float usableWidth = frameArr.getUsableSizeMm().width - oldSystemArr.getMarginLeftMm() - oldSystemArr.getMarginRightMm(); hFill.compute(oldSystemArr, usableWidth); } } } /** * Fills the frames vertically according to the {@link FrameFiller} of the frame. */ void fillFramesVertically(FramesSpacing frames, Target target, Score score) { for (int iFrame : range(frames.size())) { FrameFiller vFill = target.getArea(iFrame).vFill; vFill.compute(frames.get(iFrame), score); } } /** * Creates all {@link ScoreFrameLayout}s. */ List<ScoreFrameLayout> createScoreFrameLayouts(FramesSpacing frames, Notations notations, Context context, Map<Beam, BeamSpacing> beamsSpacing) { ArrayList<ScoreFrameLayout> ret = alist(); ArrayList<ContinuedElement> continuedElements = alist(); for (int iFrame : range(frames.size())) { ScoreFrameLayout sfl = scoreFrameLayouter.computeScoreFrameLayout(frames.get(iFrame), iFrame, notations, continuedElements, context, beamsSpacing); ret.add(sfl); continuedElements = sfl.getContinuedElements(); } return ret; } }