/** \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; }
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 GRDiminuendo::tellPosition(GObject *caller, const NVPoint & newPosition) { GRNotationElement * grel = dynamic_cast<GRNotationElement *>(caller); if (grel == 0) return; GRStaff * staff = grel->getGRStaff(); if (staff == 0) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct(staff->getGRSystem()); if (sse == 0) return; const GRNotationElement * const endElement = sse->endElement; if (grel == endElement) updateDiminuendo(staff); }
// ----------------------------------------------------------------------------- void GRBowing::tellPosition(GObject * caller, const NVPoint & newPosition) { GRNotationElement * grel = dynamic_cast<GRNotationElement *>(caller); if (grel == 0 ) return; GRStaff * staff = grel->getGRStaff(); if (staff == 0 ) return; GRSystemStartEndStruct * sse = getSystemStartEndStruct( staff->getGRSystem()); if (sse == 0) return; const GRNotationElement * const startElement = sse->startElement; const GRNotationElement * const endElement = sse->endElement; // if ( openLeftRange && openRightRange ) return; // updateBow(); if( grel == endElement || ( endElement == 0 && grel == startElement)) { updateBow( staff ); } }
// ---------------------------------------------------------------------------- void 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; }