! \internal If \ref setTangentToData is enabled, brackets need to be rotated according to the data slope. This method returns the angle in radians by which a bracket at the given \a dataIndex must be rotated. The parameter \a direction must be set to either -1 or 1, representing whether it is an opening or closing bracket. Since for slope calculation multiple data points are requir
| 16623 | \a interface1d is the interface to the plottable's data which is used to query data coordinates. |
| 16624 | */ |
| 16625 | double QCPSelectionDecoratorBracket::getTangentAngle(const QCPPlottableInterface1D *interface1d, int dataIndex, int direction) const |
| 16626 | { |
| 16627 | if (!interface1d || dataIndex < 0 || dataIndex >= interface1d->dataCount()) |
| 16628 | return 0; |
| 16629 | direction = direction < 0 ? -1 : 1; // enforce direction is either -1 or 1 |
| 16630 | |
| 16631 | // how many steps we can actually go from index in the given direction without exceeding data bounds: |
| 16632 | int averageCount; |
| 16633 | if (direction < 0) |
| 16634 | averageCount = qMin(mTangentAverage, dataIndex); |
| 16635 | else |
| 16636 | averageCount = qMin(mTangentAverage, interface1d->dataCount()-1-dataIndex); |
| 16637 | qDebug() << averageCount; |
| 16638 | // calculate point average of averageCount points: |
| 16639 | QVector<QPointF> points(averageCount); |
| 16640 | QPointF pointsAverage; |
| 16641 | int currentIndex = dataIndex; |
| 16642 | for (int i=0; i<averageCount; ++i) |
| 16643 | { |
| 16644 | points[i] = getPixelCoordinates(interface1d, currentIndex); |
| 16645 | pointsAverage += points[i]; |
| 16646 | currentIndex += direction; |
| 16647 | } |
| 16648 | pointsAverage /= (double)averageCount; |
| 16649 | |
| 16650 | // calculate slope of linear regression through points: |
| 16651 | double numSum = 0; |
| 16652 | double denomSum = 0; |
| 16653 | for (int i=0; i<averageCount; ++i) |
| 16654 | { |
| 16655 | const double dx = points.at(i).x()-pointsAverage.x(); |
| 16656 | const double dy = points.at(i).y()-pointsAverage.y(); |
| 16657 | numSum += dx*dy; |
| 16658 | denomSum += dx*dx; |
| 16659 | } |
| 16660 | if (!qFuzzyIsNull(denomSum) && !qFuzzyIsNull(numSum)) |
| 16661 | { |
| 16662 | return qAtan2(numSum, denomSum); |
| 16663 | } else // undetermined angle, probably mTangentAverage == 1, so using only one data point |
| 16664 | return 0; |
| 16665 | } |
| 16666 | |
| 16667 | /*! \internal |
| 16668 |