Ellipsen - Wie geht es einfacher?

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
Benutzeravatar
Mischa
Beiträge: 152
Registriert: 29.08.2004 06:52
Wohnort: Hellhorst

Ellipsen - Wie geht es einfacher?

Beitrag von Mischa »

Hi!

Dreht sich gerade um Kreise. :wink:
Das folgende Programm wandelt eine mit der Maus gezeichnete
Ellipse, die natürlich unschön ist, in eine perfekte API-Ellipse um.
Dabei soll und wird auch der Neigungswinkel beachtet.
Das klappt so schon ganz gut, aber meine "Methode" erscheint
mir doch sehr umständlich. Nun gut, bin auch nicht der
Mathematiker. Würde mich interessieren, ob das auch einfacher
geht. Und wehe es lacht einer über meine Patchwork-Methode! /:->

Code: Alles auswählen

Global pen
#b = 0.01745329 
Procedure.f Winkel(x,y) 
 Winkel.f 
 If x = 0 
  If y <  0 : Winkel = -90 : EndIf 
  If y >= 0 : Winkel =  90 : EndIf 
 Else 
  Winkel = ATan(y/x)/#b 
  If x < 0 : Winkel + 180 : EndIf 
 EndIf 
 ProcedureReturn Winkel 
EndProcedure


