* @brief Arc-segment count for the round join between two unit segment directions: the exterior * turn angle bucketed by kFanStep and capped at kFanMax. Pure in the directions, so the * counting and emitting passes derive an identical count without shared state. Zero for a * near-collinear join (no fan). */
| 79 | * near-collinear join (no fan). |
| 80 | */ |
| 81 | static int fanSegments(const QPointF& dIn, const QPointF& dOut) |
| 82 | { |
| 83 | const double dot = std::clamp(dIn.x() * dOut.x() + dIn.y() * dOut.y(), -1.0, 1.0); |
| 84 | const double cross = dIn.x() * dOut.y() - dIn.y() * dOut.x(); |
| 85 | const double phi = std::atan2(std::abs(cross), dot); |
| 86 | return std::clamp(static_cast<int>(std::ceil(phi / kFanStep)), 0, kFanMax); |
| 87 | } |
| 88 | |
| 89 | /** |
| 90 | * @brief Emits a symmetric four-vertex cross-section along unit normal n at half-width hw: feather |