Here's some modified code. First of all, you should be indenting and spacing your code consistently, so that it's easier to read and understand. Unfortunately, the code tags for vBulletin don't handle the spaces and tabs elegantly, so bear with this.
Code:
unit Unit1;
{$O-}
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Button1: TButton;
procedure FormClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
procedure linija(x1,y1,x2,y2:integer);
implementation
{$R *.dfm}
procedure linija(x1, y1, x2, y2: integer);
var
dx, dy, p, x, y, xend, xt: integer;
begin
dx := abs(x1 - x2);
dy := abs(y2 - y1);
p := 2 * dx - dx; //Why? This equals p := dx;
if x1 > x2
then
begin
x := x2;
y := y2;
xend := x1;
end
else
begin
x := x1;
y := y1;
xend := x2;
end;
for xt := x to xend do
begin
if p < 0
then
p := p + 2 * dy
else
begin
y := y + 1; //You don't draw the first y-point!
p := p + 2 * (dy - dx);
end;
form1.Canvas.Pixels[xt, y] := clBlack; //Use the constant's name
end;
end;
procedure TForm1.FormClick(Sender: TObject);
begin
linija(100, 100, mouse.CursorPos.X, mouse.CursorPos.Y);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
linija(strtoint(edit1.Text), strtoint(edit2.Text), strtoint(edit3.Text), strtoint(edit4.Text));
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Edit1.Text := IntToStr(Form1.ClientWidth div 2);
Edit2.Text := IntToStr(Form1.ClientHeight div 2);
Edit3.Text := '0';
Edit4.Text := '0';
end;
end.
Now, as for what's wrong, I'm not going to rewrite this for you, because it looks suspiciously like an assignment. But take a look at the conditions for x and xend as it goes through the for xt... loop. If I take (250, 250) and (250, 0) as my co-ordinates, x = xend, so the loop will just execute once (at xt := x) and stop because xt = xend. In fact, you're using x-values as a counter, and then changing the size of each y-segment. But you only ever increment y by one, so the height of each y-segment is always 1. You're not even using p, which seems designed to serve this purpose (note that p >= 0 for all cases, except if (dy < 0) and (2 * dy > p) or ((dy - dx) < 0) and (2 * (dy - dx) > p), so I think your logic there might be a little messed up). This is rather hard to explain, but take a look at the attached file, which shows lines at (what your program thinks are) (250, 250)->(250, 0),(250, 250)->(250, 10), (250, 250)->(250, 20), (250, 250)->(250, 30) & (250, 250)->(250, 40). Obviously, those aren't the lines being drawn; instead, y always goes up by 1, and x is incremented by 1 (due to the for loop). So you get 45° lines.
Further, by setting y := y + 1 at every iteration of the loop, before drawing the pixel, you're actually offsetting your line by (0, 1). Re-arrange the loop so that the first value of y is y1, not y1 + 1.
Try figuring out some logic which says:
- Find x and y distances.
- For each x, how much does y grow (i.e. y = f(x) = mx + b, where m is a slope, and b a starting co-ordinate)?
- If m = ∞, do a special case for a vertical line.
- Otherwise, since m = ∆y / ∆x, evaluate m as (y2 - y1) div (x2 - x1), and make a segment of straight line (using a for loop) from either (x, y)->(x, y + m) or (x, y)->(x + 1 div m, y), depending on the slope (either greater or less than 45°).
- Repeat for each y or x, depending on whether you increment x by 1 div m, or y by m, respectively.
Edit: I just realized that you don't want to do 1 div ((y2 - y1) div (x2 - x1)), because of roundoff concerns (you're eliminating the remainder twice!). Do instead mInverse := (x2 - x1) div (y2 - y1) for that case.
Also, it might be helpful to look up TCanvas.LineTo and TCanvas.MoveTo in the help files. Unless you need to write the code yourself, I think that these already do what you need. Call Form1.Canvas.MoveTo(x1, y1), then call Form1.Canvas.LineTo(x2, y2). With any luck, you'll get a line, without fighting with it.
Finally, I haven't rigourously checked this, so I'm not sure if
I'm right. But I think it might be of some benefit....