package com.xenoage.zong.musiclayout.spacer.beam.stem;
import com.xenoage.utils.annotations.Const;
import com.xenoage.utils.collections.CList;
import com.xenoage.utils.collections.CollectionUtils;
import com.xenoage.utils.collections.IList;
import com.xenoage.utils.kernel.Countable;
import com.xenoage.zong.core.music.chord.StemDirection;
import com.xenoage.zong.musiclayout.SLP;
import com.xenoage.zong.musiclayout.spacing.ChordSpacing;
import lombok.val;
import java.util.Iterator;
import java.util.List;
import static java.lang.Math.max;
import static java.lang.Math.min;
/**
* Positions of beamed stems.
*
* @author Andreas Wenger
*/
@Const
public class BeamedStems
implements Countable, Iterable<BeamedStem> {
private final IList<BeamedStem> stems;
//cached:
/** The primary direction of the stems. This is the direction of the first stem. */
public final StemDirection primaryStemDir;
/* The horizontal offset in IS of the stem of the first chord. */
public final float leftXIs;
/** The horizontal offset in IS of the stem of the last chord. */
public final float rightXIs;
/** The LP of the outermost stem-side note of the first chord. */
public final float leftNoteLp;
/** The LP of the outermost stem-side note of the last chord. */
public final float rightNoteLp;
public static BeamedStems fromBeam(List<ChordSpacing> beamChords) {
val stems = new CList<BeamedStem>(beamChords.size());
for (val chord : beamChords) {
//we need a stem for each beamed chord
if (chord.notation.stem == null)
throw new IllegalStateException("TODO! we need a stem for each beamed chord");
SLP stemSideNoteSlp = chord.getNotation().getStemSideNoteSlp();
SLP stemEndSlp = chord.getNotation().getStemEndSlp();
stems.add(new BeamedStem(chord.getStemXIs(), chord.notation.stemDirection,
stemSideNoteSlp, stemEndSlp));
}
return new BeamedStems(stems.close());
}
public BeamedStems(IList<BeamedStem> stems) {
this.stems = stems;
this.primaryStemDir = getFirst().dir;
this.leftXIs = getFirst().xIs;
this.rightXIs = getLast().xIs;
this.leftNoteLp = getFirst().noteSlp.lp;
this.rightNoteLp = getLast().noteSlp.lp;
}
public int getCount() {
return stems.size();
}
public BeamedStem get(int index) {
return stems.get(index);
}
public BeamedStem getFirst() {
return CollectionUtils.getFirst(stems);
}
public BeamedStem getLast() {
return CollectionUtils.getLast(stems);
}
public float getMaxNoteLp() {
float max = -1 * Float.MAX_VALUE;
for (val stem : stems)
max = max(max, stem.noteSlp.lp);
return max;
}
public float getMinNoteLp() {
float min = Float.MAX_VALUE;
for (val stem : stems)
min = min(min, stem.noteSlp.lp);
return min;
}
@Override public Iterator<BeamedStem> iterator() {
return stems.iterator();
}
}