Seite 1 von 1

Lage der Cursors in Bezug zu einer geschlossenen Kontur

Verfasst: 11.11.2008 12:28
von alter Mann
nach Vorgabe eine geschlossenen Kontur und einer Randdicke wird die Lage des Cursor (innen, außen, auf dem Rand) bestimmt

Code: Alles auswählen

; Lage des Cursors in Bezug zu einer geschlossenen Kontur
; 
; Autor : alter Mann
; Datum : 11.11.08
;
; Demo
;

Structure lPkt
  X.l
  Y.l
EndStructure

#LONG_MIN       =(-2147483647 - 1)           ; minimum (signed) long value
#LONG_MAX       =2147483647                  ; maximum (signed) long value

EnableExplicit

;##############################################################################
;Funkt.:  Lage eine Punktes in Bezug auf eine geschlossene Kontur
;E.Par.:  X,Y                Punktkoordinate
;         Anz                Anzahl Punkte der Kontur
;         Kontur(1).lPkt     Feld mit Punkten der Punktfolge
;         Abs                Randgenauigkeit
;F.Code:  -2                 falsche Eingabe
;         -1                 Punkt liegt aussen
;          0                 Punkt liegt auf Rand
;          1                 Punkt liegt innen
;##############################################################################
Procedure.l PBGeo_PktInKontur (X.l, Y.l, Anz.l, Kontur.lPkt(1), Abs.l)

  Protected Ret.l=0, A0.l, A1.l, A2.l, Vx.l, Vy.l, i.l
  Protected Abs2.q=Abs, A3.q, A4.q, A.q, H.q, Vx1.q,Vy1.q,Vx2.q,Vy2.q

  Abs2 = Abs2*Abs2 + 1

  If Anz < 3 And Abs < 0 
    ProcedureReturn -2
  EndIf

  ; Anfangspunkt auf gleicher Hoehe
  A1 = Kontur(0)\X - X
  A0 = A1
  If A0 = 0
    ; suche Punkt auf anderer Hoehe
    For i = Anz - 1 To 1 Step -1 
      A0 = Kontur(i)\X - X
      If A0 <> 0
        Break
      EndIf
    Next i
    ; alle Punkte auf gleicher Hoehe -> Punkt innerhalb ?
    If A0 = 0
      A1 = Kontur(0)\Y
      A2 = A1
      For i = 1 To Anz-1 Step 1 
        If Kontur(i)\Y < A1
          A1 = Kontur(i)\Y
        ElseIf Kontur(i)\Y > A2
          A2 = Kontur(i)\Y
        EndIf
        If Y >= A1-Abs And Y <= A2+Abs
          ProcedureReturn 0
        EndIf
      Next i
      ProcedureReturn -1
    EndIf
  EndIf
  For i=1 To Anz-1 Step 1
    A2 = Kontur(i)\X - X
    Vx = Kontur(i)\X - Kontur(i-1)\X
    Vy = Kontur(i)\Y - Kontur(i-1)\Y
    If A1 <> 0
      A = A1
    Else
      A = A0
    EndIf

    If A * A2 < 0
      H  = A1 - A2
      A3 = Kontur(i-1)\Y * H + A1 * Vy
      A4 = Y * H
    
      If (H >= 0 And A3 > A4) Or (H < 0 And A3 < A4 )
        Ret = 1 - Ret
      ElseIf A3 - Abs <= A4 And A3 + Abs >= A4 
        ProcedureReturn 0
      EndIf
    EndIf
    
    If Vx <> 0 Or Vy <> 0
      Vx1 = X - Kontur(i-1)\X
      Vy1 = Y - Kontur(i-1)\Y
      If Vx1 * Vx1 + Vy1 * Vy1 <= Abs2
        ProcedureReturn 0
      EndIf
      Vx2 = X - Kontur(i)\X
      Vy2 = Y - Kontur(i)\Y
      A3 = Vx * Vy1 - Vy * Vx1
      If A3 > #LONG_MIN And A3 < #LONG_MAX
        If A3*A3 <= Abs2*(Vx*Vx+Vy*Vy) And Vx1*Vx + Vy1*Vy >= 0 And Vx2*Vx + Vy2*Vy <= 0 
          ProcedureReturn 0
        EndIf
      Else
        Protected dA3.d = A3, dVx.d = Vx, dVy = Vy
        If dA3*dA3 <= Abs2*(dVx*dVx+dVy*dVy) And Vx1*Vx + Vy1*Vy >= 0 And Vx2*Vx + Vy2*Vy <=0  
          ProcedureReturn 0
        EndIf
      EndIf
    EndIf
    A1 = A2
    If A1 <> 0
      A0 = A1
    EndIf
  Next i
  ProcedureReturn Ret * 2 - 1
EndProcedure

#Image1 = 1
#Window = 2
#ImageGad = 3
#Button = 4
#Option1 = 5
#Option2 = 6
#Text = 7
#MaxX = 800
#MaxY = 600
#MaxAnz = 1000

