Wenn die Funktion schon zur Laufzeit feststeht, findest du eine Anleitung für TAChart/TFuncSeries unter
http://wiki.lazarus.freepascal.org/TACh ... ion_Series.
Willst du aber auch die Funktion parsen, dann hast du am wenigsten Arbeit mit plotfunction, ist bei Lazarus mit dabei, du musst aber das Package lazplotfunction noch installieren (verwendet nicht TAChart).
Ansonsten geht es auch mit TAChart und einer TFuncSeries, und zum Parsen der Funktion kannst du fpexprpars verwenden, was zum FPC gehört, (oder auch symbolic, das ich selbst aber noch nicht ausprobiert habe). Mit fpexprpars erzeugst du den Parser folgendermaßen:
Code: Alles auswählen
var
FParser: TFPExpressionParser;
...
FParser := TFpExpressionParser.Create(self);
with FParser do begin
BuiltIns := [bcMath];
Identifiers.AddFloatVariable('x', 0.0);
Identifiers.AddFloatVariable('e', exp(1.0));
Identifiers.AddFunction('tan', 'F', 'F', @ExprTan);
// etc.
end;
function ArgToFloat(Arg: TFPExpressionResult): TExprFloat;
// Utility function for the built-in math functions. Accepts also integers
// in place of the floating point arguments. To be called in builtins or
// user-defined callbacks having float results.
begin
if Arg.ResultType = rtInteger then
result := Arg.resInteger
else
result := Arg.resFloat;
end;
Procedure ExprTan(Var Result: TFPExpressionResult; Const Args: TExprParameterArray);
var
x: Double;
begin
x := ArgToFloat(Args[0]);
if IsNumber(x) and ((frac(x - 0.5) / pi) <> 0.0) then
Result.resFloat := tan(x)
else
Result.resFloat := NaN;
end;
Mit den Aufruf von "AddFloatVariable" machst du die Variable "x" bekannt. "AddFunction" wird benötigt, um weitere Funktionen einzubinden (per Default kennt FPExpressionParser nur die in der Unit System verwendeten Funktionen.). "ArgToFloat" ist ein nützliches Utility, weil der Parser bezüglich Datentypen sehr pingelig ist, d.h. "sin(1)" funktioniert nicht, weil "1" ein Integer ist, aber die Sin-Funktion Floats erwartet.
Um dann einen Funktionsterm, z.B. s := 'tan(x*4)' zu plotten, rufst du einmalig
auf und kannst dann im OnCalculate event der TFuncSeries folgendermaßen die Funktionswerte abrufen
Code: Alles auswählen
procedure TForm1.Chart1FuncSeries1Calculate(const AX: Double; out AY: Double);
var
res: TFpExpressionResult;
begin
FParser.Identifiers[0] := AX;
res := FParser.Evaluate;
case res of
rtInteger: AY := res.ResInteger;
rtFloat: AY := res.ResFloat;
end;
end;
Ach ja noch: Die Behandlung von Laufzeitfehlern, die ja bei manueller Eingabe des Funktionsterms sehr leicht vorkommen können, ist mit fpExprParser etwas stiefmütterlich gelöst, da jeder mathematische Fehler das Programm beendet. Ich habe mir daher die Parser-Units in mein Projekt kopiert und so modifiziert, dass auf Divisionen durch Null, Definitionsbereiche von Funktionen etc. geachtet wird -- mache dich auf einige spannende Programmierstunden gefasst... (aber vielleicht geht das mit "symbolic" besser).