import { GraphicalLine } from "./GraphicalLine" ; import { StaffLine } from "./StaffLine" ; import { GraphicalMeasure } from "./GraphicalMeasure" ; import { ContDynamicEnum , ContinuousDynamicExpression } from "../VoiceData/Expressions/ContinuousExpressions/ContinuousDynamicExpression" ; import { PointF2D } from "../../Common/DataObjects/PointF2D" ; import { AbstractGraphicalExpression } from "./AbstractGraphicalExpression" ; import { PlacementEnum } from "../VoiceData/Expressions/AbstractExpression" ; import { SkyBottomLineCalculator } from "./SkyBottomLineCalculator" ; import { ISqueezable } from "./ISqueezable" ; import log from "loglevel" ; import { SourceMeasure } from "../VoiceData/SourceMeasure" ; /**
 * This class prepares the graphical elements for a continuous expression. It calculates the wedges and
 * wrappings if they are split over system breaks.
 */ export class GraphicalContinuousDynamicExpression extends AbstractGraphicalExpression implements ISqueezable { /** True if expression is split over system borders */ private isSplittedPart : boolean ; /** True if this expression should not be removed if re-rendered */ private notToBeRemoved : boolean ; /** Holds the line objects that can be drawn via implementation */ private lines : GraphicalLine [ ] = [ ] ; private startMeasure : GraphicalMeasure ; private endMeasure : GraphicalMeasure ; param continuousDynamic param staffLine constructor ( continuousDynamic , staffLine , measure ) { super ( staffLine , continuousDynamic , measure ) ; this . isSplittedPart = false ; this . notToBeRemoved = false ; } /** The graphical measure where the parent continuous dynamic expression starts */ public get StartMeasure ( ) : GraphicalMeasure { return this . startMeasure ; } public set StartMeasure ( value ) { this . startMeasure = value ; } /** The graphical measure where the parent continuous dynamic expression ends */ public get EndMeasure ( ) : GraphicalMeasure { return this . endMeasure ; } public set EndMeasure ( value ) { this . endMeasure = value ; } /** The staff lin where the graphical dynamic expressions ends */ public get EndStaffLine ( ) : StaffLine { return this . endMeasure ? this . endMeasure . ParentStaffLine : undefined ; } /**  Is true if this continuous expression is a wedge, that reaches over a system border and needs to be split into two. */ public get IsSplittedPart ( ) : boolean { return this . isSplittedPart ; } public set IsSplittedPart ( value ) { this . isSplittedPart = value ; } /**  Is true if the dynamic is not a symbol but a text instruction. E.g. "decrescendo" */ public get IsVerbal ( ) : boolean { return this . ContinuousDynamic . Label && this . ContinuousDynamic . Label . length > 0 ; } /** True if this expression should not be removed if re-rendered */ public get NotToBeRemoved ( ) : boolean { return this . notToBeRemoved ; } public set NotToBeRemoved ( value ) { this . notToBeRemoved = value ; } /** Holds the line objects that can be drawn via implementation */ public get Lines ( ) : GraphicalLine [ ] { return this . lines ; } public get ContinuousDynamic ( ) : ContinuousDynamicExpression { return this . SourceExpression as ContinuousDynamicExpression ; } public updateSkyBottomLine ( ) { const skyBottomLineCalculator = this . parentStaffLine . SkyBottomLineCalculator ; const left = this . IsVerbal ? this . label . PositionAndShape . RelativePosition . x + this . label . PositionAndShape . BorderMarginLeft : 0 ; const right = this . IsVerbal ? this . label . PositionAndShape . RelativePosition . x + this . label . PositionAndShape . BorderMarginRight : 0 ; if ( ! this . IsVerbal && this . lines . length < 2 ) { log . warn ( "Not enough lines for SkyBottomLine calculation" ) ; } if ( ! this . IsVerbal ) { if ( this . ContinuousDynamic . DynamicType !== ContDynamicEnum . crescendo && this . ContinuousDynamic . DynamicType !== ContDynamicEnum . diminuendo ) { log . warn ( "GraphicalContinuousDynamicExpression.updateSkyBottomLine(): " + "unhandled continuous dynamic type. start measure: " + this . startMeasure ?. MeasureNumber ) ; } } switch ( this . Placement ) { case PlacementEnum . Above : if ( ! this . IsVerbal ) { if ( this . ContinuousDynamic . DynamicType === ContDynamicEnum . crescendo ) { skyBottomLineCalculator . updateSkyLineWithWedge ( this . lines [ 0 ] . Start , this . lines [ 0 ] . End ) ; } else if ( this . ContinuousDynamic . DynamicType === ContDynamicEnum . diminuendo ) { skyBottomLineCalculator . updateSkyLineWithWedge ( this . lines [ 0 ] . End , this . lines [ 0 ] . Start ) ; } } else { const yValue = this . label . PositionAndShape . BorderMarginTop + this . label . PositionAndShape . RelativePosition . y ; skyBottomLineCalculator . updateSkyLineInRange ( left , right , yValue ) ; } break ; case PlacementEnum . Below : if ( ! this . IsVerbal ) { if ( this . ContinuousDynamic . DynamicType === ContDynamicEnum . crescendo ) { skyBottomLineCalculator . updateBottomLineWithWedge ( this . lines [ 1 ] . Start , this . lines [ 1 ] . End ) ; } else if ( this . ContinuousDynamic . DynamicType === ContDynamicEnum . diminuendo ) { skyBottomLineCalculator . updateBottomLineWithWedge ( this . lines [ 1 ] . End , this . lines [ 1 ] . Start ) ; } } else { const yValue = this . label . PositionAndShape . BorderMarginBottom + this . label . PositionAndShape . RelativePosition . y ; skyBottomLineCalculator . updateBottomLineInRange ( left , right , yValue ) ; } break ; default : log . error ( "Placement for GraphicalContinuousDynamicExpression is unknown" ) ; } } param startX param endX param y param wedgeOpeningLength param wedgeLineWidth public createCrescendoLines ( startX , endX , y , wedgeOpeningLength = this . rules . WedgeOpeningLength , wedgeLineWidth = this . rules . WedgeLineWidth ) { const lineStart = new PointF2D ( startX , y ) ; const upperLineEnd = new PointF2D ( endX , y - wedgeOpeningLength / 2 ) ; const lowerLineEnd = new PointF2D ( endX , y + wedgeOpeningLength / 2 ) ; this . addWedgeLines ( lineStart , upperLineEnd , lowerLineEnd , wedgeLineWidth ) ; } param startX param endX param y param wedgeMeasureEndOpeningLength param wedgeOpeningLength param wedgeLineWidth public createFirstHalfCrescendoLines ( startX , endX , y , wedgeMeasureEndOpeningLength = this . rules . WedgeMeasureEndOpeningLength , wedgeLineWidth = this . rules . WedgeLineWidth ) { const lineStart = new PointF2D ( startX , y ) ; const upperLineEnd = new PointF2D ( endX , y - wedgeMeasureEndOpeningLength / 2 ) ; const lowerLineEnd = new PointF2D ( endX , y + wedgeMeasureEndOpeningLength / 2 ) ; this . addWedgeLines ( lineStart , upperLineEnd , lowerLineEnd , wedgeLineWidth ) ; } param startX param endX param y param wedgeMeasureBeginOpeningLength param wedgeOpeningLength param wedgeLineWidth public createSecondHalfCrescendoLines ( startX , endX , y , wedgeMeasureBeginOpeningLength = this . rules . WedgeMeasureBeginOpeningLength , wedgeOpeningLength = this . rules . WedgeOpeningLength , wedgeLineWidth = this . rules . WedgeLineWidth ) { const upperLineStart = new PointF2D ( startX , y - wedgeMeasureBeginOpeningLength / 2 ) ; const lowerLineStart = new PointF2D ( startX , y + wedgeMeasureBeginOpeningLength / 2 ) ; const upperLineEnd = new PointF2D ( endX , y - wedgeOpeningLength / 2 ) ; const lowerLineEnd = new PointF2D ( endX , y + wedgeOpeningLength / 2 ) ; this . addDoubleLines ( upperLineStart , upperLineEnd , lowerLineStart , lowerLineEnd , wedgeLineWidth ) ; } param startX param endX param y public recalculateCrescendoLines ( startX , endX , y ) { const isSecondHalfSplit = Math . abs ( this . lines [ 0 ] . Start . y - this . lines [ 1 ] . Start . y ) > 0.0001 ; this . lines . clear ( ) ; if ( isSecondHalfSplit ) { this . createSecondHalfCrescendoLines ( startX , endX , y ) ; } else if ( this . isSplittedPart ) { this . createFirstHalfCrescendoLines ( startX , endX , y ) ; } else { this . createCrescendoLines ( startX , endX , y ) ; } } param startX param endX param y param wedgeOpeningLength param wedgeLineWidth public createDiminuendoLines ( startX , endX , y , wedgeOpeningLength = this . rules . WedgeOpeningLength , wedgeLineWidth = this . rules . WedgeLineWidth ) { const upperWedgeStart = new PointF2D ( startX , y - wedgeOpeningLength / 2 ) ; const lowerWedgeStart = new PointF2D ( startX , y + wedgeOpeningLength / 2 ) ; const wedgeEnd = new PointF2D ( endX , y ) ; this . addWedgeLines ( wedgeEnd , upperWedgeStart , lowerWedgeStart , wedgeLineWidth ) ; } param startX param endX param y param wedgeOpeningLength param wedgeMeasureEndOpeningLength param wedgeLineWidth public createFirstHalfDiminuendoLines ( startX , endX , y , wedgeOpeningLength = this . rules . WedgeOpeningLength , wedgeMeasureEndOpeningLength = this . rules . WedgeMeasureEndOpeningLength , wedgeLineWidth = this . rules . WedgeLineWidth ) { const upperLineStart = new PointF2D ( startX , y - wedgeOpeningLength / 2 ) ; const lowerLineStart = new PointF2D ( startX , y + wedgeOpeningLength / 2 ) ; const upperLineEnd = new PointF2D ( endX , y - wedgeMeasureEndOpeningLength / 2 ) ; const lowerLineEnd = new PointF2D ( endX , y + wedgeMeasureEndOpeningLength / 2 ) ; this . addDoubleLines ( upperLineStart , upperLineEnd , lowerLineStart , lowerLineEnd , wedgeLineWidth ) ; } param startX param endX param y param wedgeMeasureBeginOpeningLength param wedgeLineWidth public createSecondHalfDiminuendoLines ( startX , endX , y , wedgeMeasureBeginOpeningLength = this . rules . WedgeMeasureBeginOpeningLength , wedgeLineWidth = this . rules . WedgeLineWidth ) { const upperLineStart = new PointF2D ( startX , y - wedgeMeasureBeginOpeningLength / 2 ) ; const lowerLineStart = new PointF2D ( startX , y + wedgeMeasureBeginOpeningLength / 2 ) ; const lineEnd = new PointF2D ( endX , y ) ; this . addWedgeLines ( lineEnd , upperLineStart , lowerLineStart , wedgeLineWidth ) ; } param startX param endX param y public recalculateDiminuendoLines ( startX , endX , yPosition ) { const isFirstHalfSplit = Math . abs ( this . lines [ 0 ] . End . y - this . lines [ 1 ] . End . y ) > 0.0001 ; this . lines . clear ( ) ; if ( isFirstHalfSplit ) { this . createFirstHalfDiminuendoLines ( startX , endX , yPosition ) ; } else if ( this . isSplittedPart ) { this . createSecondHalfDiminuendoLines ( startX , endX , yPosition ) ; } else { this . createDiminuendoLines ( startX , endX , yPosition ) ; } } /**
     * Calculate the BoundingBox (as a box around the Wedge).
     */ public calcPsi ( ) { if ( this . IsVerbal ) { this . PositionAndShape . calculateBoundingBox ( ) ; return ; } this . PositionAndShape . RelativePosition = this . lines [ 0 ] . Start ; this . PositionAndShape . BorderMarginTop = this . lines [ 0 ] . End . y - this . lines [ 0 ] . Start . y ; this . PositionAndShape . BorderMarginBottom = this . lines [ 1 ] . End . y - this . lines [ 1 ] . Start . y ; this . PositionAndShape . Center . y = ( this . PositionAndShape . BorderMarginTop + this . PositionAndShape . BorderMarginBottom ) / 2 ; if ( this . ContinuousDynamic . DynamicType === ContDynamicEnum . crescendo ) { this . PositionAndShape . BorderMarginLeft = 0 ; this . PositionAndShape . BorderMarginRight = this . lines [ 0 ] . End . x - this . lines [ 0 ] . Start . x ; } else { this . PositionAndShape . BorderMarginLeft = this . lines [ 0 ] . End . x - this . lines [ 0 ] . Start . x ; this . PositionAndShape . BorderMarginRight = 0 ; } } /**
     * Clear Lines
     */ public cleanUp ( ) { this . lines . clear ( ) ; } param shift public shiftYPosition ( shift ) { if ( this . IsVerbal ) { this . PositionAndShape . RelativePosition . y += shift ; this . PositionAndShape . calculateBoundingBox ( ) ; } else { this . lines [ 0 ] . Start . y += shift ; this . lines [ 0 ] . End . y += shift ; this . lines [ 1 ] . End . y += shift ; } } public squeeze ( value ) { if ( this . IsVerbal ) { return ; } const width = Math . abs ( this . lines [ 0 ] . End . x - this . lines [ 0 ] . Start . x ) ; if ( width < Math . abs ( value ) ) { return ; } if ( this . ContinuousDynamic . DynamicType === ContDynamicEnum . crescendo ) { if ( value > 0 ) { this . lines [ 0 ] . Start . x += value ; } else { this . lines [ 0 ] . End . x += value ; this . lines [ 1 ] . End . x += value ; } } else { if ( value < 0 ) { this . lines [ 0 ] . Start . x += value ; } else { this . lines [ 0 ] . End . x += value ; this . lines [ 1 ] . End . x += value ; } } this . calcPsi ( ) ; } param wedgePoint param upperWedgeEnd param lowerWedgeEnd param wedgeLineWidth private addWedgeLines ( wedgePoint , upperWedgeEnd , lowerWedgeEnd , wedgeLineWidth ) { const upperLine = new GraphicalLine ( wedgePoint , upperWedgeEnd , wedgeLineWidth ) ; const lowerLine = new GraphicalLine ( wedgePoint , lowerWedgeEnd , wedgeLineWidth ) ; this . lines . push ( upperLine ) ; this . lines . push ( lowerLine ) ; } param upperLineStart param upperLineEnd param lowerLineStart param lowerLineEnd param wedgeLineWidth private addDoubleLines ( upperLineStart , upperLineEnd , lowerLineStart , lowerLineEnd , wedgeLineWidth ) { const upperLine = new GraphicalLine ( upperLineStart , upperLineEnd , wedgeLineWidth ) ; const lowerLine = new GraphicalLine ( lowerLineStart , lowerLineEnd , wedgeLineWidth ) ; this . lines . push ( upperLine ) ; this . lines . push ( lowerLine ) ; } }