From aa70c34a963e3a0446907d4eb0228f0b1d8ce6fa Mon Sep 17 00:00:00 2001 From: Ulrich Meine Date: Sun, 8 Jun 2025 13:45:20 +0200 Subject: [PATCH] Fix getMin/Max + wndCenter rounding; --- lib/obp60task/PageWindPlot.cpp | 205 +++++++++++++++++++++++---------- 1 file changed, 141 insertions(+), 64 deletions(-) diff --git a/lib/obp60task/PageWindPlot.cpp b/lib/obp60task/PageWindPlot.cpp index 383bbc2..5f13f52 100644 --- a/lib/obp60task/PageWindPlot.cpp +++ b/lib/obp60task/PageWindPlot.cpp @@ -6,8 +6,8 @@ #include -class CircularBuffer { - // provides a circular buffer to store wind history values +class wndHistory { + // provides a FiFo circular buffer to store wind history values private: int SIZE; std::vector buffer; @@ -30,6 +30,9 @@ public: void add(int value) // Add a new value { + if (value > 180) { + value -= 360; // Normalize value to -180..180 to make min/max calculations working + } buffer[head] = value; head = (head + 1) % SIZE; if (count < SIZE) { @@ -40,7 +43,7 @@ public: } int get(int index) const - // Get value by index (0 = oldest, count-1 = newest) + // Get value by index in [-180..180 deg] format (0 = oldest, count-1 = newest) { int realIndex; @@ -49,14 +52,77 @@ public: } realIndex = (first + index) % SIZE; return buffer[realIndex]; + // } } - int size() const + int get(int index, int deg) const + // Get value by index in [-180..180 deg] or [0..360 deg] format (0 = oldest, count-1 = newest) + { + switch (deg) { + case 180: + // Return value in [-180..180 deg] format + return get(index); + case 360: { + // Return value in [0..360 deg] format + int value = get(index); + if (value < 0) { + value += 360; + }; + return value; + } + default: + // Return value in [-180..180 deg] format + return -1; + } + } + + int getSize() const // Get number of valid elements { return count; } + int getMin() const + // Get minimum value in the buffer + { + if (count == 0) { + return -1; // Buffer is empty + } else if (first + count <= SIZE) { + // No wrap-around + return *std::min_element(buffer.begin() + first, buffer.begin() + first + count); + } else { + // Wrap-around: check [first, end) and [begin, (first+count)%SIZE) + int min1 = *std::min_element(buffer.begin() + first, buffer.end()); + int min2 = *std::min_element(buffer.begin(), buffer.begin() + ((first + count) % SIZE)); + return std::min(min1, min2); + } + } + + int getMax() const + // Get maximum value in the buffer + { + if (count == 0) { + return -1; // Buffer is empty + } else if (first + count <= SIZE) { + // No wrap-around + return *std::max_element(buffer.begin() + first, buffer.begin() + first + count); + } else { + // Wrap-around: check [first, end) and [begin, (first+count)%SIZE) + int max1 = *std::max_element(buffer.begin() + first, buffer.end()); + int max2 = *std::max_element(buffer.begin(), buffer.begin() + ((first + count) % SIZE)); + return std::max(max1, max2); + } + } + + int getMid() const + // Get middle value in the buffer + { + if (count == 0) { + return -1; // Buffer is empty + } + return (getMin() + getMax()) / 2; + } + void mvStart(int start) // Move the start index of buffer forward by positions { @@ -105,7 +171,8 @@ public: int width = getdisplay().width(); // Get screen width int height = getdisplay().height(); // Get screen height - int cHeight = height - 98; // height of chart area + // int cHeight = height - 98; // height of chart area + int cHeight = 80; // height of chart area int xCenter = width / 2; // Center of screen in x direction static const int yOffset = 76; // Offset for y coordinates of chart area static const float radToDeg = 180.0 / M_PI; // Conversion factor from radians to degrees @@ -115,6 +182,7 @@ public: static int wndRight; // chart wind right value position static int chrtRng; // Range of wind values from mid wind value to min/max wind value in degrees int diffRng; // Difference between mid and current wind value + static bool plotShift = false; // Flag to indicate if chartplot data have been shifted int x, y; // x and y coordinates for drawing static int lastX, lastY; // Last x and y coordinates for drawing @@ -123,8 +191,8 @@ public: int count; // index for next wind value in buffer // Circular buffer to store wind values - static CircularBuffer windValues; - if (windValues.size() == 0) { + static wndHistory windValues; + if (windValues.getSize() == 0) { if (!windValues.begin(cHeight)) { // buffer holds as many values as the height of the chart area // if (!windValues.begin(60)) { // buffer holds as many values as the height of the chart area logger->logDebug(GwLog::ERROR, "Failed to initialize wind values buffer"); @@ -174,55 +242,47 @@ public: dataValid[i] = bvalue->valid; dataSValue[i] = formatValue(bvalue, *commonData).svalue; // Formatted value as string including unit conversion and switching decimal places dataUnit[i] = formatValue(bvalue, *commonData).unit; - // dataFormat[i] = bvalue->getFormat(); // Unit of value if (dataValid[i]) { dataSValueOld[i] = dataSValue[i]; // Save old value dataUnitOld[i] = dataUnit[i]; // Save old unit } } - // Store TWD wind value in buffer - windValues.add(int((dataValue[0] * radToDeg) + 0.5)); // Store TWD value (degree) in buffer (rounded to integer) - count = windValues.size(); // Get number of valid elements in buffer; maximum is cHeight - - // specify and check chart border values - if (wndCenter == -400) { - wndCenter = windValues.get(0); - chrtRng = 20; - wndLeft = wndCenter - chrtRng; - if (wndLeft < 0) - wndLeft += 360; - wndRight = wndCenter + chrtRng; - if (wndRight >= 360) - wndRight -= 360; - LOG_DEBUG(GwLog::LOG, "PageWindPlot: wndCenter + chrtRng initialized"); - } - diffRng = abs(windValues.get(count - 1) - wndCenter); - if (diffRng > chrtRng) { - chrtRng = int(ceil(diffRng / 10.0) * 10); // Round to next 10 degree value - wndLeft = wndCenter - chrtRng; - if (wndLeft < 0) - wndLeft += 360; - wndRight = wndCenter + chrtRng; - if (wndRight >= 360) - wndRight -= 360; - } - LOG_DEBUG(GwLog::LOG, "PageWindPlot dataValue[0]: %f, windValue: %d, count: %d, Range: %d, ChartRng: %d", float(dataValue[0] * radToDeg), windValues.get(count - 1), count, diffRng, chrtRng); - - // was, wenn alle Werte kleiner als current wind range sind? - // passe wndCenter an, wenn chrtRng > std und alle Werte > oder < wndCenter sind - // Optical warning by limit violation (unused) if (String(flashLED) == "Limit Violation") { setBlinkingLED(false); setFlashLED(false); } - // Logging boat values - if (bvalue == NULL) - return; - // LOG_DEBUG(GwLog::LOG, "PageWindPlot, %s:%f, %s:%f, %s:%f, %s:%f, %s:%f, cnt: %d, wind: %f", dataName[0].c_str(), dataValue[0], name2.c_str(), - // value2, name3.c_str(), value3, name4.c_str(), value4, name5.c_str(), value5, count, windValues.get(count - 1)); + // Store TWD wind value in buffer + windValues.add(int((dataValue[0] * radToDeg) + 0.5)); // Store TWD value (degree) in buffer (rounded to integer) + count = windValues.getSize(); // Get number of valid elements in buffer; maximum is cHeight + + // initialize chart range values + if (wndCenter == -400) { + wndCenter = windValues.get(0); + wndCenter = int((wndCenter + (wndCenter >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value +// wndCenter = int((windValues.get(0) + 5) / 10) * 10; // Round to nearest 10 degree value + diffRng = 30; + chrtRng = 30; + LOG_DEBUG(GwLog::LOG, "PageWindPlot initialized. wndCenter: %d, chrtRng: %d ", wndCenter, chrtRng); + } else { + diffRng = max(abs(((windValues.getMax() - wndCenter + 540) % 360) - 180), abs(((windValues.getMin() - wndCenter + 540) % 360) - 180)); // check necessary range size + if (diffRng > chrtRng) { + chrtRng = int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10; // Round up to next 10 degree value +// chrtRng = int(ceil(diffRng / 10.0) * 10); // Round to next 10 degree value + } else if (diffRng + 10 < chrtRng) { + chrtRng = max(30, int((diffRng + (diffRng >= 0 ? 9 : -1)) / 10) * 10); // Round up to next 10 degree value +// chrtRng = max(30, int(ceil(diffRng / 10.0) * 10)); // Round to next 10 degree value, but mimimum range is 30 degrees + } + } + wndLeft = wndCenter - chrtRng; + if (wndLeft < -180) + wndLeft += 360; + wndRight = wndCenter + chrtRng; + if (wndRight >= 180) + wndRight -= 360; + LOG_DEBUG(GwLog::LOG, "PageWindPlot dataValue[0]: %f, windValue: %d, count: %d, diffRng: %d, chartRng: %d", float(dataValue[0] * radToDeg), windValues.get(count - 1), count, diffRng, chrtRng); // Draw page //*********************************************************** @@ -256,43 +316,60 @@ public: // chart labels char sWndLbl[4]; // Wind label getdisplay().setFont(&Ubuntu_Bold10pt7b); - getdisplay().setCursor(xCenter - 68, yOffset - 3); - getdisplay().print(dataName[0]); // Wind name + getdisplay().setCursor(xCenter - 80, yOffset - 3); + getdisplay().print("TWD"); // Wind name getdisplay().setCursor(xCenter - 16, yOffset - 3); - snprintf(sWndLbl, 4, "%03d", wndCenter); + snprintf(sWndLbl, 4, "%03d", (wndCenter < 0) ? (wndCenter + 360) : wndCenter); getdisplay().print(sWndLbl); // Wind center value getdisplay().drawCircle(xCenter + 21, 63, 2, commonData->fgcolor); // symbol getdisplay().drawCircle(xCenter + 21, 63, 3, commonData->fgcolor); // symbol getdisplay().setCursor(2, yOffset - 3); - snprintf(sWndLbl, 4, "%03d", wndLeft); + snprintf(sWndLbl, 4, "%03d", (wndLeft < 0) ? (wndLeft + 360) : wndLeft); getdisplay().print(sWndLbl); // Wind left value getdisplay().drawCircle(39, 63, 2, commonData->fgcolor); // symbol getdisplay().drawCircle(39, 63, 3, commonData->fgcolor); // symbol getdisplay().setCursor(width - 43, yOffset - 3); - snprintf(sWndLbl, 4, "%03d", wndRight); + snprintf(sWndLbl, 4, "%03d", (wndRight < 0) ? (wndRight + 360) : wndRight); getdisplay().print(sWndLbl); // Wind right value getdisplay().drawCircle(width - 6, 63, 2, commonData->fgcolor); // symbol getdisplay().drawCircle(width - 6, 63, 3, commonData->fgcolor); // symbol // Draw wind values in chart //*********************************************************** - lastX = xCenter + ((windValues.get(0) - wndCenter) * chrtScl); - lastY = yOffset + cHeight; // Reset lastY to bottom of chart + if (dataValid[0] || holdvalues || simulation == true) { - for (int i = 0; i < count; i++) { - chrtVal = windValues.get(i); // Get value from buffer - chrtScl = xCenter / chrtRng; // current scale - x = xCenter + ((chrtVal - wndCenter) * chrtScl); // Scale to chart width - y = yOffset + cHeight - i; // Position in chart area - getdisplay().drawLine(lastX, lastY, x, y, commonData->fgcolor); - getdisplay().drawLine(lastX, lastY - 1, x, y - 1, commonData->fgcolor); - lastX = x; - lastY = y; - // LOG_DEBUG(GwLog::LOG, "PageWindPlot: loop-Counter: %d, X: %d, Y: %d, lastX: %d, lastY: %d", count, x, y, lastX, lastY); - if (i == (cHeight - 1)) { // Reaching chart area top end - windValues.mvStart(40); // virtually delete 40 values from buffer - continue; + lastX = xCenter + ((windValues.get(0) - wndCenter) * chrtScl); + lastY = yOffset + cHeight; // Reset lastY to bottom of chart + + for (int i = 0; i < count; i++) { + chrtVal = windValues.get(i); // Get value from buffer + chrtScl = xCenter / chrtRng; // current scale: pixels per degree + x = xCenter + ((chrtVal - wndCenter) * chrtScl); // Scale to chart width + // x = xCenter + ((((chrtVal - wndCenter + 540) % 360) - 180) * chrtScl); // Scale to chart width + y = yOffset + cHeight - i; // Position in chart area + // Draw line with 2 pixels width; make sure vertical line are drawn correctly + getdisplay().drawLine(lastX, lastY, x, y, commonData->fgcolor); + getdisplay().drawLine(lastX, lastY - 1, (x != lastX) ? x : x-1, (x != lastX) ? y - 1 : y, commonData->fgcolor); + lastX = x; + lastY = y; + // LOG_DEBUG(GwLog::LOG, "PageWindPlot: loop-Counter: %d, X: %d, Y: %d, lastX: %d, lastY: %d", count, x, y, lastX, lastY); + LOG_DEBUG(GwLog::LOG, "PageWindPlot Shift: Min: %d, Max: %d, Mid: %d", windValues.getMin(), windValues.getMax(), windValues.getMid()); + if (i == (cHeight - 1)) { // Reaching chart area top end + windValues.mvStart(40); // virtually delete 40 values from buffer + LOG_DEBUG(GwLog::LOG, "PageWindPlot Shift: Min: %d, Max: %d, Mid: %d", windValues.getMin(), windValues.getMax(), windValues.getMid()); + if ((windValues.getMin() > wndCenter) || (windValues.getMax() < wndCenter)) { + int mid = windValues.getMid(); + wndCenter = int((mid + (mid >= 0 ? 5 : -5)) / 10) * 10; // Set new center value; round to nearest 10 degree value + LOG_DEBUG(GwLog::LOG, "PageWindPlot Shift: Min: %d, Max: %d, new Center: %d", windValues.getMin(), windValues.getMax(), wndCenter); + } + continue; // Will leave loop + } } + } else { + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(xCenter - 55, height / 2); + getdisplay().print("No sensor data"); + return; } LOG_DEBUG(GwLog::LOG, "PageWindPlot End: lastX: %d, lastY: %d, loop-Counter: %d", lastX, lastY, count);