TFPCustomCanvas Arc Methode, Verständnisfrage

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mario Peters
Beiträge: 9
Registriert: Sa 26. Apr 2025, 22:41

TFPCustomCanvas Arc Methode, Verständnisfrage

Beitrag von Mario Peters »

Hallo,

Ich sehe zwei Arc Methoden

die erste: Arc(left,top,right,bottom, Angle16Deg,Angle16DegLength: Integer);

die zweite: Arc(left,top,right,bottom,SX,SY,EX,EY: integer);

Welche Bedeutung haben in der zweiten Methode die Parameter SX,EX,SY,EY???

Sollten das in diesem Fall die Schnittpunkte des Bogens mit dessenn Enden sein, wie berechne ich die dann?

Ich habe folgende Ellipsengleichung:

Code: Alles auswählen

procedure PaintEllipse(Canv: TFPCustomCanvas; xm, ym, xR, yR, stangle, endangle: Extended; numSteps: Integer; c: TFPColor);
   var
    t, tStart, tEnd, tStep: Extended;
    i,j: Integer;
    x, y: Extended;
    MyPutPix: TPutPixelProc;

  procedure DrawPixel(Canv: TFPCustomCanvas; x,y: Longword);
  begin
      //für meine Frage uninteressant
  end;

 begin
      if numSteps < 1 then Exit; // Sicherheitsprüfung

      // Winkel in Radiant umrechnen
      tStart := DegToRad(stangle);
      tEnd := DegToRad(endangle);

      // Normierter Parameter t von tStart bis tEnd
      tStep := (tEnd - tStart) / numSteps;

      with canv.pen do
        case mode of
          pmMask : MyPutPix := @PutPixelAnd;
          pmMerge : MyPutPix := @PutPixelOr;
          pmXor : MyPutPix := @PutPixelXor;
        else MyPutPix := @PutPixelCopy;
      end;


      // Zeichne Punkte entlang der Ellipse
      for i := 0 to numSteps do
      begin
        t := tStart + i * tStep;
        // Parametrische Darstellung der Ellipse
        x := xm + xR * Cos(t); if t=tStart  then xs:=x; if t=tEnd then xe:=x; //ist das richtig, dann hätte ich die Positionen von SX,SY,EX,EY
        y := ym + yR * Sin(t); if t=tStart  then ys:=y; if t=tEnd then ye:=y;
        DrawPixel(Canv, Round(x), Round(y)); // Zeichne Pixel

      end;
   end;

Dann aber müsste ich dies Parameter umständlich vorher berechnen, wenn ich diese Methode benutzen will. Gibt es eine elegantere Berechnungsmrthode dafür oder interpretiere ich SX,SY,EX,EY ohnehin falsch? Leider sind diese Parameter in der FPCanvas Doku auch nicht erklärt

wp_xyz
Beiträge: 5219
Registriert: Fr 8. Apr 2011, 09:01

Re: TFPCustomCanvas Arc Methode, Verständnisfrage

Beitrag von wp_xyz »

Nein, das ist einfach nur irgendein Punkt in der Ebene. Es wird intern der Mittelpunkt der Ellipse mit diesem Punkt verbunden, und dort, wo die Linie die Ellipse schneidet, beginnt/endet der Bogen; die Rechnung muss du selbst nicht ausführen.

