Skip to content

Commit

Permalink
fix(Relative Bounding Positions): Relative x positions in bounding bo…
Browse files Browse the repository at this point in the history
…xes were not adjusted to note h

#309
  • Loading branch information
bneumann committed Aug 21, 2018
1 parent 3db189b commit af21d7e
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 62 deletions.
4 changes: 4 additions & 0 deletions src/MusicalScore/Graphical/MusicSheetCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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++) {
Expand Down
14 changes: 14 additions & 0 deletions src/MusicalScore/Graphical/MusicSheetDrawer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
92 changes: 64 additions & 28 deletions src/MusicalScore/Graphical/SkyBottomLineCalculator.ts
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -264,22 +267,22 @@ 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);
}

/**
* 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);
}

Expand Down Expand Up @@ -367,42 +370,48 @@ export class SkyBottomLineCalculator {
return this.getMaxInRange(this.BottomLine, startIndex, endIndex);
}

/**
* 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)
Expand All @@ -425,10 +434,37 @@ 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
1 change: 1 addition & 0 deletions src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
38 changes: 12 additions & 26 deletions src/MusicalScore/Graphical/VexFlow/VexFlowStaffEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
14 changes: 8 additions & 6 deletions src/MusicalScore/Graphical/VexFlow/VexFlowVoiceEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit af21d7e

Please sign in to comment.