AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Eigene Ellipsen- und Arc Funktion funktioniert nicht. Warum?
Thema durchsuchen
Ansicht
Themen-Optionen

Eigene Ellipsen- und Arc Funktion funktioniert nicht. Warum?

Ein Thema von DualCoreCpu · begonnen am 7. Nov 2015 · letzter Beitrag vom 7. Nov 2015
Antwort Antwort
DualCoreCpu
(Gast)

n/a Beiträge
 
#1

Eigene Ellipsen- und Arc Funktion funktioniert nicht. Warum?

  Alt 7. Nov 2015, 14:30
Hallo, ich habe gerade Luckies Windows API Tutorial in Arbeit und wollte gerade mal die Arc- und die Ellipdenfunktion nachbauen.

Die gibt es zwar im Windows API schon. Da ich aber mal wieder meine verschütteten Mathe Kenntnisse auffrischen will, wobei mit das reine Lehrbuchstudium zu stupide ist, hab ich mich entschlossen, diese Funktionen nachzubauen, was ja ohne Mathekenntisse unmöglich sein dürfte.

Leider ist meine eigene Ellipse zu groß und die Location stimmt auch nicht, der Mittelpunkt meiner eigenen Ellipse ist die linke obere Ecke, ich möchte aber, daß der Mittelpukt der Ellipse der gleiche ist, wie in Luckies Demo Programm.

Ich möchte also erreichen, daß sich meine eigene Arc- und Ellipse Funktion, auch meine Pie Funktion exakt genau so verhalten, wie die Originale aus dem Windows API.

Was mache ich falsch?

Hier ist mein Code, zuerst Luckies Demo:

Delphi-Quellcode:
program tut1;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  Windows,
  Messages,
  arcs;


const
  ClassName = 'DrawClass';
  AppName = 'Zeichnen';

  WindowWidth = 500;
  WindowHeight = 400;


function WndProc(hWnd: HWND; uMsg: UINT; wParam: wParam; lParam: LParam):
  lresult; stdcall;
var
  x, y : integer;
  WndDC: HDC;
  ps: TPaintStruct;
  RedBrush, RedBrushOld: HBRUSH;
  GreenHatchBrush, GreenHatchBrushOld: HBRUSH;
  Pen, PenOld: HPEN;
begin
  Result := 0;
  case uMsg of
    WM_CREATE:
    begin
      { Fenster zentrieren }
      x := GetSystemMetrics(SM_CXSCREEN);
      y := GetSystemMetrics(SM_CYSCREEN);
      MoveWindow(hWnd, (x div 2) - (WindowWidth div 2),
        (y div 2) - (WindowHeight div 2),
        WindowWidth, WindowHeight, true);

    end;
    WM_PAINT:
    begin
      WndDC := BeginPaint(hWnd, ps);
         { eine einfache Linie }
         MoveToEx(WndDC, 20, 10, nil);
        LineTo(WndDC, 20, 90);

        { ein Rechteck }
        Rectangle(WndDC, 40, 10, 60, 90);

        { und das ganze gefüllt }
        RedBrush := CreateSolidBrush(RGB(255, 0, 0));
        RedBrushOld := SelectObject(WndDC, RedBrush);
        Rectangle(WndDC, 80, 10, 100, 90);
        { alten Brush wieder herstellen und benutzten löschen }
        SelectObject(WndDc, RedBrushOld);
        DeleteObject(RedBrush);

        { und das ganze noch mal mit Muster }
        GreenHatchBrush := CreateHatchBrush(HS_BDIAGONAL, RGB(0, 255, 0));
        GreenHatchBrushOld := SelectObject(WndDC, GreenHatchBrush);
        RectAngle(WndDC, 120, 10, 140, 90);
        { alten Brush wieder herstellen und benutzten löschen }
        SelectObject(WndDC, GreenHatchBrushOld);
        DeleteObject(GreenHatchBrush);

        { und nochmal mit einem anderen Stift }
        Pen := CreatePen(PS_DOT, 1, RGB(0, 0, 255));
        SetBkMode(WndDC, TRANSPARENT);
        PenOld := SelectObject(WndDC, Pen);
        RectAngle(WndDC, 160, 10, 180, 90);
        SelectObject(WndDC, PenOld);
        DeleteObject(Pen);

        { Ellipse }
        Ellipse(WndDC, 30, 110, 180, 200);
        { Kreis }
        Ellipse(WndDC, 80, 130, 130, 180);

        { Chord }
        Chord(WndDC, 220, 110, 300, 200, 280, 120, 190, 230);

        { Pie }
        Pie(WndDC, 300, 110, 500, 200, 310, 110, 200, 260);

        { RoundRect }
        RoundRect(WndDC, 30, 220, 180, 350, 35, 35);
      EndPaint(hWnd, ps);
    end;
    WM_DESTROY: PostQuitMessage(0);
  else
    Result := DefWindowProc(hWnd, uMsg, wParam, lParam);
  end;
