import { StaffLine } from "../StaffLine" ; import { BoundingBox } from "../BoundingBox" ; import { VexFlowContinuousDynamicExpression } from "./VexFlowContinuousDynamicExpression" ; import { AbstractGraphicalExpression } from "../AbstractGraphicalExpression" ; import { PointF2D } from "../../../Common/DataObjects/PointF2D" ; import { EngravingRules } from "../EngravingRules" ; import { PlacementEnum } from "../../VoiceData/Expressions/AbstractExpression" ; export class AlignmentManager { private parentStaffline : StaffLine ; private rules : EngravingRules ; constructor ( staffline ) { this . parentStaffline = staffline ; this . rules = this . parentStaffline . ParentMusicSystem . rules ; } public alignDynamicExpressions ( ) { const groups = [ ] ; let tmpList = new Array < AbstractGraphicalExpression > ( ) ; for ( let aeIdx = 0 ; aeIdx < this . parentStaffline . AbstractExpressions . length - 1 ; aeIdx ++ ) { const currentExpression = this . parentStaffline . AbstractExpressions [ aeIdx ] ; const nextExpression = this . parentStaffline . AbstractExpressions [ aeIdx + 1 ] ; const currentExpressionPlacement = currentExpression ?. SourceExpression ?. Placement ; const nextExpressionPlacement = nextExpression ?. SourceExpression ?. Placement ; if ( currentExpressionPlacement === nextExpressionPlacement ) { const dist = this . getDistance ( currentExpression . PositionAndShape , nextExpression . PositionAndShape ) ; if ( Math . abs ( dist . x ) < this . rules . DynamicExpressionMaxDistance ) { if ( tmpList . indexOf ( currentExpression ) === - 1 ) { tmpList . push ( currentExpression ) ; } tmpList . push ( nextExpression ) ; } else { groups . push ( tmpList ) ; tmpList = new Array < AbstractGraphicalExpression > ( ) ; } } } groups . push ( tmpList ) ; for ( const aes of groups ) { if ( aes . length > 0 ) { const centerYs = aes . map ( expr => expr . PositionAndShape . Center . y ) ; const yIdeal = Math . max ( ... centerYs ) ; for ( let exprIdx = 0 ; exprIdx < aes . length ; exprIdx ++ ) { const expr = aes [ exprIdx ] ; const centerOffset = centerYs [ exprIdx ] - yIdeal ; if ( expr instanceof VexFlowContinuousDynamicExpression ) { ( expr as VexFlowContinuousDynamicExpression ) . shiftYPosition ( - centerOffset ) ; ( expr as VexFlowContinuousDynamicExpression ) . calcPsi ( ) ; } else { expr . PositionAndShape . RelativePosition . y -= centerOffset * 0.8 ; expr . PositionAndShape . calculateBoundingBox ( ) ; } if ( ( expr as VexFlowContinuousDynamicExpression ) . squeeze ) { const nextExpression = exprIdx < aes . length - 1 ? aes [ exprIdx + 1 ] : undefined ; const prevExpression = exprIdx > 0 ? aes [ exprIdx - 1 ] : undefined ; if ( nextExpression ) { const overlapRight = this . getOverlap ( expr . PositionAndShape , nextExpression . PositionAndShape ) ; ( expr as VexFlowContinuousDynamicExpression ) . squeeze ( - ( overlapRight . x + this . rules . DynamicExpressionSpacer ) ) ; } if ( prevExpression ) { const overlapLeft = this . getOverlap ( prevExpression . PositionAndShape , expr . PositionAndShape ) ; ( expr as VexFlowContinuousDynamicExpression ) . squeeze ( overlapLeft . x + this . rules . DynamicExpressionSpacer ) ; } } } } } } param a param b private getDistance ( a , b ) { const rightBorderA = a . RelativePosition . x + a . BorderMarginRight ; const leftBorderB = b . RelativePosition . x + b . BorderMarginLeft ; const bottomBorderA = a . RelativePosition . y + a . BorderMarginBottom ; const topBorderB = b . RelativePosition . y + b . BorderMarginTop ; return new PointF2D ( leftBorderB - rightBorderA , topBorderB - bottomBorderA ) ; } param a param b private getOverlap ( a , b ) { return new PointF2D ( ( a . RelativePosition . x + a . BorderMarginRight ) - ( b . RelativePosition . x + b . BorderMarginLeft ) , ( a . RelativePosition . y + a . BorderMarginBottom ) - ( b . RelativePosition . y + b . BorderMarginTop ) ) ; } }