void Console::outputAll(Core &core) { cout << "OBJECTS:" << endl; if (core.sizeListObj() == 0) cout << " No objects yet." << endl; for (size_t i = 0; i < core.sizeListObj(); ++i) { Point * newp = 0; Circle *newc = 0; Segment * news = 0; switch (core.searchID(core.getObjIDs()[i])->object_type()) { case IsPoint: { newp = dynamic_cast<Point*>(core.searchID(core.getObjIDs()[i])); cout.precision(2); cout << setw(8); newp->isFixed() ? cout << "(fixed) " : cout << ""; cout << setw(8) << "POINT "; cout << setw(3) << "ID: " << setw(2) << newp->showId(); cout << setw(6) << "X: " << setw(8) << newp->getX(); cout << setw(6) << "Y: " << setw(8) << newp->getY(); newp->isPicked() ? cout << " <-" : cout << ""; cout << endl; } break; case IsSegment: { news = dynamic_cast<Segment*>(core.searchID(core.getObjIDs()[i])); cout.precision(2); cout << setw(8); news->isFixed() ? cout << "(fixed) " : cout << ""; cout << setw(8) << "SEGMENT "; cout << setw(3) << "ID: " << setw(2) << news->showId(); cout << setw(6) << news->getP1()->showId(); cout << "-----" << news->getP2()->showId(); news->isPicked() ? cout << setw(16) << "<-" : cout << ""; cout << endl << endl; } break; case IsCircle: { newc = dynamic_cast<Circle*>(core.searchID(core.getObjIDs()[i])); cout.precision(2); cout << setw(8); Point t = newc->getCenter(); newc->isFixed() ? cout << "(fixed) " : cout << ""; cout << setw(8) << "CIRCLE "; cout << setw(3) << "ID: " << setw(2) << newc->showId(); cout << setw(6) << "O: " << setw(8) << newc->getCenter().showId(); cout << setw(6) << "R: " << setw(8) << newc->getRadius(); newc->isPicked() ? cout << " <-" : cout << ""; cout << endl << endl; } break; } } cout << "RESTRICTIONS:" << endl; if (core.sizeListRestr() == 0) cout << " No restrictions yet." << endl; for (size_t i = 0; i < core.sizeListRestr(); ++i) { switch (core.searchIDRestr(core.getRestrIDs()[i])->get_type()) { case RT_P2PDIST: { auto restr = dynamic_cast<RestrP2PDIST*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "P2PDIST " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getP1()->showId() << "---" << restr->getP2()->showId() << endl; } break; case RT_P2SDIST: { auto restr = dynamic_cast<RestrP2SDIST*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "P2SDIST " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getP1()->showId() << "---" << restr->getP2()->showId(); cout << "==" << restr->getP3()->showId() << endl; } break; case RT_P2SDISTEX: { auto restr = dynamic_cast<RestrP2SDISTEX*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "P2SDISTEX " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getP1()->showId() << "---" << restr->getP2()->showId(); cout << "==" << restr->getP3()->showId() << endl; } break; case RT_S2SANGLE: { auto restr = dynamic_cast<RestrS2SANGLE*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "S2SANGLE " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getS1()->showId() << "---" << restr->getS2()->showId() << endl; } break; case RT_S2SORTHO: { auto restr = dynamic_cast<RestrS2SORTHO*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "S2SORTHO " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getS1()->showId() << "---" << restr->getS2()->showId() << endl; } break; case RT_S2SPARAL: { auto restr = dynamic_cast<RestrS2SPARAL*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "S2SPARAL " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getS1()->showId() << "---" << restr->getS2()->showId() << endl; } break; case RT_S2SEQUALS: { auto restr = dynamic_cast<RestrS2SEQUALS*>(core.searchIDRestr(core.getRestrIDs()[i])); cout.precision(2); cout << setw(16) << "S2SEQUALS " << setw(3) << "ID: " << setw(2) << restr->showId(); cout << setw(13) << "violation: " << setw(8) << restr->violation(); cout << setw(8) << restr->getS1()->showId() << "---" << restr->getS2()->showId() << endl; } break; } } core.ShowRestr(); }
Boolean ADUFromMP3Source::doGetNextFrame1() { // First, check whether we have enough previously-read data to output an // ADU for the last-read MP3 frame: unsigned tailIndex; Segment* tailSeg; Boolean needMoreData; if (fSegments->isEmpty()) { needMoreData = True; tailSeg = NULL; tailIndex = 0; // unneeded, but stops compiler warnings } else { tailIndex = SegmentQueue::prevIndex(fSegments->nextFreeIndex()); tailSeg = &(fSegments->s[tailIndex]); needMoreData = fTotalDataSizeBeforePreviousRead < tailSeg->backpointer // bp points back too far || tailSeg->backpointer + tailSeg->dataHere() < tailSeg->aduSize; // not enough data } if (needMoreData) { // We don't have enough data to output an ADU from the last-read MP3 // frame, so need to read another one and try again: doGetNextFrame(); return True; } // Output an ADU from the tail segment: fFrameSize = tailSeg->headerSize+tailSeg->sideInfoSize+tailSeg->aduSize; fPresentationTime = tailSeg->presentationTime; fDurationInMicroseconds = tailSeg->durationInMicroseconds; unsigned descriptorSize = fIncludeADUdescriptors ? ADUdescriptor::computeSize(fFrameSize) : 0; #ifdef DEBUG fprintf(stderr, "m->a:outputting ADU %d<-%d, nbr:%d, sis:%d, dh:%d, (descriptor size: %d)\n", tailSeg->aduSize, tailSeg->backpointer, fFrameSize, tailSeg->sideInfoSize, tailSeg->dataHere(), descriptorSize); #endif if (descriptorSize + fFrameSize > fMaxSize) { envir() << "ADUFromMP3Source::doGetNextFrame1(): not enough room (" << descriptorSize + fFrameSize << ">" << fMaxSize << ")\n"; fFrameSize = 0; return False; } unsigned char* toPtr = fTo; // output the ADU descriptor: if (fIncludeADUdescriptors) { fFrameSize += ADUdescriptor::generateDescriptor(toPtr, fFrameSize); } // output header and side info: memmove(toPtr, tailSeg->dataStart(), tailSeg->headerSize + tailSeg->sideInfoSize); toPtr += tailSeg->headerSize + tailSeg->sideInfoSize; // go back to the frame that contains the start of our data: unsigned offset = 0; unsigned i = tailIndex; unsigned prevBytes = tailSeg->backpointer; while (prevBytes > 0) { i = SegmentQueue::prevIndex(i); unsigned dataHere = fSegments->s[i].dataHere(); if (dataHere < prevBytes) { prevBytes -= dataHere; } else { offset = dataHere - prevBytes; break; } } // dequeue any segments that we no longer need: while (fSegments->headIndex() != i) { fSegments->dequeue(); // we're done with it } unsigned bytesToUse = tailSeg->aduSize; while (bytesToUse > 0) { Segment& seg = fSegments->s[i]; unsigned char* fromPtr = &seg.dataStart()[seg.headerSize + seg.sideInfoSize + offset]; unsigned dataHere = seg.dataHere() - offset; unsigned bytesUsedHere = dataHere < bytesToUse ? dataHere : bytesToUse; memmove(toPtr, fromPtr, bytesUsedHere); bytesToUse -= bytesUsedHere; toPtr += bytesUsedHere; offset = 0; i = SegmentQueue::nextIndex(i); } if (fFrameCounter++%fScale == 0) { // Call our own 'after getting' function. Because we're not a 'leaf' // source, we can call this directly, without risking infinite recursion. afterGetting(this); } else { // Don't use this frame; get another one: doGetNextFrame(); } return True; }
/** * @brief 点と線分の距離 * @param[in] a 判定する点 * @param[in] b 判定する線分 * @return 点aと線分bの距離 */ inline double distance(const Point &a, const Segment &b){ const Point p = b.to_line().projection(a); if(intersect(b, p)){ return (a - p).abs(); } return std::min((b.a - a).abs(), (b.b - a).abs()); }
Segment * SegmentJoinCommand::makeSegment(SegmentVec oldSegments) { // We can proceed even if composition is NULL, just normalize // rests will do less. Composition *composition = oldSegments[0]->getComposition(); // Find the leftmost segment's index and the rightmost segment's // index. timeT t0 = oldSegments[0]->getStartTime(); timeT t1 = oldSegments[0]->getEndMarkerTime(); size_t leftmostIndex = 0; size_t rightmostIndex = 0; for (size_t i = 1; i < oldSegments.size(); ++i) { timeT startTime = oldSegments[i]->getStartTime(); if (startTime < t0) { t0 = startTime; leftmostIndex = i; } timeT endMarkerTime = oldSegments[i]->getEndMarkerTime(); if (endMarkerTime > t1) { t1 = endMarkerTime; rightmostIndex = i; } } // Always begin with the leftmost segment to keep in the new segment // any clef or key change found at the start of this segment. Segment *newSegment = oldSegments[leftmostIndex]->clone(false); // drop any events beyond the end marker newSegment->setEndTime(newSegment->getEndMarkerTime()); // that duplicated the leftmost segment; now do the rest // we normalize rests in any overlapping areas timeT overlapStart = 0, overlapEnd = 0; bool haveOverlap = false; for (size_t i = 0; i < oldSegments.size(); ++i) { // Don't add twice the first old segment if (i == leftmostIndex) continue; Segment *s = oldSegments[i]; timeT start = s->getStartTime(), end = s->getEndMarkerTime(); timeT os = 0, oe = 0; bool haveOverlapHere = false; if (start < newSegment->getEndMarkerTime() && end > newSegment->getStartTime()) { haveOverlapHere = true; os = std::max(start, newSegment->getStartTime()); oe = std::min(end, newSegment->getEndMarkerTime()); RG_DEBUG << "overlap here, os = " << os << ", oe = " << oe; } if (haveOverlapHere) { if (haveOverlap) { overlapStart = std::min(overlapStart, os); overlapEnd = std::max(overlapEnd, oe); } else { overlapStart = os; overlapEnd = oe; haveOverlap = true; } } if (start > newSegment->getEndMarkerTime()) { newSegment->setEndMarkerTime(start); } for (Segment::iterator si = s->begin(); ; ++si) { // If we're in the rightmost segment if (i == rightmostIndex) { // Copy all of the events to the end if (si == s->end()) break; } else { // Just copy up to the End Marker of this segment. if (!s->isBeforeEndMarker(si)) break; } // weed out duplicate clefs and keys if ((*si)->isa(Clef::EventType)) { try { Clef newClef(**si); if (newSegment->getClefAtTime ((*si)->getAbsoluteTime() + 1) == newClef) { continue; } } catch (...) { } } if ((*si)->isa(Key::EventType)) { try { Key newKey(**si); if (newSegment->getKeyAtTime ((*si)->getAbsoluteTime() + 1) == newKey) { continue; } } catch (...) { } } newSegment->insert(new Event(**si)); } if (end > newSegment->getEndMarkerTime()) { newSegment->setEndMarkerTime(end); } } if (haveOverlap) { /// normalizeRests doesn't require Composition, but is less /// than ideal without it; newSegment->setComposition(composition); newSegment->normalizeRests(overlapStart, overlapEnd); newSegment->setComposition(0); } return newSegment; }
QPointF Pedal::linePos(Grip grip, System** sys) const { qreal x = 0.0; qreal nhw = score()->noteHeadWidth(); System* s = nullptr; if (grip == Grip::START) { ChordRest* c = toChordRest(startElement()); if (c) { s = c->segment()->system(); x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x(); if (c->type() == ElementType::REST && c->durationType() == TDuration::DurationType::V_MEASURE) x -= c->x(); if (beginHookType() == HookType::HOOK_45) x += nhw * .5; } } else { Element* e = endElement(); ChordRest* c = toChordRest(endElement()); if (!e || e == startElement() || (endHookType() == HookType::HOOK_90)) { // pedal marking on single note or ends with non-angled hook: // extend to next note or end of measure Segment* seg = nullptr; if (!e) seg = startSegment(); else seg = c->segment(); if (seg) { seg = seg->next(); for ( ; seg; seg = seg->next()) { if (seg->segmentType() == SegmentType::ChordRest) { // look for a chord/rest in any voice on this staff bool crFound = false; int track = staffIdx() * VOICES; for (int i = 0; i < VOICES; ++i) { if (seg->element(track + i)) { crFound = true; break; } } if (crFound) break; } else if (seg->segmentType() == SegmentType::EndBarLine) { break; } } } if (seg) { s = seg->system(); x = seg->pos().x() + seg->measure()->pos().x() - nhw * 2; } } else if (c) { s = c->segment()->system(); x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x(); if (c->type() == ElementType::REST && c->durationType() == TDuration::DurationType::V_MEASURE) x -= c->x(); } if (!s) { int t = tick2(); Measure* m = score()->tick2measure(t); s = m->system(); x = m->tick2pos(t); } if (endHookType() == HookType::HOOK_45) x += nhw * .5; else x += nhw; } *sys = s; return QPointF(x, 0); }
WindowingResult WindowEvaluator::eval_pt_to_seg(Point origin, Segment target) { auto end = target.delta().magsq(); // if target is a zero-length segment, there are no windows if (end == 0) return make_pair(vector<Window>{}, boost::none); if (debug) { system->drawLine(target, QColor{"Blue"}, "Debug"); } vector<Window> windows = {Window{0, end}}; // apply the obstacles vector<Robot*> bots(system->self.size() + system->opp.size()); auto filter_predicate = [&](const Robot* bot) -> bool { return bot != nullptr && bot->visible && find(excluded_robots.begin(), excluded_robots.end(), bot) == excluded_robots.end(); }; auto end_it = copy_if(system->self.begin(), system->self.end(), bots.begin(), filter_predicate); end_it = copy_if(system->opp.begin(), system->opp.end(), end_it, filter_predicate); bots.resize(distance(bots.begin(), end_it)); vector<Point> bot_locations; for_each(bots.begin(), bots.end(), [&bot_locations](Robot* bot) { bot_locations.push_back(bot->pos); }); bot_locations.insert(bot_locations.end(), hypothetical_robot_locations.begin(), hypothetical_robot_locations.end()); for (auto& pos : bot_locations) { auto d = (pos - origin).mag(); // whether or not we can ship over this bot auto chip_overable = chip_enabled && (d < max_chip_range - Robot_Radius) && (d > min_chip_range + Robot_Radius); if (!chip_overable) { obstacle_robot(windows, origin, target, pos); } } auto p0 = target.pt[0]; auto delta = target.delta() / end; for (auto& w : windows) { w.segment = Segment{p0 + delta * w.t0, p0 + delta * w.t1}; w.a0 = RadiansToDegrees((w.segment.pt[0] - origin).angle()); w.a1 = RadiansToDegrees((w.segment.pt[1] - origin).angle()); fill_shot_success(w, origin); } boost::optional<Window> best{ !windows.empty(), *max_element(windows.begin(), windows.end(), [](Window& a, Window& b) -> bool { return a.segment.delta().magsq() < b.segment.delta().magsq(); })}; if (debug) { if (best) { system->drawLine(Segment{origin, best->segment.center()}, QColor{"Green"}, "Debug"); } for (Window& window : windows) { system->drawLine(window.segment, QColor{"Green"}, "Debug"); system->drawText(QString::number(window.shot_success), window.segment.center() + Point(0, 0.1), QColor{"Green"}, "Debug"); } } return make_pair(windows, best); }
int main() { int start_s =0, stop_s =0, test_start= 0, test_stop =0; dataManipulator dm; Segment segData; start_s = clock(); cout << "*************** program starts "<<"*****************************" << endl; //*****************First test case: 100 thousand random integer cout<<endl<<"First test case: 10 thousand random Integer: "<<endl; cout<<"Creating random Integers from -100000000 to 100000000.."<<endl; const char* testfile1 = dm.createRandomInt(100000); cout<<"Read data from file....."<<endl; vector<int> RanIntData = dm.readIntFromFile(testfile1); cout<<"Data read completed, data stored."<<endl; cout<<endl<<"Execute some sample query:"<<endl<<endl; dm.executeQuery("larger", 10000, RanIntData); dm.executeQuery("smaller", 10000, RanIntData); dm.executeQuery("equals",10000,RanIntData); dm.executeQuery("larger", 33333,RanIntData); dm.executeQuery("smaller", 20160307, RanIntData); dm.executeQuery("between", 33333,20160307, RanIntData); dm.executeQuery("between", 10000,33333,RanIntData); //****************second test case: 100 thousand random floats cout<<endl<<endl<<"Second test case: 100 thousand random Floats: "<<endl; start_s = clock(); cout<<"Creating random Float from -100000000 to 100000000.."<<endl; const char* testfile2 = dm.createRandomFloat(100000); cout<<"Read data from file....."<<endl; vector<float> RanFloatData = dm.readFloatFromFile(testfile2); cout<<"Data read completed, data stored."<<endl; cout<<endl<<"Execute some sample query:"<<endl<<endl; dm.executeQuery("larger", (float)123.45, RanFloatData); dm.executeQuery("smaller",(float) 123.45, RanFloatData); dm.executeQuery("equals",(float)123.45,RanFloatData); dm.executeQuery("larger", (float)333.33,RanFloatData); dm.executeQuery("smaller", (float)2016.00, RanFloatData); dm.executeQuery("between", (float)-500.0, (float)500.0, RanFloatData); //*****************Third test case: 1 Million random integers cout << endl << "Third test case: 1 Million random Integer: " << endl; start_s = clock(); cout << "Creating random Integers from -1000000 to 1000000.." << endl; const char* testfile3 = segData.createRandomInt(1000000); cout << "Read data from file....." << endl; segData.readFromFile(testfile3); cout<<endl<<"Execute some sample query:"<<endl<<endl; segData.getAllCounts(); segData.query("smaller", 2000); segData.query("larger", 2000); segData.query("equals",2000); segData.query("between",0,1025); //*****************Fourth test case: 10 Million random integers cout << endl << "Fourth test case: 10 Million random Integer: " << endl; start_s = clock(); cout << "Creating random Integers from -1000000 to 1000000.." << endl; const char* testfile4 = segData.createRandomInt(10000000); cout << "Read data from file....." << endl; segData.readFromFile(testfile4); cout<<"Data read completed, data stored."<<endl; cout<<endl<<"Execute some sample query:"<<endl<<endl; segData.getAllCounts(); segData.query("smaller", 2000); segData.query("larger", 2000); segData.query("equals",2000); segData.query("between",0,1025); //****************Fifth test case: 50 Million random integers cout << endl << "Fifth test case: 25 Million random Integer: " << endl; start_s = clock(); cout << "Creating 25 Million random Integers from -1000000 to 1000000.." << endl; const char* testfile5 = segData.createRandomInt(25000000); cout << "Read data from file....." << endl; segData.readFromFile(testfile5); cout<<"Data read completed, data stored."<<endl; cout<<endl<<"Execute some sample query:"<<endl<<endl; segData.getAllCounts(); segData.query("smaller", 2000); segData.query("larger", 2000); segData.query("equals",2000); segData.query("between",0,1025); cout << endl << "*************** End of the program. Total time cost :"; stop_s = clock(); cout << (stop_s - start_s) / double(CLOCKS_PER_SEC) * 1000 << " ms " << "*****************************" << endl; cout<<"Wish you have a good one! ---Zhichao(Zach)."<<endl; return 0; }
float FieldController::HoleSquad( const Segment& topSegment, const std::vector<Segment>& modelTopLine ) { double holeSquad = 0; for (int i = 0, i_end = modelTopLine.size(); i < i_end; ++i) { double a_length = modelTopLine[i].length(); double b_length = Segment(modelTopLine[i].start(), Vector2F(modelTopLine[i].start().X(), topSegment.start().Y())).length(); holeSquad += a_length * b_length; } return (float)holeSquad; }
void PositionCursor::move(int tick) { QRectF r(bbox()); // // set mark height for whole system // if (_type == CursorType::LOOP_OUT) tick --; Score* score = _sv->score(); Measure* measure = score->tick2measureMM(tick); if (measure == 0) return; qreal x; int offset = 0; Segment* s; for (s = measure->first(Segment::Type::ChordRest); s;) { int t1 = s->tick(); int x1 = s->canvasPos().x(); qreal x2; int t2; Segment* ns = s->next(Segment::Type::ChordRest); if (ns) { t2 = ns->tick(); x2 = ns->canvasPos().x(); } else { t2 = measure->endTick(); x2 = measure->canvasPos().x() + measure->width(); } t1 += offset; t2 += offset; if (tick >= t1 && tick < t2) { int dt = t2 - t1; qreal dx = x2 - x1; x = x1 + dx * (tick-t1) / dt; break; } s = ns; } if (s == 0) return; System* system = measure->system(); if (system == 0) return; double y = system->staffYpage(0) + system->page()->pos().y(); double _spatium = score->spatium(); qreal mag = _spatium / (MScore::DPI * SPATIUM20); double w = (_spatium * 2.0 + score->scoreFont()->width(SymId::noteheadBlack, mag))/3; double h = 6 * _spatium; // // set cursor height for whole system // double y2 = 0.0; for (int i = 0; i < score->nstaves(); ++i) { SysStaff* ss = system->staff(i); if (!ss->show() || !score->staff(i)->show()) continue; y2 = ss->y() + ss->bbox().height(); } h += y2; y -= 3 * _spatium; if (_type == CursorType::LOOP_IN) { x = x - _spatium + w/1.5; } else { x = x - _spatium * .5; } _tick = tick; _rect = QRectF(x, y, w, h); _sv->update(_sv->matrix().mapRect(r | bbox()).toRect().adjusted(-1,-1,1,1)); }
bool AABB::Intersects(const Segment& s) const { return s.Intersects(*this); }
void Pot_Piecewise::initialize( Conf_Module* config, vector<Module*> dependencies ) { GET_LOGGER( "liee.Module.Pot_Piecewise" ); double epsilon = config->get_double("epsilon") / CONV_au_nm; rounding = config->get_array("ellipse")[0] / CONV_au_nm; scale_y = rounding / ( config->get_array("ellipse")[1] / CONV_au_eV ); X = config->get_array("r_list"); Y = config->get_array("V_list"); if ( X.size() != Y.size() || X.size() == 0 ) { LOG_ERROR( "r_list and V_list are required to have the same size with at least 1 element." ) exit(1); } if ( X.size() == 1 ) { // constant potential X.push_back( X[0] + config->get_double("r_range") ); Y.push_back( Y[0] ); } for ( size_t i = 0; i < X.size(); i++ ) { X[i] /= CONV_au_nm; Y[i] /= CONV_au_eV; if ( i > 0 && X[i-1] > X[i] ) { LOG_ERROR( "r_list is required to be sorted in ascending order. exiting." ) exit(1); } if ( i > 0 && X[i-1] == X[i] ) { X[i] += epsilon; } } Segment first; first.line( X[0], X[1], Y[0], Y[1] ); segs.push_back( first ); for ( size_t i = 1; i < X.size()-1; i++ ) { Segment left, right; left = segs.back(); right.line( X[i], X[i+1], Y[i], Y[i+1] ); if ( rounding > 0 && left.m != right.m ) { // note: tangential-circle calculation is done in a y-stretched system in order to // work with a circle instead of an ellipse. The x-positions are valid in both systems, // while the circle centre-V is scaled back to the actual ellipse-centre // (V(r) draws the ellipse according to scale_y) for ( double rr = rounding; rr > 1e-4 * rounding; rr /= 1.5 ) { Segment sleft, sright, circle; double S = scale_y; sleft.line( X[i-1], X[i], S*Y[i-1], S*Y[i] ); sright.line( X[i], X[i+1], S*Y[i], S*Y[i+1] ); circle.sign = ( left.m > right.m ) ? +1 : -1; // sign=+1: circle under the roof-like kink, positive "square-root"-circle is touching tangents and opposite for sign=-1 double dist = -circle.sign * rr; // the possible centre-positions for the tangential circle are on a parallel line, distanced 1 rounding-radius in orthogonal direction, either above or below double shifted_n_l = (S*Y[i] + dist * sleft.ortho_Y) - sleft.m * (X[i] + dist * sleft.ortho_X); // ordinate of the left-side parallel double shifted_n_r = (S*Y[i] + dist * sright.ortho_Y) - sright.m * (X[i] + dist * sright.ortho_X); circle.cr = (shifted_n_l - shifted_n_r) / (sright.m - sleft.m); // circle centre at the intersection of the two parallels circle.cV = ( sleft.m * circle.cr + shifted_n_l ) / S; circle.start_r = circle.cr - dist * sleft.ortho_X; // from circle centre back on the normal-vector to the respective lines circle.end_r = circle.cr - dist * sright.ortho_X; circle.radius = rr; // only accept rounding circle if it does not exceed the middle of neighbouring segments if ( circle.start_r > 0.5 * (segs.back().start_r + segs.back().end_r) && circle.end_r < 0.5 * (right.start_r + right.end_r) ) { segs.back().end_r = circle.start_r; // reduce left segment extend right.start_r = circle.end_r; segs.push_back( circle ); break; } // else continue loop with a smaller radius } } segs.push_back( right ); } }
void ScoreView::lyricsUnderscore() { Lyrics* lyrics = toLyrics(editData.element); int track = lyrics->track(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Placement placement = lyrics->placement(); int endTick = segment->tick(); // a previous melisma cannot extend beyond this point changeState(ViewState::NORMAL); // search next chord Segment* nextSegment = segment; while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } // look for the lyrics we are moving from; may be the current lyrics or a previous one // we are extending with several underscores Lyrics* fromLyrics = 0; while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (cr) { fromLyrics = cr->lyrics(verse, placement); if (fromLyrics) break; } segment = segment->prev1(SegmentType::ChordRest); // if the segment has a rest in this track, stop going back Element* e = segment ? segment->element(track) : 0; if (e && !e->isChord()) break; } _score->startCmd(); // one-chord melisma? // if still at melisma initial chord and there is a valid next chord (if not, // there will be no melisma anyway), set a temporary melisma duration if (fromLyrics == lyrics && nextSegment) lyrics->undoChangeProperty(Pid::LYRIC_TICKS, Lyrics::TEMP_MELISMA_TICKS); if (nextSegment == 0) { if (fromLyrics) { switch(fromLyrics->syllabic()) { case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::END: break; default: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); break; } if (fromLyrics->segment()->tick() < endTick) fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, endTick - fromLyrics->segment()->tick()); } // leave edit mode, select something (just for user feedback) and update to show extended melisam mscore->changeState(STATE_NORMAL); if (fromLyrics) _score->select(fromLyrics, SelectType::SINGLE, 0); _score->setLayoutAll(); _score->endCmd(); return; } // if a place for a new lyrics has been found, create a lyrics there ChordRest* cr = toChordRest(nextSegment->element(track)); Lyrics* toLyrics = cr->lyrics(verse, placement); bool newLyrics = (toLyrics == 0); if (!toLyrics) { toLyrics = new Lyrics(_score); toLyrics->setTrack(track); toLyrics->setParent(nextSegment->element(track)); toLyrics->setNo(verse); toLyrics->setPlacement(placement); toLyrics->setSyllabic(Lyrics::Syllabic::SINGLE); } // as we arrived at toLyrics by an underscore, it cannot have syllabic dashes before else if (toLyrics->syllabic() == Lyrics::Syllabic::MIDDLE) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::BEGIN)); else if (toLyrics->syllabic() == Lyrics::Syllabic::END) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::SINGLE)); if (fromLyrics) { // as we moved away from fromLyrics by an underscore, // it can be isolated or terminal but cannot have dashes after switch(fromLyrics->syllabic()) { case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::END: break; default: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); break; } // for the same reason, if it has a melisma, this cannot extend beyond toLyrics if (fromLyrics->segment()->tick() < endTick) fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, endTick - fromLyrics->segment()->tick()); } if (newLyrics) _score->undoAddElement(toLyrics); _score->endCmd(); _score->select(toLyrics, SelectType::SINGLE, 0); startEdit(toLyrics, Grip::NO_GRIP); adjustCanvasPosition(toLyrics, false); TextCursor* cursor = Ms::toLyrics(editData.element)->cursor(editData); Ms::toLyrics(editData.element)->selectAll(cursor); }
void ScoreView::lyricsMinus() { Lyrics* lyrics = toLyrics(editData.element); int track = lyrics->track(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Placement placement = lyrics->placement(); changeState(ViewState::NORMAL); // search next chord Segment* nextSegment = segment; while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } if (nextSegment == 0) return; // look for the lyrics we are moving from; may be the current lyrics or a previous one // we are extending with several dashes Lyrics* fromLyrics = 0; while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (!cr) { segment = segment->prev1(SegmentType::ChordRest); continue; } fromLyrics = cr->lyrics(verse, placement); if (fromLyrics) break; segment = segment->prev1(SegmentType::ChordRest); } _score->startCmd(); ChordRest* cr = toChordRest(nextSegment->element(track)); Lyrics* toLyrics = cr->lyrics(verse, placement); bool newLyrics = (toLyrics == 0); if (!toLyrics) { toLyrics = new Lyrics(_score); toLyrics->setTrack(track); toLyrics->setParent(nextSegment->element(track)); toLyrics->setNo(verse); toLyrics->setPlacement(placement); toLyrics->setSyllabic(Lyrics::Syllabic::END); } else { // as we arrived at toLyrics by a dash, it cannot be initial or isolated if (toLyrics->syllabic() == Lyrics::Syllabic::BEGIN) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::MIDDLE)); else if (toLyrics->syllabic() == Lyrics::Syllabic::SINGLE) toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); } if (fromLyrics) { // as we moved away from fromLyrics by a dash, // it can have syll. dashes before and after but cannot be isolated or terminal switch(fromLyrics->syllabic()) { case Lyrics::Syllabic::BEGIN: case Lyrics::Syllabic::MIDDLE: break; case Lyrics::Syllabic::SINGLE: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::BEGIN)); break; case Lyrics::Syllabic::END: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::MIDDLE)); break; } // for the same reason, it cannot have a melisma fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, 0); } if (newLyrics) _score->undoAddElement(toLyrics); _score->endCmd(); _score->select(toLyrics, SelectType::SINGLE, 0); startEdit(toLyrics, Grip::NO_GRIP); adjustCanvasPosition(toLyrics, false); TextCursor* cursor = Ms::toLyrics(editData.element)->cursor(editData); Ms::toLyrics(editData.element)->selectAll(cursor); _score->setLayoutAll(); }
void ScoreView::lyricsTab(bool back, bool end, bool moveOnly) { Lyrics* lyrics = toLyrics(editData.element); int track = lyrics->track(); Segment* segment = lyrics->segment(); int verse = lyrics->no(); Placement placement = lyrics->placement(); Segment* nextSegment = segment; if (back) { // search prev chord while ((nextSegment = nextSegment->prev1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } } else { // search next chord while ((nextSegment = nextSegment->next1(SegmentType::ChordRest))) { Element* el = nextSegment->element(track); if (el && el->isChord()) break; } } if (nextSegment == 0) return; changeState(ViewState::NORMAL); // look for the lyrics we are moving from; may be the current lyrics or a previous one // if we are skipping several chords with spaces Lyrics* fromLyrics = 0; if (!back) { while (segment) { ChordRest* cr = toChordRest(segment->element(track)); if (cr) { fromLyrics = cr->lyrics(verse, placement); if (fromLyrics) break; } segment = segment->prev1(SegmentType::ChordRest); } } ChordRest* cr = toChordRest(nextSegment->element(track)); if (!cr) { qDebug("no next lyrics list: %s", nextSegment->element(track)->name()); return; } Lyrics* _toLyrics = cr->lyrics(verse, placement); bool newLyrics = false; if (!_toLyrics) { _toLyrics = new Lyrics(_score); _toLyrics->setTrack(track); ChordRest* cr = toChordRest(nextSegment->element(track)); _toLyrics->setParent(cr); _toLyrics->setNo(verse); _toLyrics->setPlacement(placement); _toLyrics->setSyllabic(Lyrics::Syllabic::SINGLE); newLyrics = true; } _score->startCmd(); if (fromLyrics && !moveOnly) { switch (_toLyrics->syllabic()) { // as we arrived at toLyrics by a [Space], it can be the beginning // of a multi-syllable, but cannot have syllabic dashes before case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::BEGIN: break; case Lyrics::Syllabic::END: _toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::SINGLE)); break; case Lyrics::Syllabic::MIDDLE: _toLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::BEGIN)); break; } // as we moved away from fromLyrics by a [Space], it can be // the end of a multi-syllable, but cannot have syllabic dashes after switch (fromLyrics->syllabic()) { case Lyrics::Syllabic::SINGLE: case Lyrics::Syllabic::END: break; case Lyrics::Syllabic::BEGIN: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::SINGLE)); break; case Lyrics::Syllabic::MIDDLE: fromLyrics->undoChangeProperty(Pid::SYLLABIC, int(Lyrics::Syllabic::END)); break; } // for the same reason, it cannot have a melisma fromLyrics->undoChangeProperty(Pid::LYRIC_TICKS, 0); } if (newLyrics) _score->undoAddElement(_toLyrics); _score->endCmd(); _score->select(_toLyrics, SelectType::SINGLE, 0); startEdit(_toLyrics, Grip::NO_GRIP); adjustCanvasPosition(_toLyrics, false); TextCursor* cursor = toLyrics(editData.element)->cursor(editData); if (end) { cursor->movePosition(QTextCursor::Start, QTextCursor::MoveAnchor); cursor->movePosition(QTextCursor::End, QTextCursor::KeepAnchor); } else { cursor->movePosition(QTextCursor::End, QTextCursor::MoveAnchor); cursor->movePosition(QTextCursor::Start, QTextCursor::KeepAnchor); } _score->setLayoutAll(); }
bool Rectangle::overlaps(Segment const& segment) const noexcept { return (contains(segment.start()) || contains(segment.end()) || intersects(segment)); }
void Clef::layout() { // determine current number of lines and line distance int lines; qreal lineDist; Segment* clefSeg = segment(); qDeleteAll(elements); elements.clear(); // check clef visibility and type compatibility if (clefSeg && staff()) { StaffType* staffType = staff()->staffType(); bool show = staffType->genClef(); // check staff type allows clef display int tick = clefSeg->tick(); // check clef is compatible with staff type group: if (ClefInfo::staffGroup(clefType()) != staffType->group()) { if (tick > 0 && !generated()) // if clef is not generated, hide it show = false; else // if generated, replace with initial clef type // TODO : instead of initial staff clef (which is assumed to be compatible) // use the last compatible clef previously found in staff _clefTypes = staff()->clefType(0); } // if clef not to show or not compatible with staff group if (!show) { setbbox(QRectF()); qDebug("Clef::layout(): invisible clef at tick %d(%d) staff %d", segment()->tick(), segment()->tick()/1920, staffIdx()); return; } lines = staffType->lines(); // init values from staff type lineDist = staffType->lineDistance().val(); } else { lines = 5; lineDist = 1.0; } qreal _spatium = spatium(); qreal yoff = 0.0; Symbol* symbol = new Symbol(score()); switch (clefType()) { case ClefType::G: // G clef on 2nd line symbol->setSym(SymId::gClef); yoff = 3.0 * lineDist; break; case ClefType::G1: // G clef 8va on 2nd line symbol->setSym(SymId::gClef8va); yoff = 3.0 * lineDist; break; case ClefType::G2: // G clef 15ma on 2nd line symbol->setSym(SymId::gClef15ma); yoff = 3.0 * lineDist; break; case ClefType::G3: // G clef 8vb on 2nd line symbol->setSym(SymId::gClef8vb); yoff = 3.0 * lineDist; break; case ClefType::G3_O: // double G clef 8vb on 2nd line symbol->setSym(SymId::gClef8vbOld); yoff = 3.0 * lineDist; break; case ClefType::F: // F clef on penultimate line symbol->setSym(SymId::fClef); yoff = 1.0 * lineDist; break; case ClefType::F8: // F clef 8va bassa on penultimate line symbol->setSym(SymId::fClef8vb); yoff = 1.0 * lineDist; break; case ClefType::F15: // F clef 15ma bassa on penultimate line symbol->setSym(SymId::fClef15mb); yoff = 1.0 * lineDist; break; case ClefType::F_B: // baritone clef symbol->setSym(SymId::fClef); yoff = 2.0 * lineDist; break; case ClefType::F_C: // subbass clef symbol->setSym(SymId::fClef); yoff = 0.0; break; case ClefType::C1: // C clef in 1st line symbol->setSym(SymId::cClef); yoff = 4.0 * lineDist; break; case ClefType::C2: // C clef on 2nd line symbol->setSym(SymId::cClef); yoff = 3.0 * lineDist; break; case ClefType::C3: // C clef in 3rd line symbol->setSym(SymId::cClef); yoff = 2.0 * lineDist; break; case ClefType::C4: // C clef on 4th line symbol->setSym(SymId::cClef); yoff = 1.0 * lineDist; break; case ClefType::C5: // C clef on 5th line symbol->setSym(SymId::cClef); yoff = 0.0; break; case ClefType::TAB: // TAB clef symbol->setSym(SymId::sixStringTabClef); // on tablature, position clef at half the number of spaces * line distance yoff = lineDist * (lines - 1) * .5; break; case ClefType::TAB2: // TAB clef alternate style symbol->setSym(SymId::sixStringTabClefSerif); // on tablature, position clef at half the number of spaces * line distance yoff = lineDist * (lines - 1) * .5; break; case ClefType::PERC: // percussion clefs symbol->setSym(SymId::unpitchedPercussionClef1); yoff = lineDist * (lines - 1) * 0.5; break; case ClefType::PERC2: symbol->setSym(SymId::unpitchedPercussionClef2); yoff = lineDist * (lines - 1) * 0.5; break; case ClefType::G4: // G clef in 1st line symbol->setSym(SymId::gClef); yoff = 4.0 * lineDist; break; case ClefType::F_8VA: // F clef 8va on penultimate line symbol->setSym(SymId::fClef8va); yoff = 1.0 * lineDist; break; case ClefType::F_15MA: // F clef 15ma on penultimate line symbol->setSym(SymId::fClef15ma); yoff = 1.0 * lineDist; break; case ClefType::G5: // G clef on 2nd line symbol->setSym(SymId::gClef8vbParens); yoff = 3.0 * lineDist; break; case ClefType::INVALID: case ClefType::MAX: qDebug("Clef::layout: invalid type"); return; } addElement(symbol, .0, yoff * _spatium); QRectF r; for (Element* e : elements) { r |= e->bbox().translated(e->pos()); e->setSelected(selected()); } // clefs are right aligned to Segment QPointF off(-r.right(), 0); for (Element* e : elements) e->move(off); r.translate(off); setbbox(r); setPos(QPointF()); }
bool AreaShader::checkIntersect(const Segment& s) const { const Segment::Areastore& areas(s.getAreas()); return (areas.count(m_layer) > 0); }
void SLine::layout() { if (parent() == 0) { // // when used in a palette, SLine has no parent and // tick and tick2 has no meaning so no layout is // possible and needed // if (!spannerSegments().isEmpty()) { LineSegment* s = frontSegment(); s->layout(); setbbox(s->bbox()); } return; } if (startElement() == 0 || endElement() == 0) { qDebug("SLine::layout() failed: %s %s", parent()->name(), name()); qDebug(" start %p end %p", startElement(), endElement()); return; } System* s1; System* s2; QPointF p1 = linePos(GRIP_LINE_START, &s1); QPointF p2 = linePos(GRIP_LINE_END, &s2); QList<System*>* systems = score()->systems(); int sysIdx1 = systems->indexOf(s1); int sysIdx2 = systems->indexOf(s2); int segmentsNeeded = 0; for (int i = sysIdx1; i < sysIdx2+1; ++i) { if (systems->at(i)->isVbox()) continue; ++segmentsNeeded; } int segCount = spannerSegments().size(); if (segmentsNeeded != segCount) { if (segmentsNeeded > segCount) { int n = segmentsNeeded - segCount; for (int i = 0; i < n; ++i) { LineSegment* ls = createLineSegment(); add(ls); // set user offset to previous segment's offset if (segCount > 0) ls->setUserOff(QPointF(0, segmentAt(segCount+i-1)->userOff().y())); } } else { int n = segCount - segmentsNeeded; qDebug("SLine: segments %d needed %d, remove %d", segCount, segmentsNeeded, n); for (int i = 0; i < n; ++i) { if (spannerSegments().isEmpty()) { qDebug("SLine::layout(): no segment %d, %d expected", i, n); break; } else { // LineSegment* seg = takeLastSegment(); // TODO delete seg; } } } } int segIdx = 0; int si = staffIdx(); for (int i = sysIdx1; i <= sysIdx2; ++i) { System* system = systems->at(i); if (system->isVbox()) continue; LineSegment* seg = segmentAt(segIdx++); seg->setSystem(system); Measure* m = system->firstMeasure(); Segment* mseg = m->first(SegChordRest); qreal x1 = (mseg ? mseg->pos().x() : 0) + m->pos().x(); qreal x2 = system->bbox().right(); qreal y = system->staff(si)->y(); if (sysIdx1 == sysIdx2) { // single segment seg->setSubtype(SEGMENT_SINGLE); seg->setPos(p1); seg->setPos2(QPointF(p2.x() - p1.x(), 0.0)); } else if (i == sysIdx1) { // start segment seg->setSubtype(SEGMENT_BEGIN); seg->setPos(p1); seg->setPos2(QPointF(x2 - p1.x(), 0.0)); } else if (i > 0 && i != sysIdx2) { // middle segment seg->setSubtype(SEGMENT_MIDDLE); seg->setPos(QPointF(x1, y)); seg->setPos2(QPointF(x2 - x1, 0.0)); } else if (i == sysIdx2) { // end segment seg->setSubtype(SEGMENT_END); seg->setPos(QPointF(x1, y)); seg->setPos2(QPointF(p2.x() - x1, 0.0)); } seg->layout(); seg->rypos() += (_yoffset * spatium()); seg->adjustReadPos(); } }
SegmentSplitCommand::SegmentVec SegmentSplitCommand:: getNewSegments(Segment *segment, timeT splitTime, bool keepLabel) { Segment * newSegmentA = segment->clone(false); Segment * newSegmentB = new Segment(); newSegmentB->setTrack(segment->getTrack()); newSegmentB->setStartTime(splitTime); // !!! Set Composition? Event *clefEvent = 0; Event *keyEvent = 0; // Copy the last occurrence of clef and key // from the left hand side of the split (nb. timesig events // don't appear in segments, only in composition) // Segment::iterator it = segment->findTime(splitTime); while (it != segment->begin()) { --it; if (!clefEvent && (*it)->isa(Clef::EventType)) { clefEvent = new Event(**it, splitTime); } if (!keyEvent && (*it)->isa(Key::EventType)) { keyEvent = new Event(**it, splitTime); } if (clefEvent && keyEvent) break; } // Insert relevant meta info if we've found some // if (clefEvent) newSegmentB->insert(clefEvent); if (keyEvent) newSegmentB->insert(keyEvent); // Copy through the Events // it = segment->findTime(splitTime); if (it != segment->end() && (*it)->getAbsoluteTime() > splitTime) { newSegmentB->fillWithRests((*it)->getAbsoluteTime()); } while (it != segment->end()) { newSegmentB->insert(new Event(**it)); ++it; } newSegmentB->setEndTime(segment->getEndTime()); newSegmentB->setEndMarkerTime(segment->getEndMarkerTime()); // Set labels // std::string label = segment->getLabel(); newSegmentA->setLabel(label); newSegmentB->setLabel(label); if (!keepLabel) { newSegmentA->setLabel(appendLabel(label, qstrtostr(tr("(split)")))); newSegmentB->setLabel(appendLabel(label, qstrtostr(tr("(split)")))); } newSegmentB->setColourIndex(segment->getColourIndex()); newSegmentB->setTranspose(segment->getTranspose()); newSegmentB->setDelay(segment->getDelay()); // Resize left hand Segment // std::vector<Event *> toErase, toInsert; for (Segment::iterator i = newSegmentA->findTime(splitTime); i != newSegmentA->end(); ++i) { if ((*i)->getAbsoluteTime() >= splitTime) break; if ((*i)->getAbsoluteTime() + (*i)->getDuration() > splitTime) { Event *e = new Event(**i, (*i)->getAbsoluteTime(), splitTime - (*i)->getAbsoluteTime()); toErase.push_back(*i); toInsert.push_back(e); } } for (size_t i = 0; i < toErase.size(); ++i) { newSegmentA->eraseSingle(toErase[i]); delete toErase[i]; } for (size_t i = 0; i < toInsert.size(); ++i) { newSegmentA->insert(toInsert[i]); } newSegmentA->setEndTime(splitTime); newSegmentA->setEndMarkerTime(splitTime); SegmentVec segmentVec; segmentVec.reserve(2); segmentVec.push_back(newSegmentA); segmentVec.push_back(newSegmentB); return segmentVec; }
void BarLine::getY(qreal* y1, qreal* y2) const { qreal _spatium = spatium(); if (parent()) { int staffIdx1 = staffIdx(); int staffIdx2 = staffIdx1 + _span - 1; if (staffIdx2 >= score()->nstaves()) { qDebug("BarLine: bad _span %d", _span); staffIdx2 = score()->nstaves() - 1; } Measure* measure; System* system; qreal yp = 0.0; if (parent()->type() == Element::Type::SEGMENT) { Segment* segment = static_cast<Segment*>(parent()); measure = segment->measure(); system = measure->system(); } else { system = static_cast<System*>(parent()); measure = system->firstMeasure(); } if (measure) { // test start and end staff visibility int nstaves = score()->nstaves(); int span = _span; Staff* staff1 = score()->staff(staffIdx1); Staff* staff2 = score()->staff(staffIdx2); SysStaff* sysStaff1 = system->staff(staffIdx1); SysStaff* sysStaff2 = system->staff(staffIdx2); while (span > 0) { // if start staff not shown, reduce span and move one staff down if ( !(sysStaff1->show() && staff1->show()) ) { span--; if (staffIdx1 >= nstaves-1) // running out of staves? break; sysStaff1 = system->staff(++staffIdx1); staff1 = score()->staff(staffIdx1); } // if end staff not shown, reduce span and move one staff up else if ( !(sysStaff2->show() && staff2->show()) ) { span--; if (staffIdx2 == 0) break; sysStaff2 = system->staff(--staffIdx2); staff2 = score()->staff(staffIdx2); } // if both staves shown, exit loop else break; } // if no longer any span, set 0 length and exit if (span <= 0) { *y1 = *y2 = 0; return; } // both staffIdx1 and staffIdx2 are shown: compute corresponding line length StaffLines* l1 = measure->staffLines(staffIdx1); StaffLines* l2 = measure->staffLines(staffIdx2); if (system) yp += sysStaff1->y(); *y1 = l1->y1() - yp; *y1 += (_spanFrom * staff1->lineDistance() * staff1->spatium()) / 2; *y2 = l2->y1() - yp; *y2 += (_spanTo * staff2->lineDistance() * staff2->spatium()) / 2; } } else { // for use in palette *y1 = _spanFrom * _spatium / 2; *y2 = _spanTo * _spatium / 2; } if (selected()) { *y1 += yoff1; *y2 += yoff2; } }
void Clef::layout() { // determine current number of lines and line distance int lines; qreal lineDist; Segment* clefSeg = segment(); // check clef visibility and type compatibility if (clefSeg && staff()) { StaffType* staffType = staff()->staffType(); bool show = staffType->genClef(); // check staff type allows clef display int tick = clefSeg->tick(); // check clef is compatible with staff type group: if (ClefInfo::staffGroup(clefType()) != staffType->group()) { if (tick > 0 && !generated()) // if clef is not generated, hide it show = false; else // if generated, replace with initial clef type // TODO : instead of initial staff clef (which is assumed to be compatible) // use the last compatible clef previously found in staff _clefTypes = staff()->clefType(0); } // if clef not to show or not compatible with staff group if (!show) { setbbox(QRectF()); qDebug("Clef::layout(): invisible clef at tick %d(%d) staff %d", segment()->tick(), segment()->tick()/1920, staffIdx()); return; } lines = staffType->lines(); // init values from staff type lineDist = staffType->lineDistance().val(); } else { lines = 5; lineDist = 1.0; } qreal _spatium = spatium(); qreal yoff = 0.0; if (clefType() != ClefType::INVALID && clefType() != ClefType::MAX) { symId = ClefInfo::symId(clefType()); yoff = lineDist * (lines - ClefInfo::line(clefType())); } switch (clefType()) { case ClefType::C_19C: // 19th C clef is like a G clef yoff = lineDist * 1.5; break; case ClefType::TAB: // TAB clef // on tablature, position clef at half the number of spaces * line distance yoff = lineDist * (lines - 1) * .5; break; case ClefType::TAB4: // TAB clef 4 strings // on tablature, position clef at half the number of spaces * line distance yoff = lineDist * (lines - 1) * .5; break; case ClefType::TAB_SERIF: // TAB clef alternate style // on tablature, position clef at half the number of spaces * line distance yoff = lineDist * (lines - 1) * .5; break; case ClefType::TAB4_SERIF: // TAB clef alternate style // on tablature, position clef at half the number of spaces * line distance yoff = lineDist * (lines - 1) * .5; break; case ClefType::PERC: // percussion clefs yoff = lineDist * (lines - 1) * 0.5; break; case ClefType::PERC2: yoff = lineDist * (lines - 1) * 0.5; break; case ClefType::INVALID: case ClefType::MAX: qDebug("Clef::layout: invalid type"); return; default: break; } // clefs are right aligned to Segment QRectF r(symBbox(symId)); // setPos(-r.right(), yoff * _spatium); setPos(0.0, yoff * _spatium); setbbox(r); }
void SegmentTransposeCommand::processSegment(Segment &segment, bool changeKey, int steps, int semitones, bool transposeSegmentBack) { MacroCommand * macroCommand = this; // TODO delete it somewhere. EventSelection * wholeSegment = new EventSelection(segment, segment.getStartTime(), segment.getEndMarkerTime()); macroCommand->addCommand(new TransposeCommand (semitones, steps, *wholeSegment)); // Key insertion can do transposition, but a C4 to D becomes a D4, while // a C4 to G becomes a G3. Because we let the user specify an explicit number // of octaves to move the notes up/down, we add the keys without transposing // and handle the transposition seperately: if (changeKey) { Rosegarden::Key initialKey = segment.getKeyAtTime(segment.getStartTime()); Rosegarden::Key newInitialKey = initialKey.transpose(semitones, steps); EventSelection::eventcontainer::iterator i; //std::list<KeyInsertionCommand*> commands; for (i = wholeSegment->getSegmentEvents().begin(); i != wholeSegment->getSegmentEvents().end(); ++i) { // transpose key if ((*i)->isa(Rosegarden::Key::EventType)) { Rosegarden::Key trKey = (Rosegarden::Key (**i)).transpose(semitones, steps); //commands.push_front macroCommand->addCommand (new KeyInsertionCommand (segment, (*i)->getAbsoluteTime(), trKey, false, false, false, true)); } } std::list<KeyInsertionCommand*>::iterator ci; //for (ci=commands.begin(); ci!=commands.end(); ci++) //{ // commandHistory->addCommand(*ci); //} KeyInsertionCommand *firstKeyCommand = new KeyInsertionCommand (segment, segment.getStartTime(), newInitialKey, false, false, false, true); //commandHistory->addCommand(firstKeyCommand); macroCommand->addCommand(firstKeyCommand); } if (transposeSegmentBack) { // Transpose segment in opposite direction int newTranspose = segment.getTranspose() - semitones; macroCommand->addCommand(new SegmentChangeTransposeCommand(newTranspose, &segment)); } }
void Slice::ConnectSegmentNeighbors() { unsigned int s; unsigned int potential; unsigned int s2; double potentialangle; double potentialDist; double minDist = 10000.0; Segment* thisSeg = NULL; Segment* thatSeg = NULL; QVector2D* thisPoint = NULL; QVector2D* thatPoint = NULL; std::vector<Segment*> sameXStripSegs; std::vector<Segment*> potentialLeadSegs; Segment* finalLeadSeg = NULL; for(s = 0; s < segmentList.size(); s++)//compare from every segment { thisSeg = segmentList[s]; thisPoint = &thisSeg->p2;//compare from the 2nd point on "this" segment if(thisSeg->leadingSeg)//no need to add a connection if there already is one! continue; potentialLeadSegs.clear();//clear out the potentials list GetSegmentsAroundX(sameXStripSegs, thisPoint->x()); ////////////////////////////////////// for(s2 = 0; s2 < sameXStripSegs.size(); s2++)//to every other segment in ring { //make sure its not the same segment if(s == s2) {continue;} thatSeg = sameXStripSegs[s2]; if(thatSeg->trailingSeg)//already connected to a trailing segment... continue; thatPoint = &thatSeg->p1;//to the first point of "that" segment if(IsZero(Distance2D(*thisPoint, *thatPoint),0.03))//they are close enough to each other { potentialLeadSegs.push_back(thatSeg); } } ////////////////////////////////////// //sort through and pick from the potential pile //we want to pick a segment with the sharpest change in direction! // // //1>>>>>>>>>A>>>>>>>>2 1>>>>>>>>B>>>>>>>>>2 // ^ // large delta angle/ Right Wieghted minDist = 100000.0; finalLeadSeg = NULL; potentialangle = 0.0; for(potential = 0; potential < potentialLeadSegs.size(); potential++) { thatSeg = potentialLeadSegs[potential]; //potentialDot = (thisSeg->normal.x() * thatSeg->normal.x()) + (thisSeg->normal.y() * thatSeg->normal.y()); //gives a number indicating how sharp the angle is, -1 is the sharpest (-1,1) //potentialCross = (thisSeg->normal.x() * thatSeg->normal.y()) - (thisSeg->normal.y() * thatSeg->normal.x());//gives a number indicating a right or left turn. (uphill is positive), (downhill is negative) (-1,1) potentialDist = Distance2D(thisSeg->p2, thatSeg->p1); if(potentialDist < minDist) { minDist = potentialDist; finalLeadSeg = potentialLeadSegs[potential]; } } if(finalLeadSeg) { thisSeg->leadingSeg = finalLeadSeg; finalLeadSeg->trailingSeg = thisSeg; thisSeg->p2 = finalLeadSeg->p1; thisSeg->FormNormal(); } } }
Note* Glissando::guessInitialNote(Chord* chord) { switch (chord->noteType()) { // case NoteType::INVALID: // return nullptr; // for grace notes before, previous chord is previous chord of parent chord case NoteType::ACCIACCATURA: case NoteType::APPOGGIATURA: case NoteType::GRACE4: case NoteType::GRACE16: case NoteType::GRACE32: // move unto parent chord and proceed to standard case if (chord->parent() && chord->parent()->type() == Element::Type::CHORD) chord = static_cast<Chord*>(chord->parent()); else return nullptr; break; // for grace notes after, return top note of parent chord case NoteType::GRACE8_AFTER: case NoteType::GRACE16_AFTER: case NoteType::GRACE32_AFTER: if (chord->parent() && chord->parent()->type() == Element::Type::CHORD) return static_cast<Chord*>(chord->parent())->upNote(); else // no parent or parent is not a chord? return nullptr; case NoteType::NORMAL: { // if chord has grace notes before, the last one is the previous note QVector<Chord*>graces = chord->graceNotesBefore(); if (graces.size() > 0) return graces.last()->upNote(); } break; // else process to standard case default: break; } // standard case (NORMAL or grace before chord) // if parent not a segment, can't locate a target note if (chord->parent()->type() != Element::Type::SEGMENT) return nullptr; int chordTrack = chord->track(); Segment* segm = chord->segment(); Part* part = chord->part(); if (segm != nullptr) segm = segm->prev1(); while (segm) { // if previous segment is a ChordRest segment if (segm->segmentType() == Segment::Type::ChordRest) { Chord* target = nullptr; // look for a Chord in the same track if (segm->element(chordTrack) && segm->element(chordTrack)->type() == Element::Type::CHORD) target = static_cast<Chord*>(segm->element(chordTrack)); else // if no same track, look for other chords in the same instrument for (Element* currChord : segm->elist()) if (currChord != nullptr && currChord->type() == Element::Type::CHORD && static_cast<Chord*>(currChord)->part() == part) { target = static_cast<Chord*>(currChord); break; } // if we found a target previous chord if (target) { // if chord has grace notes after, the last one is the previous note QVector<Chord*>graces = target->graceNotesAfter(); if (graces.size() > 0) return graces.last()->upNote(); return target->upNote(); // if no grace after, return top note } } segm = segm->prev1(); } qDebug("no first note for glissando found"); return nullptr; }
void SegmentPencil::mouseReleaseEvent(QMouseEvent *e) { // Have to allow middle button for SegmentSelector's middle // button feature to work. if (e->button() != Qt::LeftButton && e->button() != Qt::MidButton) return; // No need to propagate. e->accept(); QPoint pos = m_canvas->viewportToContents(e->pos()); setContextHelpFor(pos); if (m_newRect) { QRect tmpRect = m_canvas->getNewSegmentRect(); int trackPosition = m_canvas->grid().getYBin(tmpRect.y()); Track *track = m_doc->getComposition().getTrackByPosition(trackPosition); SegmentInsertCommand *command = new SegmentInsertCommand(m_doc, track->getId(), m_startTime, m_endTime); m_newRect = false; CommandHistory::getInstance()->addCommand(command); // add the SegmentItem by hand, instead of allowing the usual // update mechanism to spot it. This way we can select the // segment as we add it; otherwise we'd have no way to know // that the segment was created by this tool rather than by // e.g. a simple file load Segment *segment = command->getSegment(); // add a clef to the start of the segment (tracks initialize to a // default of 0 for this property, so treble will be the default if it // is not specified elsewhere) segment->insert(clefIndexToClef(track->getClef()).getAsEvent (segment->getStartTime())); //!!! Should not a default key be inserted here equally in order to // have the "hide redundant clefs and keys" mechanism working // on the segments using the default key ? segment->setTranspose(track->getTranspose()); segment->setColourIndex(track->getColor()); segment->setLowestPlayable(track->getLowestPlayable()); segment->setHighestPlayable(track->getHighestPlayable()); std::string label = track->getPresetLabel(); if (label != "") { segment->setLabel( track->getPresetLabel().c_str() ); } m_canvas->getModel()->clearSelected(); m_canvas->getModel()->setSelected(segment); m_canvas->getModel()->selectionHasChanged(); m_canvas->hideNewSegment(); m_canvas->slotUpdateAll(); } }
Note* Glissando::guessFinalNote(Chord* chord) { switch (chord->noteType()) { // case NoteType::INVALID: // return nullptr; // for grace notes before, return top note of parent chord // TODO : if the grace-before is not the LAST ONE, this still returns the main note // which is probably not correct; however a glissando between two grace notes // probably makes little sense. case NoteType::ACCIACCATURA: case NoteType::APPOGGIATURA: case NoteType::GRACE4: case NoteType::GRACE16: case NoteType::GRACE32: if (chord->parent() && chord->parent()->type() == Element::Type::CHORD) return static_cast<Chord*>(chord->parent())->upNote(); else // no parent or parent is not a chord? return nullptr; // for grace notes after, next chord is next chord of parent chord // TODO : same note as case above! case NoteType::GRACE8_AFTER: case NoteType::GRACE16_AFTER: case NoteType::GRACE32_AFTER: // move unto parent chord and proceed to standard case if (chord->parent() && chord->parent()->type() == Element::Type::CHORD) chord = static_cast<Chord*>(chord->parent()); else return nullptr; break; case NoteType::NORMAL: { // if chord has grace notes after, the first one is the next note QVector<Chord*>graces = chord->graceNotesAfter(); if (graces.size() > 0) return graces.first()->upNote(); } break; default: break; } // standard case (NORMAL or grace after chord) // if parent not a segment, can't locate a target note if (chord->parent()->type() != Element::Type::SEGMENT) return nullptr; // look for first ChordRest segment after initial note is elapsed Segment* segm = chord->score()->tick2rightSegment(chord->tick() + chord->actualTicks()); int chordTrack = chord->track(); Part* part = chord->part(); while (segm) { // if next segment is a ChordRest segment if (segm->segmentType() == Segment::Type::ChordRest) { Chord* target = nullptr; // look for a Chord in the same track if (segm->element(chordTrack) && segm->element(chordTrack)->type() == Element::Type::CHORD) target = static_cast<Chord*>(segm->element(chordTrack)); else // if no same track, look for other chords in the same instrument for (Element* currChord : segm->elist()) if (currChord != nullptr && currChord->type() == Element::Type::CHORD && static_cast<Chord*>(currChord)->part() == part) { target = static_cast<Chord*>(currChord); break; } // if we found a target next chord if (target) { // if chord has grace notes before, the first one is the next note QVector<Chord*>graces = target->graceNotesBefore(); if (graces.size() > 0) return graces.first()->upNote(); return target->upNote(); // if no grace before, return top note } } segm = segm->next1(); } qDebug("no second note for glissando found"); return nullptr; }
Segment::Segment(const Segment& source) : _myId(_freeID++), _a(source.start()), _b(source.end()){ #ifdef NDEBUG cout << "Segment " << _myId << ": copy constructor. Source: " << source; #endif }
void Ambitus::layout() { int bottomLine, topLine; ClefType clf; qreal headWdt = headWidth(); Key key; qreal lineDist; int numOfLines; Segment* segm = segment(); qreal _spatium = spatium(); Staff* stf = nullptr; if (segm && track() > -1) { int tick = segm->tick(); stf = score()->staff(staffIdx()); lineDist = stf->lineDistance(tick) * _spatium; numOfLines = stf->lines(tick); clf = stf->clef(tick); } else { // for use in palettes lineDist = _spatium; numOfLines = 3; clf = ClefType::G; } // // NOTEHEADS Y POS // // if pitch == INVALID_PITCH oor tpc == INALID_TPC, set to some default: // for use in palettes and when actual range cannot be calculated (new ambitus or no notes in staff) // qreal xAccidOffTop = 0; qreal xAccidOffBottom = 0; if (stf) key = stf->key(segm->tick()); else key = Key::C; // top notehead if (_topPitch == INVALID_PITCH || _topTpc == Tpc::TPC_INVALID) _topPos.setY(0); // if uninitialized, set to top staff line else { topLine = absStep(_topTpc, _topPitch); topLine = relStep(topLine, clf); _topPos.setY(topLine * lineDist * 0.5); // compute accidental AccidentalType accidType; // if (13 <= (tpc - key) <= 19) there is no accidental) if (_topTpc - int(key) >= 13 && _topTpc - int(key) <= 19) accidType = AccidentalType::NONE; else { AccidentalVal accidVal = AccidentalVal( (_topTpc - Tpc::TPC_MIN) / TPC_DELTA_SEMITONE - 2 ); accidType = Accidental::value2subtype(accidVal); if (accidType == AccidentalType::NONE) accidType = AccidentalType::NATURAL; } _topAccid.setAccidentalType(accidType); if (accidType != AccidentalType::NONE) _topAccid.layout(); else _topAccid.setbbox(QRect()); _topAccid.rypos() = _topPos.y(); } // bottom notehead if (_bottomPitch == INVALID_PITCH || _bottomTpc == Tpc::TPC_INVALID) _bottomPos.setY( (numOfLines-1) * lineDist); // if uninitialized, set to last staff line else { bottomLine = absStep(_bottomTpc, _bottomPitch); bottomLine = relStep(bottomLine, clf); _bottomPos.setY(bottomLine * lineDist * 0.5); // compute accidental AccidentalType accidType; if (_bottomTpc - int(key) >= 13 && _bottomTpc - int(key) <= 19) accidType = AccidentalType::NONE; else { AccidentalVal accidVal = AccidentalVal( (_bottomTpc - Tpc::TPC_MIN) / TPC_DELTA_SEMITONE - 2 ); accidType = Accidental::value2subtype(accidVal); if (accidType == AccidentalType::NONE) accidType = AccidentalType::NATURAL; } _bottomAccid.setAccidentalType(accidType); if (accidType != AccidentalType::NONE) _bottomAccid.layout(); else _bottomAccid.setbbox(QRect()); _bottomAccid.rypos() = _bottomPos.y(); } // // NOTEHEAD X POS // // Note: manages colliding accidentals // qreal accNoteDist = point(score()->styleS(Sid::accidentalNoteDistance)); xAccidOffTop = _topAccid.width() + accNoteDist; xAccidOffBottom = _bottomAccid.width() + accNoteDist; // if top accidental extends down more than bottom accidental extends up, // AND ambitus is not leaning right, bottom accidental needs to be displaced bool collision = (_topAccid.ipos().y() + _topAccid.bbox().y() + _topAccid.height() > _bottomAccid.ipos().y() + _bottomAccid.bbox().y() ) && _dir != MScore::DirectionH::RIGHT; if (collision) { // displace bottom accidental (also attempting to 'undercut' flats) xAccidOffBottom = xAccidOffTop + ((_bottomAccid.accidentalType() == AccidentalType::FLAT || _bottomAccid.accidentalType() == AccidentalType::FLAT2 || _bottomAccid.accidentalType() == AccidentalType::NATURAL) ? _bottomAccid.width() * 0.5 : _bottomAccid.width()); } switch (_dir) { case MScore::DirectionH::AUTO: // noteheads one above the other // left align noteheads and right align accidentals 'hanging' on the left _topPos.setX(0.0); _bottomPos.setX(0.0); _topAccid.rxpos() = - xAccidOffTop; _bottomAccid.rxpos() = - xAccidOffBottom; break; case MScore::DirectionH::LEFT: // top notehead at the left of bottom notehead // place top notehead at left margin; bottom notehead at right of top head; // top accid. 'hanging' on left of top head and bottom accid. 'hanging' at left of bottom head _topPos.setX(0.0); _bottomPos.setX(headWdt); _topAccid.rxpos() = - xAccidOffTop; _bottomAccid.rxpos() = collision ? - xAccidOffBottom : headWdt - xAccidOffBottom; break; case MScore::DirectionH::RIGHT: // top notehead at the right of bottom notehead // bottom notehead at left margin; top notehead at right of bottomnotehead // top accid. 'hanging' on left of top head and bottom accid. 'hanging' at left of bottom head _bottomPos.setX(0.0); _topPos.setX(headWdt); _bottomAccid.rxpos() = - xAccidOffBottom; _topAccid.rxpos() = headWdt - xAccidOffTop; break; } // compute line from top note centre to bottom note centre QLineF fullLine(_topPos.x() + headWdt*0.5, _topPos.y(), _bottomPos.x() + headWdt*0.5, _bottomPos.y()); // shorten line on each side by offsets qreal yDelta = _bottomPos.y() - _topPos.y(); if (yDelta != 0.0) { qreal off = _spatium * LINEOFFSET_DEFAULT; QPointF p1 = fullLine.pointAt(off / yDelta); QPointF p2 = fullLine.pointAt(1 - (off / yDelta)); _line = QLineF(p1, p2); } else _line = fullLine; QRectF headRect = QRectF(0, -0.5*_spatium, headWdt, 1*_spatium); setbbox(headRect.translated(_topPos).united(headRect.translated(_bottomPos)) .united(_topAccid.bbox().translated(_topAccid.ipos())) .united(_bottomAccid.bbox().translated(_bottomAccid.ipos())) ); }
void find_next_edge(Segment s, std::vector<Segment>& segments, std::set<int>& unusedIndexes, std::vector<Polygon_2>& rings) { if(unusedIndexes.empty() || prev_size == unusedIndexes.size()) { return; } prev_size = unusedIndexes.size(); Point start = s.source(); Point end = s.target(); rings.back().push_back(end); std::vector<int> nextIndexes; for(unsigned int i = 0;i < segments.size(); i++) { if (unusedIndexes.find(i) != unusedIndexes.end()) { Point source = segments.at(i).source(); if(source == end) { nextIndexes.push_back(i); } } } if (nextIndexes.size() == 1) { int i = nextIndexes.at(0); unusedIndexes.erase(i); find_next_edge(segments.at(i), segments, unusedIndexes, rings); } else if (nextIndexes.size() > 1) { std::vector< std::pair<double, int> > nextAngles; for (unsigned int i = 0; i < nextIndexes.size(); i++) { int j = nextIndexes.at(i); Point target = segments.at(j).target(); double angle = get_angle(start, end, target); nextAngles.push_back(std::pair<double, int>(angle, j)); } std::sort(nextAngles.begin(), nextAngles.end()); int i = nextAngles.begin()->second; unusedIndexes.erase(i); find_next_edge(segments.at(i), segments, unusedIndexes, rings); } if (!unusedIndexes.empty()) { for (unsigned int i = 0; i < segments.size(); i++) { if (unusedIndexes.find(i) != unusedIndexes.end()) { Polygon_2 ring; ring.push_back(segments.at(i).source()); rings.push_back(ring); unusedIndexes.erase(i); find_next_edge(segments.at(i), segments, unusedIndexes, rings); } } } }
Element* Jump::nextElement() { Segment* seg = measure()->last(); return seg->firstElement(staffIdx()); }