end;


var
  wc: TWndClassEx = (
    cbSize : SizeOf(TWndClassEx);
    Style : CS_HREDRAW or CS_VREDRAW;
    lpfnWndProc : @WndProc;
    cbClsExtra : 0;
    cbWndExtra : 0;
    hbrBackground : COLOR_APPWORKSPACE;
    lpszMenuName : nil;
    lpszClassName : ClassName;
    hIconSm : 0;
  );
  msg: TMsg;

begin
  { TODO -oUser -cConsole Main : Insert code here }
  wc.hInstance := hInstance;
  wc.hIcon := LoadIcon(hInstance, IDI_WINLOGO);
  wc.hCursor := LoadCursor(0, IDC_ARROW);

  RegisterClassEx(wc);
  CreateWindowEx(0, ClassName, AppName, WS_CAPTION or WS_VISIBLE or WS_SYSMENU,
     CW_USEDEFAULT, CW_USEDEFAULT, WindowWidth, WindowHeight, 0, 0, hInstance, nil);

  while GetMessage(msg, 0,0,0) do
  begin
    TranslateMessage(msg);
    DispatchMessage(msg);
  end;
end.
Und nun meine Funktionen:

Delphi-Quellcode:
unit arcs;

interface

uses
  Windows, math;

function Arc(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;
function Ellipse(dc: HDC; left,Top,Right,Bottom: Integer): BOOL;
function Pie(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;

implementation

var _theArcDirection_: Longint = AD_COUNTERCLOCKWISE;

procedure DrawCircleSeg(Handle: HDC;X,Y,startgrd,endgrd,radius: Integer; Color: COLORREF);
var angle: Integer;
begin
  for angle:=startGrd to endGrd do
  begin
    SetPixel(Handle,
     Round(Radius * cos(angle * pi/180)) + x,
     Round(Radius * sin(angle * pi/180)) + y,
     Color
     );
  end;
  MoveToEx(Handle, Round(radius * cos (Startgrd * pi/180)) + x, Round(radius * sin(startgrd * pi/180)) + y, nil);
  LineTo(Handle,x,y);
  LineTo(Handle,Round(radius * cos (endgrd * pi/180)) + x, Round(radius * sin(endgrd * pi/180)) + y);
end;

procedure DrawEllipseSeg(Handle: HDC;X,Y,startgrd,endgrd,Xradius,Yradius: Integer; Color: COLORREF);
var angle: Integer;
begin
  case _theArcDirection_ of
   AD_COUNTERCLOCKWISE:
    for angle:=startGrd to endGrd do
    begin
      SetPixel(Handle,
       Round(Xradius * cos(angle * pi/180)) + x,
       Round(Yradius * sin(angle * pi/180)) + y,
       Color
       );
    end;
   AD_CLOCKWISE:
    for angle:=endGrd downto startGrd do
    begin
      SetPixel(Handle,
       Round(Xradius * cos(angle * pi/180)) + x,
       Round(Yradius * sin(angle * pi/180)) + y,
       Color
       );
    end;
  end;
  MoveToEx(Handle, Round(Xradius * cos (Startgrd * pi/180)) + x, Round(Yradius * sin(startgrd * pi/180)) + y, nil);
  LineTo(Handle,x,y);
  LineTo(Handle,Round(Xradius * cos (endgrd * pi/180)) + x, Round(Yradius * sin(endgrd * pi/180)) + y);
end;

procedure DrawCircleL(Handle: HDC; X,Y,R: Integer; Color: COLORREF);
var angle: Integer;
begin
  for angle:=0 to 360 do
  begin
    SetPixel(Handle,
     Round(R * cos(angle * pi/180)) + x,
     Round(R * sin(angle * pi/180)) + y,
     Color
     );
  end;
end;

procedure DrawEllipseL(Handle: HDC; X,Y,a,b: Integer; Color: COLORREF);
var angle: Integer;
begin
  for angle:=0 to 360 do
  begin
    SetPixel(Handle,
     Round(a * cos(angle * pi/180)) + x,
     Round(b * sin(angle * pi/180)) + y,
     Color
     );
  end;
end;

{filled ellipse}
procedure DrawEllipseF(Handle: HDC; xc,yc,a,b: Integer; Color: COLORREF);
 var x,y:integer; aa,aa2,bb,bb2,d,dx,dy:longint;
begin
 x:=0;y:=b;
 aa:=longint(a)*a; aa2:=2*aa;
 bb:=longint(b)*b; bb2:=2*bb;
 d:=bb-aa*b+aa div 4;
 dx:=0;dy:=aa2*b;
 MoveToEx(Handle, xc,yc-y, nil);
 LineTo(Handle,xc,yc+y); { original vLin mit denselben Parametern }
 while(dx<dy)do begin
  if(d>0)then begin dec(y); dec(dy,aa2); dec(d,dy); end;
  inc(x); inc(dx,bb2); inc(d,bb+dx);
  MoveToEx(Handle,xc-x,yc-y, nil);
  LineTo(Handle,xc-x,yc+y);
  MoveToEx(Handle,xc+x,yc-y, nil);
  LineTo(Handle,xc+x,yc+y); { original vLin mit denselben Parametern }
  end;
 inc(d,(3*(aa-bb)div 2-(dx+dy))div 2);
 while(y>=0)do begin
  if(d<0)then begin
   inc(x); inc(dx,bb2); inc(d,bb+dx);
   MoveToEx(Handle,xc-x,yc-y,nil);
   LineTo(Handle,xc-x,yc+y);
   MoveToEx(Handle,xc+x,yc-y,nil);
   LineTo(Handle,xc+x,yc+y); { original vLin mit denselben Parametern }
   end;
  dec(y); dec(dy,aa2); inc(d,aa-dy);
  end;
end;

function Arc(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;
var xm, ym, a,b, startgd, endgrad: Integer;
begin
  xm := Abs(Right - Left) div 2;
  ym := Abs(Bottom - Top) div 2;

  a := Right - xm;
  b := Bottom - ym;

  startgd := Round(arctan2(xStart, yStart));
  endgrad := Round(arctan2(xEnd, yEnd));
  
  
  case _theArcDirection_ of
   AD_COUNTERCLOCKWISE:
    begin
      DrawEllipseSeg(dc, xm, ym, startgd, endgrad, a, b, GetDCPenColor(dc));
    end;
   AD_CLOCKWISE:
    begin
      DrawEllipseSeg(dc, xm, ym, endgrad, startgd, a, b, GetDCPenColor(dc));
    end;
  end;

end;

function Pie(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;
var xm, ym, a,b: Integer;
begin
  xm := Abs(Right - Left) div 2;
  ym := Abs(Bottom - Top) div 2;

  a := Right - xm;
  b := Bottom - ym;

  SetArcDirection(dc, AD_COUNTERCLOCKWISE);
  if Arc(dc, Left, Top, Right, Bottom, xStart, yStart, xEnd, YEnd) then
  begin
    MoveToEx(dc, xStart, xStart, nil);
    LineTo(dc, xm, ym);
    MoveToEx(dc, xEnd, yEnd, nil);
    LineTo(dc, xm, ym);
  end
end;

function Ellipse(dc: HDC; left,Top,Right,Bottom: Integer): BOOL;
var xm, ym, a,b: Integer;
begin
  xm := Abs(Right - Left) div 2;
  ym := Abs(Bottom - Top) div 2;

  a := Right - xm;
  b := Bottom - ym;

  DrawEllipseL(dc, xm, ym, a-1, b-1, GetDCPenColor(dc)); //Begrenzungslinie
  DrawEllipseF(dc, xm, ym, a-1, b-1, GetDCBrushColor(dc)); //Füllung
end;

end.
Meine Ellipse erscheint außerdem schwarz gefüllt. Warum?
  Mit Zitat antworten Zitat
DualCoreCpu
(Gast)

n/a Beiträge
 
#2

AW: Eigene Ellipsen- und Arc Funktion funktioniert nicht. Warum?

  Alt 7. Nov 2015, 21:52
Das soll noch kein Push sein, habe nur die folgenden Funktionen wie folgt geändert. Dabei funktioniert die Arc Funktion noch immer überhaupt nicht, die Ellipse wird jetzt korrekt gezeichnet, ist jedoch nicht, wie im Originaldemo weiß gefüllt, sondern schwarz, obwohl ich nur die Ellipsenfunktion getauscht habe.

Delphi-Quellcode:
function Arc(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;
var xm, ym, a,b, startgd, endgrad: Integer;

//Hier eine Funktion zur Winkelberechnung aus den x,y Koordinaten von Start und Ende des Bogens
 function _angle(xS,yS,x,y: Integer): Integer;
 begin
  if (xS<x) and (yS<y) then
  begin
    startgd := Round(arctan2(-xS, -yS));
    delta := Round(arctan2(-yS, -xS));
    startgd := startgd + delta * 2;
    Result := startgd;
  end else
  if (xS<x) and (yS>y) then
  begin
    startgd := Round(arctan2(yS, -xS));
    delta := Round(arctan2(-xS, yS));
    startgd := startgd + round(2*pi);
    Result := startgd;
  end else
  if (xS>x) and (yS>y) then
  begin
    startgd := Round(arctan2(xS, yS));
    delta := Round(arctan2(yS, xS));
    startgd := startgd + delta*2 + round(2*pi);
    Result := startgd;
  end;
 end;


begin
  xm := Left + Abs(Right - Left) div 2;
  ym := Top + Abs(Bottom - Top) div 2;

  a := Right - xm;
  b := Bottom - ym;

  //startgd := Round(arctan2(xStart, yStart));
  //endgrad := Round(arctan2(xEnd, yEnd));
  
  //Hier will ich die korrekten Winkel berechnen. Laut MSDN nimmt die Arc() Funktion keinerlei
  //Korrekturen der Koordinaten vor, die müssen also vorher berechnet werden. Meine
  //Ellipsenfunktionen setzen aber auf Start- und Endwinkel. Diese will ich mit arctan()
  //berechnen, xStart,yStart,xEnd,yEnd werden ja übergeben und wenn die Strahlen passend
  //verlängert werden, schneiden sie auch einen Kreis mit gleichem Mittelpunkt.

  //Oben habe ich eine Unterfunktion, die mir den Winkel ebenso berechnet und die ich statt der
  //Winkelwerte in meine EllipseSeg Funktion eingesetzt habe.

  if (xStart<xm) and (yStart<ym) then
  begin
    startgd := Round(arctan2(-xStart, -yStart));
    delta := Round(arctan2(-yStart, -xStart));
    startgd := startgd + delta * 2;
  end else
  if (xStart<xm) and (yStart>ym) then
  begin
    startgd := Round(arctan2(yStart, -xStart));
    delta := Round(arctan2(-xStart, yStart));
    startgd := startgd + round(2*pi);
  end else
  if (xStart>xm) and (yStart>ym) then
  begin
    startgd := Round(arctan2(xStart, yStart));
    delta := Round(arctan2(yStart, xStart));
    startgd := startgd + delta*2 + round(2*pi);
  end;

  
  case _theArcDirection_ of
   AD_COUNTERCLOCKWISE:
    begin
      DrawEllipseSeg(dc, xm, ym, _angle(xStart,yStart,xm,ym), _angle(xEnd,yEnd,xm,ym), a, b, GetDCPenColor(dc));
    end;
   AD_CLOCKWISE:
    begin
      //So hatte ich die Winkelwerte vorher eingesetzt, jetzt aber wie oben
      //bei AD_COUNTERCLOCKWISE
      DrawEllipseSeg(dc, xm, ym, endgrad, startgd, a, b, GetDCPenColor(dc));
    end;
  end;

end;

function Pie(dc: HDC; Left, Top, Right, Bottom, xStart, yStart, xEnd, yEnd: Integer): BOOL;
var xm, ym, a,b: Integer;
begin
  xm := Left + Abs(Right - Left) div 2;
  ym := Top + Abs(Bottom - Top) div 2;

  a := Right - xm;
  b := Bottom - ym;

  SetArcDirection(dc, AD_COUNTERCLOCKWISE);
  if Arc(dc, Left, Top, Right, Bottom, xStart, yStart, xEnd, YEnd) then
  begin
    MoveToEx(dc, xStart, xStart, nil);
    LineTo(dc, xm, ym);
    MoveToEx(dc, xEnd, yEnd, nil);
    LineTo(dc, xm, ym);
  end
end;

function Ellipse(dc: HDC; left,Top,Right,Bottom: Integer): BOOL;
var xm, ym, a,b: Integer;
begin
  xm := Left + Abs(Right - Left) div 2;
  ym := Top + Abs(Bottom - Top) div 2;

  a := Right - xm;
  b := Bottom - ym;

  DrawEllipseL(dc, xm, ym, a-1, b-1, GetDCPenColor(dc)); //Begrenzungslinie
  DrawEllipseF(dc, xm, ym, a-1, b-1, GetDCBrushColor(dc)); //Füllung
end;
Die komplette Ellipse wird inzwischen korrekt gezeichnet, ist aber nicht weiß, sindern schwarz gefüllt. Wie also wird die Füllfarbe übergeben?

Warum funktioniert die Füllung im Original, aber nicht in meiner Funktion?

Ich bleibe dran!.

Geändert von DualCoreCpu ( 7. Nov 2015 um 21:56 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:48 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz