QPointF RoundCornersCommand::tangentAtEnd( const KoPathSegment &s ) { QList<QPointF> cp = s.controlPoints(); QPointF tn = cp[cp.count()-2] - cp.last(); qreal length = sqrt( tn.x()*tn.x() + tn.y()*tn.y() ); return tn / length; }
QPointF RoundCornersCommand::tangentAtStart(const KoPathSegment &s) { QVector<QPointF> cp = s.controlPoints(); QPointF tn = cp[1] - cp.first(); qreal length = sqrt(tn.x() * tn.x() + tn.y() * tn.y()); return tn / length; }
void KoPathSegmentChangeStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) { m_tool->canvas()->updateCanvas(m_tool->canvas()->snapGuide()->boundingRect()); QPointF snappedPosition = m_tool->canvas()->snapGuide()->snap(mouseLocation, modifiers); m_tool->canvas()->updateCanvas(m_tool->canvas()->snapGuide()->boundingRect()); QPointF localPos = m_path->documentToShape(snappedPosition); if (m_segment.degree() == 1) { // line segment is converted to a curve KoPathSegmentTypeCommand cmd(m_pointData1, KoPathSegmentTypeCommand::Curve); cmd.redo(); } QPointF move1, move2; if (m_segment.degree() == 2) { // interpolate quadratic segment between segment start, mouse position and segment end KoPathSegment ipol = KoPathSegment::interpolate(m_segment.first()->point(), localPos, m_segment.second()->point(), m_segmentParam); if (ipol.isValid()) { move1 = move2 = ipol.controlPoints()[1] - m_segment.controlPoints()[1]; } } else if (m_segment.degree() == 3) { /* * method from inkscape, original method and idea borrowed from Simon Budig * <*****@*****.**> and the GIMP * cf. app/vectors/gimpbezierstroke.c, gimp_bezier_stroke_point_move_relative() * * feel good is an arbitrary parameter that distributes the delta between handles * if t of the drag point is less than 1/6 distance form the endpoint only * the corresponding handle is adjusted. This matches the behavior in GIMP */ const qreal t = m_segmentParam; qreal feel_good; if (t <= 1.0 / 6.0) feel_good = 0; else if (t <= 0.5) feel_good = (pow((6 * t - 1) / 2.0, 3)) / 2; else if (t <= 5.0 / 6.0) feel_good = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5; else feel_good = 1; QPointF lastLocalPos = m_path->documentToShape(m_lastPosition); QPointF delta = localPos - lastLocalPos; move2 = ((1-feel_good)/(3*t*(1-t)*(1-t))) * delta; move1 = (feel_good/(3*t*t*(1-t))) * delta; } m_path->update(); if(m_segment.first()->activeControlPoint2()) { KoPathControlPointMoveCommand cmd(m_pointData1, move2, KoPathPoint::ControlPoint2); cmd.redo(); } if(m_segment.second()->activeControlPoint1()) { KoPathControlPointMoveCommand cmd(m_pointData2, move1, KoPathPoint::ControlPoint1); cmd.redo(); } m_path->normalize(); m_path->update(); m_ctrlPoint1Move += move1; m_ctrlPoint2Move += move2; // save last mouse position m_lastPosition = mouseLocation; }