[education/labplot] src: Added an option to automatically calculated the number of points to plot for the equation curve without asking the user to specify it.

Alexander Semke <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 884650e44363fe8ef351d461275c18a9cca5973a by Alexander Semke.
Committed on 20/07/2026 at 16:33.
Pushed by sgerlach into branch 'master'.

Added an option to automatically calculated the number of points to plot for the equation curve without asking the user to specify it.
It's activated on default and the user gets always a properly plotted curve without any need to thing about the number of point to be
plotted for each specific curve.

BUG: 431534
FIXED-IN: 3.0

M  +39   -20   src/backend/worksheet/plots/cartesian/XYEquationCurve.cpp
M  +1    -0    src/backend/worksheet/plots/cartesian/XYEquationCurve.h
M  +13   -1    src/frontend/dockwidgets/XYEquationCurveDock.cpp
M  +1    -0    src/frontend/dockwidgets/XYEquationCurveDock.h
M  +37   -14   src/frontend/ui/dockwidgets/xyequationcurvedockgeneraltab.ui

https://invent.kde.org/education/labplot/-/commit/884650e44363fe8ef351d461275c18a9cca5973a

diff --git a/src/backend/worksheet/plots/cartesian/XYEquationCurve.cpp b/src/backend/worksheet/plots/cartesian/XYEquationCurve.cpp
index f1e2279f81..cff55a0cf7 100644
--- a/src/backend/worksheet/plots/cartesian/XYEquationCurve.cpp
+++ b/src/backend/worksheet/plots/cartesian/XYEquationCurve.cpp
@@ -90,7 +90,8 @@ STD_SETTER_CMD_IMPL_F_S(XYEquationCurve, SetEquationData, XYEquationCurve::Equat
 void XYEquationCurve::setEquationData(const XYEquationCurve::EquationData& equationData) {
 	Q_D(XYEquationCurve);
 	if ((equationData.expression1 != d->equationData.expression1) || (equationData.expression2 != d->equationData.expression2)
-		|| (equationData.min != d->equationData.min) || (equationData.max != d->equationData.max) || (equationData.count != d->equationData.count))
+		|| (equationData.min != d->equationData.min) || (equationData.max != d->equationData.max) || (equationData.count != d->equationData.count)
+		|| (equationData.autoPointsCount != d->equationData.autoPointsCount))
 		exec(new XYEquationCurveSetEquationDataCmd(d, equationData, ki18n("%1: set equation")));
 }
 
