소스 검색

Merge branch 'feature/Expressions' into develop

Benjamin Giesinger 6 년 전
부모
커밋
7dee393102

+ 4 - 0
src/MusicalScore/Graphical/MusicSheetCalculator.ts

@@ -56,6 +56,8 @@ import { Label } from "../Label";
 import { GraphicalVoiceEntry } from "./GraphicalVoiceEntry";
 import { VerticalSourceStaffEntryContainer } from "../VoiceData/VerticalSourceStaffEntryContainer";
 import { SkyBottomLineCalculator } from "./SkyBottomLineCalculator";
+// FIXME: This shoud not be here
+import { VexFlowMeasure } from "./VexFlow/VexFlowMeasure";
 
 /**
  * Class used to do all the calculations in a MusicSheet, which in the end populates a GraphicalMusicSheet.
@@ -1963,6 +1965,8 @@ export abstract class MusicSheetCalculator {
     private calculateDynamicExpressions(): void {
         for (let i: number = 0; i < this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures.length; i++) {
             const sourceMeasure: SourceMeasure = this.graphicalMusicSheet.ParentMusicSheet.SourceMeasures[i];
+            // Clear list of all dynamic epxressions and fill again (needed if lines are removed)
+            this.graphicalMusicSheet.MeasureList[i].forEach(m => (m as VexFlowMeasure).instantaniousDynamics = []);
             for (let j: number = 0; j < sourceMeasure.StaffLinkedExpressions.length; j++) {
                 if (this.graphicalMusicSheet.MeasureList[i][j].ParentStaff.ParentInstrument.Visible) {
                     for (let k: number = 0; k < sourceMeasure.StaffLinkedExpressions[j].length; k++) {

+ 14 - 0
src/MusicalScore/Graphical/MusicSheetDrawer.ts

@@ -485,6 +485,20 @@ export abstract class MusicSheetDrawer {
             let tmpRect: RectangleF2D = new RectangleF2D(startBox.AbsolutePosition.x + startBox.BorderLeft,
                                                          startBox.AbsolutePosition.y + startBox.BorderTop ,
                                                          (relBoundingRect.width + 0), (relBoundingRect.height + 0));
+            this.drawLineAsHorizontalRectangle(new GraphicalLine(
+                                                             new PointF2D(startBox.AbsolutePosition.x - 1, startBox.AbsolutePosition.y),
+                                                             new PointF2D(startBox.AbsolutePosition.x + 1, startBox.AbsolutePosition.y),
+                                                             0.1,
+                                                             OutlineAndFillStyleEnum.BaseWritingColor),
+                                               layer - 1);
+
+            this.drawLineAsVerticalRectangle(new GraphicalLine(
+                                                                 new PointF2D(startBox.AbsolutePosition.x, startBox.AbsolutePosition.y - 1),
+                                                                 new PointF2D(startBox.AbsolutePosition.x, startBox.AbsolutePosition.y + 1),
+                                                                 0.1,
+                                                                 OutlineAndFillStyleEnum.BaseWritingColor),
+                                             layer - 1);
+
             tmpRect = this.applyScreenTransformationForRect(tmpRect);
             this.renderRectangle(tmpRect, <number>GraphicalLayers.Background, layer, 0.5);
             this.renderLabel(new GraphicalLabel(new Label(dataObjectString), 0.8, TextAlignment.CenterCenter),

+ 64 - 28
src/MusicalScore/Graphical/SkyBottomLineCalculator.ts

@@ -1,3 +1,6 @@
+/* tslint:disable no-unused-variable */
+//FIXME: Enble tslint again when all functions are implemented and in use!
+
 import { EngravingRules } from "./EngravingRules";
 import { StaffLine } from "./StaffLine";
 import { PointF2D } from "../../Common/DataObjects/PointF2D";
