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