Пример #1
0
// (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;
	}
}
Пример #2
0
// (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;
	}
}
Пример #3
0
/** 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;
}