@@ -143,38 +144,54 @@ XYEquationCurvePrivate::XYEquationCurvePrivate(XYEquationCurve* owner)
 XYEquationCurvePrivate::~XYEquationCurvePrivate() = default;
 
 void XYEquationCurvePrivate::recalculate() {
-	// resize the vector if a new number of point to calculate was provided
-	if (equationData.count != xVector->size()) {
-		if (equationData.count >= 1) {
-			xVector->resize(equationData.count);
-			yVector->resize(equationData.count);
-		} else {
-			// invalid number of points provided
-			xVector->clear();
-			yVector->clear();
-			recalc();
-			Q_EMIT q->dataChanged();
-			return;
-		}
+	int pointCount = equationData.count; // number of points of the curve to be calculated and plotted
+
+	if (equationData.autoPointsCount) { // auto-calculate number of points based on plot width
+		if (m_plot && m_plot->dataRect().width() > 0) {
+			// Base calculation: oversampling factor × pixel width
+			// Using 2.5 points per pixel as a good balance between quality and performance
+			const double OVERSAMPLING_FACTOR = 2.5;
+			int pixelWidth = m_plot->dataRect().width();
+			pointCount = static_cast<int>(pixelWidth * OVERSAMPLING_FACTOR);
+
+			// Parametric and polar functions have more complex curves and need more points
+			if (equationData.type == XYEquationCurve::EquationType::Parametric ||
+				equationData.type == XYEquationCurve::EquationType::Polar) {
+				pointCount *= 5; // 5x more points for parametric/polar
+			}
+
+			// Minimum 100 points for basic smoothness, maximum 10000 to avoid excessive computation
+			pointCount = qBound(100, pointCount, 10000);
+		} else
+			pointCount = 1000; // default to 1000 points if plot is not available or has zero width
+	} else if (pointCount < 1) { // invalid number provided, safety check
+		xVector->clear();
+		yVector->clear();
+		recalc();
+		Q_EMIT q->dataChanged();
+		return;
+	}
+
+	// Resize the vector if the calculated number of points differs from current size
+	if (pointCount != xVector->size()) {
+		xVector->resize(pointCount);
+		yVector->resize(pointCount);
 		xColumn->invalidateProperties();
 		yColumn->invalidateProperties();
-	} else {
-		if (equationData.count < 1)
-			return;
 	}
 
 	auto* parser = ExpressionParser::getInstance();
 	bool valid = false;
 	if (equationData.type == XYEquationCurve::EquationType::Cartesian) {
-		valid = parser->tryEvaluateCartesian(equationData.expression1, equationData.min, equationData.max, equationData.count, xVector, yVector);
+		valid = parser->tryEvaluateCartesian(equationData.expression1, equationData.min, equationData.max, pointCount, xVector, yVector);
 	} else if (equationData.type == XYEquationCurve::EquationType::Polar) {
-		valid = parser->tryEvaluatePolar(equationData.expression1, equationData.min, equationData.max, equationData.count, xVector, yVector);
+		valid = parser->tryEvaluatePolar(equationData.expression1, equationData.min, equationData.max, pointCount, xVector, yVector);
 	} else if (equationData.type == XYEquationCurve::EquationType::Parametric) {
 		valid = parser->tryEvaluateParametric(equationData.expression1,
 											  equationData.expression2,
 											  equationData.min,
 											  equationData.max,
-											  equationData.count,
+											  pointCount,
 											  xVector,
 											  yVector);
 	}
@@ -210,6 +227,7 @@ void XYEquationCurve::save(QXmlStreamWriter* writer) const {
 	writer->writeAttribute(QStringLiteral("min"), d->equationData.min);
 	writer->writeAttribute(QStringLiteral("max"), d->equationData.max);
 	writer->writeAttribute(QStringLiteral("count"), QString::number(d->equationData.count));
+	writer->writeAttribute(QStringLiteral("autoPointsCount"), QString::number(d->equationData.autoPointsCount));
 	writer->writeEndElement();
 
 	writer->writeEndElement();
@@ -243,6 +261,7 @@ bool XYEquationCurve::load(XmlStreamReader* reader, bool preview) {
 			READ_STRING_VALUE("min", equationData.min);
 			READ_STRING_VALUE("max", equationData.max);
 			READ_INT_VALUE("count", equationData.count, int);
+			READ_INT_VALUE("autoPointsCount", equationData.autoPointsCount, bool);
 		} else { // unknown element
 			reader->raiseUnknownElementWarning();
 			if (!reader->skipToEndElement())
diff --git a/src/backend/worksheet/plots/cartesian/XYEquationCurve.h b/src/backend/worksheet/plots/cartesian/XYEquationCurve.h
index b3ac272c87..44f1126c9d 100644
--- a/src/backend/worksheet/plots/cartesian/XYEquationCurve.h
+++ b/src/backend/worksheet/plots/cartesian/XYEquationCurve.h
@@ -38,6 +38,7 @@ public:
 		QString min; // localized strings to support expressions
 		QString max;
 		int count{1000}; // number of points of the curve
+		bool autoPointsCount{true}; // automatically calculate point count based on plot size
 	};
 
 	explicit XYEquationCurve(const QString& name);
diff --git a/src/frontend/dockwidgets/XYEquationCurveDock.cpp b/src/frontend/dockwidgets/XYEquationCurveDock.cpp
index a7d0b52ff7..e7cfc2393e 100644
--- a/src/frontend/dockwidgets/XYEquationCurveDock.cpp
+++ b/src/frontend/dockwidgets/XYEquationCurveDock.cpp
@@ -65,7 +65,7 @@ void XYEquationCurveDock::setupGeneral() {
 	uiGeneralTab.tbConstants2->setIcon(QIcon::fromTheme(QStringLiteral("labplot-format-text-symbol")));
 	uiGeneralTab.tbFunctions2->setIcon(QIcon::fromTheme(QStringLiteral("preferences-desktop-font")));
 
-
+	retranslateUi();
 
 	uiGeneralTab.pbRecalculate->setIcon(QIcon::fromTheme(QStringLiteral("run-build")));
 	uiGeneralTab.teEquation2->setExpressionType(XYEquationCurve::EquationType::Parametric);
@@ -88,6 +88,7 @@ void XYEquationCurveDock::setupGeneral() {
 	connect(uiGeneralTab.teMin, &ExpressionTextEdit::expressionChanged, this, &XYEquationCurveDock::enableRecalculate);
 	connect(uiGeneralTab.teMax, &ExpressionTextEdit::expressionChanged, this, &XYEquationCurveDock::enableRecalculate);
 	connect(uiGeneralTab.sbCount, QOverload<int>::of(&QSpinBox::valueChanged), this, &XYEquationCurveDock::enableRecalculate);
+	connect(uiGeneralTab.cbAutoPoints, &QCheckBox::toggled, this, &XYEquationCurveDock::autoPointsChanged);
 	connect(uiGeneralTab.pbRecalculate, &QPushButton::clicked, this, &XYEquationCurveDock::recalculateClicked);
 }
 
@@ -103,6 +104,8 @@ void XYEquationCurveDock::initGeneralTab() {
 	uiGeneralTab.teMin->setText(edata.min);
 	uiGeneralTab.teMax->setText(edata.max);
 	uiGeneralTab.sbCount->setValue(edata.count);
+	uiGeneralTab.cbAutoPoints->setChecked(edata.autoPointsCount);
+	uiGeneralTab.sbCount->setEnabled(!edata.autoPointsCount);
 
 	uiGeneralTab.chkLegendVisible->setChecked(m_curve->legendVisible());
 	uiGeneralTab.chkVisible->setChecked(m_curve->isVisible());
@@ -220,6 +223,7 @@ void XYEquationCurveDock::recalculateClicked() {
 	edata.min = uiGeneralTab.teMin->document()->toPlainText();
 	edata.max = uiGeneralTab.teMax->document()->toPlainText();
 	edata.count = uiGeneralTab.sbCount->value();
+	edata.autoPointsCount = uiGeneralTab.cbAutoPoints->isChecked();
 
 	for (auto* curve : m_curvesList)
 		static_cast<XYEquationCurve*>(curve)->setEquationData(edata);
@@ -345,6 +349,12 @@ void XYEquationCurveDock::enableRecalculate() {
 	updatePlotRangeList();
 }
 
+void XYEquationCurveDock::autoPointsChanged(bool checked) {
+	// Enable/disable manual point count spinbox based on auto checkbox state
+	uiGeneralTab.sbCount->setEnabled(!checked);
+	enableRecalculate();
+}
+
 //*************************************************************
 //*********** SLOTs for changes triggered in XYCurve **********
 //*************************************************************
@@ -357,4 +367,6 @@ void XYEquationCurveDock::curveEquationDataChanged(const XYEquationCurve::Equati
 	uiGeneralTab.teMin->setText(edata.min);
 	uiGeneralTab.teMax->setText(edata.max);
 	uiGeneralTab.sbCount->setValue(edata.count);
+	uiGeneralTab.cbAutoPoints->setChecked(edata.autoPointsCount);
+	uiGeneralTab.sbCount->setEnabled(!edata.autoPointsCount);
 }
diff --git a/src/frontend/dockwidgets/XYEquationCurveDock.h b/src/frontend/dockwidgets/XYEquationCurveDock.h
index 9d3a268cdc..add72a2005 100644
--- a/src/frontend/dockwidgets/XYEquationCurveDock.h
+++ b/src/frontend/dockwidgets/XYEquationCurveDock.h
@@ -36,6 +36,7 @@ private Q_SLOTS:
 	// SLOTs for changes triggered in XYCurveDock
 	void typeChanged(int);
 	void recalculateClicked();
+	void autoPointsChanged(bool);
 	void loadFunction();
 	void saveFunction();
 	void showConstants();
diff --git a/src/frontend/ui/dockwidgets/xyequationcurvedockgeneraltab.ui b/src/frontend/ui/dockwidgets/xyequationcurvedockgeneraltab.ui
index 488c4c6113..a08aeee134 100644
--- a/src/frontend/ui/dockwidgets/xyequationcurvedockgeneraltab.ui
+++ b/src/frontend/ui/dockwidgets/xyequationcurvedockgeneraltab.ui
@@ -298,20 +298,43 @@
     </widget>
    </item>
    <item row="10" column="4" colspan="2">
-    <widget class="QSpinBox" name="sbCount">
-     <property name="sizePolicy">
-      <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
-       <horstretch>0</horstretch>
-       <verstretch>0</verstretch>
-      </sizepolicy>
-     </property>
-     <property name="maximum">
-      <number>999999999</number>
-     </property>
-     <property name="value">
-      <number>100</number>
-     </property>
-    </widget>
+    <layout class="QHBoxLayout" name="horizontalLayoutPoints">
+     <item>
+      <widget class="QSpinBox" name="sbCount">
+       <property name="sizePolicy">
+        <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="toolTip">
+        <string>Number of points to evaluate</string>
+       </property>
+       <property name="minimum">
+        <number>1</number>
+       </property>
+       <property name="maximum">
+        <number>999999999</number>
+       </property>
+       <property name="value">
+        <number>1000</number>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QCheckBox" name="cbAutoPoints">
+       <property name="toolTip">
+        <string>Automatically calculate the number of points based on plot pixel width</string>
+       </property>
+       <property name="text">
+        <string>Auto</string>
+       </property>
+       <property name="checked">
+        <bool>true</bool>
+       </property>
+      </widget>
+     </item>
+    </layout>
    </item>
    <item row="5" column="4" colspan="2">
     <widget class="KComboBox" name="cbType">
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.