diff --git a/radio/src/curves.cpp b/radio/src/curves.cpp index df190584a..089192c0c 100644 --- a/radio/src/curves.cpp +++ b/radio/src/curves.cpp @@ -25,8 +25,26 @@ #include "libopenui.h" #endif +constexpr int DEFAULT_POINTS = 5; +constexpr int STD_CURVE_POINTS(int p) { return p + DEFAULT_POINTS; } +constexpr int CUSTOM_CURVE_POINTS(int p) { return 2 * p + (2 * DEFAULT_POINTS - 2); } + int8_t * curveEnd[MAX_CURVES]; +uint8_t getCurvePoints(uint8_t index) +{ + if (index >= MAX_CURVES) + return 0; + + const auto& curve = g_model.curves[index]; + if (curve.type == CURVE_TYPE_STANDARD) + return STD_CURVE_POINTS(curve.points); + else if (curve.type == CURVE_TYPE_CUSTOM) + return CUSTOM_CURVE_POINTS(curve.points); + + return 0; +} + void loadCurves() { bool showWarning= false; @@ -34,15 +52,15 @@ void loadCurves() for (int i=0; i g_model.points + sizeof(g_model.points)) { @@ -73,13 +109,8 @@ bool moveCurve(uint8_t index, int8_t shift) return false; } - int8_t * nextCrv = curveAddress(index+1); - memmove(nextCrv+shift, nextCrv, 5*(MAX_CURVES-index-1)+curveEnd[MAX_CURVES-1]-curveEnd[index]); - if (shift < 0) memclear(&g_model.points[MAX_CURVE_POINTS-1] + shift, -shift); - while (index= MAX_CURVES) + return; + CurveHeader * curve = &g_model.curves[index]; - int8_t * points = curveAddress(index); + int8_t * curvePoints = curveAddress(index); - memclear(points, 5 + curve->points); - - if (curve->type == CURVE_TYPE_CUSTOM) - resetCustomCurveX(points, 5 + curve->points); + uint8_t nPoints = getCurvePoints(index); + memclear(curvePoints, nPoints); memclear(curve, sizeof(CurveHeader)); + uint8_t newPoints = getCurvePoints(index); + + int8_t shift = newPoints - nPoints; + if (shift != 0) { + curveMove_unsafe(index, shift); + } } void curveMirror(uint8_t index) { + if (index >= MAX_CURVES) + return; + CurveHeader & curve = g_model.curves[index]; int8_t * points = curveAddress(index); - for (int i = 0; i < 5 + curve.points; i++) + // we only mirror Y axis: X axis does not change + for (int i = 0; i < STD_CURVE_POINTS(curve.points); i++) points[i] = -points[i]; } bool isCurveUsed(uint8_t index) { - return !is_memclear(&g_model.curves[index], sizeof(CurveHeader)) || !is_memclear(curveAddress(index), 5); + return !is_memclear(&g_model.curves[index], sizeof(CurveHeader)) || + !is_memclear(curveAddress(index), DEFAULT_POINTS); } -#define CUSTOM_POINT_X(points, count, idx) ((idx)==0 ? -100 : (((idx)==(count)-1) ? 100 : points[(count)+(idx)-1])) -int32_t compute_tangent(CurveHeader * crv, const int8_t * points, int i) +#define CUSTOM_POINT_X(points, count, idx) \ + ((idx) == 0 ? -100 : (((idx) == (count)-1) ? 100 : points[(count) + (idx)-1])) + +int32_t compute_tangent(CurveHeader* crv, const int8_t* points, int i) { - int32_t m=0; - uint8_t num_points = crv->points + 5; - #define MMULT 1024 - if (i == 0) { - //linear interpolation between 1st 2 points - //keep 3 decimal-places for m - if (crv->type == CURVE_TYPE_CUSTOM) { - int8_t x0 = CUSTOM_POINT_X(points, num_points, 0); - int8_t x1 = CUSTOM_POINT_X(points, num_points, 1); - if (x1 > x0) m = (MMULT * (points[1] - points[0])) / (x1 - x0); - } - else { - int32_t delta = (2 * 100) / (num_points - 1); - m = (MMULT * (points[1] - points[0])) / delta; - } + int32_t m = 0; + uint8_t num_points = STD_CURVE_POINTS(crv->points); +#define MMULT 1024 + if (i == 0) { + // linear interpolation between 1st 2 points + // keep 3 decimal-places for m + if (crv->type == CURVE_TYPE_CUSTOM) { + int8_t x0 = CUSTOM_POINT_X(points, num_points, 0); + int8_t x1 = CUSTOM_POINT_X(points, num_points, 1); + if (x1 > x0) m = (MMULT * (points[1] - points[0])) / (x1 - x0); + } else { + int32_t delta = (2 * 100) / (num_points - 1); + m = (MMULT * (points[1] - points[0])) / delta; } - else if (i == num_points - 1) { - //linear interpolation between last 2 points - //keep 3 decimal-places for m - if (crv->type == CURVE_TYPE_CUSTOM) { - int8_t x0 = CUSTOM_POINT_X(points, num_points, num_points-2); - int8_t x1 = CUSTOM_POINT_X(points, num_points, num_points-1); - if (x1 > x0) m = (MMULT * (points[num_points-1] - points[num_points-2])) / (x1 - x0); - } - else { - int32_t delta = (2 * 100) / (num_points - 1); - m = (MMULT * (points[num_points-1] - points[num_points-2])) / delta; - } + } else if (i == num_points - 1) { + // linear interpolation between last 2 points + // keep 3 decimal-places for m + if (crv->type == CURVE_TYPE_CUSTOM) { + int8_t x0 = CUSTOM_POINT_X(points, num_points, num_points - 2); + int8_t x1 = CUSTOM_POINT_X(points, num_points, num_points - 1); + if (x1 > x0) + m = (MMULT * (points[num_points - 1] - points[num_points - 2])) / + (x1 - x0); + } else { + int32_t delta = (2 * 100) / (num_points - 1); + m = (MMULT * (points[num_points - 1] - points[num_points - 2])) / delta; } - else { - //apply monotone rules from - //http://en.wikipedia.org/wiki/Monotone_cubic_interpolation - //1) compute slopes of secant lines - int32_t d0=0, d1=0; - if (crv->type == CURVE_TYPE_CUSTOM) { - int8_t x0 = CUSTOM_POINT_X(points, num_points, i-1); - int8_t x1 = CUSTOM_POINT_X(points, num_points, i); - int8_t x2 = CUSTOM_POINT_X(points, num_points, i+1); - if (x1 > x0) d0 = (MMULT * (points[i] - points[i-1])) / (x1 - x0); - if (x2 > x1) d1 = (MMULT * (points[i+1] - points[i])) / (x2 - x1); - } - else { - int32_t delta = (2 * 100) / (num_points - 1); - d0 = (MMULT * (points[i] - points[i-1])) / (delta); - d1 = (MMULT * (points[i+1] - points[i])) / (delta); - } - //2) compute initial average tangent - m = (d0 + d1) / 2; - //3 check for horizontal lines - if (d0 == 0 || d1 == 0 || (d0 > 0 && d1 < 0) || (d0 < 0 && d1 > 0)) { - m = 0; - } - else if (MMULT * m / d0 > 3 * MMULT) { - m = 3 * d0; - } - else if (MMULT * m / d1 > 3 * MMULT) { - m = 3 * d1; - } + } else { + // apply monotone rules from + // http://en.wikipedia.org/wiki/Monotone_cubic_interpolation + // 1) compute slopes of secant lines + int32_t d0 = 0, d1 = 0; + if (crv->type == CURVE_TYPE_CUSTOM) { + int8_t x0 = CUSTOM_POINT_X(points, num_points, i - 1); + int8_t x1 = CUSTOM_POINT_X(points, num_points, i); + int8_t x2 = CUSTOM_POINT_X(points, num_points, i + 1); + if (x1 > x0) d0 = (MMULT * (points[i] - points[i - 1])) / (x1 - x0); + if (x2 > x1) d1 = (MMULT * (points[i + 1] - points[i])) / (x2 - x1); + } else { + int32_t delta = (2 * 100) / (num_points - 1); + d0 = (MMULT * (points[i] - points[i - 1])) / (delta); + d1 = (MMULT * (points[i + 1] - points[i])) / (delta); } - return m; + // 2) compute initial average tangent + m = (d0 + d1) / 2; + // 3 check for horizontal lines + if (d0 == 0 || d1 == 0 || (d0 > 0 && d1 < 0) || (d0 < 0 && d1 > 0)) { + m = 0; + } else if (MMULT * m / d0 > 3 * MMULT) { + m = 3 * d0; + } else if (MMULT * m / d1 > 3 * MMULT) { + m = 3 * d1; + } + } + return m; } /* The following is a hermite cubic spline. @@ -197,7 +237,7 @@ int16_t hermite_spline(int16_t x, uint8_t idx) { CurveHeader &crv = g_model.curves[idx]; int8_t *points = curveAddress(idx); - uint8_t count = crv.points+5; + uint8_t count = STD_CURVE_POINTS(crv.points); bool custom = (crv.type == CURVE_TYPE_CUSTOM); if (x < -RESX) @@ -240,37 +280,37 @@ int16_t hermite_spline(int16_t x, uint8_t idx) int intpol(int x, uint8_t idx) // -100, -75, -50, -25, 0 ,25 ,50, 75, 100 { - CurveHeader & crv = g_model.curves[idx]; - int8_t * points = curveAddress(idx); - uint8_t count = crv.points+5; + CurveHeader& crv = g_model.curves[idx]; + int8_t* points = curveAddress(idx); + uint8_t count = STD_CURVE_POINTS(crv.points); bool custom = (crv.type == CURVE_TYPE_CUSTOM); int16_t erg; x += RESXu; if (x <= 0) { - erg = (int16_t)points[0] * (RESX/4); - } - else if (x >= (RESX*2)) { - erg = (int16_t)points[count-1] * (RESX/4); - } - else { - uint16_t a=0, b=0; + erg = (int16_t)points[0] * (RESX / 4); + } else if (x >= (RESX * 2)) { + erg = (int16_t)points[count - 1] * (RESX / 4); + } else { + uint16_t a = 0, b = 0; uint8_t i; if (custom) { - for (i=0; i 0 && index < count - 1) { result.x = calc100toRESX(points[count + index - 1]); diff --git a/radio/src/curves.h b/radio/src/curves.h index dad374cd2..4e209e4f5 100644 --- a/radio/src/curves.h +++ b/radio/src/curves.h @@ -33,7 +33,7 @@ enum BaseCurves { CURVE_BASE }; -void curveReset(uint8_t index); +void curveClear(uint8_t index); void curveMirror(uint8_t index); bool isCurveUsed(uint8_t index); void loadCurves(); diff --git a/radio/src/gui/128x64/model_curve_edit.cpp b/radio/src/gui/128x64/model_curve_edit.cpp index 5b510890e..2043a79d0 100644 --- a/radio/src/gui/128x64/model_curve_edit.cpp +++ b/radio/src/gui/128x64/model_curve_edit.cpp @@ -72,19 +72,12 @@ void onCurveOneMenu(const char * result) POPUP_INPUT(STR_PRESET, runPopupCurvePreset); } else if (result == STR_MIRROR) { - CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; - int8_t * points = curveAddress(s_currIdxSubMenu); - for (int i=0; i<5+crv.points; i++) - points[i] = -points[i]; + curveMirror(s_currIdxSubMenu); + storageDirty(EE_MODEL); } else if (result == STR_CLEAR) { - CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; - int8_t * points = curveAddress(s_currIdxSubMenu); - for (int i=0; i<5+crv.points; i++) - points[i] = 0; - if (crv.type == CURVE_TYPE_CUSTOM) { - resetCustomCurveX(points, 5+crv.points); - } + curveClear(s_currIdxSubMenu); + storageDirty(EE_MODEL); } } diff --git a/radio/src/gui/212x64/model_curve_edit.cpp b/radio/src/gui/212x64/model_curve_edit.cpp index 7908b7010..da67ba7f8 100644 --- a/radio/src/gui/212x64/model_curve_edit.cpp +++ b/radio/src/gui/212x64/model_curve_edit.cpp @@ -74,19 +74,12 @@ void onCurveOneMenu(const char * result) POPUP_INPUT(STR_PRESET, runPopupCurvePreset); } else if (result == STR_MIRROR) { - CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; - int8_t * points = curveAddress(s_currIdxSubMenu); - for (int i=0; i<5+crv.points; i++) - points[i] = -points[i]; + curveMirror(s_currIdxSubMenu); + storageDirty(EE_MODEL); } else if (result == STR_CLEAR) { - CurveHeader & crv = g_model.curves[s_currIdxSubMenu]; - int8_t * points = curveAddress(s_currIdxSubMenu); - for (int i=0; i<5+crv.points; i++) - points[i] = 0; - if (crv.type == CURVE_TYPE_CUSTOM) { - resetCustomCurveX(points, 5+crv.points); - } + curveClear(s_currIdxSubMenu); + storageDirty(EE_MODEL); } } diff --git a/radio/src/gui/colorlcd/model_curves.cpp b/radio/src/gui/colorlcd/model_curves.cpp index 938086718..d66655477 100644 --- a/radio/src/gui/colorlcd/model_curves.cpp +++ b/radio/src/gui/colorlcd/model_curves.cpp @@ -361,7 +361,7 @@ void ModelCurvesPage::build(FormWindow * window, int8_t focusIndex) button->invalidate(); }); menu->addLine(STR_CLEAR, [=]() { - curveReset(index); + curveClear(index); storageDirty(EE_MODEL); rebuild(window, index); });