Tacho

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
Lukas-P
Beiträge: 262
Registriert: 07.10.2004 12:03

Tacho

Beitrag von Lukas-P »

Hallo ich möchte mit linexy() oder line() einen Tacho machen, den man aber auch bewegen kann. Kann mkir da irgndwie jemand helfen??





danke schonmal im Voraus
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Also einen analogen Tacho mit Zeigern? Dann solltest du dich mit Sinus, Cosinus und Tangents auskennen. Diese wirst du brauchen zur Berechnung wie lang der Zeiger in bestimmten Winkellagen sein soll.

Dazu zeichne dir mal auf, wie der Zeiger liegen könnte. Etwa so:

Code: Alles auswählen

               /|
              / |
             /  |
            /   |
           /    |
        z /     |
         /      |
        /\      |
       /  \     |
______/_a_)_____|
Der Strich nach oben rechts ist der Zeiger, unten ist die horizontale Achse. Das "a" ist der Winkel unter dem Zeiger. Die vertikale Linie rechts ist eine gedankliche Linie von Zeigerspitze zur horizintalen Achse.
Schon hast du ein rechtwinkliges Dreieck welches du berechnen kannst. Du brauchst also den Winkel a und musst wissen wie lang der Zeiger ist (solltest du dir vorher überlegen, versteht sich) und kannst dann errechnen wo wie weit die Zeigerspitze nach rechts gehen muss.
Das geht dann so:

Code: Alles auswählen

cos(a) = X-Strecke / z
umgestellt nach der X-Strecke ergibt sich:

Code: Alles auswählen

X-Strecke = cos(a) * z
Somit musst du den cosinus() des Winkels berechnen und z ist die Länge des Zeigers, dann erhälst du schonmal die erste koordinate für die Linie des Zeigers. Um nun noch die Höhe zu erhalten, könnte man den Sinus nehmen:

Code: Alles auswählen

sin(a) = Y-Strecke / z
umgestellt nach der Y-Strecke ergibt sich:

Code: Alles auswählen

Y-Strecke = sin(a) * z
Schon hast du auch diese Strecke. Dein Zeiger müsste dann so angezeigt werden:
line(0,0, X-strecke, Y-strecke)

Alles aber setzt vorraus dass du den Winkel des Zeigers kennst. Das sollte aber kein Problem sein. Wenn der Halbkreis 180 Grad sind, und du etwa 200 Km/h als volle halbe Drehung anzeigen willst, und der Tache jetzt auf 100 Km/h steht, sind das also 90 Grad, also ist der Winkel dann 90 Grad groß.

Das war jetzt ein Beispiel für den positiven Halbkreis des Tachos. Wenn es ein kompletter Kreis werden soll, musst du mein Muster von oben noch übertragen auf den unteren Kreis. Da legst du wieder ein Dreieck an und kannst per Sinus und Cosinus die Seiten (also die Kooridnaten des Zeigers) berechnen. ;)
Benutzeravatar
Lukas-P
Beiträge: 262
Registriert: 07.10.2004 12:03

Beitrag von Lukas-P »

Ich glaub ich hol doch lieber ein Sprite, das ich rotiere. Das ist mir irgendwie zu kompliziert. Trotzdem danke!!! :allright: :allright:
Benutzeravatar
wichtel
Beiträge: 150
Registriert: 09.09.2004 08:35
Wohnort: Hattersheim

Beitrag von wichtel »

ich habe mal eine analog Uhr gemacht.
(jaja, heute würde ich das resize und das ruckeln anders machen, aber für zum zeigen wie nen Tacho geht langt es hoffe ich)

Code: Alles auswählen

; Variablen und Konstanten initialisieren

#version="(c) oppi 2003, V1.70"
#appname="ANACLOX"
#ininame="anaclox.ini"

Global width, height, winx, winy
Global box.l,s, PI2.f, PI.f, xm, ym, radius
Global tickcol.l, seccol.l, mincol.l, hcol.l, backcol.l, boxcol.l, jewcol.l, txtcol.l 
Global tid.l, info$, font.l,s.l,os.l
Global flags.l

