/** \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 GRTrill::tellPosition( GObject * caller, const NVPoint & np ) { fType = static_cast<ARTrill *>(mAbstractRepresentation)->getType(); GREvent * ev = dynamic_cast<GREvent *>(caller); if (ev) { const int dir = chooseDirection(ev); NVPoint newPoint (np); const bool upward = (dir == dirUP); if( upward ) // if stemsUp { if (newPoint.y >= ev->getStemLength()) newPoint.y = -LSPACE; else newPoint.y -= (ev->getStemLength() + LSPACE); } else { newPoint.y = (newPoint.y > 0)? -LSPACE : newPoint.y - 1.5f*LSPACE; } setPosition(newPoint); // Accidental NVPoint accidentalPos = NVPoint(newPoint); accidentalPos.x += GetSymbolExtent(mSymbol)*0.5f + 0.4f*LSPACE; accidentalPos.y -= 1.5f*LSPACE; fAccidental->setPosition(accidentalPos); } }
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; }
void GRBeam::setError(const GRStaff * grstaff, int p_error) { GRTag::setError(p_error); if (error && mAssociated) { GuidoPos pos = mAssociated->GetHeadPosition(); while (pos) { GREvent * grnot = GREvent::cast (mAssociated->GetNext(pos)); if (grnot) { grnot->setFlagOnOff(1); } } } // this just removes the associations from // all active SSE's. The SSE's themselves // stay, where they are, so that they are // delete properly later .... DeleteAllSSEs(); delete mAssociated; mAssociated = NULL; }
/** \brief Break a tag at a previously saved PBreak-Location. It sets the sse-Positions ... (It is somewhat equivalent to StaffFinished with the difference, that assocpos is used). assocpos is the tail-position of the mAssociated list at the time of the pbreak- situation. */ void GRBeam::BreakTag( GRStaff * grstaff, GuidoPos & assocpos) { if (!grstaff) return; // do the "basic" stuff. GRPositionTag::BreakTag(grstaff,assocpos); if (error) return; GRSystemStartEndStruct *sse = getSystemStartEndStruct(grstaff->getGRSystem()); assert(sse); // GRBeamSaveStruct *st = (GRBeamSaveStruct *) sse->p; GREvent * grn; checkNotes(grstaff); if (error) return; GuidoPos pos = sse->startpos; while (pos) { GuidoPos prevpos = pos; grn = GREvent::cast(mAssociated->GetNext(pos)); if (grn) grn->setFlagOnOff(0); if (prevpos == sse->endpos) break; } }
// ---------------------------------------------------------------------------- void GRArticulation::tellPosition(GObject * caller, const NVPoint & inPos) // Called by GREvent when event position { // is set GREvent * ev = GREvent::cast(caller); if( ev == 0 ) return; // GRStaff * staff = ev->getGRStaff(); // const float currLSpace = staff->getStaffLSPACE(); // const float halfSpace = float(0.5) * currLSpace; // const float linesCount = staff->getNumlines(); NVPoint newPoint (inPos); switch( mArticulationFlag ) { case kFlagStaccato: placeStaccato( ev, newPoint ); break; case kFlagStaccmo: placeStaccmo( ev, newPoint); break; case kFlagAccent: placeAccent( ev, newPoint ); break; case kFlagMarcato: placeMarcato( ev, newPoint ); break; case kFlagMarcatoUp: placeMarcatoUp( ev, newPoint ); break; case kFlagMarcatoDown: placeMarcatoDown( ev, newPoint ); break; case kFlagTenuto: placeTenuto( ev, newPoint ); break; case kFlagFermataUp: placeFermataUp( ev, newPoint ); break; case kFlagFermataDown: placeFermataDown(ev, newPoint ); break; case kFlagBreathMark: placeBreathMark( ev, newPoint ); break; case kFlagPizz : placePizz (ev, newPoint); break; case kFlagHarmonic : placeHarmonic(ev, newPoint); break; } setPosition( newPoint ); // - TEST, Update bounding box, but only if we're not a breath-mark if( mArticulationFlag != kFlagBreathMark ) { ev->addToBoundingBox( this ); ev->updateBoundingBox(); } }
GRCluster::GRCluster(GRStaff * stf, ARCluster * arcls, GRSingleNote *sngNote, ARNoteFormat * curnoteformat) : GRARCompositeNotationElement(arcls), GRPositionTag(arcls->getEndPosition(), arcls), fDuration(0), fNoteFormatColor(0), fClusterOrientation(ARTHead::NORMAL), fStemDir(dirAUTO) { assert(stf); mGrStaff = stf; fDuration = sngNote->getDurTemplate(); const TagParameterString *tmpColor; mTagSize = stf->getSizeRatio(); firstNote = secondNote = sngNote; int noteFormatDx = 0; int noteFormatDy = 0; if (curnoteformat) { // - Size const TagParameterFloat * tmp = curnoteformat->getSize(); if (tmp) mTagSize = tmp->getValue(); // - Color tmpColor = curnoteformat->getColor(); if (tmpColor) { fNoteFormatColor = new unsigned char[4]; tmpColor->getRGB(fNoteFormatColor); } // - Offset const TagParameterFloat * tmpdx = curnoteformat->getDX(); const TagParameterFloat * tmpdy = curnoteformat->getDY(); if (tmpdx) noteFormatDx = (int) (tmpdx->getValue(stf->getStaffLSPACE())); if (tmpdy) noteFormatDy = (int) (tmpdy->getValue(stf->getStaffLSPACE())); } float clusterDx = mTagOffset.x; float clusterDy = mTagOffset.y; mTagOffset.x += noteFormatDx; mTagOffset.y += noteFormatDy; fdx = mTagOffset.x; fdy = mTagOffset.y; fhdx = arcls->getahdx(); fhdy = arcls->getahdy(); fsize = (arcls->getSize() ? arcls->getSize()->getValue() : 1.0f); GREvent *grEvent = dynamic_cast<GREvent *>(sngNote); if (grEvent) { grEvent->getGlobalStem()->setOffsetXY(clusterDx, - clusterDy); grEvent->getGlobalStem()->setMultiplicatedSize(fsize); } fNoteCount = arcls->getNoteCount(); }
// (JB) \bug There is probably a bug somewhere: with map mode // different than "ISOTROPIC" (proportionnal), beamings polygons between "UP" stems // draw at an incorrect x position, while "DOWN" beams are always ok. // // Too long, needs some code-factorization, if possible. void GRBeam::tellPosition( GObject * gobj, const NVPoint & p_pos) { /* Beams are polygons made of four points: 0 2 ------------------ | | ------------------ 1 3 */ // a new test is performed: if it is a systemTag and // it is not a systemcall (checkpos), than we can just do nothing. if (error || !mAssociated || ( mAssociated->GetCount() == 0 ) || ( tagtype == GRTag::SYSTEMTAG && !mIsSystemCall )) return; GRNotationElement * el = dynamic_cast<GRNotationElement *>(gobj); if (!el || !el->getGRStaff()) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(el->getGRStaff()->getGRSystem()); assert(sse); if (el != sse->endElement) return; GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; GuidoPos pos; GREvent * startEl = GREvent::cast(sse->startElement); GREvent * endEl = GREvent::cast(sse->endElement); // this is the staff to which the beam belongs and who draws it. const GRStaff * beamstaff = sse->startElement->getGRStaff(); PosInfos infos = { dirUP, LSPACE, 1.0f, (endEl == startEl)}; ARBeam * arBeam = getARBeam(); const bool isSpecBeam = arBeam->isGuidoSpecBeam(); if(startEl) infos.stemdir = startEl->getStemDirection(); else if(endEl) infos.stemdir = endEl->getStemDirection(); if(level != 0) return; NVPoint offset = initp0 (sse, startEl, infos); initp1 (sse, infos); offset = initp2 (sse, endEl, infos); initp3 (sse, infos); // ----------------------------------------------------------- // Now, we adjust the stemlengths, according to beamslope ... // we have the start and end-position in st->p // We have to determine the slope and adjust the slope to minimum and maximum ... // ----------------------------------------------------------- float stemWidth = st->p[2].x - st->p[0].x; float slope = (st->p[2].y - st->p[0].y) / stemWidth; // another hack to control the slope when events are on different staves - DF sept 15 2009 if (startEl && endEl && (startEl->getGRStaff() != endEl->getGRStaff())) { while ((slope < -0.20) || (slope > 0.20)) { float shift = (slope < 0) ? -LSPACE/4 : LSPACE/4; st->p[0].y += shift; st->p[1].y += shift; st->p[2].y -= shift; st->p[3].y -= shift; slope = (st->p[2].y - st->p[0].y) / stemWidth; } } bool needsadjust = true; // we have to adjust the slope ONLY if the stemlength // of the first and last element has not been set automatically! // and if we are note in the case of a chained feather beam if ( (startEl && startEl->getStemLengthSet() && endEl && endEl->getStemLengthSet()) || tagtype == SYSTEMTAG || (arBeam && isSpecBeam) || (isFeathered && startEl && startEl->stemHasBeenChanged())) { needsadjust = false; } else slopeAdjust (sse, startEl, endEl, slope, infos); if (arBeam && isSpecBeam) { // then we have to set the length ... if it is not set otherwise ... GRSingleNote * nt = dynamic_cast<GRSingleNote *>(sse->startElement); if(nt && !nt->getStemLengthSet()) { const float myval = arBeam->dy1->getValue(); nt->setStemLength( myval); } nt = dynamic_cast<GRSingleNote *>(sse->endElement); if(nt && !nt->getStemLengthSet()) { float myval; if (arBeam->dy3 && arBeam->dy3->TagIsSet()) myval = arBeam->dy3->getValue(); else myval = arBeam->dy1->getValue(); nt->setStemLength( myval); } } float offsetbeam = 0; // nobeamoffset describes, if no beamoffset is valid: if notes ask for different beam-offsets // then, there is just no offset .... things must be changed manually then .... bool nobeamoffset = false; if(( startEl && startEl->getStemLengthSet()) || ( endEl && endEl->getStemLengthSet())) nobeamoffset = true; for (int counter = 0; counter < 2; ++counter ) { if (counter == 1) { if ((offsetbeam == 0) || nobeamoffset) break; else if (!nobeamoffset) { st->p[0].y -= offsetbeam; st->p[1].y -= offsetbeam; st->p[2].y -= offsetbeam; st->p[3].y -= offsetbeam; offsetbeam = 0; } } pos = sse->startpos; while (pos) { // now we calculate the stem-end-positions ... GuidoPos oldpos = pos; GREvent * sn = GREvent::cast(mAssociated->GetNext(pos)); if (sn) { float rx = sn->getStemStartPos().x - st->p[0].x; if (tagtype == SYSTEMTAG) rx += sn->getGRStaff()->getPosition().x; float disty = st->p[2].y - st->p[0].y; float distx = st->p[2].x - st->p[0].x; float ly = disty / distx * rx; ly += st->p[0].y; float diffy = (float)sn->getStemStartPos().y; GDirection adjustdir=dirAUTO; if (sn->getStemDirection() == dirUP) { diffy += (float)sn->getStemLength(); adjustdir = dirUP; } else if (sn->getStemDirection() == dirDOWN) { adjustdir = dirDOWN; diffy -= (float)sn->getStemLength(); } ly -= diffy; if (tagtype == SYSTEMTAG) ly -= (float)sn->getGRStaff()->getPosition().y; // if we have a beam between grace notes, we don't want an offbase that whould make the stems too long GRNote * gnote = dynamic_cast<GRNote*>(startEl); bool isGrace = gnote ? gnote->isGraceNote() : false; float offbase = isGrace ? 0 : 3.5f * infos.currentLSPACE; if (ly < 0) { if (needsadjust) { if (adjustdir == dirDOWN) { const float newoffs = ly - offbase; if (newoffs < offsetbeam) { if (offsetbeam > 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } ly = -offbase; } else if (ly > -offbase) { const float newoffs = ly + offbase; if (newoffs > offsetbeam) { if (offsetbeam < 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } } } ly = -ly; } else if (needsadjust) { if (adjustdir == dirUP) { const float newoffs = ly + offbase; if (newoffs > offsetbeam) { if (offsetbeam < 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } ly = offbase; } else if (ly < offbase) { const float newoffs = ly - offbase; if (newoffs < offsetbeam) { if (offsetbeam > 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } } } // sn->changeStemLength( ly ); // adjusted - DF sept 15 2009 sn->changeStemLength( ly - infos.currentLSPACE/20 ); // so that the possible next featherd beam knows that he is chained // (and musn't change its slope) sn->setStemChanged(); } if (oldpos == sse->endpos) break; } //endEl->setStemChanged(); } if(!smallerBeams.empty()) { for(std::vector<GRBeam *>::iterator it = smallerBeams.begin(); it < smallerBeams.end(); it++) { (*it)->decLevel(); (*it)->tellPosition((*it)->getEndElement(), (*it)->getEndElement()->getPosition()); } return; } // -- Now we need to add the simplebeams as simplebeamgroups ... NVPoint myp[4]; int dir = st->direction; if (st->dirset) { // then the direction was set explicitly by the user ... GREvent * sn = GREvent::cast(mAssociated->GetHead()); if (sn) dir = sn->getStemDirection(); } else dir = infos.stemdir; bool first = true; pos = sse->startpos; // - These constants define the space and the thickness of additionnal beams. const float yFact1 = 0.75f * infos.currentLSPACE; // was 0.7f const float yFact2 = 0.4f * infos.currentLSPACE; // if we have a feathered beam, we just have to draw the main beam (already done) // and the other simple beams will only depend on the begining and ending // points, regardless of the durations of the inner notes. if(isFeathered) { ARFeatheredBeam * ar = static_cast<ARFeatheredBeam *>(getARBeam()->isARFeatheredBeam()); int begin = 0; int end = 0; GREvent * stemNoteBegin = GREvent::cast(mAssociated->GetHead()); GDirection localDir = stemNoteBegin->getStemDirection(); float yLocalFact1 = yFact1 * localDir * infos.currentSize; float yLocalFact2 = yFact2 * localDir * infos.currentSize; // if the user hasn't set the durations as parameters, // we will take the first and last notes'durations if(!ar->isDurationsSet()) { ar->findDefaultPoints(); } end = ar->getLastBeaming(); begin = ar->getFirstBeaming(); for(int i=1;i<=begin; i++) { myp[0] = st->p[0]; myp[0].y += (i-1) * yLocalFact1; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; myp[2] = st->p[2]; if(end>i ||(end==i && i!=1)) // no need to draw the main beam again. myp[2].y += (i-1) * yLocalFact1; else myp[2].y += (end-1) * yLocalFact1; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); } // if end > begin for(int i=begin; i<end; i++) { myp[0] = st->p[0]; myp[0].y += (begin-1) * yLocalFact1; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; myp[2] = st->p[2]; myp[2].y += i * yLocalFact1; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); } // in order to draw the total duration of the beam if(drawDur) { TYPE_TIMEPOSITION begin = ar->getBeginTimePosition(); TYPE_TIMEPOSITION end = ar->getEndTimePosition(); TYPE_DURATION dur = end - begin; int num = dur.getNumerator(); int den = dur.getDenominator(); stringstream out; out << num << '/' << den; st->duration = out.str(); size_t n = st->duration.length(); GREvent * ev = dynamic_cast<GREvent *>(mAssociated->GetHead()); const NVPoint p1 = ev->getStemEndPos(); float xBegin = ev->getPosition().x; ev = dynamic_cast<GREvent *>(mAssociated->GetTail()); const NVPoint p2 = ev->getStemEndPos(); float xEnd = ev->getPosition().x + ev->getBoundingBox().Width()/2; int dir = ev->getStemDirection(); float Y1; float Y2; if(dir>0) { Y1 = min(p1.y, p2.y) - LSPACE; if(Y1>=getLastPositionOfBarDuration().first && Y1<getLastPositionOfBarDuration().second+LSPACE/2) Y1 -= LSPACE; Y2 = Y1 - LSPACE/2; getLastPositionOfBarDuration().first = Y2; getLastPositionOfBarDuration().second = Y1; } else { Y1 = max(p1.y, p2.y) + LSPACE; if(Y1>=getLastPositionOfBarDuration().first-LSPACE/2 && Y1<getLastPositionOfBarDuration().second) Y1 += LSPACE; Y2 = Y1 + LSPACE/2; getLastPositionOfBarDuration().first = Y1; getLastPositionOfBarDuration().second = Y2; } if (xBegin > xEnd) { if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) xEnd = sse->endElement->getPosition().x; if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) xBegin = sse->startElement->getPosition().x; } float x = xBegin + (xEnd - xBegin) / 2; float X1 = x - (n - 0.5f) / 2 * LSPACE; float X2 = x + (n - 0.5f) / 2 * LSPACE; st->DurationLine[0] = NVPoint(xBegin, Y1); st->DurationLine[1] = NVPoint(xBegin, Y2); st->DurationLine[2] = NVPoint(X1, Y2); st->DurationLine[3] = NVPoint(X2, Y2); st->DurationLine[4] = NVPoint(xEnd, Y2); st->DurationLine[5] = NVPoint(xEnd, Y1); } } // for beam length adjustment - DF sept 15 2009 const float xadjust = infos.currentLSPACE/10; GDirection lastLocalDir = dirOFF; int previousBeamsCount = 0; while (pos && !isFeathered) { GuidoPos oldpos = pos; GREvent * stemNote = GREvent::cast(mAssociated->GetNext(pos)); if (stemNote) { GDirection localDir = stemNote->getStemDirection(); float yLocalFact1 = yFact1 * localDir * infos.currentSize; float yLocalFact2 = yFact2 * localDir * infos.currentSize; // now we check the number of beams ... if (stemNote->getBeamCount() < stemNote->getNumFaehnchen()) { float beamCount = (float)(stemNote->getBeamCount()); stemNote->incBeamCount(); if (first && (sse->startflag == GRSystemStartEndStruct::OPENLEFT)) { // the additional beam starts at the startElement (glue), we have more beams to draw myp[0] = sse->startElement->getPosition(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[1] = myp[0]; // first = false; // never read (according to clang :-) } else { // the additional beam starts at sn. We have more beams to draw myp[0] = stemNote->getStemStartPos(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[0].y += beamCount * yLocalFact1; if (localDir != dir) myp[0].y -= yLocalFact2; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; } // now we look for the endposition GREvent * sn2 = NULL; GuidoPos tmppos = pos; // partialbeam is set, if the new SimpleBeam only covers part of the masterBeam. int partialbeam = 0; while (tmppos) { GuidoPos oldpos2 = tmppos; GREvent * tmpsn = GREvent::cast(mAssociated->GetNext(tmppos)); if (tmpsn) { if (tmpsn->getBeamCount() < tmpsn->getNumFaehnchen()) { sn2 = tmpsn; sn2->incBeamCount(); continue; } else { partialbeam = 1; break; } } if (oldpos2 == sse->endpos) break; } if (sn2) { if (!partialbeam && sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { // then the position is different ... myp[2] = sse->endElement->getPosition(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y = myp[0].y; } else { // we have an End-Position ... myp[2] = sn2->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y += beamCount * yLocalFact1; } if (localDir != dir) myp[2].y -= yLocalFact2; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; } else { // we do not have an End-Positon single beam ... (meaning a single straight flag) // but only, if it is not open on the left or the right hand side. const float slope = (float)(st->p[2].y - st->p[0].y ) / (float)(st->p[2].x - st->p[0].x); if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) { // then we have to deal with the startposition of the glue-element .... // BUT, you can only set this, if the previous beam had this beamcount at the end .... // how do I know that? not now. // sn is the only element .... and we are open on the left ... if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[1] = myp[0]; myp[2] = stemNote->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += stemNote->getGRStaff()->getPosition(); myp[2].y += beamCount * yLocalFact1; if (localDir != dir) myp[2].y -= yLocalFact2; myp[3] = myp[2]; myp[3].y += yLocalFact2; } else if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { myp[0] = stemNote->getStemEndPos(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[0].y += beamCount * yLocalFact1; if (localDir != dir) myp[0].y -= yLocalFact2; myp[1] = myp[0]; myp[1].y += yLocalFact2; myp[2] = sse->endElement->getPosition(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y = myp[0].y; myp[3].x = myp[2].x; myp[3].y = myp[1].y; } /* 26/11/03 Beaming bug: wrong direction for partial beam (beam-bug.gmn) can be tested but changing this test. startpos check added to correct problem with partial beam going outside a group like in [ _/16 c d/8 ] */ else if( oldpos == sse->endpos || pos == NULL || ((!stemNote->isSyncopated()) && (oldpos != sse->startpos))) { // Partial beams leftward ( using slope) myp[2] = stemNote->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += stemNote->getGRStaff()->getPosition(); if (localDir != dir) myp[2].y -= yLocalFact2; myp[2].y += beamCount * yLocalFact1; myp[3] = myp[2]; myp[3].y += yLocalFact2; myp[0] = myp[2]; myp[0].x -= infos.currentLSPACE; myp[0].y -= slope * infos.currentLSPACE; myp[1] = myp[0]; myp[1].y += yLocalFact2; // ? We are at the end, there is no valid event at the end ... so what do we do? // useless tests: the code was the same and is now outside the test (above) - DF sept 15 2009 /* if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { } else { } */ } else { // Partial beams rightward ( using slope) myp[2] = myp[0]; myp[2].x += infos.currentLSPACE; myp[2].y += slope * infos.currentLSPACE; myp[3] = myp[2]; myp[3].y += yLocalFact2; } } // now we construct a SimpleBeam, we now have to "undo" the systemTag-stuff if (tagtype == SYSTEMTAG) { const NVPoint & offset = beamstaff->getPosition(); myp[0] -= offset; myp[1] -= offset; myp[2] -= offset; myp[3] -= offset; } if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) { myp[0].y = myp[2].y; myp[1].y = myp[3].y; } GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); pos = sse->startpos; oldpos = pos; first = true; lastLocalDir = localDir; previousBeamsCount = stemNote->getBeamCount() - 1; } // a new hack, again to catch stems directions change - DF sept 15 2009 else if (localDir != dir) { // check for stems length NVPoint stemloc = stemNote->getStemStartPos(); if (tagtype == SYSTEMTAG) stemloc += stemNote->getGRStaff()->getPosition(); int beamscount = stemNote->getBeamCount() - 1; if ((beamscount > 0) && (previousBeamsCount > beamscount) && (lastLocalDir != localDir)) { if (localDir == dirUP) stemNote->changeStemLength(stemNote->getStemLength() + (yLocalFact1 * beamscount)); else if (localDir == dirDOWN) stemNote->changeStemLength(stemNote->getStemLength() - (yLocalFact1 * beamscount)); } } } if (oldpos == sse->endpos) break; } GuidoPos stemPos = sse->startpos; while(stemPos) { GREvent * stemNote = GREvent::cast(mAssociated->GetNext(stemPos)); if(stemNote) { GuidoPos tagpos = NULL; if (stemNote->getAssociations()) tagpos = stemNote->getAssociations()->GetHeadPosition(); while(tagpos) { GRNotationElement * tag = stemNote->getAssociations()->GetNext(tagpos); GRTremolo * trem = dynamic_cast<GRTremolo*>(tag); if(trem) { trem->tellPosition(stemNote,stemNote->getPosition()); if(trem->isTwoNotesTremolo()) // in order to force the second pitch (especially the chords) to update { GREvent * secondPitch = dynamic_cast<GREvent*>(mAssociated->GetNext(stemPos)); if(secondPitch) trem->tellPosition(secondPitch, secondPitch->getPosition()); } } } } } // now we have to make sure, that the original positions // for the beam are set for the right staff if (tagtype == SYSTEMTAG) { const NVPoint &offset = beamstaff->getPosition(); st->p[0] -= offset; st->p[1] -= offset; st->p[2] -= offset; st->p[3] -= offset; } }
void GRBeam::StaffFinished(GRStaff * grstaff) { assert(false); assert(grstaff); // first, all the BASIC stuff is handled ... GRPositionTag::StaffFinished(grstaff); if (error) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(grstaff->getGRSystem()); assert(sse); GuidoPos syststpos = sse->startpos; if (syststpos) { // this is all done so that I really get a correct first staff to // test my stuff ... while (syststpos && !/*ynamic_cast<GRNotationElement *>*/(mAssociated->GetAt(syststpos))) { mAssociated->GetNext(syststpos); } const GRStaff *tststaff = mAssociated->GetNext(syststpos)->getGRStaff(); while (syststpos) { GRNotationElement * el = mAssociated->GetNext(syststpos); if (el) { if (el->getGRStaff() != tststaff) { tagtype = GRTag::SYSTEMTAG; GRSystemTag * mysystag = new GRSystemTag(this); el->getGRSystemSlice()->addSystemTag(mysystag); break; } } } } GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; GREvent * grn; checkNotes(grstaff); if (error) return; GuidoPos pos = sse->startpos; while (pos) { grn = GREvent::cast(mAssociated->GetNext(pos)); if (grn) { if (!st->dirset) { if (st->direction > 0) grn->setStemDirection(dirUP); else grn->setStemDirection(dirDOWN); } grn->setFlagOnOff(false); } } }
void GRBeam::RangeEnd(GRStaff * grstaff) { assert(grstaff); GRPositionTag::RangeEnd(grstaff); if (error) return; if (!mAssociated) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(grstaff->getGRSystem()); assert(sse); if (mAssociated && (mAssociated->GetCount() == 1) && isAutoBeam()) { GREvent * ev = GREvent::cast(mAssociated->GetHead()); if (ev) { ev->setFlagOnOff(true); ev->decBeamCount(); if (sse->startElement) // something did not work, if the starElement is a glue ... and not an event ev->removeAssociation(this); if (sse->endElement) ev->removeAssociation(this); } return; } GREvent * grn; GuidoPos syststpos = sse->startpos; if (syststpos) { // this is all done so that I really get a correct first staff to test my stuff ... while (syststpos && !(mAssociated->GetAt(syststpos))) { mAssociated->GetNext(syststpos); } int tststaffnum = mAssociated->GetNext(syststpos)->getStaffNumber(); while (syststpos) { GRNotationElement * el = mAssociated->GetNext(syststpos); if (el) { if (el->getStaffNumber() != tststaffnum) { tagtype = GRTag::SYSTEMTAG; GRSystemTag * mysystag = new GRSystemTag(this); el->getGRSystemSlice()->addSystemTag(mysystag); break; } } } } GuidoPos pos = sse->startpos; GRBeamSaveStruct * st = (GRBeamSaveStruct *) sse->p; bool first = true; GDirection mytmpdir = dirOFF; while (pos) { grn = GREvent::cast(mAssociated->GetNext(pos)); if (grn) { if (!st->dirset) { if (first) { // get the stemdir of the first !? maybe it now has been set? mytmpdir = grn->getStemDirection(); } if (mytmpdir != dirOFF) grn->setStemDirection(mytmpdir); else if (st->direction>=0) grn->setStemDirection(dirUP); else grn->setStemDirection(dirDOWN); } grn->setFlagOnOff(false); first = false; } } }
void GRBeam::addAssociation(GRNotationElement * grnot) { if (error || !grnot) return ; const GRStaff * grstf = grnot->getGRStaff(); if (grstf == 0) return; GRNote * grnote = dynamic_cast<GRNote*>(grnot); bool isGrace = grnote ? grnote->isGraceNote() : false; if (grnot->getDuration() == DURATION_0 && !isGrace) { GREvent * grn = GREvent::cast(grnot); if (!grn || grn->getGlobalStem() == NULL) return; } // if we are an autobeam we do not beam rests .... const bool isautobeam = isAutoBeam(); // (dynamic cast<GRAutoBeam *>(this) != 0); GREvent * grn = GREvent::cast(grnot); if (grn == 0) { setError(grstf,1); return ; } const bool isRest = (dynamic_cast<GRRest *>(grnot) != 0); if (isautobeam && isRest) { if (mAssociated && mAssociated->GetCount() > 0) mHasRestInMiddle = true; } if (mHasRestInMiddle && !isRest) { // then we have a real Error setError(grstf,1); return; } // ignore all elements with duration 0 // but only, if I already have the stem if (grnot->getDuration() == DURATION_0 && !isGrace) { if (mAssociated) { GRNotationElement * el = mAssociated->GetTail(); if (el) { GREvent * ev = GREvent::cast(el); if (ev->getGlobalStem() == NULL || ev->getGlobalStem() == grn->getGlobalStem()) return; } } } if (dynamic_cast<GRSingleRest *>(grn)) { // ignoriere Pausen ! // setError(grstf,1); return; } if (grn->getNumFaehnchen() == 0) { setError(grstf,1); return ; } GRSystemStartEndStruct * sse = getSystemStartEndStruct(grstf->getGRSystem()); if (!sse) return ; GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; if (grn->getStemDirSet()) { st->dirset = 1; } else { if (grn->getStemDirection() == dirUP) st->direction++; else if (grn->getStemDirection() == dirDOWN) st->direction--; } GRPTagARNotationElement::addAssociation(grnot); // this is a test ... // and cannot be done that way. // otherwise we do not get the flags on again ... grn->setFlagOnOff(false); //if we increment the beamCount, we can't allow several beams to be superposed // grn->incBeamCount(); }
// (JB) \bug There is probably a bug somewhere: with map mode // different than "ISOTROPIC" (proportionnal), beamings polygons between "UP" stems // draw at an incorrect x position, while "DOWN" beams are always ok. // // Too long, needs some code-factorization, if possible. void GRBeam::tellPosition( GObject * gobj, const NVPoint & p_pos) { /* Beams are polygons made of four points: 0 2 ------------------ | | ------------------ 1 3 */ // a new test is performed: if it is a systemTag and // it is not a systemcall (checkpos), than we can just do nothing. if (error || !mAssociated || ( mAssociated->GetCount() == 0 ) || ( tagtype == GRTag::SYSTEMTAG && !mIsSystemCall )) return; GRNotationElement * el = dynamic_cast<GRNotationElement *>(gobj); if (!el || !el->getGRStaff()) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(el->getGRStaff()->getGRSystem()); assert(sse); if (el != sse->endElement) return; GRBeamSaveStruct * st = (GRBeamSaveStruct *)sse->p; GuidoPos pos; GREvent * startEl = GREvent::cast(sse->startElement); GREvent * endEl = GREvent::cast(sse->endElement); // this is the staff to which the beam belongs and who draws it. const GRStaff * beamstaff = sse->startElement->getGRStaff(); PosInfos infos = { dirUP, LSPACE, 1.0f, (endEl == startEl)}; ARBeam * arBeam = getARBeam(); const bool isSpecBeam = arBeam->isGuidoSpecBeam(); NVPoint offset = initp0 (sse, startEl, infos); initp1 (sse, infos); offset = initp2 (sse, endEl, infos); initp3 (sse, infos); // ----------------------------------------------------------- // Now, we adjust the stemlengths, according to beamslope ... // we have the start and end-position in st->p // We have to determine the slope and adjust the slope to minimum and maximum ... // ----------------------------------------------------------- float stemWidth = st->p[2].x - st->p[0].x; float slope = (st->p[2].y - st->p[0].y) / stemWidth; // another hack to control the slope when events are on different staves - DF sept 15 2009 if (startEl && endEl && (startEl->getGRStaff() != endEl->getGRStaff())) { while ((slope < -0.20) || (slope > 0.20)) { float shift = (slope < 0) ? -LSPACE/4 : LSPACE/4; st->p[0].y += shift; st->p[1].y += shift; st->p[2].y -= shift; st->p[3].y -= shift; slope = (st->p[2].y - st->p[0].y) / stemWidth; } } bool needsadjust = true; // we have to adjust the slope ONLY, if the stemlength // of the first and last element has not been set automatically! if ( (startEl && startEl->getStemLengthSet() && endEl && endEl->getStemLengthSet()) || tagtype == SYSTEMTAG || (arBeam && isSpecBeam)) { needsadjust = false; } else slopeAdjust (sse, startEl, endEl, slope, infos); if (arBeam && isSpecBeam) { // then we have to set the length ... if it is not set otherwise ... GRSingleNote * nt = dynamic_cast<GRSingleNote *>(sse->startElement); if(nt && !nt->getStemLengthSet()) { const float myval = arBeam->dy1->getValue(); nt->setStemLength( myval); } nt = dynamic_cast<GRSingleNote *>(sse->endElement); if(nt && !nt->getStemLengthSet()) { float myval; if (arBeam->dy3 && arBeam->dy3->TagIsSet()) myval = arBeam->dy3->getValue(); else myval = arBeam->dy1->getValue(); nt->setStemLength( myval); } } float offsetbeam = 0; // nobeamoffset describes, if no beamoffset is valid: if notes ask for different beam-offsets // then, there is just no offset .... things must be changed manually then .... bool nobeamoffset = false; if(( startEl && startEl->getStemLengthSet()) || ( endEl && endEl->getStemLengthSet())) nobeamoffset = true; for (int counter = 0; counter < 2; ++counter ) { if (counter == 1) { if ((offsetbeam == 0) || nobeamoffset) break; else if (!nobeamoffset) { st->p[0].y -= offsetbeam; st->p[1].y -= offsetbeam; st->p[2].y -= offsetbeam; st->p[3].y -= offsetbeam; offsetbeam = 0; } } pos = sse->startpos; while (pos) { // now we calculate the stem-end-positions ... GuidoPos oldpos = pos; GREvent * sn = GREvent::cast(mAssociated->GetNext(pos)); if (sn) { float rx = sn->getStemStartPos().x - st->p[0].x; if (tagtype == SYSTEMTAG) rx += sn->getGRStaff()->getPosition().x; float disty = st->p[2].y - st->p[0].y; float distx = st->p[2].x - st->p[0].x; float ly = disty / distx * rx; ly += st->p[0].y; float diffy = (float)sn->getStemStartPos().y; GDirection adjustdir=dirAUTO; if (sn->getStemDirection() == dirUP) { diffy += (float)sn->getStemLength(); adjustdir = dirUP; } else if (sn->getStemDirection() == dirDOWN) { adjustdir = dirDOWN; diffy -= (float)sn->getStemLength(); } ly -= diffy; if (tagtype == SYSTEMTAG) ly -= (float)sn->getGRStaff()->getPosition().y; float offbase = 3.5f * infos.currentLSPACE; if (ly < 0) { if (needsadjust) { if (adjustdir == dirDOWN) { const float newoffs = ly - offbase; if (newoffs < offsetbeam) { if (offsetbeam > 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } ly = -offbase; } else if (ly > -offbase) { const float newoffs = ly + offbase; if (newoffs > offsetbeam) { if (offsetbeam < 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } } } ly = -ly; } else if (needsadjust) { if (adjustdir == dirUP) { const float newoffs = ly + offbase; if (newoffs > offsetbeam) { if (offsetbeam < 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } ly = offbase; } else if (ly < offbase) { const float newoffs = ly - offbase; if (newoffs < offsetbeam) { if (offsetbeam > 0) { GuidoTrace("WARNING: different beam adjustments!"); nobeamoffset = true; } else offsetbeam = newoffs; } } } // sn->changeStemLength( ly ); // adjusted - DF sept 15 2009 sn->changeStemLength( ly - infos.currentLSPACE/20 ); } if (oldpos == sse->endpos) break; } } // -- Now we need to add the simplebeams as simplebeamgroups ... NVPoint myp[4]; int dir = st->direction; if (st->dirset) { // then the direction was set explicitly by the user ... GREvent * sn = GREvent::cast(mAssociated->GetHead()); if (sn) dir = sn->getStemDirection(); } else dir = infos.stemdir; bool first = true; pos = sse->startpos; // - These constants defines the space and the thickness of additionnal beams. const float yFact1 = 0.75f * infos.currentLSPACE; // was 0.7f const float yFact2 = 0.4f * infos.currentLSPACE; // for beam length adjustment - DF sept 15 2009 const float xadjust = infos.currentLSPACE/10; GDirection lastLocalDir = dirOFF; int previousBeamsCount = 0; while (pos) { GuidoPos oldpos = pos; GREvent * stemNote = GREvent::cast(mAssociated->GetNext(pos)); if (stemNote) { GDirection localDir = stemNote->getStemDirection(); float yLocalFact1 = yFact1 * localDir; float yLocalFact2 = yFact2 * localDir; // now we check the number of beams ... if (stemNote->getBeamCount() < stemNote->getNumFaehnchen()) { float beamCount = (float)(stemNote->getBeamCount()); stemNote->incBeamCount(); if (first && (sse->startflag == GRSystemStartEndStruct::OPENLEFT)) { // the additional beam starts at the startElement (glue), we have more beams to draw myp[0] = sse->startElement->getPosition(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[1] = myp[0]; // first = false; // never read (according to clang :-) } else { // the additional beam starts at sn. We have more beams to draw myp[0] = stemNote->getStemStartPos(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[0].y += beamCount * yLocalFact1; if (localDir != dir) myp[0].y -= yLocalFact2; myp[1].x = myp[0].x; myp[1].y = myp[0].y + yLocalFact2; } // now we look for the endposition GREvent * sn2 = NULL; GuidoPos tmppos = pos; // partialbeam is set, if the new SimpleBeam only covers part of the masterBeam. int partialbeam = 0; while (tmppos) { GuidoPos oldpos2 = tmppos; GREvent * tmpsn = GREvent::cast(mAssociated->GetNext(tmppos)); if (tmpsn) { if (tmpsn->getBeamCount() < tmpsn->getNumFaehnchen()) { sn2 = tmpsn; sn2->incBeamCount(); continue; } else { partialbeam = 1; break; } } if (oldpos2 == sse->endpos) break; } if (sn2) { if (!partialbeam && sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { // then the position is different ... myp[2] = sse->endElement->getPosition(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y = myp[0].y; } else { // we have an End-Position ... myp[2] = sn2->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y += beamCount * yLocalFact1; } if (localDir != dir) myp[2].y -= yLocalFact2; myp[3].x = myp[2].x; myp[3].y = myp[2].y + yLocalFact2; } else { // we do not have an End-Positon single beam ... (meaning a single straight flag) // but only, if it is not open on the left or the right hand side. const float slope = (float)(st->p[2].y - st->p[0].y ) / (float)(st->p[2].x - st->p[0].x); if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) { // then we have to deal with the startposition of the glue-element .... // BUT, you can only set this, if the previous beam had this beamcount at the end .... // how do I know that? not now. // sn is the only element .... and we are open on the left ... if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[1] = myp[0]; myp[2] = stemNote->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += stemNote->getGRStaff()->getPosition(); myp[2].y += beamCount * yLocalFact1; if (localDir != dir) myp[2].y -= yLocalFact2; myp[3] = myp[2]; myp[3].y += yLocalFact2; } else if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { myp[0] = stemNote->getStemEndPos(); if (tagtype == SYSTEMTAG) myp[0] += stemNote->getGRStaff()->getPosition(); myp[0].y += beamCount * yLocalFact1; if (localDir != dir) myp[0].y -= yLocalFact2; myp[1] = myp[0]; myp[1].y += yLocalFact2; myp[2] = sse->endElement->getPosition(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += sn2->getGRStaff()->getPosition(); myp[2].y = myp[0].y; myp[3].x = myp[2].x; myp[3].y = myp[1].y; } /* 26/11/03 Beaming bug: wrong direction for partial beam (beam-bug.gmn) can be tested but changing this test. startpos check added to correct problem with partial beam going outside a group like in [ _/16 c d/8 ] */ else if( oldpos == sse->endpos || pos == NULL || ((!stemNote->isSyncopated()) && (oldpos != sse->startpos))) { // Partial beams leftward ( using slope) myp[2] = stemNote->getStemEndPos(); myp[2].x += xadjust; if (tagtype == SYSTEMTAG) myp[2] += stemNote->getGRStaff()->getPosition(); if (localDir != dir) myp[2].y -= yLocalFact2; myp[2].y += beamCount * yLocalFact1; myp[3] = myp[2]; myp[3].y += yLocalFact2; myp[0] = myp[2]; myp[0].x -= infos.currentLSPACE; myp[0].y -= slope * infos.currentLSPACE; myp[1] = myp[0]; myp[1].y += yLocalFact2; // ? We are at the end, there is no valid event at the end ... so what do we do? // useless tests: the code was the same and is now outside the test (above) - DF sept 15 2009 /* if (sse->endflag == GRSystemStartEndStruct::OPENRIGHT) { } else { } */ } else { // Partial beams rightward ( using slope) myp[2] = myp[0]; myp[2].x += infos.currentLSPACE; myp[2].y += slope * infos.currentLSPACE; myp[3] = myp[2]; myp[3].y += yLocalFact2; } } // now we construct a SimpleBeam, we now have to "undo" the systemTag-stuff if (tagtype == SYSTEMTAG) { const NVPoint & offset = beamstaff->getPosition(); myp[0] -= offset; myp[1] -= offset; myp[2] -= offset; myp[3] -= offset; } if (sse->startflag == GRSystemStartEndStruct::OPENLEFT) { myp[0].y = myp[2].y; myp[1].y = myp[3].y; } GRSimpleBeam * tmpbeam = new GRSimpleBeam(this,myp); if( st->simpleBeams == 0 ) st->simpleBeams = new SimpleBeamList(1); st->simpleBeams->AddTail(tmpbeam); pos = sse->startpos; oldpos = pos; first = true; lastLocalDir = localDir; previousBeamsCount = stemNote->getBeamCount() - 1; } // a new hack, again to catch stems directions change - DF sept 15 2009 else if (localDir != dir) { // check for stems length NVPoint stemloc = stemNote->getStemStartPos(); if (tagtype == SYSTEMTAG) stemloc += stemNote->getGRStaff()->getPosition(); int beamscount = stemNote->getBeamCount() - 1; if ((beamscount > 0) && (previousBeamsCount > beamscount) && (lastLocalDir != localDir)) { if (localDir == dirUP) stemNote->changeStemLength(stemNote->getStemLength() + (yLocalFact1 * beamscount)); else if (localDir == dirDOWN) stemNote->changeStemLength(stemNote->getStemLength() - (yLocalFact1 * beamscount)); } } } if (oldpos == sse->endpos) break; } // now we have to make sure, that the original positions // for the beam are set for the right staff if (tagtype == SYSTEMTAG) { const NVPoint &offset = beamstaff->getPosition(); st->p[0] -= offset; st->p[1] -= offset; st->p[2] -= offset; st->p[3] -= offset; } }
void GRGlobalStem::addAssociation(GRNotationElement * grnot) { if (error) return; GREvent * ev = GREvent::cast(grnot); if( ev ) { TYPE_DURATION evdur (ev->getDuration()); TYPE_DURATION durtempl; GRSingleNote * sngnot = dynamic_cast<GRSingleNote *>(ev); if (sngnot) { durtempl = sngnot->getDurTemplate(); } // this changes the display-duration // (nested display-duration-tags!) if (durtempl>evdur && durtempl> dispdur) dispdur = durtempl; // take the length ... if (evdur > DURATION_0) { if (mFirstEl) { // then we already have one duration event. In this // case, the association is added because an other // voice uses this globalstem because of a \chord<label>-Tag ev->setGlobalStem(this); ev->setNeedsSpring(1); } else { // then our springconstant changes ... ev->setGlobalStem(this); if (!mFirstEl) ev->setNeedsSpring(1); } } else { ev->setGlobalStem(this); if (!mFirstEl) ev->setNeedsSpring(1); } } // This sets the first element in the range ... if (mFirstEl == 0) { // this associates the first element with // this tag .... mFirstEl = grnot; mFirstEl->addAssociation(this); return; // the firstElement is not added to the associated // ones -> it does not have to told anything!? } GRPTagARNotationElement::addAssociation(grnot); // this is needed, because the share location can // be used in different staves. Elements that need // be told of the location can be deleted before this // tag, therefor we must know, if these elements are // deleted. // The recursive cycle with tellPosition is broken, // because only the first element really sets the // position. And the first is not included in the // own mAssociated list. grnot->addAssociation(this); }
// ---------------------------------------------------------------------------- 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(); // } }
/** 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; }