@@ -264,14 +267,14 @@ export class SkyBottomLineCalculator {
      * @param endIndex End index of the range
      */
     public resetBottomLineInRange(startIndex: number, endIndex: number): void {
-        this.updateInRange(this.BottomLine, startIndex, endIndex);
+        this.setInRange(this.BottomLine, startIndex, endIndex);
     }
 
     /**
      * Update the whole skyline with a certain value
      * @param value value to be set
      */
-    public updateSkyLineWithValue(value: number): void {
+    public setSkyLineWithValue(value: number): void {
         this.SkyLine.forEach(sl => sl = value);
     }
 
@@ -279,7 +282,7 @@ export class SkyBottomLineCalculator {
      * Update the whole bottomline with a certain value
      * @param value value to be set
      */
-    public updateBottomLineWithValue(value: number): void {
+    public setBottomLineWithValue(value: number): void {
         this.BottomLine.forEach(bl => bl = value);
     }
 
@@ -368,41 +371,47 @@ export class SkyBottomLineCalculator {
     }
 
     /**
-     * This method finds the BottomLine's maximum value within a given range.
-     * @param staffLine Staffline to find the max value in
-     * @param startIndex Start index of the range
-     * @param endIndex End index of the range
-     */
-
-
-    /**
      * This method returns the maximum value of the bottom line around a specific
      * bounding box. Will return undefined if the bounding box is not valid or inside staffline
      * @param boundingBox Bounding box where the maximum should be retrieved from
      * @returns Maximum value inside bounding box boundaries or undefined if not possible
      */
     public getBottomLineMaxInBoundingBox(boundingBox: BoundingBox): number {
-        // FIXME: See if this really works as expected!
-        let iteratorBB: BoundingBox = boundingBox;
-        let startIndex: number = boundingBox.BorderLeft;
-        let endIndex: number = boundingBox.BorderRight;
-        let successfull: boolean = false;
-        while (iteratorBB.Parent) {
-            if (iteratorBB === this.mStaffLineParent.PositionAndShape) {
-                successfull = true;
-                break;
-            }
-            startIndex += iteratorBB.BorderLeft;
-            endIndex += iteratorBB.BorderRight;
-            iteratorBB = iteratorBB.Parent;
-        }
-        return successfull ? this.getMaxInRange(this.BottomLine, startIndex, endIndex) : undefined;
+        const startPoint: number = Math.floor(boundingBox.AbsolutePosition.x + boundingBox.BorderMarginLeft);
+        const endPoint: number = Math.ceil(boundingBox.AbsolutePosition.x + boundingBox.BorderMarginRight);
+        return this.getMaxInRange(this.mBottomLine, startPoint, endPoint);
     }
 
     //#region Private methods
 
     /**
-     * Update an array value inside a range
+     * Updates sky- and bottom line with a boundingBox and it's children
+     * @param boundingBox Bounding box to be added
+     * @param topBorder top
+     */
+    private updateWithBoundingBoxRecursivly(boundingBox: BoundingBox): void {
+        if (boundingBox.ChildElements && boundingBox.ChildElements.length > 0) {
+            this.updateWithBoundingBoxRecursivly(boundingBox);
+        } else {
+            const currentTopBorder: number = boundingBox.BorderMarginTop + boundingBox.AbsolutePosition.y;
+            const currentBottomBorder: number = boundingBox.BorderMarginBottom + boundingBox.AbsolutePosition.y;
+
+            if (currentTopBorder < 0) {
+                const startPoint: number = Math.floor(boundingBox.AbsolutePosition.x + boundingBox.BorderMarginLeft);
+                const endPoint: number = Math.ceil(boundingBox.AbsolutePosition.x + boundingBox.BorderMarginRight) ;
+
+                this.updateInRange(this.mSkyLine, startPoint, endPoint, currentTopBorder);
+            } else if (currentBottomBorder > this.mRules.StaffHeight) {
+                const startPoint: number = Math.floor(boundingBox.AbsolutePosition.x + boundingBox.BorderMarginLeft);
+                const endPoint: number = Math.ceil(boundingBox.AbsolutePosition.x + boundingBox.BorderMarginRight);
+
+                this.updateInRange(this.mBottomLine, startPoint, endPoint, currentBottomBorder);
+            }
+        }
+    }
+
+    /**
+     * Update an array with the value given inside a range. NOTE: will only be updated if value > oldValue
      * @param array Array to fill in the new value
      * @param startIndex start index to begin with (default: 0)
      * @param endIndex end index of array (default: array length)
@@ -425,11 +434,38 @@ export class SkyBottomLineCalculator {
         }
 
         for (let i: number = startIndex; i < endIndex; i++) {
-            array[i] = value;
+            array[i] = value > array[i] ? value : array[i];
         }
     }
 
     /**
+     * Sets the value given to the range inside the array. NOTE: will always update the value
+     * @param array Array to fill in the new value
+     * @param startIndex start index to begin with (default: 0)
+     * @param endIndex end index of array (default: array length)
+     * @param value value to fill in (default: 0)
+     */
+    private setInRange(array: number[], startIndex: number = 0, endIndex: number = array.length, value: number = 0): void {
+        startIndex = Math.floor(startIndex * this.SamplingUnit);
+        endIndex = Math.ceil(endIndex * this.SamplingUnit);
+
+        if (endIndex < startIndex) {
+            throw new Error("start index of line is greater then the end index");
+        }
+
+        if (startIndex < 0) {
+            startIndex = 0;
+        }
+
+        if (endIndex > array.length) {
+            endIndex = array.length;
+        }
+
+        for (let i: number = startIndex; i < endIndex; i++) {
+            array[i] = value;
+        }
+    }
+    /**
      * Get all values of the selected line inside the given range
      * @param skyBottomArray Skyline or bottom line
      * @param startIndex start index

+ 4 - 2
src/MusicalScore/Graphical/VexFlow/VexFlowInstantaniousDynamicExpression.ts

@@ -23,8 +23,10 @@ export class VexFlowInstantaniousDynamicExpression extends GraphicalInstantaniou
                                          TextAlignment.LeftTop,
                                          staffEntry ? staffEntry.PositionAndShape : undefined);
 
-        const offset: number = staffEntry ? staffEntry.parentMeasure.ParentStaffLine
-                                       .SkyBottomLineCalculator.getBottomLineMaxInBoundingBox(staffEntry.parentMeasure.PositionAndShape) : 0;
+        let offset: number = staffEntry ? staffEntry.parentMeasure.ParentStaffLine
+                                     .SkyBottomLineCalculator.getBottomLineMaxInBoundingBox(staffEntry.parentMeasure.PositionAndShape) : 0;
+        // TODO: this should not happen: Bug in sbc?
+        offset = offset < 0 ? 0 : offset;
         this.mLabel.PositionAndShape.RelativePosition.y += offset;
         this.mLabel.Label.fontStyle = FontStyles.BoldItalic;
         this.mLabel.setLabelPositionAndShapeBorders();

+ 1 - 0
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -327,6 +327,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
         for (const voiceID in this.vfVoices) {
             if (this.vfVoices.hasOwnProperty(voiceID)) {
                 this.vfVoices[voiceID].draw(ctx, this.stave);
+                // this.vfVoices[voiceID].tickables.forEach(t => t.getBoundingBox().draw(ctx));
             }
         }
         // Draw beams

+ 12 - 26
src/MusicalScore/Graphical/VexFlow/VexFlowStaffEntry.ts

@@ -20,35 +20,21 @@ export class VexFlowStaffEntry extends GraphicalStaffEntry {
      */
     public calculateXPosition(): void {
         const stave: Vex.Flow.Stave = (this.parentMeasure as VexFlowMeasure).getVFStave();
-        let tickablePosition: number = 0;
-        let numberOfValidTickables: number = 0;
-        for (const gve of this.graphicalVoiceEntries) {
-            if (gve.parentVoiceEntry.IsGrace) {
-                continue;
-            }
-            const tickable: Vex.Flow.StemmableNote = (gve as VexFlowVoiceEntry).vfStaveNote;
-            // This will let the tickable know how to calculate it's bounding box
-            tickable.setStave(stave);
-            // setting Borders from Vexflow to OSMD
-            (gve as VexFlowVoiceEntry).applyBordersFromVexflow();
-            // The middle of the tickable is also the OSMD BoundingBox center
-            if (tickable.getAttribute("type") === "StaveNote") {
-                // The middle of the tickable is also the OSMD BoundingBox center
-                const staveNote: Vex.Flow.StaveNote = tickable as Vex.Flow.StaveNote;
-                tickablePosition += staveNote.getNoteHeadEndX() - staveNote.getGlyphWidth() / 2;
-            } else {
-                const ghostNote: Vex.Flow.GhostNote = tickable;
-                // That's basically the same as the StaveNote does.
-                tickablePosition = ghostNote.getAbsoluteX() + ghostNote.x_shift;
-            }
-            numberOfValidTickables++;
-        }
-        tickablePosition = tickablePosition / numberOfValidTickables;
+
         // sets the vexflow x positions back into the bounding boxes of the staff entries in the osmd object model.
         // The positions are needed for cursor placement and mouse/tap interactions
-        if (!(this.graphicalVoiceEntries[0] as VexFlowVoiceEntry).parentVoiceEntry.IsGrace) {
-            this.PositionAndShape.RelativePosition.x = (this.graphicalVoiceEntries[0] as VexFlowVoiceEntry).vfStaveNote.getBoundingBox().x / unitInPixels;
+        let lastBorderLeft: number = 0;
+        for (const gve of this.graphicalVoiceEntries as VexFlowVoiceEntry[]) {
+            if (gve.vfStaveNote) {
+                gve.vfStaveNote.setStave(stave);
+                gve.applyBordersFromVexflow();
+                this.PositionAndShape.RelativePosition.x = gve.vfStaveNote.getBoundingBox().x / unitInPixels;
+                if (gve.PositionAndShape.BorderLeft < lastBorderLeft) {
+                    lastBorderLeft = gve.PositionAndShape.BorderLeft;
+                }
+            }
         }
+        this.PositionAndShape.RelativePosition.x -= lastBorderLeft;
         this.PositionAndShape.calculateBoundingBox();
     }
 }

+ 8 - 6
src/MusicalScore/Graphical/VexFlow/VexFlowVoiceEntry.ts

@@ -11,13 +11,15 @@ export class VexFlowVoiceEntry extends GraphicalVoiceEntry {
     }
 
     public applyBordersFromVexflow(): void {
-        const a: any = (this.vfStaveNote as any);
-        const bb: any = a.getBoundingBox();
-        this.PositionAndShape.RelativePosition.y = bb.y / unitInPixels;
+        const staveNote: any = (this.vfStaveNote as any);
+        const boundingBox: any = staveNote.getBoundingBox();
+        const modifierWidth: number = staveNote.getNoteHeadBeginX() - boundingBox.x;
+
+        this.PositionAndShape.RelativePosition.y = boundingBox.y / unitInPixels;
         this.PositionAndShape.BorderTop = 0;
-        this.PositionAndShape.BorderBottom = bb.h / unitInPixels;
-        this.PositionAndShape.BorderLeft = bb.x / unitInPixels;
-        this.PositionAndShape.BorderRight = bb.w / unitInPixels;
+        this.PositionAndShape.BorderBottom = boundingBox.h / unitInPixels;
+        this.PositionAndShape.BorderLeft = -(modifierWidth + staveNote.width / 2) / unitInPixels; // Left of our X origin is the modifier
+        this.PositionAndShape.BorderRight = (boundingBox.w - modifierWidth) / unitInPixels; // Right of x origin is the note
     }
 
     public set vfStaveNote(value: Vex.Flow.StemmableNote) {