PI2=ATan(1)*8
PI=ATan(1)*4

Structure xy
  xa.l
  ya.l
  xe.l
  ye.l
  xb.l
  yb.l
  xc.l
  yc.l
  xf.l
  yf.l
EndStructure

Dim ticks.xy(60)
Dim secs.xy(60)
Dim mins.xy(60)
Dim hrs.xy(60)
Dim M$(12)
M$(1)="JAN"
M$(2)="FEB"
M$(3)="MAR"
M$(4)="APR"
M$(5)="MAY"
M$(6)="JUN"
M$(7)="JUL"
M$(8)="AUG"
M$(9)="SEP"
M$(10)="OCT"
M$(11)="NOV"
M$(12)="DEZ"



;- GUI Konstanten

#win=0
#clock=0

#set=0
#OnTop=0
#ShowDay=1
#ShowMonth=2
#ShowYear=3
#ShowInfo=4
#setInfo=5
#default=8
#ver=9
#quit=10

#seccol=11
#mincol=12
#hrscol=13
#jewcol=14
#txtcol=15
#backcol=16
#boxcol=17
#tickcol=18


Procedure LoadPrefs(ininame.s)
  OpenPreferences(ininame)
  info$  =ReadPreferenceString("info",#version)
  width  =ReadPreferenceLong("width",300)  
  height =ReadPreferenceLong("height",300)  
  winx   =ReadPreferenceLong("winx",GetSystemMetrics_(#SM_CXSCREEN)/2-width/2) 
  winy   =ReadPreferenceLong("winy",GetSystemMetrics_(#SM_CYSCREEN)/2-height/2)
  boxcol =ReadPreferenceLong("boxcol",$FFFFFF)
  backcol=ReadPreferenceLong("backcol",$FFFFFF)
  tickcol=ReadPreferenceLong("tickcol",$AAAAAA)
  jewcol =ReadPreferenceLong("jewcol",$00FFFF)
  seccol =ReadPreferenceLong("seccol",$0000FF)
  mincol =ReadPreferenceLong("mincol",$00FF00)
  hcol   =ReadPreferenceLong("hcol",$FF0000)
  txtcol =ReadPreferenceLong("txtcol",$111111)
  flags  =ReadPreferenceLong("flags",1+2+16)
  ClosePreferences()
EndProcedure

Procedure savePrefs(ininame.s)
  CreatePreferences(ininame)
  WritePreferenceString("info",info$)
  WritePreferenceLong("width",WindowWidth())  
  WritePreferenceLong("height",WindowHeight())  
  WritePreferenceLong("winx",WindowX()) 
  WritePreferenceLong("winy",WindowY())
  WritePreferenceLong("boxcol",boxcol)
  WritePreferenceLong("backcol",backcol)
  WritePreferenceLong("tickcol",tickcol)
  WritePreferenceLong("jewcol",jewcol)
  WritePreferenceLong("seccol",seccol)
  WritePreferenceLong("mincol",mincol)
  WritePreferenceLong("hcol",hcol)
  WritePreferenceLong("txtcol",txtcol)
  WritePreferenceLong("flags",flags)
  ClosePreferences()
EndProcedure

Procedure resetPrefs(ininame.s)
  CreatePreferences(ininame)
  ClosePreferences()
  LoadPrefs(ininame)  
EndProcedure

Procedure DrawClock()
  xm=WindowWidth()/2 : ym=WindowHeight()/2
  If ym<xm : radius=ym*0.98 : Else : radius=xm*0.98 : EndIf 
  font = LoadFont(0, "comic sans ms", radius*0.06) 
  ;- Koordinaten berechnen
  a.f=PI2 : t=0
  While a >= 0
   ticks(t)\xa=Sin(a+PI)*(radius*0.91)+xm
   ticks(t)\ya=Cos(a+PI)*(radius*0.91)+ym
   ticks(t)\xb=Sin(a+PI+PI/40)*(radius*0.89)+xm
   ticks(t)\yb=Cos(a+PI+PI/40)*(radius*0.89)+ym
   ticks(t)\xc=Sin(a+PI-PI/40)*(radius*0.89)+xm
   ticks(t)\yc=Cos(a+PI-PI/40)*(radius*0.89)+ym
   ticks(t)\xf=Sin(a+PI)*(radius*0.89)+xm
   ticks(t)\yf=Cos(a+PI)*(radius*0.89)+ym
   ticks(t)\xe=Sin(a+PI)*(radius*0.87)+xm
   ticks(t)\ye=Cos(a+PI)*(radius*0.87)+ym

   secs(t)\xa=Sin(a+PI)*(radius*0.10)+xm
   secs(t)\ya=Cos(a+PI)*(radius*0.10)+ym
   secs(t)\xe=Sin(a+PI)*(radius*0.84)+xm
   secs(t)\ye=Cos(a+PI)*(radius*0.84)+ym
   secs(t)\xf=Sin(a+PI)*(radius*0.75)+xm
   secs(t)\yf=Cos(a+PI)*(radius*0.75)+ym

   mins(t)\xa=Sin(a+PI)*(radius*0.10)+xm
   mins(t)\ya=Cos(a+PI)*(radius*0.10)+ym
   mins(t)\xb=Sin(a+PI+PI/40)*(radius*0.60)+xm
   mins(t)\yb=Cos(a+PI+PI/40)*(radius*0.60)+ym
   mins(t)\xc=Sin(a+PI-PI/40)*(radius*0.60)+xm
   mins(t)\yc=Cos(a+PI-PI/40)*(radius*0.60)+ym
   mins(t)\xf=Sin(a+PI)*(radius*0.60)+xm
   mins(t)\yf=Cos(a+PI)*(radius*0.60)+ym
   mins(t)\xe=Sin(a+PI)*(radius*0.80)+xm
   mins(t)\ye=Cos(a+PI)*(radius*0.80)+ym

   hrs(t)\xa=Sin(a+PI)*(radius*0.10)+xm
   hrs(t)\ya=Cos(a+PI)*(radius*0.10)+ym
   hrs(t)\xb=Sin(a+PI+PI/20)*(radius*0.50)+xm
   hrs(t)\yb=Cos(a+PI+PI/20)*(radius*0.50)+ym
   hrs(t)\xc=Sin(a+PI-PI/20)*(radius*0.50)+xm
   hrs(t)\yc=Cos(a+PI-PI/20)*(radius*0.50)+ym
   hrs(t)\xf=Sin(a+PI)*(radius*0.50)+xm
   hrs(t)\yf=Cos(a+PI)*(radius*0.50)+ym
   hrs(t)\xe=Sin(a+PI)*(radius*0.70)+xm
   hrs(t)\ye=Cos(a+PI)*(radius*0.70)+ym

   a-PI2/60
   t+1
  Wend

  ;- Ziffernblatt
  box = CreateImage(0, 2*xm,2*ym) 
  StartDrawing(ImageOutput()) 
  Box(0, 0,2*xm, 2*ym,boxcol) 
  Circle(xm,ym,radius,tickcol)
  Circle(xm,ym,radius*0.95,backcol)
  Circle(xm,ym,radius*0.09,tickcol)
  For t=0 To 59
    If t=0 Or t=15 Or t=30 Or t=45
      LineXY(ticks(t)\xa,ticks(t)\ya,ticks(t)\xb,ticks(t)\yb,tickcol)
      LineXY(ticks(t)\xb,ticks(t)\yb,ticks(t)\xe,ticks(t)\ye,tickcol)
      LineXY(ticks(t)\xe,ticks(t)\ye,ticks(t)\xc,ticks(t)\yc,tickcol)
      LineXY(ticks(t)\xc,ticks(t)\yc,ticks(t)\xa,ticks(t)\ya,tickcol)
      FillArea(ticks(t)\xf,ticks(t)\yf,tickcol,jewcol) 
    ElseIf t=5 Or t=10 Or t=20 Or t=25 Or t=35 Or t=40 Or t=50 Or t=55
      Circle(ticks(t)\xf,ticks(t)\yf,radius*0.02,jewcol)
      DrawingMode(4)
      Circle(ticks(t)\xf,ticks(t)\yf,radius*0.02,tickcol)
      DrawingMode(0)
    Else
     LineXY(ticks(t)\xa,ticks(t)\ya,ticks(t)\xe,ticks(t)\ye,tickcol)
    EndIf 
  Next
  StopDrawing()
EndProcedure

Procedure tick(value.l)
  Repeat
    s=Second(Date())
    If s<>os
      m=Minute(Date())
      h=Hour(Date())
      If h > 12 : h=h-12 : EndIf
      h=h*5+m/12
      If h > 60 : h=h-60 : EndIf
      d$=""
 
      UseImage(0)
      StartDrawing(ImageOutput()) 
      DrawingMode(0)

      Circle(xm,ym,radius*0.85,backcol)
      Circle(xm,ym,radius*0.09,tickcol)
      
      If flags&16
        FrontColor(Red(txtcol),Green(txtcol),Blue(txtcol))
        BackColor(Red(backcol),Green(backcol),Blue(backcol))
        DrawingFont(font)
        l=TextLength(info$)
        Locate(xm-l/2,ym+radius*0.40)
        DrawText(info$)
      EndIf


      If flags&2 : d$=Str(Day(Date())) : EndIf
      If flags&2 And flags&4 : d$=" "+d$ : EndIf
      If flags&4 : d$=M$( Month(Date() ))+d$ : EndIf
      If (flags&2 Or flags&4) And flags&8 : d$+", " : EndIf
      If flags&8 : d$+Str(Year(Date())) : EndIf


      If d$
        DrawingFont(font)
        dl=TextLength(d$)
        dh=TextLength("Mx")
        Box(xm-dl/2*1.5,ym-radius*0.62,dl*1.5,dh*1.5,jewcol)
        DrawingMode(4)
        Box(xm-dl/2*1.5,ym-radius*0.62,dl*1.5,dh*1.5,tickcol)

        DrawingMode(0)
        Locate(xm-dl/2,ym-radius*0.60)
        FrontColor(Red(txtcol),Green(txtcol),Blue(txtcol))
        BackColor(Red(jewcol),Green(jewcol),Blue(jewcol))
        DrawText(d$)
      EndIf
      
;       ;- neue Zeiger malen
      LineXY(mins(m)\xa,mins(m)\ya,mins(m)\xb,mins(m)\yb,mincol)
      LineXY(mins(m)\xb,mins(m)\yb,mins(m)\xe,mins(m)\ye,mincol)
      LineXY(mins(m)\xe,mins(m)\ye,mins(m)\xc,mins(m)\yc,mincol)
      LineXY(mins(m)\xc,mins(m)\yc,mins(m)\xa,mins(m)\ya,mincol)
      FillArea(mins(m)\xf,mins(m)\yf,mincol,mincol) 

      LineXY(hrs(h)\xa,hrs(h)\ya,hrs(h)\xb,hrs(h)\yb,hcol)
      LineXY(hrs(h)\xb,hrs(h)\yb,hrs(h)\xe,hrs(h)\ye,hcol)
      LineXY(hrs(h)\xe,hrs(h)\ye,hrs(h)\xc,hrs(h)\yc,hcol)
      LineXY(hrs(h)\xc,hrs(h)\yc,hrs(h)\xa,hrs(h)\ya,hcol)
      FillArea(hrs(h)\xf,hrs(h)\yf,hcol,hcol) 

      LineXY(secs(s)\xa,secs(s)\ya,secs(s)\xe,secs(s)\ye,seccol)
      Circle(secs(s)\xf,secs(s)\yf,radius*0.03,seccol)

 
      StopDrawing()
      SetGadgetState(0,box)
      os=s
 ;     Delay(800); ein bischen warten, damit repeat until nicht soviel loopt
    EndIf
    Delay(1)  
  ForEver
EndProcedure

Procedure ToggleOnTop()
  If GetMenuItemState(#set,#OnTop)
    SetWindowPos_(WindowID(),#HWND_TOPMOST,0,0,0,0,#SWP_SHOWWINDOW|#SWP_NOMOVE|#SWP_NOSIZE) 
  Else
    SetWindowPos_(WindowID(),#HWND_NOTOPMOST,0,0,0,0,#SWP_SHOWWINDOW|#SWP_NOMOVE|#SWP_NOSIZE) 
  EndIf  
EndProcedure


;-main
LoadPrefs(#ininame)
box = CreateImage(0, width,height) 

;-create window
OpenWindow(#win,winx,winy,width,height,#PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget|#PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_TitleBar,#appname)
CreateGadgetList(WindowID(0))
ImageGadget(#clock,0,0,width,height,box)
CreatePopupMenu(#set)
 MenuTitle(#appname+" settings")
 MenuItem(#OnTop,"always on top")
  SetMenuItemState(#set,#OnTop,flags&1) 
  ToggleOnTop()
 MenuItem(#ShowDay,"show day")
  SetMenuItemState(#set,#ShowDay,flags&2)
 MenuItem(#ShowMonth,"show month")
  SetMenuItemState(#set,#ShowMonth,flags&4)
 MenuItem(#ShowYear,"show year")
  SetMenuItemState(#set,#ShowYear,flags&8)
 MenuItem(#ShowInfo,"show info")
  SetMenuItemState(#set,#ShowInfo,flags&16)
 OpenSubMenu("change colors")
  MenuItem(#seccol,"seconds")
  MenuItem(#mincol,"minutes")
  MenuItem(#hrscol,"hours")
  MenuItem(#jewcol,"jewels")
  MenuItem(#txtcol,"text")
  MenuItem(#tickcol,"border")
  MenuItem(#backcol,"background")
  MenuItem(#boxcol,"box")
 CloseSubMenu()
 MenuItem(#setInfo,"change info")
 MenuBar()
 MenuItem(#default,"set defaults")
 MenuBar()
 MenuItem(#quit, "close")
 MenuItem(#ver,#version)
 

  DisableMenuItem(#ver,1)
 
  
;-draw clock
DrawClock()
tid=CreateThread(@tick(),0)
;SetWindowCallback(@SizeCallback())

;event loop
Repeat
  EventID = WaitWindowEvent()
  Select EventID
    Case #PB_Event_SizeWindow
      PauseThread(tid) 
      winx=WindowX() : winy=WindowY() 
      height=WindowHeight() : width=WindowWidth()
      If height<50 : winy-(50-height) : height=50 : EndIf
      MoveWindow(winx,winy) : ResizeWindow(width,height)
      os=s-1 : DrawClock() 
      ResumeThread(tid) 
    
    Case #WM_SIZE 
      ; PauseThread(tid) 
      ; winx=WindowX() : winy=WindowY() 
      ; height=WindowHeight() : width=WindowWidth()
      ; If height<50 : winy-(50-height) : height=50 : EndIf
      ; MoveWindow(winx,winy) : ResizeWindow(width,height)
      ; os=s-1 : DrawClock() 
      ; ResumeThread(tid) 
    Case #WM_RButtonDown 
      popx.l=WindowX()+WindowMouseX()
      popy.l=WindowY()+WindowMouseY()
      DisplayPopupMenu(0,WindowID(0),popx,popy) 
;      Case #PB_EventGadget
;        GadgetID = EventGadgetID()
;        Select GadgetID
;     
;        EndSelect
    Case #PB_EventMenu
      MenuID = EventMenuID()
      Select MenuID
        Case #quit
          
        Case #OnTop
          SetMenuItemState(#set,#OnTop,GetMenuItemState(#set,#OnTop)!1) 
          ToggleOnTop()  
          Flags!1
        Case #ShowDay
          SetMenuItemState(#set,#ShowDay,GetMenuItemState(#set,#ShowDay)!1) 
          Flags!2
        Case #ShowMonth
          SetMenuItemState(#set,#ShowMonth,GetMenuItemState(#set,#ShowMonth)!1) 
          Flags!4
        Case #ShowYear
          SetMenuItemState(#set,#ShowYear,GetMenuItemState(#set,#ShowYear)!1) 
          Flags!8
        Case #ShowInfo
          SetMenuItemState(#set,#ShowInfo,GetMenuItemState(#set,#ShowInfo)!1) 
          Flags!16
        Case #setInfo
          Repeat
          info$=InputRequester(#appname+" info text edit","your text has: "+Str(Len(info$))+" chars, max. 30 chars are allowed",info$)
          Until Len(info$)<30
          
        Case #default
          resetPrefs(#ininame)  
;          setwindowpos_(WindowID(),#HWND_TOP,winx,winy,width,height,#SWP_SHOWWINDOW) 
          PauseThread(tid)
          MoveWindow(winx,winy) : ResizeWindow(width,height)
          SetMenuItemState(#set,#OnTop,Flags&1) 
          SetMenuItemState(#set,#ShowDay,Flags&2)
          SetMenuItemState(#set,#ShowMonth,Flags&4)
          SetMenuItemState(#set,#ShowYear,Flags&8)
          SetMenuItemState(#set,#ShowInfo,Flags&16)
          os=s-1 : DrawClock() 
          ResumeThread(tid) 
          ToggleOnTop()
        Case #seccol
          seccol=ColorRequester()
        Case #mincol
          mincol=ColorRequester()
        Case #hrscol
          hcol=ColorRequester()
        Case #jewcol
          jewcol=ColorRequester()
          PauseThread(tid) : os=s-1 : DrawClock() : ResumeThread(tid) 
        Case #txtcol
          txtcol=ColorRequester()
        Case #tickcol
          tickcol=ColorRequester()
          PauseThread(tid) : os=s-1 : DrawClock() : ResumeThread(tid) 
        Case #backcol
          backcol=ColorRequester()
          PauseThread(tid) : os=s-1 : DrawClock() : ResumeThread(tid) 
        Case #boxcol
          boxcol=ColorRequester()
          PauseThread(tid) : os=s-1 : DrawClock() : ResumeThread(tid) 
      EndSelect
  EndSelect
Until EventID = #PB_EventCloseWindow
savePrefs(#ininame)
CloseWindow(0)
PB / jaPBe jeweils aktuellste Version, seit 3.62 dabei, XP sp3 de/en & W7 en
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Dann braucht es aber ein 3D-Sprite welches nicht mehr auf Linux und Co. läuft. Und außerdem, Sinus und Cosinus sind Grundwissen wenn es um Programmierung geht. In vielen Dingen braucht man sowas. Schau mal hier, da kannst du es relativ schnell lernen:
http://robsite.de/php/pureboard/viewtop ... ight=sinus
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

...der link von sunny ist echt gut...da bleiben eigentlich keine fragen offen...

...das beispiel von wichtel finde ich auch nett... muss man halt erstmal durchsteigen...

von mir noch ein tipp: ich erzeuge gern vorher ein array für die werte, das lässt sich in performance-kritischen situationen schneller abfragen, als die sin/cos-funktionen:

Code: Alles auswählen

#pi.f = 3.14159265

; define Calculation Arrays

Dim Sinus.f(720)
Dim Cosin.f(720)

For r=0 To 319 Step 1
  Sinus(r)     = Sin(#pi*r/180)
  Sinus(r+360) = Sin(#pi*r/180)
  Cosin(r)     = Cos(#pi*r/180)
  Cosin(r+360) = Cos(#pi*r/180)
Next r
der kreis ist hier zweimal im array, damit man auch von startwerten >0 mittels einer schleife auslesen kann... :wink:

das array-feld Sinus(80) enthält hier eben den sinus von 80°

(ich weiss garnicht mehr, warum ich damals ein STEP 1 gesetzt hatte, kann man glaubich auch weglassen... gab da irgendeine ungenauigkeit vorher... :| )
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Antworten