Пример #1
0
void Beam::FilterList( ListOfObjects *childList )
{
    bool firstNoteGrace = false;
    // We want to keep only notes and rest
    // Eventually, we also need to filter out grace notes properly (e.g., with sub-beams)
    ListOfObjects::iterator iter = childList->begin();

    while ( iter != childList->end()) {
        if ( !(*iter)->IsLayerElement() ) {
            // remove anything that is not an LayerElement (e.g. Verse, Syl, etc)
            iter = childList->erase( iter );
            continue;
        }
        LayerElement *currentElement = dynamic_cast<LayerElement*>(*iter);
        assert( currentElement );
        if ( !currentElement->HasInterface(INTERFACE_DURATION) )
        {
            // remove anything that has not a DurationInterface
            iter = childList->erase( iter );
        } else {
            // Drop notes that are signaled as grace notes
            Note *n = dynamic_cast<Note*>(currentElement);

            if (n) {
                // if we are at the beginning of the beam
                // and the note is cueSize
                // assume all the beam is of grace notes
                if (childList->begin() == iter) {
                    if (n->HasGrace())
                        firstNoteGrace = true;
                }

                // if the first note in beam was NOT a grace
                // we have grace notes embedded in a beam
                // drop them
                if ( !firstNoteGrace && n->HasGrace() == true)
                    iter = childList->erase( iter );
                else
                    iter++;

            } else {
                // if it is a Rest, do not drop
                iter++;
            }
        }
    }

    InitCoords( childList );
}
Пример #2
0
void Tuplet::FilterList()
{
    // We want to keep only notes and rest
    // Eventually, we also need to filter out grace notes properly (e.g., with sub-beams)
    ListOfObjects::iterator iter = m_list.begin();
    
    while ( iter != m_list.end()) {
        LayerElement *currentElement = dynamic_cast<LayerElement*>(*iter);
        if ( currentElement && !currentElement->HasDurationInterface() )
        {
            iter = m_list.erase( iter );
        } else {
            iter++;
        }
    }
    
}
Пример #3
0
void PaeInput::addLayerElement(LayerElement *element) {
    
    if (m_nested_objects.size() > 0) {
        LayerElement *bottom = m_nested_objects.back();
        
        if ( bottom->Is() == BEAM ) {
            Beam *beam = dynamic_cast<Beam*>( bottom );
            assert( beam );
            beam->AddLayerElement( element );
        }
        else if ( bottom->Is() == TUPLET ) {
            Tuplet *tuplet = dynamic_cast<Tuplet*>( bottom );
            assert( tuplet );
            tuplet->AddLayerElement( element );
        }
        
    } else {
        m_layer->AddLayerElement(element);
    }
}
Пример #4
0
LayerElement *Layer::GetAtPos(int x)
{
    Object *first = this->GetFirst();
    if (!first || !first->IsLayerElement()) return NULL;

    LayerElement *element = dynamic_cast<LayerElement *>(first);
    assert(element);
    if (element->GetDrawingX() > x) return NULL;

    Object *next;
    while ((next = this->GetNext())) {
        if (!next->IsLayerElement()) continue;
        LayerElement *nextLayerElement = dynamic_cast<LayerElement *>(next);
        assert(nextLayerElement);
        if (nextLayerElement->GetDrawingX() > x) return element;
        element = nextLayerElement;
    }
    // This can be NULL if the layer is empty
    return element;
}
Пример #5
0
data_STEMDIRECTION Layer::GetDrawingStemDir(const ArrayOfBeamElementCoords *coords)
{
    assert(!coords->empty());

    // Adjust the x position of the first and last element for taking into account the stem width
    LayerElement *first = dynamic_cast<LayerElement *>(coords->front()->m_element);
    LayerElement *last = dynamic_cast<LayerElement *>(coords->back()->m_element);

    if (!first || !last) {
        return m_drawingStemDir;
    }

    Measure *measure = dynamic_cast<Measure *>(this->GetFirstParent(MEASURE));
    assert(measure);

    // First check if there is any <space> in the measure - if not we can return the layer stem direction
    if (!measure->FindChildByType(SPACE)) {
        return m_drawingStemDir;
    }

    Alignment *alignmentFirst = first->GetAlignment();
    assert(alignmentFirst);
    Alignment *alignmentLast = last->GetAlignment();
    assert(alignmentLast);

    // We are ignoring cross-staff situation here because this should not be called if we have one
    Staff *staff = dynamic_cast<Staff *>(first->GetFirstParent(STAFF));
    assert(staff);

    double time = alignmentFirst->GetTime();
    double duration = alignmentLast->GetTime() - time + last->GetAlignmentDuration();
    duration = durRound(duration);

    return GetDrawingStemDir(time, duration, measure, staff->GetN());
}
Пример #6
0
data_STEMDIRECTION View::GetTupletCoordinates(Tuplet *tuplet, Layer *layer, Point *start, Point *end, Point *center)
{
    assert(tuplet);
    assert(layer);
    assert(start);
    assert(end);
    assert(center);

    Point first, last;
    int x, y;
    data_STEMDIRECTION direction = STEMDIRECTION_up;

    ListOfObjects *tupletChildren = tuplet->GetList(tuplet);
    LayerElement *firstElement = dynamic_cast<LayerElement *>(tupletChildren->front());
    LayerElement *lastElement = dynamic_cast<LayerElement *>(tupletChildren->back());

    // AllNotesBeamed tries to figure out if all the notes are in the same beam
    if (OneBeamInTuplet(tuplet)) {

        // yes they are in a beam
        x = firstElement->GetDrawingX()
            + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->m_selfBB_x2) / 2;

        // align the center point at the exact center of the first an last stem
        // TUPLET_OFFSET is summed so it does not collide with the stem
        Note *firstNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE));
        Note *lastNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE, UNLIMITED_DEPTH, BACKWARD));

        y = firstElement->GetDrawingY();
        if (firstNote && lastNote) {
            if (firstNote->GetDrawingStemDir() == STEMDIRECTION_up)
                y = lastNote->GetDrawingStemEnd().y
                    + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 + TUPLET_OFFSET;
            else
                y = lastNote->GetDrawingStemEnd().y
                    + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 - TUPLET_OFFSET;
        }

        // Copy the generated coordinates
        center->x = x;
        center->y = y;
        direction = firstNote->GetDrawingStemDir(); // stem direction is the same for all notes
    }
    else {
        // There are unbeamed notes of two different beams
        // treat all the notes as unbeamed
        int ups = 0, downs = 0; // quantity of up- and down-stems

        // In this case use the center of the notehead to calculate the exact center
        // as it looks better
        x = firstElement->GetDrawingX()
            + (lastElement->GetDrawingX() - firstElement->GetDrawingX() + lastElement->m_selfBB_x2) / 2;

        // Return the start and end position for the brackes
        // starting from the first edge and last of the BBoxes
        start->x = firstElement->m_selfBB_x1 + firstElement->GetDrawingX();
        end->x = lastElement->m_selfBB_x2 + lastElement->GetDrawingX();

        // The first step is to calculate all the stem directions
        // cycle into the elements and count the up and down dirs
        ListOfObjects::iterator iter = tupletChildren->begin();
        while (iter != tupletChildren->end()) {
            if ((*iter)->Is() == NOTE) {
                Note *currentNote = dynamic_cast<Note *>(*iter);
                assert(currentNote);
                if (currentNote->GetDrawingStemDir() == STEMDIRECTION_up)
                    ups++;
                else
                    downs++;
            }
            ++iter;
        }
        // true means up
        direction = ups > downs ? STEMDIRECTION_up : STEMDIRECTION_down;

        // if ups or downs are 0, it means all the stems go in the same direction
        if (ups == 0 || downs == 0) {

            Note *firstNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE));
            Note *lastNote = dynamic_cast<Note *>(tuplet->FindChildByType(NOTE, UNLIMITED_DEPTH, BACKWARD));

            // Calculate the average between the first and last stem
            // set center, start and end too.
            y = firstElement->GetDrawingY();
            if (firstNote && lastNote) {
                if (direction == STEMDIRECTION_up) { // up
                    y = lastNote->GetDrawingStemEnd().y
                        + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 + TUPLET_OFFSET;
                    start->y = firstNote->GetDrawingStemEnd().y + TUPLET_OFFSET;
                    end->y = lastNote->GetDrawingStemEnd().y + TUPLET_OFFSET;
                }
                else {
                    y = lastNote->GetDrawingStemEnd().y
                        + (firstNote->GetDrawingStemEnd().y - lastNote->GetDrawingStemEnd().y) / 2 - TUPLET_OFFSET;
                    start->y = firstNote->GetDrawingStemEnd().y - TUPLET_OFFSET;
                    end->y = lastNote->GetDrawingStemEnd().y - TUPLET_OFFSET;
                }
            }

            // Now we cycle again in all the intermediate notes (i.e. we start from the second note
            // and stop at last -1)
            // We will see if the position of the note is more (or less for down stems) of the calculated
            // average. In this case we offset down or up all the points
            iter = tupletChildren->begin();
            while (iter != tupletChildren->end()) {
                if ((*iter)->Is() == NOTE) {
                    Note *currentNote = dynamic_cast<Note *>(*iter);
                    assert(currentNote);

                    if (direction == STEMDIRECTION_up) {
                        // The note is more than the avg, adjust to y the difference
                        // from this note to the avg
                        if (currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET > y) {
                            int offset = y - (currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET);
                            y -= offset;
                            end->y -= offset;
                            start->y -= offset;
                        }
                    }
                    else {
                        if (currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET < y) {
                            int offset = y - (currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET);
                            y -= offset;
                            end->y -= offset;
                            start->y -= offset;
                        }
                    }
                }
                ++iter;
            }
        }
        else {
            // two-directional beams
            // this case is similar to the above, but the bracket is only horizontal
            // y is 0 because the final y pos is above the tallest stem
            y = 0;

            // Find the tallest stem and set y to it (with the offset distance)
            iter = tupletChildren->begin();
            while (iter != tupletChildren->end()) {
                if ((*iter)->Is() == NOTE) {
                    Note *currentNote = dynamic_cast<Note *>(*iter);
                    assert(currentNote);

                    if (currentNote->GetDrawingStemDir() == direction) {
                        if (direction == STEMDIRECTION_up) {
                            if (y == 0 || currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET >= y)
                                y = currentNote->GetDrawingStemEnd().y + TUPLET_OFFSET;
                        }
                        else {
                            if (y == 0 || currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET <= y)
                                y = currentNote->GetDrawingStemEnd().y - TUPLET_OFFSET;
                        }
                    }
                    else {
                        // do none for now
                        // but if a notehead with a reversed stem is taller that the last
                        // calculated y, we need to offset
                    }
                }
                ++iter;
            }

            // end and start are on the same line (and so il center when set later)
            end->y = start->y = y;
        }
    }

    center->x = x;
    center->y = y;
    return direction;
}
Пример #7
0
void Chord::FilterList( ListOfObjects *childList )
{
    // Retain only note children of chords
    ListOfObjects::iterator iter = childList->begin();
    
    while ( iter != childList->end()) {
        LayerElement *currentElement = dynamic_cast<LayerElement*>(*iter);
        if ( !currentElement ) {
            // remove anything that is not an LayerElement
            iter = childList->erase( iter );
        }
        else if ( !currentElement->HasDurationInterface() )
        {
            iter = childList->erase( iter );
        }
        else /*if ( dynamic_cast<EditorialElement*>(currentElement))
        {
            Object* object = currentElement->GetFirstChild(&typeid(Note));
            if (dynamic_cast<Note*>(object))
            {
                iter++;
            }
        }
        else */{
            Note *n = dynamic_cast<Note*>(currentElement);
            
            if (n) {
                iter++;
            } else {
                // if it is not a note, drop it
                iter = childList->erase( iter );
            }
        }
    }
    
    childList->sort(compare_pitch);
    
    iter = childList->begin();
    
    this->ClearClusters();
    
    Note *curNote, *lastNote = dynamic_cast<Note*>(*iter);
    int curPitch, lastPitch = lastNote->GetDiatonicPitch();
    ChordCluster* curCluster = NULL;
    
    iter++;
    
    while ( iter != childList->end()) {
        curNote = dynamic_cast<Note*>(*iter);
        curPitch = curNote->GetDiatonicPitch();
        
        if (curPitch - lastPitch == 1) {
            if(!lastNote->m_cluster)
            {
                curCluster = new ChordCluster();
                m_clusters.push_back(curCluster);
                curCluster->push_back(lastNote);
                lastNote->m_cluster = curCluster;
                lastNote->m_clusterPosition = (int)curCluster->size();
            }
            curCluster->push_back(curNote);
            curNote->m_cluster = curCluster;
            curNote->m_clusterPosition = (int)curCluster->size();
        }
        
        lastNote = curNote;
        lastPitch = curPitch;
        
        iter++;
    }
}
Пример #8
0
void PaeInput::parseNote(NoteObject note) {
    
    LayerElement *element;
    
    if (note.rest) {
        Rest *rest =  new Rest();
        
        rest->SetDots( note.dots );
        rest->SetDur(note.duration);

        if (note.fermata) {
            rest->SetFermata(PLACE_above); // always above for now
        }
        
        element = rest;
    } else {
        Note *mnote = new Note();
        
        mnote->SetPname(note.pitch);
        mnote->SetOct(note.octave);
        mnote->SetAccid(note.accidental);
        
        mnote->SetDots( note.dots );
        mnote->SetDur(note.duration);
        
        if (note.fermata) {
            mnote->SetFermata(PLACE_above); // always above for now
        }
        
        if (note.trill == true)
            mnote->m_embellishment = EMB_TRILL;
        
        if (m_last_tied_note != NULL) {
            mnote->SetTie(TIE_t);
            m_last_tied_note = NULL;
        }
        
        if (note.tie) {
            if (mnote->GetTie()==TIE_t) mnote->SetTie(TIE_m);
            else mnote->SetTie(TIE_i);
            m_last_tied_note = mnote;
        }
        
        element = mnote;
    }
    
    // Does this note have a clef change? push it before everyting else
    if (note.clef)
        addLayerElement(note.clef);

    // Same thing for time changes
    // You can find this sometimes
    if (note.meter)
        addLayerElement(note.meter);
    
    // Handle key change. Evil if done in a beam
    if (note.key)
        addLayerElement(note.key);
    
    // Acciaccaturas are similar but do not get beamed (do they)
    // this case is simpler. NOTE a note can not be acciacctura AND appoggiatura
    // Acciaccatura rests do not exist
    if (note.acciaccatura && (element->Is() == NOTE) ) {
        Note *note = dynamic_cast<Note*>(element);
        assert( note );
        note->SetDur(DURATION_8);
        note->SetGrace(GRACE_acc);
        note->SetStemDir(STEMDIRECTION_up);
    }
    
    if ( (note.appoggiatura > 0) && (element->Is() == NOTE) ) {
        Note *note = dynamic_cast<Note*>(element);
        assert( note );
        note->SetGrace(GRACE_unacc);
        note->SetStemDir(STEMDIRECTION_up);
    }

    if (note.beam == BEAM_INITIAL) {
        pushContainer(new Beam());
    }
    
    // we have a tuplet, the tuplet_note is > 0
    // which means we are counting a tuplet
    if (note.tuplet_note > 0 && note.tuplet_notes == note.tuplet_note) { // first elem in tuplet
        Tuplet *newTuplet = new Tuplet();
        newTuplet->SetNum(note.tuplet_notes);
        newTuplet->SetNumbase(note.tuplet_notes);
        pushContainer(newTuplet);
    }
    
    
    // Add the note to the current container
    addLayerElement(element);
    
    // the last note counts always '1'
    // insert the tuplet elem
    // and reset the tuplet counter
    if (note.tuplet_note == 1)
        popContainer();
    
    if (note.beam == BEAM_TERMINAL)
        popContainer();
}
Пример #9
0
int Artic::CalcArtic(FunctorParams *functorParams)
{
    FunctorDocParams *params = dynamic_cast<FunctorDocParams *>(functorParams);
    assert(params);

    /************** Get the parent and the stem direction **************/

    LayerElement *parent = NULL;
    Note *parentNote = NULL;
    Chord *parentChord = dynamic_cast<Chord *>(this->GetFirstParent(CHORD, 2));
    data_STEMDIRECTION stemDir = STEMDIRECTION_NONE;
    data_STAFFREL place = STAFFREL_NONE;

    if (!parentChord) {
        parentNote = dynamic_cast<Note *>(this->GetFirstParent(NOTE));
        parent = parentNote;
    }
    else {
        parent = parentChord;
    }

    if (!parentChord && !parentNote) {
        // no parent chord or note, nothing we can do...
        return FUNCTOR_CONTINUE;
    }

    Staff *staff = dynamic_cast<Staff *>(this->GetFirstParent(STAFF));
    assert(staff);
    Layer *layer = dynamic_cast<Layer *>(this->GetFirstParent(LAYER));
    assert(layer);

    stemDir = parentNote ? parentNote->GetDrawingStemDir() : parentChord->GetDrawingStemDir();

    /************** placement **************/

    bool allowAbove = true;

    // for now we ignore within @place
    if (this->HasPlace() && (this->GetPlace() != STAFFREL_within)) {
        place = this->GetPlace();
        // If we have a place indication do not allow to be changed to above
        allowAbove = false;
    }
    else if (layer->GetDrawingStemDir() != STEMDIRECTION_NONE) {
        place = (layer->GetDrawingStemDir() == STEMDIRECTION_up) ? STAFFREL_above : STAFFREL_below;
        // If we have more than one layer do not allow to be changed to above
        allowAbove = false;
    }
    else if (stemDir == STEMDIRECTION_up)
        place = STAFFREL_below;
    else
        place = STAFFREL_above;

    /************** set it to both the inside and outside part **************/

    ArticPart *insidePart = this->GetInsidePart();
    ArticPart *outsidePart = this->GetOutsidePart();

    if (insidePart) {
        insidePart->SetPlace(place);
    }

    if (outsidePart) {
        // If allowAbove is true it will place the above if the content requires so (even if place below if given)
        if (place == STAFFREL_below && allowAbove && outsidePart->AlwaysAbove()) place = STAFFREL_above;
        outsidePart->SetPlace(place);
    }

    /************** calculate the y position **************/

    Staff *staffAbove = NULL;
    Staff *staffBelow = NULL;

    // Cross-staff handling of articulation will need to be re-thought. We can look at assiging a cross-staff to the
    // appropriate ArticPart
    // (see below) - For chords, we need to distinguish cross-staff chords and cross-staff chord notes
    if (parent->m_crossStaff && parent->m_crossLayer) {
        staff = parent->m_crossStaff;
        staffAbove = staff;
        staffBelow = staff;
    }
    else if (parentChord) {
        parentChord->GetCrossStaffExtremes(staffAbove, staffBelow);
    }

    int staffYBottom = -params->m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize);
    // Avoid in artic to be in legder lines
    int yInAbove = std::max(
        parent->GetDrawingTop(params->m_doc, staff->m_drawingStaffSize, false) - staff->GetDrawingY(), staffYBottom);
    int yInBelow
        = std::min(parent->GetDrawingBottom(params->m_doc, staff->m_drawingStaffSize, false) - staff->GetDrawingY(), 0);
    int yOutAbove = std::max(yInAbove, 0);
    int yOutBelow = std::min(yInBelow, staffYBottom);

    // Does not work properly with chords, needs rethinking - It might be better to make artic or articPart relative to
    // notes
    // The problem is that in MEI artic are children of chord element and not of the notes
    if (insidePart) {
        if (insidePart->GetPlace() == STAFFREL_above) {
            insidePart->SetDrawingYRel(yInAbove);
            insidePart->m_crossStaff = staffAbove;
        }
        else {
            insidePart->SetDrawingYRel(yInBelow);
            insidePart->m_crossStaff = staffBelow;
        }
    }

    if (outsidePart) {
        if (outsidePart->GetPlace() == STAFFREL_above) {
            outsidePart->SetDrawingYRel(yOutAbove);
            outsidePart->m_crossStaff = staffAbove;
        }
        else {
            outsidePart->SetDrawingYRel(yOutBelow);
            outsidePart->m_crossStaff = staffBelow;
        }
    }

    // If we have both an inside and outside part we need to move the outside part away when they are both on the same
    // side
    if (insidePart && outsidePart) {

        int margin = params->m_doc->GetTopMargin(insidePart->GetClassId())
            * params->m_doc->GetDrawingUnit(staff->m_drawingStaffSize) / PARAM_DENOMINATOR;

        if (insidePart->GetPlace() == outsidePart->GetPlace()) {
            if (insidePart->GetPlace() == STAFFREL_above) {
                int inTop = insidePart->GetContentTop();
                int outBottom = outsidePart->GetContentBottom();
                if (inTop > outBottom)
                    outsidePart->SetDrawingYRel(outsidePart->GetDrawingYRel() + inTop - outBottom + margin);
            }
            else {
                int inBottom = insidePart->GetContentBottom();
                int outTop = outsidePart->GetContentTop();
                if (inBottom < outTop)
                    outsidePart->SetDrawingYRel(outsidePart->GetDrawingYRel() + outTop - inBottom + margin);
            }
        }
    }

    return FUNCTOR_SIBLINGS;
}
Пример #10
0
void View::DrawSlurInitial(FloatingCurvePositioner *curve, Slur *slur, int x1, int x2, Staff *staff, char spanningType)
{
    Beam *parentBeam = NULL;
    Chord *startParentChord = NULL;
    Chord *endParentChord = NULL;
    Note *startNote = NULL;
    Note *endNote = NULL;
    Chord *startChord = NULL;
    Chord *endChord = NULL;

    curvature_CURVEDIR drawingCurveDir = curvature_CURVEDIR_above;
    data_STEMDIRECTION startStemDir = STEMDIRECTION_NONE;
    data_STEMDIRECTION endStemDir = STEMDIRECTION_NONE;
    data_STEMDIRECTION stemDir = STEMDIRECTION_NONE;
    bool isGraceToNoteSlur = false;
    int y1 = staff->GetDrawingY();
    int y2 = staff->GetDrawingY();

    /************** parent layers **************/

    LayerElement *start = dynamic_cast<LayerElement *>(slur->GetStart());
    LayerElement *end = dynamic_cast<LayerElement *>(slur->GetEnd());

    if (!start || !end) {
        // no start and end, obviously nothing to do...
        return;
    }

    if (start->Is(TIMESTAMP_ATTR) && end->Is(TIMESTAMP_ATTR)) {
        // for now ignore slur using 2 tstamps
        return;
    }

    if (start->Is(NOTE)) {
        startNote = dynamic_cast<Note *>(start);
        assert(startNote);
        startParentChord = startNote->IsChordTone();
        startStemDir = startNote->GetDrawingStemDir();
    }
    else if (start->Is(CHORD)) {
        startChord = dynamic_cast<Chord *>(start);
        assert(startChord);
        startStemDir = startChord->GetDrawingStemDir();
    }
    if (end->Is(NOTE)) {
        endNote = dynamic_cast<Note *>(end);
        assert(endNote);
        endParentChord = endNote->IsChordTone();
        endStemDir = endNote->GetDrawingStemDir();
    }
    else if (end->Is(CHORD)) {
        endChord = dynamic_cast<Chord *>(end);
        assert(endChord);
        endStemDir = endChord->GetDrawingStemDir();
    }

    if (startNote && endNote && startNote->IsGraceNote() && !endNote->IsGraceNote()) {
        isGraceToNoteSlur = true;
    }

    Layer *layer = NULL;
    LayerElement *layerElement = NULL;
    // For now, with timestamps, get the first layer. We should eventually look at the @layerident (not implemented)
    if (!start->Is(TIMESTAMP_ATTR)) {
        layer = dynamic_cast<Layer *>(start->GetFirstParent(LAYER));
        layerElement = start;
    }
    else {
        layer = dynamic_cast<Layer *>(end->GetFirstParent(LAYER));
        layerElement = end;
    }
    assert(layer);

    if (!start->Is(TIMESTAMP_ATTR) && !end->Is(TIMESTAMP_ATTR) && (spanningType == SPANNING_START_END)) {
        System *system = dynamic_cast<System *>(staff->GetFirstParent(SYSTEM));
        assert(system);
        // If we have a start to end situation, then store the curvedir in the slur for mixed drawing stem dir
        // situations
        if (system->HasMixedDrawingStemDir(start, end)) {
            slur->SetDrawingCurvedir(curvature_CURVEDIR_above);
        }
    }

    /************** calculate the radius for adjusting the x position **************/

    int startRadius = 0;
    if (!start->Is(TIMESTAMP_ATTR)) {
        startRadius = start->GetDrawingRadius(m_doc);
    }

    int endRadius = 0;
    if (!end->Is(TIMESTAMP_ATTR)) {
        endRadius = end->GetDrawingRadius(m_doc);
    }

    /************** note stem dir **************/

    if (spanningType == SPANNING_START_END) {
        stemDir = startStemDir;
    }
    // This is the case when the tie is split over two system of two pages.
    // In this case, we are now drawing its beginning to the end of the measure (i.e., the last aligner)
    else if (spanningType == SPANNING_START) {
        stemDir = startStemDir;
    }
    // Now this is the case when the tie is split but we are drawing the end of it
    else if (spanningType == SPANNING_END) {
        stemDir = endStemDir;
    }
    // Finally, slur accross an entire system; use the staff position and up (see below)
    else {
        stemDir = STEMDIRECTION_down;
    }

    /************** direction **************/

    data_STEMDIRECTION layerStemDir;

    // first should be the tie @curvedir
    if (slur->HasCurvedir()) {
        drawingCurveDir
            = (slur->GetCurvedir() == curvature_CURVEDIR_above) ? curvature_CURVEDIR_above : curvature_CURVEDIR_below;
    }
    // grace notes - always below unless we have a drawing stem direction on the layer
    else if (isGraceToNoteSlur && (layer->GetDrawingStemDir(layerElement) == STEMDIRECTION_NONE)) {
        drawingCurveDir = curvature_CURVEDIR_below;
    }
    // the normal case
    else if (slur->HasDrawingCurvedir()) {
        drawingCurveDir = slur->GetDrawingCurvedir();
    }
    // then layer direction trumps note direction
    else if (layer && ((layerStemDir = layer->GetDrawingStemDir(layerElement)) != STEMDIRECTION_NONE)) {
        drawingCurveDir = (layerStemDir == STEMDIRECTION_up) ? curvature_CURVEDIR_above : curvature_CURVEDIR_below;
    }
    // look if in a chord
    else if (startParentChord) {
        if (startParentChord->PositionInChord(startNote) < 0) {
            drawingCurveDir = curvature_CURVEDIR_below;
        }
        else if (startParentChord->PositionInChord(startNote) > 0) {
            drawingCurveDir = curvature_CURVEDIR_above;
        }
        // away from the stem if odd number (center note)
        else {
            drawingCurveDir = (stemDir != STEMDIRECTION_up) ? curvature_CURVEDIR_above : curvature_CURVEDIR_below;
        }
    }
    else if (stemDir == STEMDIRECTION_up) {
        drawingCurveDir = curvature_CURVEDIR_below;
    }
    else if (stemDir == STEMDIRECTION_NONE) {
        // no information from the note stem directions, look at the position in the notes
        int center = staff->GetDrawingY() - m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize) * 2;
        drawingCurveDir = (start->GetDrawingY() > center) ? curvature_CURVEDIR_above : curvature_CURVEDIR_below;
    }

    /************** adjusting y position **************/

    bool isShortSlur = false;
    if (x2 - x1 < 1 * m_doc->GetDrawingDoubleUnit(staff->m_drawingStaffSize)) isShortSlur = true;

    int yChordMax, yChordMin;
    if ((spanningType == SPANNING_START_END) || (spanningType == SPANNING_START)) {
        // first get the min max of the chord (if any)
        if (startParentChord) {
            startParentChord->GetYExtremes(yChordMax, yChordMin);
        }
        else if (startChord) {
            startChord->GetYExtremes(yChordMax, yChordMin);
        }
        // slur is up
        if (drawingCurveDir == curvature_CURVEDIR_above) {
            // P(^)
            if (startStemDir == STEMDIRECTION_down) y1 = start->GetDrawingTop(m_doc, staff->m_drawingStaffSize);
            //  d(^)d
            else if (isShortSlur) {
                y1 = start->GetDrawingTop(m_doc, staff->m_drawingStaffSize);
            }
            // same but in beam - adjust the x too
            else if ((parentBeam = start->IsInBeam()) && !parentBeam->IsLastInBeam(start)) {
                y1 = start->GetDrawingTop(m_doc, staff->m_drawingStaffSize);
                x1 += startRadius - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize);
            }
            // d(^)
            else {
                // put it on the side, move it left, but not if we have a @stamp
                if (!start->Is(TIMESTAMP_ATTR)) x1 += m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 4 / 2;
                if (startChord || startParentChord)
                    y1 = yChordMin + m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
                else
                    y1 = start->GetDrawingY() + m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
            }
        }
        // slur is down
        else {
            // d(_)
            if (startStemDir == STEMDIRECTION_up) y1 = start->GetDrawingBottom(m_doc, staff->m_drawingStaffSize);
            // P(_)P
            else if (isShortSlur) {
                y1 = start->GetDrawingBottom(m_doc, staff->m_drawingStaffSize);
            }
            // same but in beam
            else if ((parentBeam = start->IsInBeam()) && !parentBeam->IsLastInBeam(start)) {
                y1 = start->GetDrawingBottom(m_doc, staff->m_drawingStaffSize);
                x1 -= startRadius - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize);
            }
            // P(_)
            else {
                // put it on the side, but no need to move it left
                if (startChord || startParentChord)
                    y1 = yChordMin - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
                else
                    y1 = start->GetDrawingY() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
            }
        }
    }
    if ((spanningType == SPANNING_START_END) || (spanningType == SPANNING_END)) {
        // get the min max of the chord if any
        if (endParentChord) {
            endParentChord->GetYExtremes(yChordMax, yChordMin);
        }
        else if (endChord) {
            endChord->GetYExtremes(yChordMax, yChordMin);
        }
        // get the stem direction of the end
        // slur is up
        if (drawingCurveDir == curvature_CURVEDIR_above) {
            // (^)P
            if (endStemDir == STEMDIRECTION_down) y2 = end->GetDrawingTop(m_doc, staff->m_drawingStaffSize);
            // d(^)d
            else if (isShortSlur) {
                y2 = end->GetDrawingTop(m_doc, staff->m_drawingStaffSize);
            }
            // same but in beam - adjust the x too
            else if ((parentBeam = end->IsInBeam()) && !parentBeam->IsFirstInBeam(end)) {
                y2 = end->GetDrawingTop(m_doc, staff->m_drawingStaffSize);
                x2 += endRadius - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize);
            }
            // (^)d
            else {
                // put it on the side, no need to move it right
                if (endChord || endParentChord)
                    y2 = yChordMin + m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
                else
                    y2 = end->GetDrawingY() + m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
            }
        }
        else {
            if (isGraceToNoteSlur) {
                if (endNote) {
                    y2 = endNote->GetDrawingY();
                    x2 -= m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 2;
                    isShortSlur = true;
                }
                else {
                    y2 = y1;
                }
            }
            // (_)d
            else if (endStemDir == STEMDIRECTION_up)
                y2 = end->GetDrawingBottom(m_doc, staff->m_drawingStaffSize);
            // P(_)P
            else if (isShortSlur) {
                y2 = end->GetDrawingBottom(m_doc, staff->m_drawingStaffSize);
            }
            // same but in beam
            else if ((parentBeam = end->IsInBeam()) && !parentBeam->IsFirstInBeam(end)) {
                y2 = end->GetDrawingBottom(m_doc, staff->m_drawingStaffSize);
                //
                x2 -= endRadius - m_doc->GetDrawingStemWidth(staff->m_drawingStaffSize);
            }
            // (_)P
            else {
                // put it on the side, move it right, but not if we have a @stamp2
                if (!end->Is(TIMESTAMP_ATTR)) x2 -= m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 2;
                if (endChord || endParentChord)
                    y2 = yChordMin - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
                else
                    y2 = end->GetDrawingY() - m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * 3;
            }
        }
    }

    // Positions not attached to a note
    if (spanningType == SPANNING_START) {
        if (drawingCurveDir == curvature_CURVEDIR_above)
            y2 = std::max(staff->GetDrawingY(), y1);
        else
            y2 = std::min(staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize), y1);
    }
    if (end->Is(TIMESTAMP_ATTR)) {
        if (drawingCurveDir == curvature_CURVEDIR_above)
            y2 = std::max(staff->GetDrawingY(), y1);
        else
            y2 = std::min(staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize), y1);
    }
    if (spanningType == SPANNING_END) {
        if (drawingCurveDir == curvature_CURVEDIR_above)
            y1 = std::max(staff->GetDrawingY(), y2);
        else
            y1 = std::min(staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize), y2);
    }
    if (start->Is(TIMESTAMP_ATTR)) {
        if (drawingCurveDir == curvature_CURVEDIR_above)
            y1 = std::max(staff->GetDrawingY(), y2);
        else
            y1 = std::min(staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize), y2);
    }
    // slur accross an entire system; use the staff position
    else if (spanningType == SPANNING_MIDDLE) {
        // To be adjusted
        if (drawingCurveDir == curvature_CURVEDIR_above)
            y1 = staff->GetDrawingY();
        else
            y1 = staff->GetDrawingY() - m_doc->GetDrawingStaffSize(staff->m_drawingStaffSize);
        y2 = y1;
    }

    /************** y position **************/

    if (drawingCurveDir == curvature_CURVEDIR_above) {
        y1 += 1 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
        y2 += 1 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
    }
    else {
        y1 -= 1 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
        y2 -= 1 * m_doc->GetDrawingUnit(staff->m_drawingStaffSize);
    }

    Point points[4];
    points[0] = Point(x1, y1);
    points[3] = Point(x2, y2);

    float angle = CalcInitialSlur(curve, slur, staff, layer->GetN(), drawingCurveDir, points);
    int thickness = m_doc->GetDrawingUnit(staff->m_drawingStaffSize) * m_options->m_slurThickness.GetValue();

    curve->UpdateCurveParams(points, angle, thickness, drawingCurveDir);

    /************** articulation **************/

    // First get all artic children
    ClassIdComparison matchType(ARTIC);
    ArrayOfObjects artics;
    ArrayOfObjects::iterator articIter;

    // the normal case or start
    if ((spanningType == SPANNING_START_END) || (spanningType == SPANNING_START)) {
        start->FindAllChildByComparison(&artics, &matchType);
        // Then the @n of each first staffDef
        for (articIter = artics.begin(); articIter != artics.end(); ++articIter) {
            Artic *artic = dynamic_cast<Artic *>(*articIter);
            assert(artic);
            ArticPart *outsidePart = artic->GetOutsidePart();
            if (outsidePart) {
                if ((outsidePart->GetPlace().GetBasic() == STAFFREL_basic_above)
                    && (drawingCurveDir == curvature_CURVEDIR_above)) {
                    outsidePart->AddSlurPositioner(curve, true);
                }
                else if ((outsidePart->GetPlace().GetBasic() == STAFFREL_basic_below)
                    && (drawingCurveDir == curvature_CURVEDIR_below)) {
                    outsidePart->AddSlurPositioner(curve, true);
                }
            }
        }
    }
    // normal case or end
    if ((spanningType == SPANNING_START_END) || (spanningType == SPANNING_END)) {
        end->FindAllChildByComparison(&artics, &matchType);
        // Then the @n of each first staffDef
        for (articIter = artics.begin(); articIter != artics.end(); ++articIter) {
            Artic *artic = dynamic_cast<Artic *>(*articIter);
            assert(artic);
            ArticPart *outsidePart = artic->GetOutsidePart();
            if (outsidePart) {
                if ((outsidePart->GetPlace().GetBasic() == STAFFREL_basic_above)
                    && (drawingCurveDir == curvature_CURVEDIR_above)) {
                    outsidePart->AddSlurPositioner(curve, false);
                }
                else if ((outsidePart->GetPlace().GetBasic() == STAFFREL_basic_below)
                    && (drawingCurveDir == curvature_CURVEDIR_below)) {
                    outsidePart->AddSlurPositioner(curve, false);
                }
            }
        }
    }

    return;
}
Пример #11
0
int Object::SetBoundingBoxXShift( ArrayPtrVoid params )
{
    // param 0: the minimu position (i.e., the width of the previous element)
    // param 1: the maximum width in the current measure
    // param 2: the Doc
    int *min_pos = static_cast<int*>(params[0]);
    int *measure_width = static_cast<int*>(params[1]);
    Doc *doc = static_cast<Doc*>(params[2]);

    // starting a new measure
    Measure *current_measure = dynamic_cast<Measure*>(this);
    if ( current_measure  ) {
        // we reset the measure width and the minimum position
        (*measure_width) = 0;
        (*min_pos) = 0;
        if (current_measure->GetLeftBarlineType() != BARRENDITION_NONE) {
            current_measure->GetLeftBarline()->SetBoundingBoxXShift( params );
        }
        return FUNCTOR_CONTINUE;
    }
    
    // starting an new layer
    Layer *current_layer = dynamic_cast<Layer*>(this);
    if ( current_layer  ) {
        // reset it as the minimum position to the step (HARDCODED)
        (*min_pos) = 30 * doc->m_drawingUnit[0] / 10;
        // set scoreDef attr
        if (current_layer->GetDrawingClef()) {
            current_layer->GetDrawingClef()->SetBoundingBoxXShift( params );
        }
        if (current_layer->GetDrawingKeySig()) {
            current_layer->GetDrawingKeySig()->SetBoundingBoxXShift( params );
        }
        if (current_layer->GetDrawingMensur()) {
            current_layer->GetDrawingMensur()->SetBoundingBoxXShift( params );
        }
        if (current_layer->GetDrawingMeterSig()) {
            current_layer->GetDrawingMeterSig()->SetBoundingBoxXShift( params );
        }
        return FUNCTOR_CONTINUE;
    }

    LayerElement *current = dynamic_cast<LayerElement*>(this);
    if ( !current  ) {
        return FUNCTOR_CONTINUE;
    }
    
    // we should have processed aligned before
    assert( current->GetAlignment() );

    if ( !current->HasUpdatedBB() ) {
        // if nothing was drawn, do not take it into account
        return FUNCTOR_CONTINUE;
    }
    
    if ( current->IsBeam() ) {
        return FUNCTOR_CONTINUE;
    }
    
    if ( current->IsNote() ) {
        Chord* chordParent = dynamic_cast<Chord*>(current->GetFirstParent( &typeid( Chord ), MAX_CHORD_DEPTH));
        if( chordParent ) {
            return FUNCTOR_CONTINUE;
        }
    }
    
    if ( current->IsTie() ) {
        return FUNCTOR_CONTINUE;
    }
    
    if ( current->IsTuplet() ) {
        return FUNCTOR_CONTINUE;
    }
    
    if ( current->IsVerse() || current->IsSyl() ) {
        return FUNCTOR_CONTINUE;
    }
    
    // the negative offset it the part of the bounding box that overflows on the left
    // |____x_____|
    //  ---- = negative offset
    //int negative_offset = current->GetAlignment()->GetXRel() - current->m_contentBB_x1;
    int negative_offset = - (current->m_contentBB_x1) + (doc->GetLeftMargin(&typeid(*current)) * doc->m_drawingUnit[0] / PARAM_DENOMINATOR);
    
    // this should never happen (but can with glyphs not exactly registered at position x=0 in the SMuFL font used
    if ( negative_offset < 0 ) {
        //LogDebug("%s negative offset %d;", current->GetClassName().c_str(), negative_offset );
        negative_offset = 0;
    }
    
    if ( current->IsMRest() ) {
        // With MRest, the only thing we want to do it keep their with as possible measure with (if only MRest in all staves/layers)
        int width =  current->m_contentBB_x2 + doc->GetRightMargin(&typeid(*current)) * doc->m_drawingUnit[0] / PARAM_DENOMINATOR + negative_offset ;
        // Keep it if more than the current measure width
        (*measure_width) = std::max( (*measure_width), width );
        (*min_pos) = 0;
        return FUNCTOR_CONTINUE;
    }
    
    // check if the element overlaps with the preceeding one given by (*min_pos)
    int overlap = 0;
    overlap = (*min_pos) - current->GetAlignment()->GetXRel() + negative_offset;
    if ( (current->GetAlignment()->GetXRel() - negative_offset) < (*min_pos) ) {
        overlap = (*min_pos) - current->GetAlignment()->GetXRel() + negative_offset;
        // shift the current element
        current->GetAlignment()->SetXShift( overlap );
    }
    
    //LogDebug("%s min_pos %d; negative offset %d;  drawXRel %d; overlap %d; m_drawingX %d", current->GetClassName().c_str(), (*min_pos), negative_offset, current->GetAlignment()->GetXRel(), overlap, current->GetDrawingX() );
    
    // the next minimal position if given by the right side of the bounding box + the spacing of the element
    (*min_pos) = current->GetAlignment()->GetXRel() + current->m_contentBB_x2 + doc->GetRightMargin(&typeid(*current)) * doc->m_drawingUnit[0] / PARAM_DENOMINATOR;
    current->GetAlignment()->SetMaxWidth( current->m_contentBB_x2 + doc->GetRightMargin(&typeid(*current)) * doc->m_drawingUnit[0] / PARAM_DENOMINATOR );
    
    return FUNCTOR_CONTINUE;
}