Witam,
Zrobiłem sobie coś takiego:
procedure Tforma.wykresPaint(Sender: TObject);
var mx, my, wx, wy: integer;
i: integer;
errorinlast: boolean;
const border = 10;
begin
with wykres do
begin
// Obliczanie grubości
mx := (Width - border*2) div 2;
my := (Height - border*2) div 2;
// Obliczanie wielkości
wx := mx div FFunctionVisibleRange;
wy := my div FFunctionVisibleRange;
with Canvas do
begin
// Wyczyszczenie wykresu
brush.Color := clWhite;
FillRect(ClientRect);
// Rysowanie
pen.Color := clBlack; // Czarny kolor dla wykresu
MoveTo(border, my + border);
LineTo(wykres.Width-border, my + border);
MoveTo(border + mx, border);
LineTo(border + mx, wykres.Height-border);
for i := -FFunctionVisibleRange to FFunctionVisibleRange do
begin
if (i = 0) or ((FFunctionVisibleRange >= 10) and (i mod (FFunctionVisibleRange div 10) <> 0)) then
begin
continue;
end;
TextOut(border + mx + (i * wx) - (TextWidth(IntToStr(i)) div 2), border + my + 2, IntToStr(i));
MoveTo(border + mx + (i * wx), border + my - 2);
LineTo(border + mx + (i * wx), border + my + 2);
end;
for i := -FFunctionVisibleRange to FFunctionVisibleRange do
begin
if (i = 0) or ((FFunctionVisibleRange >= 10) and (i mod (FFunctionVisibleRange div 10) <> 0)) then
begin
continue;
end;
TextOut(border + mx + 4, border + my - (i * wy) - (TextHeight(IntToStr(i)) div 2), IntToStr(i));
MoveTo(border + mx + 2, border + my + (i * wy));
LineTo(border + mx - 2, border + my + (i * wy));
end;
if AFuncTree = nil then
begin
Exit; // Zakończenie rysowania jeżeli AFuncTree jest puste
end;
try
pen.Color := clBlue; // Niebieski kolor zaznacza funkcję
try
AFuncParser.ConstantValues['x'] := (FFunctionVisibleRange * 2) * 100;
MoveTo(trunc(border + mx + int(-(FFunctionVisibleRange*2) * wx)), trunc(border + my + int(AFuncParser.CalcTree(AFuncTree) * wy)));
except
errorinlast := true;
end;
errorinlast := false;
for i := -(FFunctionVisibleRange * 2) * 100 to (FFunctionVisibleRange * 2) * 100 do
begin
try
AFuncParser.ConstantValues['x'] := i / 100;
if not errorinlast then
begin
LineTo(trunc(border + mx + (i / 100 * wx)), trunc(border + my - (AFuncParser.CalcTree(AFuncTree) * wy)));
end
else
begin
MoveTo(trunc(border + mx + (i / 100 * wx)), trunc(border + my - (AFuncParser.CalcTree(AFuncTree) * wy)));
errorinlast:=false;
end;
except
errorinlast := true;
end;
end;
except on e: EMathParserException do
begin
AFuncParser.FreeTermTree(AFuncTree);
ShowMessage('(Błąd) '+e.ErrorDescription);
funkcja.SetFocus;
funkcja.SelStart:=e.ErrorPos-1;
funkcja.SelLength:=e.ErrorLength;
Exit;
end;
end;
end;
end;
end;
funkcja = wzór funkcji w polu TEdit
wykres = TPaintBox
Dalej główna procedura przycisku rysującego (pominąłem obliczanie funkcji itp.):
try
AFuncTree := AFuncParser.ParseTerm(funkcja.Text);
except on e: EMathParserException do
begin
ShowMessage('(BŁĄD) ' + e.ErrorDescription);
funkcja.SetFocus;
funkcja.SelStart := e.ErrorPos-1;
funkcja.SelLength := e.ErrorLength;
end;
end;
if AFuncParser.ParseError = mpeNone then
begin
wykres.Repaint;
end
else
begin
AFuncParser.FreeTermTree(AFuncTree);
end;
Wszystko działa wporządku, ale mój program potrafi jedynie rysować wykres funkcji w linii prostej (z czego i tak jestem dumny, bo nie pytałem się nikogo jak to zrobić) i teraz moje pytanie - jeżeli funkcja jest taka, że wykresem musi być linia prosta, ale ukośna, to jak to zrobić?
PS: wszystkie obiekty "Parser" to utworzone w OnCreate obiekty z modułu parsera matematycznego