void Stem::layout() { qreal l = _len + _userLen; qreal _up = up() ? -1.0 : 1.0; l *= _up; qreal y1 = 0.0; // vertical displacement to match note attach point Staff* stf = staff(); if (chord()) { int tick = chord()->tick(); StaffType* st = stf->staffType(tick); if (st->isTabStaff() ) { // TAB staves if (st->stemThrough()) { // if stems through staves, gets Y pos. of stem-side note relative to chord other side qreal lineDist = st->lineDistance().val() * spatium(); y1 = (chord()->downString() - chord()->upString()) * _up * lineDist; // if fret marks above lines, raise stem beginning by 1/2 line distance if (!st->onLines()) y1 -= lineDist * 0.5; // shorten stem by 1/2 lineDist to clear the note and a little more to keep 'air' betwen stem and note lineDist *= 0.7 * mag(); y1 += _up * lineDist; } // in other TAB types, no correction } else { // non-TAB // move stem start to note attach point Note* n = up() ? chord()->downNote() : chord()->upNote(); y1 += (up() ? n->stemUpSE().y() : n->stemDownNW().y()); rypos() = n->rypos(); } } qreal lw5 = _lineWidth * .5; line.setLine(0.0, y1, 0.0, l); // compute bounding rectangle QRectF r(line.p1(), line.p2()); setbbox(r.normalized().adjusted(-lw5, -lw5, lw5, lw5)); adjustReadPos(); // does not work if stem is layouted twice }
bool ON_Intersect( const ON_BoundingBox& bbox, const ON_Line& line, double tol, ON_Interval* line_parameters) { double a,b,d,mn,mx,s0,s1, t0, t1; const double M = 1.0e308; // i,j,k are indices of coordinates to trim. // trim the direction with the biggest line deltas first ON_3dVector v = line.Direction(); const int i = v.MaximumCoordinateIndex(); // gaurd against ON_UNSET_VALUE as input if ( !(tol >= 0.0) ) tol = 0.0; // clip i-th coordinate a = line.from[i]; b = line.to[i]; mn = bbox.m_min[i]; mx = bbox.m_max[i]; if ( !(mn <= mx) ) return false; mn -= (tol+a); mx += (tol-a); if ( !(mn <= mx) ) return false; d = b-a; if ( 0.0 == d ) { // happens when line.from == line.to if ( 0.0 < mn || 0.0 > mx ) { // point is in box if ( line_parameters ) { // setting parameters makes no sense - just use 0.0 // so it's clear we have a point line_parameters->Set(0.0,0.0); } return true; } return false; // point is outside box } if ( fabs(d) < 1.0 && (fabs(mn) >= fabs(d)*M || fabs(mx) >= fabs(d)*M) ) { // the value of mn/d or mx/d is too large for a realistic answer to be computed return false; } d = 1.0/d; t0 = mn*d; t1 = mx*d; // set "chord" = line segment that begins and ends on the // i-th coordinate box side planes. ON_Line chord(line.PointAt(t0),line.PointAt(t1)); // test j-th coordinate direction const int j = (i + (fabs(v[(i+1)%3])>fabs(v[(i+2)%3])?1:2) ) % 3; a = chord.from[j]; b = chord.to[j]; mn = bbox.m_min[j]; mx = bbox.m_max[j]; if ( !(mn <= mx) ) return false; mn -= (tol+a); mx += (tol-a); if ( !(mn <= mx) ) return false; d = b-a; if ( (0.0 < mn && d < mn) || (0.0 > mx && d > mx) ) { // chord lies outside the box return false; } while ( fabs(d) >= 1.0 || (fabs(mn) <= fabs(d)*M && fabs(mx) <= fabs(d)*M) ) { // The chord is not (nearly) parallel to the j-th sides. // See if the chord needs to be trimmed by the j-th sides. d = 1.0/d; s0 = mn*d; s1 = mx*d; if ( s0 > 1.0 ) { if ( s1 > 1.0 ) { // unstable calculation happens when // fabs(d) is very tiny and chord is // on the j-th side. break; } s0 = 1.0; } else if ( s0 < 0.0 ) { if (s1 < 0.0) { // unstable calculation happens when // fabs(d) is very tiny and chord is // on the j-th side. break; } s0 = 0.0; } if ( s1 < 0.0 ) s1 = 0.0; else if ( s1 > 1.0 ) s1 = 1.0; d = (1.0-s0)*t0 + s0*t1; t1 = (1.0-s1)*t0 + s1*t1; t0 = d; v = chord.PointAt(s0); chord.to = chord.PointAt(s1); chord.from = v; break; } // test k-th coordinate direction const int k = (i&&j) ? 0 : ((i!=1&&j!=1)?1:2); a = chord.from[k]; b = chord.to[k]; mn = bbox.m_min[k]; mx = bbox.m_max[k]; if ( !(mn <= mx) ) return false; mn -= (tol+a); mx += (tol-a); if ( !(mn <= mx) ) return false; d = b-a; if ( (0.0 < mn && d < mn) || (0.0 > mx && d > mx) ) { // chord does not intersect the rectangle return false; } if ( line_parameters ) { while ( fabs(d) >= 1.0 || (fabs(mn) <= fabs(d)*M && fabs(mx) <= fabs(d)*M) ) { // The chord is not (nearly) parallel to the k-th sides. // See if the chord needs to be trimmed by the k-th sides. d = 1.0/d; s0 = mn*d; s1 = mx*d; if ( s0 > 1.0 ) { if ( s1 > 1.0 ) { // unstable calculation happens when // fabs(d) is very tiny and chord is // on the k-th side. break; } s0 = 1.0; } else if ( s0 < 0.0 ) { if (s1 < 0.0) { // unstable calculation happens when // fabs(d) is very tiny and chord is // on the k-th side. break; } s0 = 0.0; } if ( s1 < 0.0 ) s1 = 0.0; else if ( s1 > 1.0 ) s1 = 1.0; d = (1.0-s0)*t0 + s0*t1; t1 = (1.0-s1)*t0 + s1*t1; t0 = d; break; } if (t0 > t1 ) { line_parameters->Set(t1,t0); } else { line_parameters->Set(t0,t1); } } return true; }
bool Stem::up() const { return chord() ? chord()->up() : true; }
void Stem::draw(QPainter* painter) const { // hide if second chord of a cross-measure pair if (chord() && chord()->crossMeasure() == CrossMeasure::SECOND) return; Staff* st = staff(); bool useTab = st && st->isTabStaff(); qreal lw = lineWidth(); painter->setPen(QPen(curColor(), lw, Qt::SolidLine, Qt::RoundCap)); painter->drawLine(line); if (!useTab || !chord()) return; // TODO: adjust bounding rectangle in layout() for dots and for slash StaffType* stt = st->staffType(); qreal sp = spatium(); bool _up = up(); // slashed half note stem if (chord()->durationType().type() == TDuration::DurationType::V_HALF && stt->minimStyle() == TablatureMinimStyle::SLASHED) { // position slashes onto stem qreal y = _up ? -(_len+_userLen) + STAFFTYPE_TAB_SLASH_2STARTY_UP*sp : (_len+_userLen) - STAFFTYPE_TAB_SLASH_2STARTY_DN*sp; // if stems through, try to align slashes within or across lines if (stt->stemThrough()) { qreal halfLineDist = stt->lineDistance().val() * sp * 0.5; qreal halfSlashHgt = STAFFTYPE_TAB_SLASH_2TOTHEIGHT * sp * 0.5; y = lrint( (y + halfSlashHgt) / halfLineDist) * halfLineDist - halfSlashHgt; } // draw slashes qreal hlfWdt= sp * STAFFTYPE_TAB_SLASH_WIDTH * 0.5; qreal sln = sp * STAFFTYPE_TAB_SLASH_SLANTY; qreal thk = sp * STAFFTYPE_TAB_SLASH_THICK; qreal displ = sp * STAFFTYPE_TAB_SLASH_DISPL; QPainterPath path; for (int i = 0; i < 2; ++i) { path.moveTo( hlfWdt, y); // top-right corner path.lineTo( hlfWdt, y+thk); // bottom-right corner path.lineTo(-hlfWdt, y+thk+sln); // bottom-left corner path.lineTo(-hlfWdt, y+sln); // top-left corner path.closeSubpath(); y += displ; } painter->setBrush(QBrush(curColor())); painter->setPen(Qt::NoPen); painter->drawPath(path); } // dots // NOT THE BEST PLACE FOR THIS? // with tablatures and stems beside staves, dots are not drawn near 'notes', but near stems int nDots = chord()->dots(); if (nDots > 0 && !stt->stemThrough()) { qreal x = chord()->dotPosX(); qreal y = ( (STAFFTYPE_TAB_DEFAULTSTEMLEN_DN * 0.2) * sp) * (_up ? -1.0 : 1.0); qreal step = score()->styleS(StyleIdx::dotDotDistance).val() * sp; for (int dot = 0; dot < nDots; dot++, x += step) drawSymbol(SymId::augmentationDot, painter, QPointF(x, y)); } }
//==== Generate Fuse Component ====// void PropGeom::generate() { int i, j; //==== Copy Current Section Data into SectVec ====// sectVec[currSectID].chord = chord(); sectVec[currSectID].twist = twist(); sectVec[currSectID].x_off = loc(); sectVec[currSectID].y_off = offset(); Xsec_surf surf; surf.set_num_pnts( numPnts.iget() ); surf.set_num_xsecs( sectVec.size()+2 ); //==== Load Up Airfoil ====// for ( int ip = 0 ; ip < surf.get_num_pnts() ; ip++ ) surf.set_pnt(0, ip, sectVec[0].foil->get_end_cap(ip) ); int numxs = sectVec.size(); for ( i = 0 ; i < numxs ; i++ ) { for ( j = 0 ; j < surf.get_num_pnts() ; j++ ) { surf.set_pnt( i+1, j, sectVec[i].foil->get_pnt(j) ); } } for ( int ip = 0 ; ip < surf.get_num_pnts() ; ip++ ) surf.set_pnt(numxs+1, ip, sectVec[numxs-1].foil->get_end_cap(ip) ); //==== Build Up One Blade ====// double rad = diameter()/2.0; for ( i = 0 ; i < surf.get_num_xsecs() ; i++ ) { int sid = i; if ( i > 0 ) sid = i-1; if ( i > (int)sectVec.size()-1 ) sid = (int)sectVec.size()-1; Section* sPtr = &(sectVec[sid]); surf.scale_xsec_x( i, sPtr->chord()*rad ); surf.scale_xsec_z( i, sPtr->chord()*rad ); surf.offset_xsec_x( i, -0.5*(sPtr->chord()*rad) ); surf.rotate_xsec_y( i, 90.0 ); surf.rotate_xsec_y( i, -sPtr->twist() - pitch() ); surf.offset_xsec_y( i, sPtr->x_off()*rad ); surf.offset_xsec_z( i, -sPtr->y_off()*rad ); } //==== Set Flags So Trailing Edge Remains Sharp ====// surf.set_pnt_tan_flag( 0, Bezier_curve::SHARP ); surf.set_pnt_tan_flag( 1, Bezier_curve::SHARP ); int num_pnts = surf.get_num_pnts(); surf.set_pnt_tan_flag( num_pnts-1, Bezier_curve::SHARP ); if ( !smoothFlag ) { for ( i = 0 ; i < surf.get_num_xsecs() ; i++ ) { surf.set_xsec_tan_flag( i, Bezier_curve::SHARP ); } } else // Sharpen End Caps { surf.set_xsec_tan_flag( surf.get_num_xsecs()-2, Bezier_curve::SHARP ); } bezier_surf besurf; surf.load_bezier_surface( &besurf ); int umax = besurf.get_u_max(); int wmax = besurf.get_w_max(); Xsec_surf smooth_surf; smooth_surf.set_num_pnts( (surf.get_num_pnts()-1)*numW + 1 ); smooth_surf.set_num_xsecs( (surf.get_num_xsecs()-1)*numU + 1 ); for ( i = 0 ; i < smooth_surf.get_num_xsecs() ; i++ ) { double fu = (double)i/(double)(smooth_surf.get_num_xsecs()-1); double u = fu*(double)umax; for ( j = 0 ; j < smooth_surf.get_num_pnts() ; j++ ) { double fw = (double)j/(double)(smooth_surf.get_num_pnts()-1); double w = fw*(double)wmax; vec3d p = besurf.comp_pnt( u, w ); smooth_surf.set_pnt( i, j, p ); } } //==== Load Blades into bladeVec ====// for ( int nb = 0 ; nb < (int)bladeVec.size() ; nb++ ) { bladeVec[nb].set_num_pnts( smooth_surf.get_num_pnts() ); bladeVec[nb].set_num_xsecs( smooth_surf.get_num_xsecs() ); //==== Load Points ====// for ( i = 0 ; i < smooth_surf.get_num_xsecs() ; i++ ) for ( j = 0 ; j < smooth_surf.get_num_pnts() ; j++ ) bladeVec[nb].set_pnt( i, j, smooth_surf.get_pnt( i, j ) ); double xang = 360.0*(double)nb/(double)(bladeVec.size()); for ( i = 0 ; i < bladeVec[nb].get_num_xsecs() ; i++ ) { bladeVec[nb].rotate_xsec_z( i, cone_angle() ); bladeVec[nb].rotate_xsec_x( i, xang ); } bladeVec[nb].load_refl_pnts_xsecs(); bladeVec[nb].load_hidden_surf(); bladeVec[nb].load_normals(); bladeVec[nb].load_uw(); } for ( int i = 0 ; i < (int)sectVec.size() ; i++ ) sectVec[i].SetGeomPtr( this ); update_bbox(); }
void ChordLine::layout() { if (!modified) { qreal x2 = 0; qreal y2 = 0; switch(_chordLineType) { case ChordLineType::NOTYPE: break; case ChordLineType::FALL: x2 = _initialLength; y2 = _initialLength; break; case ChordLineType::PLOP: x2 = -_initialLength; y2 = -_initialLength; break; case ChordLineType::SCOOP: x2 = -_initialLength; y2 = _initialLength; break; default: case ChordLineType::DOIT: x2 = _initialLength; y2 = -_initialLength; break; } if (_chordLineType != ChordLineType::NOTYPE) { path = QPainterPath(); // chordlines to the right of the note if (_chordLineType == ChordLineType::FALL || _chordLineType == ChordLineType::DOIT) { if (_straight) path.lineTo(x2, y2); else path.cubicTo(x2/2, 0.0, x2, y2/2, x2, y2); } // chordlines to the left of the note else if (_chordLineType == ChordLineType::PLOP || _chordLineType == ChordLineType::SCOOP) { if (_straight) path.lineTo(x2, y2); else path.cubicTo(0.0, y2/2, x2/2, y2, x2, y2); } } } qreal _spatium = spatium(); if (parent()) { Note* note = chord()->upNote(); QPointF p(note->pos()); // chordlines to the right of the note if (_chordLineType == ChordLineType::FALL || _chordLineType == ChordLineType::DOIT) setPos(p.x() + note->headWidth() + _spatium * .2, p.y()); // chordlines to the left of the note if (_chordLineType == ChordLineType::PLOP) setPos(p.x() + note->headWidth() * .25, p.y() - note->headHeight() * .75); if (_chordLineType == ChordLineType::SCOOP) { qreal x = p.x() + (chord()->up() ? note->headWidth() * .25 : _spatium * -.2); setPos(x, p.y() + note->headHeight() * .75); } } else setPos(0.0, 0.0); QRectF r(path.boundingRect()); int x1, y1, width, height = 0; x1 = r.x() * _spatium; y1 = r.y() * _spatium; width = r.width() * _spatium; height = r.height() * _spatium; bbox().setRect(x1, y1, width, height); }
void LedgerLine::draw(QPainter* painter) const { if(chord()->crossMeasure() == CrossMeasure::SECOND) return; Line::draw(painter); }
QPointF LedgerLine::pagePos() const { System* system = chord()->measure()->system(); qreal yp = y() + system->staff(staffIdx())->y() + system->y(); return QPointF(pageX(), yp); }