|
@@ -4,6 +4,8 @@ import { VexFlowContinuousDynamicExpression } from "./VexFlowContinuousDynamicEx
|
|
import { AbstractGraphicalExpression } from "../AbstractGraphicalExpression";
|
|
import { AbstractGraphicalExpression } from "../AbstractGraphicalExpression";
|
|
import { PointF2D } from "../../../Common/DataObjects/PointF2D";
|
|
import { PointF2D } from "../../../Common/DataObjects/PointF2D";
|
|
import { EngravingRules } from "../EngravingRules";
|
|
import { EngravingRules } from "../EngravingRules";
|
|
|
|
+import { PlacementEnum } from "../../VoiceData/Expressions";
|
|
|
|
+import { GraphicalUnknownExpression } from "../GraphicalUnknownExpression";
|
|
|
|
|
|
export class AlignmentManager {
|
|
export class AlignmentManager {
|
|
private parentStaffline: StaffLine;
|
|
private parentStaffline: StaffLine;
|
|
@@ -21,9 +23,54 @@ export class AlignmentManager {
|
|
for (let aeIdx: number = 0; aeIdx < this.parentStaffline.AbstractExpressions.length - 1; aeIdx++) {
|
|
for (let aeIdx: number = 0; aeIdx < this.parentStaffline.AbstractExpressions.length - 1; aeIdx++) {
|
|
const currentExpression: AbstractGraphicalExpression = this.parentStaffline.AbstractExpressions[aeIdx];
|
|
const currentExpression: AbstractGraphicalExpression = this.parentStaffline.AbstractExpressions[aeIdx];
|
|
const nextExpression: AbstractGraphicalExpression = this.parentStaffline.AbstractExpressions[aeIdx + 1];
|
|
const nextExpression: AbstractGraphicalExpression = this.parentStaffline.AbstractExpressions[aeIdx + 1];
|
|
- if (currentExpression.Placement === nextExpression.Placement) {
|
|
|
|
|
|
+
|
|
|
|
+ let currentExpressionPlacement: PlacementEnum = undefined;
|
|
|
|
+ if (currentExpression?.SourceExpression) {
|
|
|
|
+ currentExpressionPlacement = currentExpression.Placement;
|
|
|
|
+ } else if (currentExpression instanceof GraphicalUnknownExpression) {
|
|
|
|
+ currentExpressionPlacement = (currentExpression as GraphicalUnknownExpression).
|
|
|
|
+ sourceMultiExpression?.getPlacementOfFirstEntry();
|
|
|
|
+ }
|
|
|
|
+ // same for nextExpression:
|
|
|
|
+ let nextExpressionPlacement: PlacementEnum = undefined;
|
|
|
|
+ if (nextExpression?.SourceExpression) {
|
|
|
|
+ nextExpressionPlacement = nextExpression.Placement;
|
|
|
|
+ } else if (nextExpression instanceof GraphicalUnknownExpression) {
|
|
|
|
+ nextExpressionPlacement = (nextExpression as GraphicalUnknownExpression).
|
|
|
|
+ sourceMultiExpression?.getPlacementOfFirstEntry();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // if (currentExpression?.SourceExpression === undefined ||
|
|
|
|
+ // nextExpression?.SourceExpression === undefined) {
|
|
|
|
+ // continue;
|
|
|
|
+ // // TODO: this doesn't work yet for GraphicalUnknownExpression, because it doesn't have an AbstractExpression,
|
|
|
|
+ // // so it doesn't have a .Placement.
|
|
|
|
+ // // this lead to if (currentExpression.Placement...) crashing.
|
|
|
|
+
|
|
|
|
+ // // same result:
|
|
|
|
+ // // if (currentExpression instanceof GraphicalUnknownExpression ||
|
|
|
|
+ // // nextExpression instanceof GraphicalUnknownExpression) {
|
|
|
|
+ // // continue;
|
|
|
|
+ // // }
|
|
|
|
+ // } else {
|
|
|
|
+ // samePlacement = currentExpression.Placement === nextExpression.Placement;
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ // 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 (currentExpressionPlacement === nextExpressionPlacement) {
|
|
|
|
+ // if ((currentExpression as any).label?.label?.text?.startsWith("dim") ||
|
|
|
|
+ // (nextExpression as any).label?.label?.text?.startsWith("dim")) {
|
|
|
|
+ // console.log("here");
|
|
|
|
+ // }
|
|
const dist: PointF2D = this.getDistance(currentExpression.PositionAndShape, nextExpression.PositionAndShape);
|
|
const dist: PointF2D = this.getDistance(currentExpression.PositionAndShape, nextExpression.PositionAndShape);
|
|
- if (dist.x < this.rules.DynamicExpressionMaxDistance) {
|
|
|
|
|
|
+ if (Math.abs(dist.x) < this.rules.DynamicExpressionMaxDistance) {
|
|
// Prevent last found expression to be added twice. e.g. p<f as three close expressions
|
|
// Prevent last found expression to be added twice. e.g. p<f as three close expressions
|
|
if (tmpList.indexOf(currentExpression) === -1) {
|
|
if (tmpList.indexOf(currentExpression) === -1) {
|
|
tmpList.push(currentExpression);
|
|
tmpList.push(currentExpression);
|
|
@@ -42,18 +89,31 @@ export class AlignmentManager {
|
|
if (aes.length > 0) {
|
|
if (aes.length > 0) {
|
|
// Get the median y position and shift all group members to that position
|
|
// Get the median y position and shift all group members to that position
|
|
const centerYs: number[] = aes.map(expr => expr.PositionAndShape.Center.y);
|
|
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);
|
|
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++) {
|
|
for (let exprIdx: number = 0; exprIdx < aes.length; exprIdx++) {
|
|
const expr: AbstractGraphicalExpression = aes[exprIdx];
|
|
const expr: AbstractGraphicalExpression = aes[exprIdx];
|
|
const centerOffset: number = centerYs[exprIdx] - yIdeal;
|
|
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.
|
|
// FIXME: Expressions should not behave differently.
|
|
if (expr instanceof VexFlowContinuousDynamicExpression) {
|
|
if (expr instanceof VexFlowContinuousDynamicExpression) {
|
|
(expr as VexFlowContinuousDynamicExpression).shiftYPosition(-centerOffset);
|
|
(expr as VexFlowContinuousDynamicExpression).shiftYPosition(-centerOffset);
|
|
|
|
+ (expr as VexFlowContinuousDynamicExpression).calcPsi();
|
|
} else {
|
|
} else {
|
|
- // TODO: The 0.8 are because the letters are a bit to far done
|
|
|
|
|
|
+ // TODO: The 0.8 are because the letters are a bit too far done
|
|
expr.PositionAndShape.RelativePosition.y -= centerOffset * 0.8;
|
|
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
|
|
// Squeeze wedges
|
|
if ((expr as VexFlowContinuousDynamicExpression).squeeze) {
|
|
if ((expr as VexFlowContinuousDynamicExpression).squeeze) {
|
|
const nextExpression: AbstractGraphicalExpression = exprIdx < aes.length - 1 ? aes[exprIdx + 1] : undefined;
|
|
const nextExpression: AbstractGraphicalExpression = exprIdx < aes.length - 1 ? aes[exprIdx + 1] : undefined;
|
|
@@ -80,10 +140,11 @@ export class AlignmentManager {
|
|
private getDistance(a: BoundingBox, b: BoundingBox): PointF2D {
|
|
private getDistance(a: BoundingBox, b: BoundingBox): PointF2D {
|
|
const rightBorderA: number = a.RelativePosition.x + a.BorderMarginRight;
|
|
const rightBorderA: number = a.RelativePosition.x + a.BorderMarginRight;
|
|
const leftBorderB: number = b.RelativePosition.x + b.BorderMarginLeft;
|
|
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;
|
|
const topBorderB: number = b.RelativePosition.y + b.BorderMarginTop;
|
|
return new PointF2D(leftBorderB - rightBorderA,
|
|
return new PointF2D(leftBorderB - rightBorderA,
|
|
topBorderB - bottomBorderA);
|
|
topBorderB - bottomBorderA);
|
|
|
|
+ // note: this is a distance vector, not absolute distance, otherwise we need Math.abs
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|