Global nw,nh
Procedure Transform(dc,winkel.f,w,h)
  s.f=Sin(6.28318531*winkel/360)
  c.f=Cos(6.28318531*winkel/360)
  wtform.XFORM
  wtform\eM11 = c
  wtform\eM12 = s
  wtform\eM21 = -s 
  wtform\eM22 = c
  wtform\eDx   = w/2
  wtform\eDy   = h/2
  tdc=CreateEnhMetaFile_(dc,0,0,0)
  SetGraphicsMode_(tdc,#GM_ADVANCED)
  SetWorldTransform_(tdc,wtform)
  SelectObject_(tdc,GetStockObject_(#HOLLOW_BRUSH))
  oldpen=SelectObject_(tdc,pen)
  Ellipse_(tdc,0,0,w,h)
  SelectObject_(tdc,oldpen)
  trotwmf=CloseEnhMetaFile_(tdc)
  GetEnhMetaFileHeader_(trotwmf,SizeOf(ENHMETAHEADER),ehead.ENHMETAHEADER)
  nw=ehead\rclBounds\right-ehead\rclBounds\left
  nh=ehead\rclBounds\bottom-ehead\rclBounds\top
  ProcedureReturn trotwmf
EndProcedure


If OpenWindow(0, 0, 0, 800, 640, "Circles",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  CreateImage(0,800,600)
  StartDrawing(ImageOutput(0))
    Box(0,0,800,600,RGB(0,0,255))
  StopDrawing()
  CopyImage(0,1)
  CopyImage(0,2)

  ;  
  ImageGadget(0, 0, 0, 0, 0, ImageID(1))
  reset = ButtonGadget(#PB_Any,300,610,200,20,"Reset")
  NewList p.POINT()
  pen=CreatePen_(#PS_SOLID,10,RGB(255,255,0))
  
  Repeat
    EventID = WaitWindowEvent()
    x = WindowMouseX(0)
    y = WindowMouseY(0)
    
    If EventID=#PB_Event_Gadget
      If EventGadget()=reset
        CopyImage(0,1)
        CopyImage(0,2)
        SetGadgetState(0,ImageID(2))
        While GetAsyncKeyState_(#VK_LBUTTON):Wend
      EndIf
    Else
      GetAsyncKeyState_(#VK_LBUTTON)
      If GetAsyncKeyState_(#VK_LBUTTON)
        If first
          If x<>oldx Or y<>oldy
            hdc=StartDrawing(ImageOutput(2))
              oldpen=SelectObject_(hdc,pen)
              MoveToEx_(hdc,oldx,oldy,0)
              LineTo_(hdc,x,y)
              SelectObject_(hdc,oldpen)
            StopDrawing()
            SetGadgetState(0,ImageID(2))
            If x<lx
              lx = x : ly = y
            ElseIf x>rx
              rx = x : ry = y
            EndIf
            If y<ty
              ty = y : tx = x
            ElseIf y>by
              by = y : bx = x
            EndIf
            AddElement(p())
            p()\x = x
            p()\y = y
            oldx = x
            oldy = y
          EndIf
        Else
          pressed=1
          oldx = x
          oldy = y
          first=1
          ClearList(p())
          AddElement(p())
          p()\x = x
          p()\y = y          
          lx = x : ly = y
          rx = x : ry = y
          tx = x : ty = y
          bx = x : by = y
        EndIf
      ElseIf pressed
        first=0
        pressed=0

        ay = by-ty
        ax = rx-lx
        my = ay/2 + ty
        mx = ax/2 + lx
        slx = lx
        sly = ty

        
        a.f  = Winkel(ax,ay)
        If tx<bx
          suba.f = 90.0 - a
          rev = 1
        Else
          suba.f = a
          rev = 0
        EndIf
        If ay<ax
          If rev=0
            nosuba.f = 0.0
          Else
            nosuba = 90.0
          EndIf
        Else
          If rev=0
            nosuba.f = 90.0
          Else
            nosuba = 0.0
          EndIf
        EndIf

        
        lx = mx : ly = my
        rx = mx : ry = my
        tx = mx : ty = my
        bx = mx : by = my
        
        ForEach p()
          arx.f = (p()\x - mx) * Cos(6.28318531*suba/360) - (p()\y - my) * Sin(6.28318531*suba/360) + mx
          ary.f = (p()\x - mx) * Sin(6.28318531*suba/360) + (p()\y - my) * Cos(6.28318531*suba/360) + my
          If arx<lx
            lx = arx : ly = ary
          ElseIf arx>rx
            rx = arx : ry = ary
          EndIf
          If ary<ty
            ty = ary : tx = arx
          ElseIf ary>by
            by = ary : bx = arx
          EndIf
        Next

        If a>70.0 Or a<20.0 ;Toleranz-Grenzen
          suba = nosuba
        Else
          suba * -1
        EndIf
        
        w  = rx - lx
        h  = by - ty

        dc=StartDrawing(ImageOutput(1))
          SetGraphicsMode_(dc,#GM_ADVANCED)
          emf=Transform(dc,suba,w,h)
          rdiffx = (w-nw)/2 + lx
          rdiffy = (h-nh)/2 + ty

          rmeta.RECT
          rmeta\left = rdiffx
          rmeta\top  = rdiffy
          rmeta\right  = rdiffx + nw-1
          rmeta\bottom = rdiffy + nh-1
          PlayEnhMetaFile_(dc,emf,rmeta)
          DeleteEnhMetaFile_(emf)
        StopDrawing()
        CopyImage(1,2)
        SetGadgetState(0,ImageID(2))
      EndIf
    EndIf
    
  Until EventID = #PB_Event_CloseWindow
  
EndIf

End
Gruß,
Mischa
Benutzeravatar
Mischa
Beiträge: 152
Registriert: 29.08.2004 06:52
Wohnort: Hellhorst

Beitrag von Mischa »

Entschuldigung! :oops:

Die Größe des Metafileheaders ist abweichend in verschiedenen
PB-Versionen. Ich habe mal 'n SizeOf() eingefügt.
(Sollte man ja sowieso machen. Böser Fehler)

Hat sich denn irgendwer mal mit dem Thema beschäftigt?
Oder gibt es keine ordentliche mathematische Lösung für diese
Sache. Na ja, die EMFs haben natürlich den Vorteil der
Skalierbarkeit, von soher verbaue ich wohl meinen
Workaround. Geht ja auch so.

Gruß,
Mischa
Benutzeravatar
dige
Beiträge: 1235
Registriert: 08.09.2004 08:53

Beitrag von dige »

Mischa, schön das Du noch dabei bist und ... ja, schönes Codebeispiel,
glaube nicht das das noch zu verbessern geht.
"Papa, ich laufe schneller - dann ist es nicht so weit."
Benutzeravatar
Mischa
Beiträge: 152
Registriert: 29.08.2004 06:52
Wohnort: Hellhorst

Beitrag von Mischa »

Hi!

Danke für das Feedback.
Doch, doch, bin noch dabei. 8)
Allerdings ist der Zeitfaktor immer so 'ne Sache
mit (mittlerweile) zwei Kindern.

Nichts desto trotz ist Yovo jetzt fertig und bei dem
nächsten "kommerziellen" Programm "Pix" fehlt nur noch
die Hilfe. Und dann ist da noch eins (ca. 70% fertig)

Das sind zwar sehr spezielle Anwendungen, aber für mich
auch in meiner täglichen Arbeit nützlich.
Und bislang bin ich PB treu geblieben..

Der Code hier ist übrigens natürlich optimierbar. Mit ging es
eher um eine alternative Methode.
Ist aber auch mal wieder eine sehr spezielle Funktion, die außer
mir keiner braucht. :wink:

Ist auch bereits in Yovo eingebaut, als Markierungsfunktion, um
besondere Stellen eines Bildes hervorzuheben, z.B. wenn man
eine Anleitung herstellen möchte.

Gruß,
Mischa
Antworten