25 #define _USE_MATH_DEFINES
27 #include <QInputDialog>
32 #include <physical_constants.h>
34 #define SIGN(x) (x < 0 ? -1 : 1)
52 fillet_radius = QInputDialog::getDouble(callingUi, tr(
"Select filleting radius"), tr(
"In m:"),
53 fillet_radius, 0, 1000, 1, &ok);
87 int newWaypointIdx = 0;
93 float previous_curvature;
95 for (
int wpIdx = 0; wpIdx < model->
rowCount(); wpIdx++) {
104 float ModeParameters =
111 case Waypoint::MODE_CIRCLEPOSITIONRIGHT:
113 case Waypoint::MODE_CIRCLERIGHT:
114 curvature = 1.0f / ModeParameters;
116 case Waypoint::MODE_CIRCLEPOSITIONLEFT:
118 case Waypoint::MODE_CIRCLELEFT:
119 curvature = -1.0f / ModeParameters;
125 setNewWaypoint(newWaypointIdx++, pos_current, finalVelocity, curvature);
130 if (fillet_radius > 0 && wpIdx < (model->
rowCount() - 1)) {
134 if (newWaypointIdx > 0) {
146 float previous_radius =
150 previous_curvature = (previous_radius < 1
e-4) ? 0 : 1.0 / previous_radius;
156 previous_curvature = 0;
168 float NextModeParameter =
172 NextModeParameter = 0;
173 bool future_path_is_circle = NextMode == Waypoint::MODE_CIRCLEPOSITIONRIGHT
174 || NextMode == Waypoint::MODE_CIRCLEPOSITIONLEFT;
178 float q_future_mag = 0;
180 float q_current_mag = 0;
185 && (NextModeParameter == 0
186 || future_path_is_circle)) {
192 q_current[0] = pos_current[0] - pos_prev[0];
193 q_current[1] = pos_current[1] - pos_prev[1];
196 q_future[0] = pos_next[0] - pos_current[0];
197 q_future[1] = pos_next[1] - pos_current[1];
200 else if (curvature == 0
201 && (NextModeParameter != 0
202 && !future_path_is_circle)) {
208 q_current[0] = pos_current[0] - pos_prev[0];
209 q_current[1] = pos_current[1] - pos_prev[1];
212 bool clockwise = curvature > 0;
215 if (clockwise ==
true) {
222 float arcCenter_NE[2];
223 find_arc_center(pos_current, pos_next, 1.0f / curvature, arcCenter_NE,
224 curvature > 0,
true);
227 q_future[0] = -lambda * (pos_current[1] - arcCenter_NE[1]);
228 q_future[1] = lambda * (pos_current[0] - arcCenter_NE[0]);
231 else if (curvature != 0
232 && (NextModeParameter == 0
233 || future_path_is_circle)) {
238 bool clockwise = previous_curvature > 0;
242 if ((clockwise ==
true && minor ==
true)
243 || (clockwise ==
false
244 && minor ==
false)) {
251 float arcCenter_NE[2];
252 find_arc_center(pos_prev, pos_current, 1.0f / previous_curvature, arcCenter_NE,
256 q_current[0] = -lambda * (pos_current[1] - arcCenter_NE[1]);
257 q_current[1] = lambda * (pos_current[0] - arcCenter_NE[0]);
260 q_future[0] = pos_next[0] - pos_current[0];
261 q_future[1] = pos_next[1] - pos_current[1];
265 else if (curvature != 0
266 && (NextModeParameter != 0
267 && !future_path_is_circle)) {
273 bool clockwise = previous_curvature > 0;
277 if ((clockwise ==
true && minor ==
true)
278 || (clockwise ==
false
279 && minor ==
false)) {
286 float arcCenter_NE[2];
287 find_arc_center(pos_prev, pos_current, 1.0f / previous_curvature, arcCenter_NE,
291 q_current[0] = -lambda * (pos_prev[1] - arcCenter_NE[1]);
292 q_current[1] = lambda * (pos_prev[0] - arcCenter_NE[0]);
301 find_arc_center(pos_current, pos_next, 1.0f / curvature, arcCenter_NE,
302 curvature > 0,
true);
305 q_future[0] = -lambda * (pos_current[1] - arcCenter_NE[1]);
306 q_future[1] = lambda * (pos_current[0] - arcCenter_NE[0]);
310 q_current_mag = VectorMagnitude(q_current);
312 q_future_mag = VectorMagnitude(q_future);
315 if (q_current_mag > 0) {
316 for (
int i = 0;
i < 3;
i++)
317 q_current[
i] = q_current[
i] / q_current_mag;
319 if (q_future_mag > 0) {
320 for (
int i = 0;
i < 3;
i++)
321 q_future[
i] = q_future[
i] / q_future_mag;
325 float theta = angle_between_2d_vectors(q_current, q_future);
328 float rho = circular_modulus_rad(theta - M_PI);
331 float rho2 = rho / 2.0f;
334 if (fabsf(rho) < M_PI / 3.0f) {
335 float R = fillet_radius;
336 if (q_current_mag > 0 && q_current_mag < R * sqrtf(3))
337 R = q_current_mag / sqrtf(3)
339 if (q_future_mag > 0 && q_future_mag < R * sqrtf(3))
340 R = q_future_mag / sqrtf(3)
347 float f1[3] = { pos_current[0] - R * q_current[0] * sqrtf(3),
348 pos_current[1] - R * q_current[1] * sqrtf(3), pos_current[2] };
349 float f2[3] = { pos_current[0] + R * q_future[0] * sqrtf(3),
350 pos_current[1] + R * q_future[1] * sqrtf(3), pos_current[2] };
354 addNonCircleToSwitchingLoci(f1, finalVelocity, curvature, newWaypointIdx);
356 float gamma = atan2f(q_current[1], q_current[0]);
365 eta = gamma - M_PI / 2.0f;
366 sigma = gamma + theta - M_PI / 2.0f;
368 eta = gamma + M_PI / 2.0f;
369 sigma = gamma + theta + M_PI / 2.0f;
373 float pos[3] = { (pos_current[0] + f1[0] + R * cosf(eta)) / 2,
374 (pos_current[1] + f1[1] + R * sinf(eta)) / 2, pos_current[2] };
375 setNewWaypoint(newWaypointIdx++, pos, finalVelocity, -SIGN(theta) * 1.0f / R);
378 pos[0] = pos_current[0] + R * cosf(gamma);
379 pos[1] = pos_current[1] + R * sinf(gamma);
380 pos[2] = pos_current[2];
381 setNewWaypoint(newWaypointIdx++, pos, finalVelocity, SIGN(theta) * 1.0f / R);
384 pos[0] = (pos_current[0] + (f2[0] + R * cosf(sigma))) / 2;
385 pos[1] = (pos_current[1] + (f2[1] + R * sinf(sigma))) / 2;
386 pos[2] = pos_current[2];
387 setNewWaypoint(newWaypointIdx++, pos, finalVelocity, SIGN(theta) * 1.0f / R);
392 pos[2] = pos_current[2];
393 setNewWaypoint(newWaypointIdx++, pos, finalVelocity, -SIGN(theta) * 1.0f / R);
394 }
else if (theta != 0) {
395 float R = fillet_radius;
399 if (q_current_mag > 0 && q_current_mag < fabsf(R / tanf(rho2)))
400 R = qMin(R, q_current_mag * fabsf(tanf(rho2)) - 0.1f);
401 if (q_future_mag > 0 && q_future_mag < fabsf(R / tanf(rho2)))
402 R = qMin(R, q_future_mag * fabsf(tanf(rho2)) - 0.1f);
406 f1[0] = pos_current[0] - R / fabsf(tanf(rho2)) * q_current[0];
407 f1[1] = pos_current[1] - R / fabsf(tanf(rho2)) * q_current[1];
408 f1[2] = pos_current[2];
410 addNonCircleToSwitchingLoci(f1, finalVelocity, curvature, newWaypointIdx);
413 float pos[3] = { pos_current[0] + R / fabsf(tanf(rho2)) * q_future[0],
414 pos_current[1] + R / fabsf(tanf(rho2)) * q_future[1],
416 setNewWaypoint(newWaypointIdx++, pos, finalVelocity, SIGN(theta) * 1.0f / R);
420 newWaypointIdx += addNonCircleToSwitchingLoci(pos_current, finalVelocity, curvature,
423 }
else if (wpIdx == model->
rowCount() - 1)
426 addNonCircleToSwitchingLoci(pos_current, finalVelocity, curvature, newWaypointIdx);
444 void PathFillet::setNewWaypoint(
int index,
float *pos,
float velocity,
float curvature)
446 if (index >= new_model->
rowCount() - 1)
447 new_model->insertRow(index);
450 quint8 mode = Waypoint::MODE_VECTOR;
452 if (curvature > 0 && !std::isinf(curvature)) {
453 mode = Waypoint::MODE_CIRCLERIGHT;
454 radius = 1.0 / curvature;
455 }
else if (curvature < 0 && !std::isinf(curvature)) {
456 mode = Waypoint::MODE_CIRCLELEFT;
457 radius = -1.0 / curvature;
478 int PathFillet::addNonCircleToSwitchingLoci(
float position[3],
float finalVelocity,
float curvature,
481 setNewWaypoint(index, position, finalVelocity, curvature);
487 float PathFillet::VectorMagnitude(
float *v)
489 return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
493 double PathFillet::VectorMagnitude(
double *v)
495 return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
505 float PathFillet::circular_modulus_rad(
float err)
507 float val = fmodf(err + M_PI, 2 * M_PI);
532 enum PathFillet::arc_center_results PathFillet::find_arc_center(
float start_point[2],
533 float end_point[2],
float radius,
534 float center[2],
bool clockwise,
538 if (fabsf(start_point[0] - end_point[0]) < 1
e-6
539 && fabsf(start_point[1] - end_point[1]) < 1
e-6) {
544 return COINCIDENT_POINTS;
547 float m_n, m_e, p_n, p_e, d, d2;
550 m_n = (start_point[0] + end_point[0]) / 2;
551 m_e = (start_point[1] + end_point[1]) / 2;
554 if ((clockwise ==
true && minor ==
true)
555 || (clockwise ==
false && minor ==
false)) {
556 p_n = -(end_point[1] - start_point[1]);
557 p_e = (end_point[0] - start_point[0]);
559 p_n = (end_point[1] - start_point[1]);
560 p_e = -(end_point[0] - start_point[0]);
564 d2 = radius * radius / (p_n * p_n + p_e * p_e) - 0.25f;
566 if (d2 > -powf(radius * 0.01f, 2))
571 return INSUFFICIENT_RADIUS;
578 if (fabsf(p_n) < 1
e-3 && fabsf(p_e) < 1
e-3) {
582 center[0] = m_n + p_n * d;
583 center[1] = m_e + p_e * d;
596 float PathFillet::measure_arc_rad(
float oldPosition_NE[2],
float newPosition_NE[2],
597 float arcCenter_NE[2])
599 float a[2] = { oldPosition_NE[0] - arcCenter_NE[0], oldPosition_NE[1] - arcCenter_NE[1] };
600 float b[2] = { newPosition_NE[0] - arcCenter_NE[0], newPosition_NE[1] - arcCenter_NE[1] };
602 float theta = angle_between_2d_vectors(a, b);
613 float PathFillet::angle_between_2d_vectors(
float a[2],
float b[2])
623 float theta = atan2f(a[0] * b[1] - a[1] * b[0], (a[0] * b[0] + a[1] * b[1]));
int rowCount(const QModelIndex &parent=QModelIndex()) const
Return the number of waypoints.
PathFillet(QObject *parent=nullptr)
bool replaceData(FlightDataModel *newModel)
Replace a model data with another model.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
FlightDataModel::setData Set the data at a given location.
virtual bool configure(QWidget *callingUi=nullptr)
virtual bool processPath(FlightDataModel *model)
Algorithm to add filtets to path.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
FlightDataModel::data Fetch the data from the model.
virtual bool verifyPath(FlightDataModel *model, QString &err)