! \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
| 17359 | \a interface1d is the interface to the plottable's data which is used to query data coordinates. |
| 17360 | */ |
| 17361 | double QCPSelectionDecoratorBracket::getTangentAngle(const QCPPlottableInterface1D *interface1d, int dataIndex, int direction) const |
| 17362 | { |
| 17363 | if (!interface1d || dataIndex < 0 || dataIndex >= interface1d->dataCount()) |
| 17364 | return 0; |
| 17365 | direction = direction < 0 ? -1 : 1; // enforce direction is either -1 or 1 |
| 17366 | |
| 17367 | // how many steps we can actually go from index in the given direction without exceeding data bounds: |
| 17368 | int averageCount; |
| 17369 | if (direction < 0) |
| 17370 | averageCount = qMin(mTangentAverage, dataIndex); |
| 17371 | else |
| 17372 | averageCount = qMin(mTangentAverage, interface1d->dataCount()-1-dataIndex); |
| 17373 | qDebug() << averageCount; |
| 17374 | // calculate point average of averageCount points: |
| 17375 | QVector<QPointF> points(averageCount); |
| 17376 | QPointF pointsAverage; |
| 17377 | int currentIndex = dataIndex; |
| 17378 | for (int i=0; i<averageCount; ++i) |
| 17379 | { |
| 17380 | points[i] = getPixelCoordinates(interface1d, currentIndex); |
| 17381 | pointsAverage += points[i]; |
| 17382 | currentIndex += direction; |
| 17383 | } |
| 17384 | pointsAverage /= double(averageCount); |
| 17385 | |
| 17386 | // calculate slope of linear regression through points: |
| 17387 | double numSum = 0; |
| 17388 | double denomSum = 0; |
| 17389 | for (int i=0; i<averageCount; ++i) |
| 17390 | { |
| 17391 | const double dx = points.at(i).x()-pointsAverage.x(); |
| 17392 | const double dy = points.at(i).y()-pointsAverage.y(); |
| 17393 | numSum += dx*dy; |
| 17394 | denomSum += dx*dx; |
| 17395 | } |
| 17396 | if (!qFuzzyIsNull(denomSum) && !qFuzzyIsNull(numSum)) |
| 17397 | { |
| 17398 | return qAtan2(numSum, denomSum); |
| 17399 | } else // undetermined angle, probably mTangentAverage == 1, so using only one data point |
| 17400 | return 0; |
| 17401 | } |
| 17402 | |
| 17403 | /*! \internal |
| 17404 |