//----------------------------------------------------------------------------//
// //
// S c a l e //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.sheet;
import omr.constant.Constant;
import omr.util.DoubleValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Class {@code Scale} encapsulates what drives the scale of a sheet,
* namely the main lengths of foreground and background vertical runs
* (which are staff line thickness and white interval between staff
* lines respectively), and the sum of these lengths which represents
* the main interline value.
*
* <p>This class also provides methods for converting values based on what the
* interline and the line thickness are actually worth.
* There are two different measurements, pixels and fractions :
*
* <dl> <dt> <b>pixel</b> </dt> <dd> This is simply an absolute number of
* pixels, so generally an integer. One pixel is worth 1 pixel (sic) </dd>
*
* <dt> <b>(interline) fraction</b> </dt> <dd> This is a number of interlines,
* so generally a fraction which is implemented as a double. One interline is
* worth whatever the scale is, generally something around 20 pixels </dd>
*
* <dt> <b>line fraction</b> </dt> <dd> This is a number of line thickness,
* so generally a line fraction which is implemented as a double. One line is
* worth whatever the scale is, generally something around 4 pixels </dd>
*
* @author Hervé Bitteur
*/
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "scale")
public class Scale
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(Scale.class);
//~ Instance fields --------------------------------------------------------
/** Line thickness range */
private final Range lineRange;
/** Main interline range */
private final Range interlineRange;
/** Beam thickness, if any */
private final Integer beamValue;
/** Second interline range, if any */
private final Range secondInterlineRange;
//~ Constructors -----------------------------------------------------------
//-------//
// Scale //
//-------//
/**
* Create a degenerated scale entity, meant for computing
* scale-dependent parameters.
*
* @param interline the score interline value.
*/
public Scale (int interline)
{
this(interline, -1);
}
//-------//
// Scale //
//-------//
/**
* Create a scale entity, meant for a staff.
*
* @param interline the interline value
* @param mainFore the line thickness
*/
public Scale (int interline,
int mainFore)
{
this(
new Range(-1, mainFore, -1),
new Range(-1, interline, -1),
null,
null);
}
//-------//
// Scale //
//-------//
/**
* Create a scale entity, meant for a whole sheet.
*
* @param lineRange range of line thickness
* @param interlineRange range of interline
* @param beamValue beam thickness
* @param secondInterlineRange range of secondInterline
*/
public Scale (Range lineRange,
Range interlineRange,
Integer beamValue,
Range secondInterlineRange)
{
this.lineRange = lineRange;
this.interlineRange = interlineRange;
this.beamValue = beamValue;
this.secondInterlineRange = secondInterlineRange;
}
//-------//
// Scale //
//-------//
/** No-arg constructor, needed by JAXB. */
private Scale ()
{
this(null, null, null, null);
}
//~ Methods ----------------------------------------------------------------
//--------------//
// fracToPixels //
//--------------//
/**
* Convert a fraction of interline to a number of pixels.
*
* @param val the fraction value
* @return the (double) number of pixels
*/
public double fracToPixels (double val)
{
return interlineRange.best * val;
}
//--------------//
// getInterline //
//--------------//
/**
* Report the interline value this scale is based upon.
*
* @return the number of pixels (black + white) from one line to the other.
*/
public int getInterline ()
{
return interlineRange.best;
}
//-------------//
// getMainBeam //
//-------------//
/**
* Report the main beam thickness, if any.
*
* @return the main beam thickness, or null
*/
public Integer getMainBeam ()
{
return beamValue;
}
//-------------//
// getMainFore //
//-------------//
/**
* Report the line thickness this scale is based upon.
*
* @return the number of black pixels in a staff line
*/
public int getMainFore ()
{
return lineRange.best;
}
//------------//
// getMaxFore //
//------------//
/**
* Report the maximum line thickness (using standard percentile).
*
* @return the maxFore value
*/
public Integer getMaxFore ()
{
return lineRange.max;
}
//-----------------//
// getMaxInterline //
//-----------------//
/**
* Report the maximum interline (using standard percentile).
*
* @return the maxInterline
*/
public Integer getMaxInterline ()
{
return interlineRange.max;
}
//-----------------------//
// getMaxSecondInterline //
//-----------------------//
/**
* Report the maximum second interline (using standard percentile).
*
* @return the maxSecondInterline
*/
public Integer getMaxSecondInterline ()
{
if (secondInterlineRange != null) {
return secondInterlineRange.max;
} else {
return null;
}
}
//-----------------//
// getMinInterline //
//-----------------//
/**
* Report the minimum interline (using standard percentile).
*
* @return the minInterline
*/
public Integer getMinInterline ()
{
return interlineRange.min;
}
//-----------------------//
// getMinSecondInterline //
//-----------------------//
/**
* Report the minimum second interline (using standard percentile).
*
* @return the minSecondInterline
*/
public Integer getMinSecondInterline ()
{
if (secondInterlineRange != null) {
return secondInterlineRange.min;
} else {
return null;
}
}
//--------------------//
// getSecondInterline //
//--------------------//
/**
* Report the second interline value this scale is based upon.
*
* @return the second number if any of pixels (black + white) from one line
* to the other, otherwise null.
*/
public Integer getSecondInterline ()
{
if (secondInterlineRange != null) {
return secondInterlineRange.best;
} else {
return null;
}
}
//------------------//
// pixelsToAreaFrac //
//------------------//
/**
* Compute the interline area fraction that corresponds to the
* given number of pixels.
*
* @param pixels the equivalent in number of pixels
* @return the interline area fraction
* @see #toPixels
*/
public double pixelsToAreaFrac (double pixels)
{
return pixels / (interlineRange.best * interlineRange.best);
}
//--------------//
// pixelsToFrac //
//--------------//
/**
* Compute the interline fraction that corresponds to the given
* number of pixels.
*
* @param pixels the equivalent in number of pixels
* @return the interline fraction
* @see #toPixels
*/
public double pixelsToFrac (double pixels)
{
return pixels / interlineRange.best;
}
//----------//
// toPixels //
//----------//
/**
* Compute the number of pixels that corresponds to the fraction of
* interline provided, according to the scale.
*
* @param frac a measure based on interline (1 = one interline)
* @return the actual number of pixels with the current scale
*/
public int toPixels (Fraction frac)
{
return (int) Math.rint(toPixelsDouble(frac));
}
//----------//
// toPixels //
//----------//
/**
* Compute the number of pixels that corresponds to the fraction of
* line thickness provided, according to the scale.
*
* @param lineFrac a measure based on line thickness (1 = one line height)
* @return the actual number of pixels with the current scale
*/
public int toPixels (LineFraction lineFrac)
{
return (int) Math.rint(toPixelsDouble(lineFrac));
}
//----------//
// toPixels //
//----------//
/**
* Compute the squared-normalized number of pixels, according to
* the scale.
*
* @param areaFrac a measure based on interline (1 = one interline square)
* @return the actual squared number of pixels with the current scale
*/
public int toPixels (AreaFraction areaFrac)
{
return (int) Math.rint(
interlineRange.best * interlineRange.best * areaFrac.getValue());
}
//----------------//
// toPixelsDouble //
//----------------//
/**
* Convenient method, working directly on a constant of interline
* fraction.
* Same as toPixels, but the result is a double instead of a rounded int.
*
* @param frac the interline fraction constant
* @return the equivalent in number of pixels
* @see #toPixels
*/
public double toPixelsDouble (Fraction frac)
{
return fracToPixels(frac.getWrappedValue().doubleValue());
}
//----------------//
// toPixelsDouble //
//----------------//
/**
* Convenient method, working directly on a constant of line
* fraction.
* Same as toPixels, but the result is a double instead of a rounded int.
*
* @param lineFrac the line fraction constant
* @return the equivalent in number of pixels
* @see #toPixels
*/
public double toPixelsDouble (LineFraction lineFrac)
{
return (double) lineRange.best * lineFrac.getWrappedValue()
.doubleValue();
}
//----------//
// toString //
//----------//
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder();
sb.append("{Scale");
sb.append(" line:")
.append(lineRange);
sb.append(" interline:")
.append(interlineRange);
if (beamValue != null) {
sb.append(" beam:")
.append(beamValue);
}
if (secondInterlineRange != null) {
sb.append(" secondInterline:")
.append(secondInterlineRange);
}
sb.append("}");
return sb.toString();
}
//~ Inner Classes ----------------------------------------------------------
//--------------//
// AreaFraction //
//--------------//
/**
* A subclass of Constant.Double, meant to store a fraction of
* interline-based area.
*/
public static class AreaFraction
extends Constant.Double
{
//~ Constructors -------------------------------------------------------
/**
* Specific constructor, where 'unit' and 'name' are assigned
* later.
*
* @param defaultValue the (double) default value
* @param description the semantic of the constant
*/
public AreaFraction (double defaultValue,
java.lang.String description)
{
super("Interline**2", defaultValue, description);
}
}
//----------//
// Fraction //
//----------//
/**
* A subclass of Constant.Double, meant to store a fraction of
* interline, since many distances on a music sheet are expressed
* in fraction of staff interline (as opposed to
* {@link Scale.LineFraction} which stores a fraction of line
* thickness).
*/
public static class Fraction
extends Constant.Double
{
//~ Constructors -------------------------------------------------------
/**
* Specific constructor, where 'unit' and 'name' are assigned
* later.
*
* @param defaultValue the (double) default value
* @param description the semantic of the constant
*/
public Fraction (double defaultValue,
java.lang.String description)
{
super("Interline", defaultValue, description);
}
// Meant for JAXB
private Fraction ()
{
this(0d, null);
}
//~ Methods ------------------------------------------------------------
@Override
public DoubleValue getWrappedValue ()
{
return (DoubleValue) getCachedValue();
}
@Override
public void setValue (double val)
{
setTuple(java.lang.Double.toString(val), new DoubleValue(val));
}
@Override
protected DoubleValue decode (java.lang.String str)
{
return new DoubleValue(java.lang.Double.valueOf(str));
}
}
//--------------//
// LineFraction //
//--------------//
/**
* A subclass of Constant.Double, meant to store a fraction of line
* thickness (as opposed to {@link Scale.Fraction} which stores a
* fraction of interline).
*/
public static class LineFraction
extends Constant.Double
{
//~ Constructors -------------------------------------------------------
/**
* Specific constructor, where 'unit' and 'name' are assigned
* later.
*
* @param defaultValue the (double) default value
* @param description the semantic of the constant
*/
public LineFraction (double defaultValue,
java.lang.String description)
{
super("Line", defaultValue, description);
}
// Meant for JAXB
private LineFraction ()
{
this(0d, null);
}
//~ Methods ------------------------------------------------------------
@Override
public DoubleValue getWrappedValue ()
{
return (DoubleValue) getCachedValue();
}
@Override
public void setValue (double val)
{
setTuple(java.lang.Double.toString(val), new DoubleValue(val));
}
@Override
protected DoubleValue decode (java.lang.String str)
{
return new DoubleValue(java.lang.Double.valueOf(str));
}
}
//-------//
// Range //
//-------//
public static class Range
{
//~ Instance fields ----------------------------------------------------
/** Value at beginning of range */
public final int min;
/** Value at highest point in range */
public final int best;
/** Value at end of range */
public final int max;
//~ Constructors -------------------------------------------------------
public Range (int min,
int best,
int max)
{
this.min = min;
this.best = best;
this.max = max;
}
//~ Methods ------------------------------------------------------------
@Override
public String toString ()
{
return "(" + min + "," + best + "," + max + ")";
}
}
}