Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Kreis auf Canvas zeichen


suga2001 - Mi 14.01.09 17:32
Titel: Kreis auf Canvas zeichen
ich möchte einen Kreis zeichen und dazu habe ich unterschiedliche Varianten ausprobiert
Als Ellipse gings am einfachste :D , nun bin ich aber hängen geblieben, hab schon einiges gelesen aber irgendwie kommt trotzdem nicht das gewünschte Ergebnis dabei raus.
Das ist mein Quelltext um einen Kreis anhand von sin und cos zu zeichen.

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
  i:=Image1;
  r:=90;      // vorgegebener Radius

  for j := 0 to 360 do     //von 0 bis 360 Grad des Kreises
    begin
      x:=cos(DegToRad(j)) * r + i.Width / 2// i um den Kreis mittig zu zeichenn
      y:=sin(DegToRad(j)) * r + i.Height / 2// ----------''--------------
                                              //Mittelpunkt wird anhand der Größe
                                              //vom Image gemessen und darum der Raduis gesetzt
      i.Canvas.Lineto(Round(x), Round(y));    //Kreis wird gezeichnet, solange bis j=360° sind
    end;
 end;

funktioniert auch ganz gut, wenn da nicht eine störende Linie entstehen würde. Ich gehe davon aus, dass der Punkt, wo die Linie endet und zum "Kreis" wird, durch meine Gleichung vorher angegeben wird. Stimmt das? :?: Ich möchte diese Linie aber nicht gezeichnet haben. Benutze ich ein moveto, wird gar kein Kreis mehr gezeichnet.


Möchte ich nun einen Kreis über r²=x² + y² und stelle mir das nach x oder y um, dann wird nur ein sekrechter Strich gezeichnet.
Dazu mein Quellcode:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
r:integer;
x,y:real;

begin

r:=90;

y := (sqrt(sqr(r) - (sqr(x))));
x := (sqrt(sqr(r) - (sqr(y))));
Image1.Canvas.Lineto(round(x),round(y));

auf was bezieht sich x und y? Vielleicht hab ich ja an etwas nicht gedacht? :oops:

Danke schon mal im Voraus :roll:


jaenicke - Mi 14.01.09 17:42

Warum benutzt du denn nicht einfach die vorgefertigte Methode? Ich meine, gibt es einen Grund oder willst du das nur aus Interesse machen? ;-)

user profile iconsuga2001 hat folgendes geschrieben Zum zitierten Posting springen:
Möchte ich nun einen Kreis über r²=x² + y² und stelle mir das nach x oder y um, dann wird nur ein sekrechter Strich gezeichnet.
Mehr zeichnest du ja auch nicht.
user profile iconsuga2001 hat folgendes geschrieben Zum zitierten Posting springen:

Delphi-Quelltext
1:
Image1.Canvas.Lineto(round(x),round(y));                    
Wie meinst du das also? Ist dir nicht klar was LineTo macht? Das zeichnet ja nur einen Strich... :gruebel:

// EDIT:
Ach ja:
user profile iconsuga2001 hat folgendes geschrieben Zum zitierten Posting springen:
funktioniert auch ganz gut, wenn da nicht eine störende Linie entstehen würde. Ich gehe davon aus, dass der Punkt, wo die Linie endet und zum "Kreis" wird, durch meine Gleichung vorher angegeben wird. Stimmt das? :?: Ich möchte diese Linie aber nicht gezeichnet haben. Benutze ich ein moveto, wird gar kein Kreis mehr gezeichnet.
Am Anfang ist ja der Zeichenstift schon auf der Zeichenfläche. Nämlich bei (0,0). Wenn du dann das erste LineTo machst, dann wird von dort zu den angegebenen Koordinaten die Linie gezeichnet. (Und danach dann zwischen den berechneten Punkten des Kreises, wie es sein soll.)

Du musst zuerst mit MoveTo zu der ersten Koordinate des Kreises gehen und kannst dann von dort aus anfangen zu zeichnen. ;-)


suga2001 - Mi 14.01.09 18:19

Danke, hat mir schon weitergeholfen. :D
das tue ich doch mit dem code

Delphi-Quelltext
1:
Image1.Canvas.MoveTo(r+i.Width,r+i.Height);                    

Dann habe ich aber statt dem Lineto von 0,0 kommend nun den Lineto von der anderen Seite unten meines Canvas kommend. :?

mit

Delphi-Quelltext
1:
i.Canvas.Lineto(Round(x), Round(y));                    

Zeichne ich doch jeweils von Punkt zu Punkt über 360° meine Punkte, oder?


jaenicke - Mi 14.01.09 18:40

user profile iconsuga2001 hat folgendes geschrieben Zum zitierten Posting springen:
das tue ich doch mit dem code

Delphi-Quelltext
1:
Image1.Canvas.MoveTo(r+i.Width,r+i.Height);                    