Das ist wahrscheinlich deswegen so gemacht, weil mit diesen Argumenten die Endpunkte klar definiert sind. Nimmt man dagegen die andere Variante mit den Winkel, ist unklar welcher Winkel gemeint ist. Ist es der Winkel, den so eine Verbindungslinie mit der x-Achse hat? Oder ist es der Winkel in den Ellipsengleichungen x = a * cos(phi), y = b * sin(phi)? Beide sind nicht identisch! Ich habe dazu vor kurzem einen Bug bearbeitet (https://gitlab.com/freepascal.org/lazar ... sues/41748), in dem sich eine Inkonsistenz der Arc-Methode zwischen win32 und den Linux-Widgetsets herausgestellt hat. In Laz/main wird künftig die zweite Definition (die mit den Ellipsengleichungen) verwendet.

Mario Peters
Beiträge: 9
Registriert: Sa 26. Apr 2025, 22:41

Re: TFPCustomCanvas Arc Methode, Verständnisfrage

Beitrag von Mario Peters »

Danke für die schnelle Antwort. Habe mir die .zip Datei runter geladen aber eine Frage ist noch offen:

So wie ich das verstehe, sind die Punkte SX,SY,EX,EY bisher beliebige Punkte der Ebene gewesen, deren Verbindungslinie vom Mittelpunkt der Ellipse zum Schnittpunkt Ellipse Verbindungslinie Mittelpunkt<-> Schnittpunkt auch diese Pukte SX,SY,EX,EY schnneiden, Nun aber sind das keine beliebigen Ounkte mehr sondern werden nach der Ellipsengleichung berechnet. Also wie in der von mir aufgeführten Methode. Da tritt aber ein neues Problem auf. wie kommt der Multiplikator 1000 zustande? C ist nach meinem Verständnis der Mittelpunkt der Ellipse ,P1, P2, die beiden Schnittpunkte mit der Ellipse, bei mie SX,SY,EX und EY und damit Endpunkte des Bogens. Warum aber muss da der Multiplikator, hier 1000 hinzugefügt werden? Warum gerade die 1000? ist das sowas wie in meiner Version die Anzahl der Steps?

Und unten in der PaintBox der Summand +/-5 ist mir in der Bedeutung auch unklar. Oder ist das eine Linienstärke?

Hier:

Code: Alles auswählen

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
  R: TRect;
  C, P1, P2: TPoint;
  phi1, phi2: Double;
begin
  R := Rect(10, 10, 210, 110);
  C := Point((R.Left + R.Right) div 2, (R.Top + R.Bottom) div 2);

  Paintbox1.Canvas.Brush.Style := bsClear;
  Paintbox1.Canvas.Pen.Style := psDash;
  Paintbox1.Canvas.Pen.Color := clSilver;
  Paintbox1.Canvas.Rectangle(R);

  Paintbox1.Canvas.Pen.Style := psSolid;
  Paintbox1.Canvas.Pen.Color := clRed;
  Paintbox1.Canvas.Brush.Color := clRed;
  {$IFDEF FPC}
  if RadioButton2.Checked or RadioButton3.Checked then
    Paintbox1.Canvas.RadialPie(R.Left, R.Top, R.Right, R.Bottom, Scrollbar1.Position * 16, Scrollbar2.Position * 16);
  if RadioButton1.Checked or RadioButton3.Checked then
  begin
    Paintbox1.Canvas.Pen.Color := clBlue;
    Paintbox1.Canvas.Pen.Width := 3;
    Paintbox1.Canvas.Arc(R.Left, R.Top, R.Right, R.Bottom, Scrollbar1.Position * 16, Scrollbar2.Position * 16);
    Paintbox1.Canvas.Pen.Width := 1;
  end;
  {$ELSE}
  phi1 := Scrollbar1.Position * pi/180;
  phi2 := (Scrollbar1.Position + Scrollbar2.Position) * pi/180;
  P1 := C + Point(round(cos(phi1) * 1000), round(-sin(phi1) * 1000));
  P2 := C + Point(round(cos(phi2) * 1000), round(-sin(phi2) * 1000));
  Paintbox1.Canvas.Arc(R.Left, R.Top, R.Right, R.Bottom, P1.X, P1.Y, P2.X, P2.Y);
  {$ENDIF}

  // Draw angle lines (lines from center to far-away point in direction defined by angle w.r.t x axis)
  phi1 := Scrollbar1.Position * pi/180;
  phi2 := (Scrollbar1.Position + Scrollbar2.Position) * pi/180;
  P1 := C + Point(round(cos(phi1) * 1000), round(-sin(phi1) * 1000));
  P2 := C + Point(round(cos(phi2) * 1000), round(-sin(phi2) * 1000));
  Paintbox1.Canvas.Pen.Color := clSilver;
  Paintbox1.Canvas.MoveTo(C.X, C.Y);
  Paintbox1.Canvas.LineTo(P1.X, P1.Y);
  Paintbox1.Canvas.MoveTo(C.X, C.Y);
  Paintbox1.Canvas.LineTo(P2.X, P2.Y);

  // Calculate ellipse points (points on ellipsis at angles)
  P1 := Point(round(cos(phi1) * ((R.Right - R.Left) div 2)) + C.X, round(-sin(phi1) * ((R.Bottom - R.Left) div 2)) + C.Y);
  P2 := Point(round(cos(phi2) * ((R.Right - R.Left) div 2)) + C.X, round(-sin(phi2) * ((R.Bottom - R.Left) div 2)) + C.Y);
  Paintbox1.Canvas.Brush.Style := bsSolid;
  Paintbox1.Canvas.Brush.Color := clWhite;
  Paintbox1.Canvas.Ellipse(P1.X - 5, P1.Y - 5, P1.X + 5, P1.Y + 5);
  Paintbox1.Canvas.Ellipse(P2.X - 5, P2.Y - 5, P2.X + 5, P2.Y + 5);

end;

wp_xyz
Beiträge: 5219
Registriert: Fr 8. Apr 2011, 09:01

Re: TFPCustomCanvas Arc Methode, Verständnisfrage

Beitrag von wp_xyz »

Du beziehst dich auf das "arc_radialpie.zip"-File? Der Faktor 1000 ist der Abstand der Punkte (SX,SY) und (EX,EY) vom Ellipsenmittelpunkt; der Wert ist völlig egal, er sollte nur nicht zu klein sein, weil der Abstand ja mit sin und cos des Winkels multipliziert wird, und da erhält man nach dem Runden auf Integer bei zu kleinem Abstand einfach zu ungenaue Werte.

Das +/-5 hat nichts mit dem Zeichnen des Arcs zu tun. Es soll da nur ein kleiner Kreis gezeichnet werden, um die Endpukte des Bogens hervorzuheben.

Mario Peters
Beiträge: 9
Registriert: Sa 26. Apr 2025, 22:41

Re: TFPCustomCanvas Arc Methode, Verständnisfrage

Beitrag von Mario Peters »

Ich habe das Projekt gerade in der Bearbeitung, Ich versteh noch nicht warum der Winkel zwischen den Kreisen die die Bogenenden markieren, je nach Stellung der Scrollbars auch mal auf dem Bogen liegen, nicht an den Enden. Wenn ich den Scrollbar für StartAngle verändere liegen die kleinen Kreise auch mal außerhalb des Bogens. Ich nehme an, der rote Bereich markiert den eingeschlossenen Winkel. Der wird mit dem ScrollBar "Sweep Angle" verändert, der unterscheidet sich aber immer vom Winkel zwischen den beiden anderen Strecken ( Strahlen), die vom Ellipsenmittelpunkt aus über das Ellipsenrechteck (das die Ellipse umschließende Rechteck) hinaus gehen. Warum ist das so?
Du schreibst ja selber oben dass der Mittelpunkt der Ellppse mit den Punkten SX,SY, EX,EY verbunden wird, Dann werden die Schnittpunkte mit der Ellipse also intern berechnet. Soweit Ok, aber warum habe ich dann im Besidpileprojekt das hier oben in meiner Frage genannte Phänomen?

wp_xyz
Beiträge: 5219
Registriert: Fr 8. Apr 2011, 09:01

Re: TFPCustomCanvas Arc Methode, Verständnisfrage

Beitrag von wp_xyz »

Ich habe nochmal ein kleines Programm geschrieben, das die Verhältnisse darstellen soll. Leider ist es unter Windows nicht sehr aussagekräftig, weil eine der beiden Arc-Routinen in den Lazarus-Release-Versionen da einen Bug hat. Ich hänge daher auch noch einen Screenshot an, der mit Laz/main gemacht wurde, wo der Fehler behoben ist (oder du arbeitest mit Linux, wo das Problem gar nicht auftritt).

Die linke Paintbox in dem Screenshot zeigt den Ellipsenbogen, der mit der Arc-Prozedur gezeichnet wurde, die die SX, SY, EX, EY-Argumente verwendet. Die Punkte (SX,SY) und (EX,EY) (im Programm P1 und P2) sind so gewählt, dass sie vom Ellipsenmittelpunkt 1000 Einheiten entfernt sind und die Verbindungslinien zum Mittelpunkt mit der x-Achse den Winkel 45° bzw 180° einschließen. Der so gezeichnete Bogen beginnt genau dort, wo diese Verbindungslinien die Ellipse schneiden.

Die rechte Paintbox zeigt den Ellipsenbogen, bei dem die Arc-Prozedur mit den Winkelargumenten aufgerufen wurde. Nimmt man an, dass diese Winkel dieselben wären, die in dem ersten Beispiel verwendet wurden, so sieht man dass der Ellipsenbogen an einer anderen Stelle beginnt als dem Schnittpunkt der Winkellinie mit der Ellipse. Das liegt daran, dass das Winkelargument hier nicht der geometrisch Winkel zwischen dieser Geraden und der x-Achse ist, sondern das Winkelargument in den Ellipsengleichungen, mit dem man jeden Punkt auf der Ellipse beschreiben kann (x = a * cos(angle), y = b * sin(angle)). Die beiden wären identisch im Fall eines Kreises, doch im Fall der gezeigten Ellipse ist der y-Wert im Verhältnis b/a gestaucht, und damit ändert sich auch der Winkel.

Wiegesagt, das kannst du mit den Lazarus-Release-Versionen unter Windows nicht nachvollziehen, weil da die Start- und Endpunkte falsch berechnet werden.
Dateianhänge
arc_SxSyExEy_angle_sweep.zip
(2.78 KiB) Noch nie heruntergeladen
arc.png
arc.png (10.88 KiB) Noch nicht betrachtet

Antworten