参考:https://blog.csdn.net/weixin_39383896/article/details/99615371
原理:
1、θ为V1、V2的夹角,距离 = Qi到V1、V2的距离
向量PiQi = 向量V1+ 向量V2
V1、V2的长度 = 距离 / sinθ
2、点乘算夹角θ
公式:
cosθ = 向量BA * 向量BC / (BA长度 * BC长度) // BA长度也叫BA的模
// 向量BA
double x1' = x2 - x1;
double y1' = y2 - y1;
// 向量BC
double x2' = x2 - x3;
double y2' = y2 - y3;
// 求线段AB的长度
double d1 = sqrt(x1'*x1' + y1' * y1');
// 求线段BC的长度
double d2 = sqrt(x2'*x2' + y2' * y2');
// 点乘
double ab = x1' * x2' + y1' * y2';
// cosθ = A * B / (|A| * |B|)
double cosA = ab / (d1 * d2);
代码:
QVector<QPointF> calcPoint(const QVector<QPointF> &datas, int sec_dis)
{
QVector<double> x;
QVector<double> y;
int number = datas.size();
if (number < 3)
{
return QVector<QPointF>();
}
for (int i = 0; i < number; ++i)
{
x.append(data[i].x());
y.append(data[i].y());
}
/* b
a--------->b
| θ
A |
V
d----------c
*/
QVector<QPointF> points;
for (int i = 0; i < number; ++i)
{
// 向量A
double x1 = x[i % number] - x[(i - 1 + number) % number];
double y1 = y[i % number] - y[(i - 1 + number) % number];
// 向量B
double x2 = x[i % number] - x[(i + 1)% number];
double y2 = y[i % number] - y[(i + 1)% number];
// 求线段的长度
double d1 = sqrt(x1*x1 + y1 * y1);
double d2 = sqrt(x2*x2 + y2 * y2);
// 点乘
double ab = x1 * x2 + y1 * y2;
// cosθ = A * B / (|A| * |B|)
double cosA = ab / (d1 * d2);
// 求sinA
double sinA;
if (cosA > 0) // 表示夹角0-90度 锐角
{
sinA = sqrt(1 - cosA * cosA);
double dv1 = sec_dis / sinA;
// # 向量V1,V2的坐标
double v1_x = (dv1 / d1) * x1;
double v1_y = (dv1 / d1) * y1;
double v2_x = (dv1 / d2) * x2;
double v2_y = (dv1 / d2) * y2;
double PiQi_x = v1_x + v2_x;
double PiQi_y = v1_y + v2_y;
double Qi_x = PiQi_x + x[i];
double Qi_y = PiQi_y + y[i];
points.append(QPointF(Qi_x, Qi_y));
}
else if(cosA < 0) // 钝角 钝角分为外钝角和 内钝角
{
// 判断凹凸点(叉积)
double P1P3_x = x[(i + 1) % number] - x[i];
double P1P3_y = y[(i + 1) % number] - y[i];
double P1P2_x = x[i] - x[(i - 1) % number];
double P1P2_y = y[i] - y[(i - 1) % number];
double P = (P1P3_y*P1P2_x) - (P1P3_x*P1P2_y);
// 为凹
if (P < 0)
{
sinA = -sqrt(1 - cosA * cosA);
double dv1 = sec_dis / sinA;
double v1_x = (dv1 / d1) * x1;
double v1_y = (dv1 / d1) * y1;
double v2_x = (dv1 / d2) * x2;
double v2_y = (dv1 / d2) * y2;
double PiQi_x = v1_x + v2_x;
double PiQi_y = v1_y + v2_y;
double Qi_x = PiQi_x + x[i];
double Qi_y = PiQi_y + y[i];
points.append(QPointF(Qi_x, Qi_y));
}
else if (P > 0)
{
sinA = -sqrt(1 - cosA * cosA);
double dv1 = -sec_dis / sinA;
double v1_x = (dv1 / d1) * x1;
double v1_y = (dv1 / d1) * y1;
double v2_x = (dv1 / d2) * x2;
double v2_y = (dv1 / d2) * y2;
double PiQi_x = v1_x + v2_x;
double PiQi_y = v1_y + v2_y;
double Qi_x = PiQi_x + x[i];
double Qi_y = PiQi_y + y[i];
points.append(QPointF(Qi_x, Qi_y));
}
else // error
{
return QVector<QPointF>();
}
}
else if(cosA == 0)
{
sinA = 1;
double dv1 = sec_dis / sinA;
double v1_x = (dv1 / d1) * x1;
double v1_y = (dv1 / d1) * y1;
double v2_x = (dv1 / d2) * x2;
double v2_y = (dv1 / d2) * y2;
double PiQi_x = v1_x + v2_x;
double PiQi_y = v1_y + v2_y;
double Qi_x = PiQi_x + x[i];
double Qi_y = PiQi_y + y[i];
points.append(QPointF(Qi_x, Qi_y));
}
}
return points;
}