Dann habe ich aber statt dem Lineto von 0,0 kommend nun den Lineto von der anderen Seite unten meines Canvas kommend. :?
Ja, klar. Überlege dir einmal wo die Koordinaten sind, die du dort angibst...
user defined image
(i ist das Image in rot, der Punkt ist die Koordinate wo du den Stift hinbewegst...)
Du musst zu dem Punkt auf dem Kreis, von dem aus dann weitergezeichnet werden soll.

user profile iconsuga2001 hat folgendes geschrieben Zum zitierten Posting springen:
mit

Delphi-Quelltext
1:
i.Canvas.Lineto(Round(x), Round(y));                    

Zeichne ich doch jeweils von Punkt zu Punkt über 360° meine Punkte, oder?
Ja, von der aktuellen Stiftposition zu der neuen angegebenen. Die neue Stiftposition ist dann an dem neuen Punkt.


suga2001 - Mi 14.01.09 18:51

so, nun hab ich den Strich immerhin schon im Kreis, als Radius, sozusagen :lol: ist doch schon mal was :wink:
wie bekomme ich den nun weg? er wird doch immer gezeichnet, weil ich das doch schließlich mit angegeben habe, oder?


jaenicke - Mi 14.01.09 19:05

Naja, ich glaube es ist besser, wenn ich es direkt schreibe:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
  i := Image1;
  r := 90;      // vorgegebener Radius

  x := cos(DegToRad(0)) * r + i.Width / 2// kann man natürlich vereinfachen ;-)
  y := sin(DegToRad(0)) * r + i.Height / 2;
  i.Canvas.MoveTo(Round(x), Round(y));

  for j := 1 to 360 do     //von 0 bis 360 Grad des Kreises
  begin
    x := cos(DegToRad(j)) * r + i.Width / 2// i um den Kreis mittig zu zeichenn
    y := sin(DegToRad(j)) * r + i.Height / 2// ----------''--------------
                                              //Mittelpunkt wird anhand der Größe
                                              //vom Image gemessen und darum der Raduis gesetzt
    i.Canvas.Lineto(Round(x), Round(y));    //Kreis wird gezeichnet, solange bis j=360° sind
  end;
end;
So gehst du zuerst zum ersten Punkt, den du natürlich genauso wie in der Schleife berechnen kannst, bevor du die Linie zum nächsten Punkt ziehst.

Den Punkt kannst du natürlich auch einfacher berechnen, ich wollte dir nur deutlich machen wie das Prinzip ist.


suga2001 - Mi 14.01.09 19:16

guuuuuuuuut, schick.das geht... ich danke dir für die tolle Hilfe :D


suga2001 - Mi 14.01.09 20:17

Wenn ich diesen Kreis nun auch noch ausmalen möchte, mir einer mir vorgegeben Farbe, bleibt meins immer weiß, also so, wie ichs gezeichnet hatte. an welcher stelle der Prozedur muss ich denn

Delphi-Quelltext
1:
2:
//Canvas.Pen.Color := clGreen;
Canvas.Brush.Color := clGreen;

Eine Frehlermeldung bekomme ich nicht. Kann ich das nicht mit in die Prozedur reinschreiben, in der mein kreis gezeichnet wird? so, gleich zum Anfang nach dem ersten begin in dem o.g Quellcode??
Oder muss ich dazu extra einen Button machen, der das denn ausmalt, und denn denn mein brush.color einfach????


jaenicke - Mi 14.01.09 20:36

So wie du jetzt zeichnest zeichnest du nur Linien, d.h. du musst das Füllen selbst machen. Deshalb wiederhole ich meine Frage: Musst du das so kompliziert machen bzw. willst du das so machen?

Schließlich kann man einen Kreis auch direkt mit einem einzigen Befehl (Ellipse) zeichnen und dann wird auch Brush automatisch zum Füllen benutzt.


suga2001 - Do 15.01.09 12:20

Sorry, ich war noch so in dem ganzen mathematischen drinn, dass ich das einfach kopiert und auf meinen Button gesetzt habe. :lol:
Mit einer Elipse gehts ja wesentlich schneller.
Aber das einfache

Delphi-Quelltext
1:
2:
image1.Canvas.Ellipse(0,0,180,180);
Canvas.Brush.Color := clGreen;
funktioniert nicht. Auch nicht,wenn ich es davor setzte. Meine Hilfedatei von Delphi geht auch nicht, da ich Vista64 benutzte, es startet immer nur die windows-Hilfe...


jaenicke - Do 15.01.09 12:40

Weil du dich einmal aufs Canvas des Formulars (ohne image1.) und einmal auf das des Images beziehst... ;-)
Ansonsten ist die umgekehrte Reihenfolge dann richtig, du musst natürlich die Farbe zuerst setzen.


suga2001 - Do 15.01.09 12:43