Dim K.lPkt(#MaxAnz)
Define i.l,Px.l,Py.l,Abs.l
Define Anzahl.l = 0
Define Event.l
Define Aktion.l = #Option1
Define Input$

If CreateImage(#Image1,#MaxX,#MaxY) = 0
  MessageRequester("Achtung!","Kann Image nicht erstellen")
  End
EndIf

If OpenWindow(#Window,0,0,#MaxX+10,#MaxY+55,"Cursor in Kontur",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
  If CreateGadgetList(WindowID(#Window))
    ImageGadget (#ImageGad,  5,10, #MaxX,#MaxY,ImageID(#Image1))
    ButtonGadget(#Button,5,#MaxY+20,100,25, "Schließen")
    OptionGadget(#Option1,110,#MaxY+15,100,20,"Kontur eingeben")
    OptionGadget(#Option2,110,#MaxY+35,100,20,"Lage des Cursors anzeigen")
    TextGadget(#Text,250,#MaxY+30,200,30,"Lage : -")
  EndIf
  
  StartDrawing(ImageOutput(#Image1))
  Box(0,0,#MaxX,#MaxY,RGB(50,50,50))
  StopDrawing()
  SetGadgetState(#ImageGad,ImageID(#Image1))

  SetGadgetState(#Option1,1)  

  Repeat
    Event = WaitWindowEvent()
     
    Select Event

      Case #PB_Event_Gadget
        
        Select EventGadget()
          
          Case #ImageGad
            If Aktion = #Option1 And EventType() = #PB_EventType_LeftClick And Anzahl < #MaxAnz
              K(Anzahl)\X = WindowMouseX(#Window) - GadgetX(#ImageGad)
              K(Anzahl)\Y = WindowMouseY(#Window) - GadgetY(#ImageGad)
              Anzahl + 1

              StartDrawing(ImageOutput(#Image1))
              Box(0,0,#MaxX,#MaxY,RGB(50,50,50))
              For i = 1 To Anzahl-1    
                LineXY(K(i-1)\X,K(i-1)\Y,K(i)\X,K(i)\Y,RGB(250,250,0))
              Next
              LineXY(K(i-1)\X,K(i-1)\Y,K(0)\X,K(0)\Y,RGB(250,250,0))
              StopDrawing()
              SetGadgetState(#ImageGad,ImageID(#Image1))                            
            EndIf
          
          Case #Button
            Event = #PB_Event_CloseWindow
             
          Case #Option1
            If Aktion <> #Option1
              Anzahl = 0
              StartDrawing(ImageOutput(#Image1))
              Box(0,0,#MaxX,#MaxY,RGB(50,50,50))
              StopDrawing()
              SetGadgetState(#ImageGad,ImageID(#Image1))               
              Aktion = #Option1
              SetGadgetText(#Text,"Lage: - ")
            EndIf
               
          Case #Option2
            If Aktion <> #Option2
              If Anzahl > 2 
                Aktion = #Option2
                K(Anzahl)\X = K(0)\X
                K(Anzahl)\Y = K(0)\Y
                Anzahl + 1
                Repeat
                  Input$ = InputRequester("Randbreite","Breite (in Pixeln) (>=0)","2")
                  Abs = Val(Input$)
                Until Abs > 0
              Else
                MessageRequester("Achtung!","zu wenig Punkte")
                SetGadgetState(#Option1,1)
                SetGadgetText(#Text,"Lage: - ")
              EndIf
            EndIf
        EndSelect
    EndSelect
    If Aktion = #Option2
      Px = WindowMouseX(#WindoW) - GadgetX(#ImageGad)
      Py = WindowMouseY(#WindoW) - GadgetY(#ImageGad)
      i = PBGeo_PktInKontur(Px,Py,Anzahl,K(),Abs)
      If i = -1
        SetGadgetText(#Text,"Lage ("+Str(Px)+","+Str(Py)+"): außen")
      ElseIf i = 0
        SetGadgetText(#Text,"Lage ("+Str(Px)+","+Str(Py)+"): Rand")
      Else
        SetGadgetText(#Text,"Lage ("+Str(Px)+","+Str(Py)+"): innen")
      EndIf
    EndIf
  Until Event = #PB_Event_CloseWindow
EndIf
CloseWindow(#Window)
...als Ablenkung zur angefangenen Numeric-Lib

Verfasst: 11.11.2008 12:44
von STARGÅTE
Nett, aber er beachtet dabei nur die Orientierung des Randes oder ?

Denn wenn man überlagerte "Flächen" erzeugt sollte die Überlagerte Fläche immer noch innen sein oder ?

Muss ja kein BUG sein, vllt soll es auch so sein, nur anschaulich gesehen wäre diese fläche doch immer noch innen oder?

Bild
Hier wird im Stern außen angezeigt...
... rein mathematisch würe es hier zu auslöschung der fläche kommen, aber ob das in einem "Spiel" oder Anwendung auch gewünscht ist ?

Verfasst: 11.11.2008 13:48
von alter Mann
Ist kein Bug sondern so gewollt.
Aber der Hinweis ist schon richtig, sollte ich vielleich per Flag noch abfangen.

Verfasst: 11.11.2008 14:35
von alter Mann
allerdings kann man den Stern auch ohne sich kreuzende Linien
beschreiben