|
@@ -4,6 +4,7 @@ import { VexFlowContinuousDynamicExpression } from "./VexFlowContinuousDynamicEx
|
|
|
import { AbstractGraphicalExpression } from "../AbstractGraphicalExpression";
|
|
|
import { PointF2D } from "../../../Common/DataObjects/PointF2D";
|
|
|
import { EngravingRules } from "../EngravingRules";
|
|
|
+import { GraphicalContinuousDynamicExpression } from "../GraphicalContinuousDynamicExpression";
|
|
|
|
|
|
export class AlignmentManager {
|
|
|
private parentStaffline: StaffLine;
|
|
@@ -21,6 +22,15 @@ export class AlignmentManager {
|
|
|
for (let aeIdx: number = 0; aeIdx < this.parentStaffline.AbstractExpressions.length - 1; aeIdx++) {
|
|
|
const currentExpression: AbstractGraphicalExpression = this.parentStaffline.AbstractExpressions[aeIdx];
|
|
|
const nextExpression: AbstractGraphicalExpression = this.parentStaffline.AbstractExpressions[aeIdx + 1];
|
|
|
+
|
|
|
+ // TODO this shifts dynamics in An die Ferne Geliebte, showing that there's something wrong with the RelativePositions etc with wedges
|
|
|
+ // if (currentExpression instanceof GraphicalContinuousDynamicExpression) {
|
|
|
+ // currentExpression.calcPsi();
|
|
|
+ // }
|
|
|
+ // if (nextExpression instanceof GraphicalContinuousDynamicExpression) {
|
|
|
+ // nextExpression.calcPsi();
|
|
|
+ // }
|
|
|
+
|
|
|
if (currentExpression.Placement === nextExpression.Placement) {
|
|
|
const dist: PointF2D = this.getDistance(currentExpression.PositionAndShape, nextExpression.PositionAndShape);
|
|
|
if (dist.x < this.rules.DynamicExpressionMaxDistance) {
|
|
@@ -39,21 +49,47 @@ export class AlignmentManager {
|
|
|
groups.push(tmpList);
|
|
|
|
|
|
for (const aes of groups) {
|
|
|
+ // only align if there are wedges
|
|
|
+ // fixes placement in Clementi Op. 36 No. 1 Pt 2
|
|
|
+ let hasWedges: boolean = false;
|
|
|
+ for (const ae of aes) {
|
|
|
+ if (ae instanceof GraphicalContinuousDynamicExpression && !(ae as GraphicalContinuousDynamicExpression).IsVerbal) {
|
|
|
+ hasWedges = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!hasWedges) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
if (aes.length > 0) {
|
|
|
// Get the median y position and shift all group members to that position
|
|
|
const centerYs: number[] = aes.map(expr => expr.PositionAndShape.Center.y);
|
|
|
+ // TODO this may not give the right position for wedges (GraphicalContinuousDynamic, !isVerbal())
|
|
|
const yIdeal: number = Math.max(...centerYs);
|
|
|
+ // for (const ae of aes) { // debug
|
|
|
+ // if (ae.PositionAndShape.Center.y > 6) {
|
|
|
+ // // dynamic positioned at edge of skybottomline
|
|
|
+ // console.log(`max expression in measure ${ae.SourceExpression.parentMeasure.MeasureNumber}: `);
|
|
|
+ // console.dir(aes);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
for (let exprIdx: number = 0; exprIdx < aes.length; exprIdx++) {
|
|
|
const expr: AbstractGraphicalExpression = aes[exprIdx];
|
|
|
const centerOffset: number = centerYs[exprIdx] - yIdeal;
|
|
|
+ // TODO centerOffset is way too big sometimes, like 7.0 in An die Ferne Geliebte (measure 10, dim.)
|
|
|
// FIXME: Expressions should not behave differently.
|
|
|
if (expr instanceof VexFlowContinuousDynamicExpression) {
|
|
|
(expr as VexFlowContinuousDynamicExpression).shiftYPosition(-centerOffset);
|
|
|
+ (expr as VexFlowContinuousDynamicExpression).calcPsi();
|
|
|
} else {
|
|
|
// TODO: The 0.8 are because the letters are a bit to far done
|
|
|
expr.PositionAndShape.RelativePosition.y -= centerOffset * 0.8;
|
|
|
+ // note: verbal GraphicalContinuousDynamicExpressions have a label, nonverbal ones don't.
|
|
|
+ // take care to update and take the right bounding box for skyline.
|
|
|
+ expr.PositionAndShape.calculateBoundingBox();
|
|
|
}
|
|
|
- expr.PositionAndShape.calculateBoundingBox();
|
|
|
// Squeeze wedges
|
|
|
if ((expr as VexFlowContinuousDynamicExpression).squeeze) {
|
|
|
const nextExpression: AbstractGraphicalExpression = exprIdx < aes.length - 1 ? aes[exprIdx + 1] : undefined;
|
|
@@ -80,7 +116,7 @@ export class AlignmentManager {
|
|
|
private getDistance(a: BoundingBox, b: BoundingBox): PointF2D {
|
|
|
const rightBorderA: number = a.RelativePosition.x + a.BorderMarginRight;
|
|
|
const leftBorderB: number = b.RelativePosition.x + b.BorderMarginLeft;
|
|
|
- const bottomBorderA: number = b.RelativePosition.y + a.BorderMarginBottom;
|
|
|
+ const bottomBorderA: number = a.RelativePosition.y + a.BorderMarginBottom;
|
|
|
const topBorderB: number = b.RelativePosition.y + b.BorderMarginTop;
|
|
|
return new PointF2D(leftBorderB - rightBorderA,
|
|
|
topBorderB - bottomBorderA);
|