Example #1
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;
}