hab ich gemacht. Einmal möchte ich es mit floodfill füllen und einmal mit brush.
Floodfill funktioniert wunderbar.

Delphi-Quelltext
1:
Canvas.FloodFill(90,90,clBlack,fsBorder);                    

ich muss das aber irgendwie wieder löschen. benutze ich
canvas.Free , stürtzt mir das programm ab :(
ich muss den farbwert ja irgendwie wieder zurücksetzten, damit ich den einmal grün für floodfill und einmal blau für brush machen kann...


jaenicke - Do 15.01.09 12:48

Mit Canvas.Free entfernst du das Objekt Canvas aus dem Speicher. Dann ist es weg. Das ist wie wenn du im Auto sagst "Lenkrad nach links drehen", "Lenkrad aus dem Fenster wegschmeißen", "Lenkrad nach rechts drehen" (welches Lenkrad?). ;-)

Was Floodfill macht ist dir klar? :gruebel:


suga2001 - Do 15.01.09 13:14


Delphi-Quelltext
1:
2:
Image1.Canvas.Brush.Color:=clred;
image1.Canvas.Ellipse(0,0,180,180);


klappt auch :D

Danke schön :wink:


Horst_H - Do 15.01.09 13:31

Hallo,

ich hätte nicht gedacht, dass ein Eigenbau so schnell ist.
Aber brush kann ja mehr und zudem zeichne ich nicht den äusseren Rand in der passenden Farbe.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
procedure canvasfilledCircle(can:TCanvas;MittelPunkt:Tpoint;radius:integer);
//Zeichnet das innere eines Kreises mittels horizontaler Linien
var
  x,y,dy : integer;
  tmpColour : Tcolor;
begin
  tmpColour := can.Pen.Color;
  can.Pen.Color := can.Brush.Color;
  radius := radius-1;// nur inneren Teil
  with can do
    begin
    for dy := -radius to radius do
      begin
      x := round(sqrt(sqr(radius)-sqr(dy)));
      moveto(Mittelpunkt.x-x, Mittelpunkt.y+dy);
      Lineto(Mittelpunkt.x+x, Mittelpunkt.y+dy);
      end;
    end;
  can.Pen.Color := tmpColour;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i : integer;
  t1,t0: dword;
begin
   t0:= gettickcount;
   for i := 1 to 5000 do
     begin
     Form1.canvas.Brush.Color := random(high(TColor));
     canvasfilledCircle(Form1.canvas,Point(150,200),70);
     end;
   t1:= gettickcount;
   memo1.Lines.Add(Format('Eigenbau %d',[t1-t0]));

   t0:= gettickcount;
   for i := 1 to 5000 do
     begin
     Form1.canvas.Brush.Color := random(high(TColor));
     Form1.canvas.ellipse(150-70,200-70,150+70,200+70);
     end;
   t1 := gettickcount;
   memo1.Lines.Add(Format('Ellipse %d',[t1-t0]));
end;


Gruß Horst


Henneberg - Di 30.11.10 17:18

ok ich hab dann jetzt nur noch eine frage

ich hab es nach langen versuchen nun endlich auch daheim geschafft und wollte nun noch ausprobieren ob ich denn die koordinaten bzw den radius selbst eingeben kann(im edit)
und da müsste ich noch wissen wofür welche varaible steht

image1.Canvas.Ellipse(0,0,180,180);

also bei mir image1.Canvas.Ellipse(x,y,m,n);

danke im vorraus
henneberg


bummi - Di 30.11.10 17:26


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var
x,y,m,n:Integer;
begin
If  TryStrToInt(Edit1.text,x) 
 and TryStrToInt(Edit2.text,y)  
 and TryStrToInt(Edit3.text,m)  
 and TryStrToInt(Edit4.text,n)  then
  begin
          // malen
        end 
 else Showmessage('Ungültige Eingabe');


Henneberg - Di 30.11.10 17:33

Naia ne..
ich meine z.B. welche variable steht für den mittelpunkt


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button1Click(Sender: TObject);
var x,y,m,n:integer;
begin
x:=StrToInt (Edit1.Text);  //Breite angeben
y:=StrToInt (Edit2.Text);  //LÄNGE angeben
m:=StrToInt (Edit3.Text);
n:=StrToInt (Edit4.Text);
image1.Canvas.Ellipse(x,y,m,n);
end;


ich habs jetzt mal so gemacht und durch versuchen herausgefinden das bei mir x für die breite und y für die länge steht aber was bestimmen jetzt m und n? bzw kann ich hierbei überhaupt angeben wo der kreis liegt?

danke im vorraus
henneberg

Moderiert von user profile iconMartok: Delphi-Tags eingefügt


bummi - Di 30.11.10 17:49

Du gibst das umgebende Rechteck an, den Mittelpunkt kannst du Dir herausrechnen, wenn Du es anders eingeben willst rückwärts rechnen.