first commit
This commit is contained in:
54
modern-qt/utility/solution/round-angle.cc
Normal file
54
modern-qt/utility/solution/round-angle.cc
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "round-angle.hh"
|
||||
#include <eigen3/Eigen/Dense>
|
||||
|
||||
using namespace creeper;
|
||||
using Eigen::Vector2d, std::numbers::pi;
|
||||
|
||||
static inline auto impl_round_angle_solution(
|
||||
RoundAngleSolution& solution, Vector2d e0, Vector2d e1, Vector2d e2, double radius) -> void {
|
||||
|
||||
// solve the arc origin
|
||||
const auto v1 = Vector2d { e1 - e0 };
|
||||
const auto v2 = Vector2d { e2 - e0 };
|
||||
|
||||
const auto dot = v1.x() * v2.x() + v1.y() * v2.y();
|
||||
const auto det = v1.x() * v2.y() - v1.y() * v2.x();
|
||||
|
||||
const auto angle = std::abs(std::atan2(det, dot));
|
||||
const auto width = radius / std::tan(angle / 2);
|
||||
|
||||
const auto point_begin = Vector2d { e0 + width * v1.normalized() };
|
||||
const auto point_end = Vector2d { e0 + width * v2.normalized() };
|
||||
|
||||
const auto origin = Vector2d { point_begin + radius * v1.unitOrthogonal() };
|
||||
|
||||
solution.start = QPointF { point_begin.x(), point_begin.y() };
|
||||
solution.end = QPointF { point_end.x(), point_end.y() };
|
||||
|
||||
// solve the rect corners
|
||||
const auto v3 = Vector2d { e0 - origin }.normalized();
|
||||
const auto v4 = Vector2d { v3.unitOrthogonal() };
|
||||
const Vector2d corner0 = origin + Vector2d::UnitX() * radius + Vector2d::UnitY() * radius;
|
||||
const Vector2d corner1 = origin - Vector2d::UnitX() * radius - Vector2d::UnitY() * radius;
|
||||
solution.rect = QRectF { QPointF(corner1.x(), corner1.y()), QPointF(corner0.x(), corner0.y()) };
|
||||
|
||||
// solve the arc angle
|
||||
// 角度计算时,注意Qt的系Y的正方向向下,但角度又是从X正方向逆时针开始计算,可谓混乱
|
||||
const auto angle_begin_vector = Vector2d { point_begin - origin };
|
||||
const auto angle_end_vector = Vector2d { point_end - origin };
|
||||
|
||||
const auto angle_end = std::atan2(-angle_end_vector.y(), angle_end_vector.x());
|
||||
|
||||
solution.angle_begin = std::atan2(-angle_begin_vector.y(), angle_begin_vector.x());
|
||||
solution.angle_length = angle_end - solution.angle_begin;
|
||||
|
||||
if (solution.angle_length < -pi) solution.angle_length = 2 * pi + solution.angle_length;
|
||||
|
||||
solution.angle_begin = solution.angle_begin * 180 / pi;
|
||||
solution.angle_length = solution.angle_length * 180 / pi;
|
||||
}
|
||||
|
||||
RoundAngleSolution::RoundAngleSolution(QPointF e0, QPointF e1, QPointF e2, double radius) noexcept {
|
||||
impl_round_angle_solution(
|
||||
*this, Eigen::Vector2d { e0.x(), e0.y() }, { e1.x(), e1.y() }, { e2.x(), e2.y() }, radius);
|
||||
}
|
||||
25
modern-qt/utility/solution/round-angle.hh
Normal file
25
modern-qt/utility/solution/round-angle.hh
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <qpoint.h>
|
||||
#include <qrect.h>
|
||||
|
||||
namespace creeper {
|
||||
|
||||
struct RoundAngleSolution {
|
||||
|
||||
/// @brief 给定原点和端点,按逆时针方向计算圆弧
|
||||
/// @note 圆弧注意按照逆时针算
|
||||
/// @param e0 两切线交点
|
||||
/// @param e1 圆弧起始点切线
|
||||
/// @param e2 圆弧终点切线
|
||||
/// @param radius 半径
|
||||
RoundAngleSolution(QPointF e0, QPointF e1, QPointF e2, double radius) noexcept;
|
||||
|
||||
QRectF rect;
|
||||
QPointF start;
|
||||
QPointF end;
|
||||
double angle_begin;
|
||||
double angle_length;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user