//----------------------------------------------------------------------------// // // // D o t P a t t e r n // // // //----------------------------------------------------------------------------// // <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.glyph.pattern; import omr.constant.Constant; import omr.constant.ConstantSet; import omr.glyph.Glyphs; import omr.glyph.Shape; import omr.glyph.ShapeSet; import omr.glyph.facets.Glyph; import omr.run.Orientation; import omr.sheet.Scale; import omr.sheet.SystemInfo; import omr.text.TextLine; import omr.text.TextWord; import omr.util.Predicate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.Rectangle; import java.awt.geom.Line2D; import java.util.Collections; import java.util.Set; /** * Class {@code DotPattern} filters the dot glyphs to remove those * which are actually text dashes ('-') within sentences. * * @author Hervé Bitteur */ public class DotPattern extends GlyphPattern { //~ Static fields/initializers --------------------------------------------- /** Specific application parameters */ private static final Constants constants = new Constants(); /** Usual logger utility */ private static final Logger logger = LoggerFactory.getLogger( DotPattern.class); //~ Instance fields -------------------------------------------------------- // /** Max dx from sentence end to dot. */ private final int maxLineDx; /** Max dy from sentence baseline to dot. */ private final int maxLineDy; //~ Constructors ----------------------------------------------------------- // //------------// // DotPattern // //------------// /** * Creates a new DotPattern object. * * @param system the dedicated system */ public DotPattern (SystemInfo system) { super("Dot", system); // Scale-dependent parameters maxLineDx = scale.toPixels(constants.maxLineDx); maxLineDy = scale.toPixels(constants.maxLineDy); } //~ Methods ---------------------------------------------------------------- // //------------// // runPattern // //------------// /** * In a specified system, look for all dots that should not be kept. * * @return the number of dots deassigned */ @Override public int runPattern () { int nb = 0; String language = system.getSheet() .getPage() .getTextParam() .getTarget(); for (Glyph glyph : getQuestionableDots()) { // Check alignment with a TextLine TextLine line = getEmbracingLine(glyph); if (line == null) { continue; } // Check shape if (!isDashLooking(glyph)) { continue; } // OK, assign it the character shape glyph.setShape(Shape.CHARACTER); // Insert it into line TextWord word = TextWord.createManualWord(glyph, "-"); glyph.setTextWord(language, word); line.addWords(Collections.singleton(word)); logger.debug("Reassign dot#{} to {}", glyph.getId(), line); // Counters nb++; } return nb; } //------------------// // getEmbracingLine // //------------------// /** * Lookup for a TextLine that embraces the provided glyph. * * @param the (dot) glyph to check * @return glyph the embracing line if any, otherwise null */ private TextLine getEmbracingLine (Glyph glyph) { Rectangle glyphBox = glyph.getBounds(); for (TextLine sentence : system.getSentences()) { Line2D baseline = sentence.getBaseline(); // Check in abscissa: not before sentence beginning if ((glyphBox.x + glyphBox.width) <= baseline.getX1()) { continue; } // Check in abscissa: not too far after sentence end if ((glyphBox.x - baseline.getX2()) > maxLineDx) { continue; } // Check in abscissa: not overlapping any sentence word for (TextWord word : sentence.getWords()) { if (word.getBounds() .intersects(glyphBox)) { continue; } } // Check in ordinate: distance from baseline double dy = baseline.ptLineDist(glyph.getAreaCenter()); if (dy > maxLineDy) { continue; } // This line is OK, take it return sentence; } // Nothing found return null; } //---------------------// // getQuestionableDots // //---------------------// /** * Retrieve questionable dots. * * @return the set of dots to further check */ private Set<Glyph> getQuestionableDots () { Set<Glyph> dots = Glyphs.lookupGlyphs( system.getGlyphs(), new Predicate<Glyph>() { @Override public boolean check (Glyph glyph) { Shape shape = glyph.getShape(); return (shape != null) && ShapeSet.Dots.contains(shape) && !glyph.isManualShape() && glyph.isActive(); } }); if (logger.isDebugEnabled()) { logger.debug( "{} Questionable {}", system.getLogPrefix(), Glyphs.toString("dots", dots)); } return dots; } //---------------// // isDashLooking // //---------------// /** * Check whether the provided glyph looks like a '-' character. * * @param glyph the glyph to check * @return true if tests are OK */ private boolean isDashLooking (Glyph glyph) { return glyph.getAspect(Orientation.HORIZONTAL) >= constants.minAspect.getValue(); } //~ Inner Classes ---------------------------------------------------------- // //-----------// // Constants // //-----------// private static final class Constants extends ConstantSet { //~ Instance fields ---------------------------------------------------- Constant.Ratio minAspect = new Constant.Ratio( 2, "Minimum width / height ratio for a dash"); Scale.Fraction maxLineDx = new Scale.Fraction( 10, "Maximum abscissa offset from line to dash"); Scale.Fraction maxLineDy = new Scale.Fraction( 2, "Maximum ordinate offset from line to dash"); } }