/** \brief Use tag parameters to calculate the control points position. */ void GRBowing::manualControlPoints( GRBowingContext * bowContext, ARBowing * arBow, GRSystemStartEndStruct * sse ) { GRBowingSaveStruct * bowInfos = (GRBowingSaveStruct *)sse->p; GRStaff * staff = bowContext->staff; const float distx = bowInfos->offsets[2].x - bowInfos->offsets[0].x; const float disty = bowInfos->offsets[2].y - bowInfos->offsets[0].y; const int dir = bowContext->curveDir; // -- Get the initial middle control point position. // If the R3 factor is near zero, the control point will be near the first anchor point // if the R3 factor is near 1, the control point will be near the second anchor point. const TagParameterFloat * tagR3 = arBow->getR3(); const TYPE_FLOATPARAMETER valueR3 = tagR3 ? tagR3->getValue() : float(0.5); bowInfos->offsets[1].x = (GCoord)(distx * valueR3 ); bowInfos->offsets[1].y = (GCoord)(disty * valueR3 * dir); // -- Apply the middle control point y-offset. const float staffLSpace = staff->getStaffLSPACE(); const TagParameterFloat * tagH = arBow->getH(); const TYPE_FLOATPARAMETER valueH = tagH ? tagH->getValue( staffLSpace ) : float(2); bowInfos->offsets[1].y += -dir * ((valueH > 0) ? valueH : -valueH); // - Store bowInfos->offsets[1] += bowInfos->offsets[0]; }
// -------------------------------------------------------------------------- void GRRepeatBegin::updateBoundingBox() { const float halfExtent = GetSymbolExtent(mSymbol) * 0.5f; mBoundingBox.top = 0; mBoundingBox.left = -halfExtent; mBoundingBox.right = halfExtent; mBoundingBox.bottom = 4 * LSPACE; GRStaff *staff = getGRStaff(); if (staff) { fLineNumber = staff->getNumlines(); int linesOffset = fLineNumber - 5; if (linesOffset) mPosition.y += staff->getStaffLSPACE() * linesOffset / 2; fStaffThickness = staff->getLineThickness(); fSize = staff->getSizeRatio(); fBaseThickness = LSPACE * 0.6f * fSize; mTagSize *= fSize; } }
GRPage * GRVoice::getPageNum(int num,int denom) { // I have to travers the voice and find the element // at the position num/denom. Then I have to find the // pagenumber of that element. const TYPE_TIMEPOSITION tpsearch ( num,denom ); GuidoPos pos = First(); while (pos) { GRNotationElement * el = GetNext(pos); GREvent * ev = GREvent::cast(el); if (ev) { if (ev->getRelativeTimePosition() == tpsearch) { GRStaff * stf = ev->getGRStaff(); GRSystem * sys = stf->getGRSystem(); GRPage * page = sys->getGRPage(); return page; } else if (ev->getRelativeTimePosition() > tpsearch) return NULL; } } return NULL; }
/** \brief Returns a page corresponding to a time position. It finds the musical element which time position is immediately before or equal to the input time position. Then it returns the page of that musical element. getPageForTimePos() always try to return a page, while getPageNum() only returns a page when the input time position match the time position of an existing musical element. TODO: Check if the page keeps track of both its start timepos and end timepos, therefore we could directly jump from one page to another \bug The last system of a page point to the next page instead of its parent page. */ GRPage * GRVoice::getPageForTimePos( int num, int denom ) const { GRPage * outPage = 0; TYPE_TIMEPOSITION inTime ( num, denom ); GuidoPos pos = First(); // - Find the event which best match the input date GREvent * bestEv = 0; while (pos) { GRNotationElement * el = GetNext(pos); GREvent * ev = GREvent::cast(el); if( ev ) { const TYPE_TIMEPOSITION & currTime = ev->getRelativeTimePosition(); if( currTime <= inTime ) bestEv = ev; else break; // (JB) I suppose that all next elements have a greater time pos. } } // - Get the page corresponding to the event found if( bestEv ) { GRStaff * staff = bestEv->getGRStaff(); GRSystem * sys = staff->getGRSystem(); outPage = sys->getGRPage(); } return outPage; }
// ---------------------------------------------------------------------------- void GRPage::trace(VGDevice & hdc) const { NVRect r; cout << "Page trace - page " << r << " " << getPosition() << endl; cout << " => page num systems : " << getSystems()->size() << endl; SystemPointerList::const_iterator ptr; for( ptr = getSystems()->begin(); ptr != getSystems()->end(); ++ptr ) { GRSystem * system = *ptr; r = system->getBoundingBox(); r += system->getPosition(); cout << " system " << r << endl; SSliceList * slices = system->getSlices(); if (slices) { GuidoPos pos = slices->GetHeadPosition(); while (pos) { GRSystemSlice * ss = slices->GetNext(pos); r = ss->getBoundingBox(); r += ss->getPosition(); cout << " slice " << r << endl; StaffVector * sv = ss->getStaves(); // get the staves list if (sv) { for( int i = sv->GetMinimum(); i <= sv->GetMaximum(); ++i) { GRStaff * staff = sv->Get(i); if (staff) { cout << " - staff " << staff->getBoundingBox() << " " << staff->getPosition() << endl; /* NEPointerList * selts = staff->getElements(); if (selts) { GuidoPos pos = selts->GetHeadPosition(); while (pos) { GRNotationElement * nelt = selts->GetNext(pos); if (nelt) { cout << *nelt; nelt->DrawBoundingBox (hdc, GColor(0, 0, 255)); } else cout << "==> GRStaff notation element is NULL" << endl; } } else cout << "==> GRStaff elements is NULL" << endl; */ } else cout << "==> GRStaff is NULL" << endl; } } else cout << "==> StaffVector is NULL" << endl; } } else cout << "==> no slices in system" << endl; } }
//-------------------------------------------------------------------- NVPoint GRBeam::initp0 (GRSystemStartEndStruct * sse, const GREvent * startEl, PosInfos& infos) { // -- Init point 0 (top left) GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; const ARBeam * arBeam = getARBeam(); GRStaff * refStaff; NVPoint offset; if (startEl) { st->p[0] = startEl->getStemStartPos(); if (arBeam && arBeam->isGuidoSpecBeam()) st->p[0].y = startEl->getPosition().y; refStaff = startEl->getGRStaff(); infos.stemdir = startEl->getStemDirection(); infos.currentSize = startEl->getSize(); } else { st->p[0] = sse->startElement->getPosition(); infos.currentSize = 1.0f; refStaff = sse->startElement->getGRStaff(); } offset = refStaff->getPosition(); if (tagtype == SYSTEMTAG) st->p[0] += offset; infos.currentLSPACE = refStaff->getStaffLSPACE(); st->p[1] = st->p[0]; // -- Adjust point 0 if (arBeam->dx1 && arBeam->dx1->TagIsSet()) st->p[0].x += (GCoord)(arBeam->dx1->getValue(infos.currentLSPACE)); else { // This depends on the direction, we do not know this yet (do we?) if (infos.oneNote) { double result; bool conversionOk = TagParameterFloat::convertValue(2.0f, result, "hs", infos.currentLSPACE); if (conversionOk) st->p[0].x -= (float)result * infos.currentSize; } } if (arBeam->dy1 && arBeam->dy1->TagIsSet()) st->p[0].y -= (arBeam->dy1->getValue(infos.currentLSPACE)); return offset; }
void GRArticulation::placeFermataDown(GREvent * inParent, NVPoint & ioPos) { const int dir = chooseDirection(inParent); const bool othersAreUpward = (dir == dirUP); GRStaff * staff = inParent->getGRStaff(); const float currLSpace = staff->getStaffLSPACE(); if (othersAreUpward) //stemsDown { ioPos.y = (ioPos.y + inParent->getStemLength() <= float(4)*currLSpace) ? float(4.5f)*currLSpace : ioPos.y + (inParent->getStemLength()) + 0.5f*currLSpace; //test placement } else { placeAfterNote(inParent, ioPos, false); } }
// ---------------------------------------------------------------------------- // void GRArticulation::placePizz(GREvent * inParent, NVPoint & ioPos) { const int dir = chooseDirection (inParent); const bool upward = (dir == dirUP); GRStaff * staff = inParent->getGRStaff(); const float currLSpace = staff->getStaffLSPACE(); //const float halfSpace = float(0.5) * currLSpace; if( upward ) // if stemsDown { placeAfterNote( inParent, ioPos, true ); } else // if stemsUp { ioPos.y = (ioPos.y >= inParent->getStemLength()) ? -currLSpace : ioPos.y - (inParent->getStemLength()+currLSpace); } }
void GRDiminuendo::tellPosition(GObject *caller, const NVPoint & newPosition) { GRNotationElement * grel = dynamic_cast<GRNotationElement *>(caller); if (grel == 0) return; GRStaff * staff = grel->getGRStaff(); if (staff == 0) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(staff->getGRSystem()); if (sse == 0) return; const GRNotationElement * const endElement = sse->endElement; if (grel == endElement) updateDiminuendo(staff); }
//-------------------------------------------------------------------- NVPoint GRBeam::initp2 (GRSystemStartEndStruct * sse, const GREvent * endEl, PosInfos& infos) { // -- Init point 2 (top right) GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; const ARBeam * arBeam = getARBeam(); GRStaff * refStaff; NVPoint offset; if (endEl) { st->p[2] = endEl->getStemEndPos(); // beam length adjustment - DF sept 15 2009 st->p[2].x += infos.currentLSPACE/10; if (arBeam && arBeam->isGuidoSpecBeam()) st->p[2].y = endEl->getPosition().y; refStaff = endEl->getGRStaff(); } else { st->p[2] = sse->endElement->getPosition(); refStaff = sse->startElement->getGRStaff(); } offset = refStaff->getPosition(); if (tagtype == SYSTEMTAG) st->p[2] += offset; infos.currentLSPACE = refStaff->getStaffLSPACE(); st->p[3] = st->p[2]; // -- Adjust point 2 if (arBeam->dx3) st->p[2].x += arBeam->dx3->getValue(infos.currentLSPACE); if (arBeam->dy3 && arBeam->dy3->TagIsSet()) st->p[2].y -= arBeam->dy3->getValue(infos.currentLSPACE); else { GCoord val = 0; if (arBeam->dy1 && arBeam->dy1->TagIsSet()) val = arBeam->dy1->getValue(infos.currentLSPACE); st->p[2].y -= val; } return offset; }
// ----------------------------------------------------------------------------- void GRBowing::tellPosition(GObject * caller, const NVPoint & newPosition) { GRNotationElement * grel = dynamic_cast<GRNotationElement *>(caller); if (grel == 0 ) return; GRStaff * staff = grel->getGRStaff(); if (staff == 0 ) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct( staff->getGRSystem()); if (sse == 0) return; const GRNotationElement * const startElement = sse->startElement; const GRNotationElement * const endElement = sse->endElement; // if ( openLeftRange && openRightRange ) return; // updateBow(); if( grel == endElement || ( endElement == 0 && grel == startElement)) { updateBow( staff ); } }
// ----------------------------------------------------------------------------- void GRBowing::applyAnchorPointsOffsets( GRBowingContext * bowContext, ARBowing * arBow, GRSystemStartEndStruct * sse ) { GRBowingSaveStruct * bowInfos = (GRBowingSaveStruct *)sse->p; GRStaff * staff = bowContext->staff; // -- Applies the offset settings to the start anchor point -- const float staffLSpace = staff->getStaffLSPACE(); if( arBow->getDX1()) bowInfos->offsets[0].x += (arBow->getDX1()->getValue( staffLSpace )); if( arBow->getDY1()) bowInfos->offsets[0].y -= (arBow->getDY1()->getValue( staffLSpace )); // -- Applies the offset settings to the end anchor point -- if( arBow->getDX2()) bowInfos->offsets[2].x += (arBow->getDX2()->getValue( staffLSpace )); if( arBow->getDY2()) bowInfos->offsets[2].y -= (arBow->getDY2()->getValue( staffLSpace )); }
// ---------------------------------------------------------------------------- void GRArticulation::placeFermataUp( GREvent * inParent, NVPoint & ioPos ) { // - Check if the fermata (which is always upward) is on the // same side as other articulations (if any) const int dir = chooseDirection( inParent ); const bool othersAreUpward = (dir == dirUP); GRStaff * staff = inParent->getGRStaff(); const float currLSpace = staff->getStaffLSPACE(); /*const float halfSpace = float(0.5) * currLSpace;*/ if( othersAreUpward ) // if stemsDown { placeAfterNote( inParent, ioPos, true ); } else // if stemsUp { ioPos.y = (ioPos.y >= inParent->getStemLength()) ? 0 : ioPos.y - (inParent->getStemLength()); if (inParent->hasArticulation(kFlagPizz)) ioPos.y -= (1.5f*currLSpace); } }
// -------------------------------------------------------------------------- void GRRepeatEnd::InitRepeatEnd() { mNeedsSpring = 1; sconst = SCONST_BAR - 2; // sconst = 5; //SCONST_BAR; mSymbol = kRepeatEndSymbol; mLeftSpace = mRightSpace = 0; refpos.Set( -LSPACE * 0.8f, 4 * LSPACE ); GRStaff *staff = getGRStaff(); if (staff) { fLineNumber = staff->getNumlines(); fStaffThickness = staff->getLineThickness(); fSize = staff->getSizeRatio(); fBaseThickness = LSPACE * 0.6f * fSize; } mBoundingBox.bottom = 4 * LSPACE; }
int compaccposy( const GRAccidental * el1, const GRAccidental * el2 ) { assert( el1 ); assert( el2 ); int staffnum1 = -1; int staffnum2 = -1; NVPoint pt1 (el1->getPosition()); NVPoint pt2 (el2->getPosition()); GRStaff * staff = el1->getGRStaff(); if( staff ) staffnum1 = staff->getStaffNumber(); staff = el2->getGRStaff(); if( staff ) staffnum2 = staff->getStaffNumber(); pt1.y += (float)(staffnum1 * 20 * LSPACE); pt2.y += (float)(staffnum2 * 20 * LSPACE); if (pt1.y > pt2.y ) return 1; if (pt1.y < pt2.y ) return -1; return 0; }
void GRArticulation::placeAfterNote( GREvent * inParent, NVPoint & ioPos, bool upward ) { GRStaff * staff = inParent->getGRStaff(); const float space = staff->getStaffLSPACE(); const float halfSpace = float(0.5) * space; const int externalFlags = (kFlagAccent | kFlagMarcato | kFlagFermataUp); const bool hasExternal = inParent->hasArticulation( externalFlags ); if( upward ) { // -- Walk from the note through the possible attribute positions // Stop when we've reached our attribute position. // - Starts at one space from the note. ioPos.y -= space; if(( ioPos.y >= 0 ) && positionIsOnStaffLine( ioPos.y, space )) ioPos.y -= halfSpace; // - If we have internal mixed with externals, don't start deeper // than one linespace if( hasExternal && ( ioPos.y > halfSpace )) ioPos.y = halfSpace; // - If we're a staccato or a staccatissimo, we have finished. if(( mArticulationFlag & ( kFlagStaccato )) != 0 ) return; // - Move by one position if we passed an existing staccato or staccatissimo if( inParent->hasArticulation( kFlagStaccato )) ioPos.y += (ioPos.y > 0) ? -space : -halfSpace; // - If we're a tenuto, then we have finished. if( mArticulationFlag == kFlagTenuto ) return; // - Move by one position if we passed an existing tenuto if( inParent->hasArticulation( kFlagTenuto )) ioPos.y += (ioPos.y > 0) ? -space : -halfSpace; // - So, we're an outside-staff symbol, force being outside-staff. /*if( ioPos.y > -space ) ioPos.y = -space; else ioPos.y -= halfSpace;*/ if (ioPos.y > -halfSpace) ioPos.y = -halfSpace; else /*ioPos.y -= halfSpace*/; // only if... // - If we're a pizzicato then we have finished if((mArticulationFlag & (kFlagPizz)) != 0) { ioPos.y -= halfSpace; return; } // - Move by one linespace and a half if we passed an existing pizzicato if (inParent->hasArticulation(kFlagPizz)) ioPos.y -= (1.5f*space); // - If we're an Accent or a Marcato, then we have finished. if(( mArticulationFlag & (kFlagAccent | kFlagMarcato)) != 0 ) { ioPos.y -= halfSpace; return; } // - Move by one position if we passed an existing Accent, // or by 1.5 positions if we passed an existing Marcato if( inParent->hasArticulation( kFlagAccent )) ioPos.y -= space; else { if( inParent->hasArticulation( kFlagMarcato )) ioPos.y -= (space + halfSpace); else ioPos.y += halfSpace; // it's a fermata : we need one less halfspace } } else { int linesCount = staff->getNumlines(); const float bottom = (linesCount - 1) * space; ioPos.y += space; if(( ioPos.y <= bottom ) && positionIsOnStaffLine( ioPos.y, space )) ioPos.y += halfSpace; // - If we have internal mixed with externals, don't start deeper // than one linespace if( hasExternal && ( ioPos.y < ( bottom - halfSpace ))) ioPos.y = (bottom - halfSpace); // - If we're a staccato or a staccatissimo, we have finished. if(( mArticulationFlag & (kFlagStaccato)) != 0 ) return; // - Move by one position if we passed an existing staccato or staccatissimo if( inParent->hasArticulation( kFlagStaccato )) ioPos.y += (ioPos.y < bottom) ? space : halfSpace; // - If we're a tenuto, then we have finished. if( mArticulationFlag == kFlagTenuto ) return; // - Move by one position if we passed an existing tenuto if( inParent->hasArticulation( kFlagTenuto )) ioPos.y += (ioPos.y < bottom) ? space : halfSpace; // - So, we're an outside-staff symbol, force being outside-staff. if( ioPos.y < ( bottom + halfSpace )) ioPos.y = ( bottom + halfSpace ); else /*ioPos.y += space*/; // ? // - If we're an Accent or a Marcato, then we have finished. if(( mArticulationFlag & (kFlagAccent | kFlagMarcato)) != 0 ) { ioPos.y += halfSpace; return; } // - Move by one position if we passed an existing Accent, // or by 1.5 positions if we passed an existing Marcato if( inParent->hasArticulation( kFlagAccent )) ioPos.y += (space + halfSpace); else if( inParent->hasArticulation( kFlagMarcato )) ioPos.y += 2 * space; } }
void GRPossibleBreakState::SaveState(KF_IVector<GRStaff> * vstaffs, KF_IVector<GRVoiceManager> * vvcemgrs, GRStaffManager * staffmgr, const TYPE_TIMEPOSITION & curtp, float parforce, float breakval) { // this saves the staff-stuff int i; for (i=vstaffs->GetMinimum();i<=vstaffs->GetMaximum();i++) { GRStaff * staff = vstaffs->Get(i); if (staff) { GRStaffAndState * sas = new GRStaffAndState; sas->pstaff = staff; sas->setLastRod(staff->lastrod); sas->setFirstRod(staff->firstrod); sas->tpos = staff->mCompElements.GetTailPosition(); sas->staffstate = staff->getGRStaffState(); ssvect->Set(i,sas); } } // now the voice-mgr-stuff ... // (grtags ...) for (i = vvcemgrs->GetMinimum();i<=vvcemgrs->GetMaximum();i++) { GRVoiceManager * vcmgr = vvcemgrs->Get(i); if (vcmgr) { GRVoiceTagsAndStaff * vts = new GRVoiceTagsAndStaff(vcmgr); GRVoice * v = vcmgr->getGRVoice(); vts->SaveGRTags(vcmgr->grtags); vts->setLastRod(v ? v->getLastRod() : 0); vts->setFirstRod(v ? v->getFirstRod() : 0); vts->pstaff = vcmgr->mCurGrStaff; vts->staffnum = vcmgr->staffnum; vtsvect->Set(i,vts); } } // now for the staffmgr (springID, positions // for rod-lists ...) springID = staffmgr->mSpringID; simplerodspos = staffmgr->mSimpleRods->GetTailPosition(); complexrodspos = staffmgr->mComplexRods->GetTailPosition(); // and now for the system ... the position of // the last system-element .... // systemelementendpos = staffmgr->grsystem->GetTailPosition(); // the timeposition tp = curtp; force = parforce; pbreakval = breakval; lastrod = staffmgr->lastrod; firstrod = staffmgr->firstrod; }
// ---------------------------------------------------------------------------- void GRTuplet::manualPosition(GObject * caller, const NVPoint & inPos ) { GREvent * event = GREvent::cast( caller ); if( event == 0 ) return; GRStaff * staff = event->getGRStaff(); if( staff == 0 ) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(staff->getGRSystem()); if( sse == 0 ) return; GRNotationElement * startElement = sse->startElement; GRNotationElement * endElement = sse->endElement; // if ( openLeftRange && openRightRange ) return; GRTupletSaveStruct * st = (GRTupletSaveStruct *)sse->p; const ARTuplet * arTuplet = getARTuplet(); float dy1 = arTuplet->isDySet() ? arTuplet->getDy1() : 0; float dy2 = arTuplet->isDySet() ? arTuplet->getDy2() : 0; if(( dy1 > 0 ) || ( dy2 > 0 )) mDirection = dirUP; const float halfNoteWidth = LSPACE * float(0.65); // harcoded if (event == startElement) { st->p1 = startElement->getPosition(); st->p1.x -= halfNoteWidth; // to enclose all the element width st->p1.y -= dy1; } else if (event == endElement) { st->p2 = endElement->getPosition(); st->p2.x += halfNoteWidth; // to enclose all the element width st->p2.y -= dy2; } if(event == endElement || (endElement == 0 && event == startElement)) { if (startElement && endElement) { const float posx = (st->p2.x - st->p1.x) * 0.5f + st->p1.x; const float posy = st->p2.y > st->p1.y ? (st->p2.y - st->p1.y) * 0.5f + st->p1.y + 40 : (st->p1.y - st->p2.y) * 0.5f + st->p2.y + 40; st->textpos.x = posx; st->textpos.y = posy; } else st->textpos = inPos; } // if( arTuplet->isFormatSet()) // { mShowLeftBrace = arTuplet->getLeftBrace(); mShowRightBrace = arTuplet->getRightBrace(); // } }
/** Adds a slice to the current slice-height we are friends of GRSystemSlice so we can directly access the staves. */ void GRSliceHeight::AddSystemSlice( const GRSystemSlice * slc, bool doboundingrect ) { if (slc == 0) return; int j; int first = 1; float laststaffposy = 0; float lastvectposy = 0; float staffposy = 0; float vectposy = 0; float cury = 0; for (j=slc->mStaffs->GetMinimum();j<=slc->mStaffs->GetMaximum();++j) { GRStaff * tmpstaff = slc->mStaffs->Get(j); if (tmpstaff) { vectposy = mHVector.Get(j); float newvectposy = vectposy; if (!doboundingrect) { staffposy = tmpstaff->getPosition().y; if (first) { // The first one just saves the part // below ... the upper bounding rectangle // is not concerned. first = 0; } else { if (staffposy - laststaffposy > vectposy - lastvectposy) { newvectposy = lastvectposy + staffposy - laststaffposy; mHVector.Set(j,float(newvectposy)); } } laststaffposy = staffposy; lastvectposy = newvectposy; } else { // we do the bounding-rectangle thing ... // this is actually not needed here : the bounding box update is // already computed by GRSystemSlice::Finish // tmpstaff->updateBoundingBox(); // the boundingBoxPreview method has been temporary use here to test code restructuration // tmpstaff->boundingBoxPreview(); const NVRect & myrect = tmpstaff->getBoundingBox(); if (!first) { if (cury - myrect.top > vectposy) mHVector.Set(j, float(cury - myrect.top)); cury += myrect.Height(); } else { first = 0; cury = myrect.bottom; } } if (j == slc->mStaffs->GetMaximum()) { float tmpbr = tmpstaff->getBoundingBox().bottom; if (tmpbr > boundingRectBottom) boundingRectBottom = tmpbr; } if (j == slc->mStaffs->GetMinimum()) { float tmpbr = tmpstaff->getBoundingBox().top; if (tmpbr < boundingRectTop) boundingRectTop = tmpbr; } } } if (doboundingrect) { // it might be that the slice is a beginning slice // that has not yet set the staff positions, // in this case we have to set the minimum height float tmpheight = float(slc->getBoundingBox().Height()); if (getHeight() < tmpheight) { minHeight = tmpheight; } } }
/** Places the tuplet bracket and/or numeral, close to its group of notes. Calculates the positions of the two possible tuplet bracket (above and below) then choose the best one. */ void GRTuplet::automaticPosition(GObject * caller, const NVPoint & inPos ) { GREvent * callerEv = GREvent::cast( caller ); if( callerEv == 0 ) return; GRStaff * staff = callerEv->getGRStaff(); if( staff == 0 ) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(staff->getGRSystem()); if( sse == 0 ) return; GRTupletSaveStruct * st = (GRTupletSaveStruct *)sse->p; if( st == 0 ) return; GREvent * startElement = GREvent::cast( sse->startElement ); if( startElement == 0 ) return; GREvent * endElement = GREvent::cast( sse->endElement ); if( endElement == 0 ) return; // - Accept being positioned only once, if possible by the last tuplet element. //if(( callerEv != endElement ) && ((callerEv != startElement) || (endElement != 0))) if( callerEv != endElement ) return; // - Check for beams const bool firstBeamed = (startElement->getBeamCount() > 0); const bool lastBeamed = (endElement->getBeamCount() > 0); mShowLeftBrace = !(firstBeamed && lastBeamed ); mShowRightBrace = mShowLeftBrace; // - Get first and last element positions to work with float startX, endX; endX = 0; float startUpY, startDownY, endUpY, endDownY; // x positions const float halfNoteWidth = LSPACE * float(0.65); // harcoded startX = startElement->getPosition().x; endX = endElement->getPosition().x; // if( endX == startX ) return; // DF commented: results in strange vertical bars startX -= halfNoteWidth; endX += halfNoteWidth; // y positions const NVRect & leftBox = startElement->getBoundingBox(); const NVRect & rightBox = endElement->getBoundingBox(); const float elPos1y = startElement->getPosition().y; const float elPos2y = endElement->getPosition().y; startUpY = leftBox.top + elPos1y; endUpY = rightBox.top + elPos2y; startDownY = leftBox.bottom + elPos1y; endDownY = rightBox.bottom + elPos2y; // - Calculate a virtual line from the first to the last element, int stemStats = 0; const float deltaX = (endX - startX); float slopeUp = (endUpY - startUpY) / deltaX; // slope of the virtal line above float slopeDown = (endDownY - startDownY) / deltaX; // slope of the virtal line below float x, yUp, yDown, distUp, distDown; float mxUp = 0, myUp = 0, mxDown = 0, myDown = 0; // 'extreme' middle point bool collideUp = false; bool collideDown = false; GuidoPos pos = mAssociated->GetHeadPosition(); while( pos ) { GREvent * el = GREvent::cast( mAssociated->GetNext(pos)); if( el == 0 ) continue; // - Generate stats about stem directions GDirection stemDir = el->getStemDirection(); if( stemDir == dirUP ) ++ stemStats; else if( stemDir == dirDOWN ) -- stemStats; if(( el != startElement ) && ( el != endElement )) { // - Get the element box const NVRect & elBox = el->getBoundingBox(); const NVPoint & elPos = el->getPosition(); x = elPos.x; yUp = elBox.top + elPos.y; yDown = elBox.bottom + elPos.y; // - Calculate the y-distance between the element and the virtual line. // distY = startY - (y - slope * (x - startX)); distUp = (startUpY - yUp) + (x - startX) * slopeUp; distDown = (startDownY - yDown) + (x - startX) * slopeDown; if( distUp > 0 ) // then the point is above the virtual line { mxUp = x; myUp = yUp; collideUp = true; //startUpY -= distUp; // TODO: better handling of this collision //endUpY -= distUp; } if( distDown < 0 ) // then the point is below the virtual line { mxDown = x; myDown = yDown; collideDown = true; //startDownY -= distDown; //endDownY -= distDown; } } } // - Adjust the brace to avoid collisions. It must be above (or below) all elements, // while remaining close to those elements, and avoid being in the staff. // brace 1 (upward) if( collideUp ) { if(( myUp <= startUpY ) && ( myUp <= endUpY )) // middle point above start and end points { // slopeUp = 0; // horizontal startUpY = myUp; endUpY = myUp; } else { if( myUp <= endUpY ) // middle point above end point only: shift the end point up { slopeUp = (myUp - startUpY) / (mxUp - startX); endUpY = startUpY + (deltaX * slopeUp); } else // middle point above start point only: shift the start point up { slopeUp = (endUpY - myUp) / (endX - mxUp); startUpY = endUpY - (deltaX * slopeUp); } } } // brace 2 (downward) if( collideDown ) { if(( myDown >= startDownY ) && ( myDown >= endDownY )) // middle point below start and end points { // slopeDown = 0; // horizontal startDownY = myDown; endDownY = myDown; } else { if( myDown >= endDownY ) // middle point below end point only: shift the end point down { slopeDown = (myDown - startDownY) / (mxDown - startX); endDownY = startDownY + (deltaX * slopeDown); } else // middle point below start point only: shift the start point down { slopeDown = (endDownY - myDown) / (endX - mxDown); startDownY = endDownY - (deltaX * slopeDown); } } } // - Avoid being inside staff if( startUpY > 0 ) startUpY = 0; if( endUpY > 0 ) endUpY = 0; const float staffHeight = staff->getDredgeSize(); if( startDownY < staffHeight ) startDownY = staffHeight; if( endDownY < staffHeight ) endDownY = staffHeight; // - Tune float marginY = LSPACE * float(1.25); startUpY -= marginY; endUpY -= marginY; startDownY += marginY; endDownY += marginY; // - Choose the best solution (above or below) // We put the brace and the tuplet numeral on the stem side. float startY; float endY; if( stemStats >= 0 ) // stems tend to be up. { mDirection = dirUP; startY = startUpY; endY = endUpY; } else { mDirection = dirDOWN; startY = startDownY; endY = endDownY; } // - Store results const float textOffsetY = LSPACE; st->p1.x = startX; st->p1.y = startY; st->p2.x = endX; st->p2.y = endY; st->textpos.x = (startX + endX) * float(0.5); st->textpos.y = (startY + endY) * float(0.5) + textOffsetY - 9; }