Danke für den Hinweis, habs jetzt überarbeitet.#NULL hat geschrieben:Bei der Demo hinter dem Showcase Link stimmt irgendwas nicht, die Minutenstriche und der Minutenzeiger stimmen nicht ganz überein.
DrawVector RotateCoordinates, Box drehen + Ecken berechnen
Re: DrawVector RotateCoordinates, Box drehen + Ecken berechn
"Papa, mein Wecker funktioniert nicht! Der weckert immer zu früh."
Re: DrawVector RotateCoordinates, Box drehen + Ecken berechn
Ich habe es nochmal erweitert. Die Zeiger zeigen jetzt auch die Zwischenschritte an sodass z.B. der Stundenzeiger nicht immer nur auf der vollen Stunde steht und der Sekundenzeiger bewegt sich optional natürlicher (Fenster 3, im Select anpassen). Das übergibt man alles in einer Config-Struktur (Fenster 2 macht das zufällig mit Farben und Stärken/Größen).
Code: Alles auswählen
DeclareModule vectorDrawingClock
EnableExplicit
Macro sConfig_private
_last_s.f
_last_ms.f
EndMacro
Structure sConfig ; for default values see getDefaultConfig()
canvas.i ; -1 if not set. otherwise the PureBasic canvas object #number used as a drawing output.
image.i ; -1 if not set. otherwise the PureBasic image object #number used as a drawing output.
colorBackground.i ; Background color of the entire output area.
colorClockFill.i ; Background color of the clock area.
colorClockRim.i ; Stroke color of the clock rim.
colorTick.i ; Stroke color of minute ticks.
colorTick5th.i ; Stroke color of 5th minute ticks.
colorTick15th.i ; Stroke color of 15th minute ticks.
colorHourHand.i ; Stroke color of the hour hand.
colorMinuteHand.i ; Stroke color of the minute hand.
colorSecondHand.i ; Stroke color of the second hand.
radiusClockRim.f ; 0.0 .. 1.0, percentage, relative to space available.
radiusHourHand.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusMinuteHand.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusSecondHand.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusTickFrom.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusTickTo.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusTick5thFrom.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusTick5thTo.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusTick15thFrom.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
radiusTick15thTo.f ; 0.0 .. 1.0, percentage, relative to clock rim radius.
lineWidthClockRim.f ; Stroke strength.
lineWidthHourHand.f ; Stroke strength.
lineWidthMinuteHand.f ; Stroke strength.
lineWidthSecondHand.f ; Stroke strength.
lineWidthTick.f ; Stroke strength.
lineWidthTick5th.f ; Stroke strength.
lineWidthTick15th.f ; Stroke strength.
roundCaps.i ; Bool, #False results in square line ends, #True results in round line ends.
smoothHours.i ; Bool, #False results in hours hand pointing at full hours only, #True shows progress between hours.
smoothMinutes.i ; Bool, #False results in minutes hand pointing at full minutes only, #True shows progress between minutes.
smoothSeconds.i ; Bool, #False results in seconds hand pointing at full seconds only, #True shows progress between hours. (continuous second hand movement)
smootherSeconds.i ; Bool, similar to smoothSeconds but with an ease-in-out interpolation.
sConfig_private ; (private fields hidden from IDE)
EndStructure
Declare update(canvas, date = -1)
Declare.i getDefaultConfig()
EndDeclareModule
Module vectorDrawingClock
EnableExplicit
Define msSecondSwitch.q
Define thread, mutex
Procedure getSecondSwitch(*param.Quad)
Shared mutex
Protected second, second2, milliseconds.q
second = Second(Date())
Repeat
second2 = Second(Date())
milliseconds = ElapsedMilliseconds()
Until second2 <> second
*param\q = milliseconds
UnlockMutex(mutex)
EndProcedure
CompilerIf Not #PB_Compiler_Thread
CompilerError "Please enable the threadsafe compiler option."
CompilerEndIf
ElapsedMilliseconds()
If (Not mutex) And (Not thread)
mutex = CreateMutex()
; our mutex will be locked until the thread is done.
LockMutex(mutex)
; get a milliseconds value at which a second switch occurred.
thread = CreateThread( @ getSecondSwitch(), @ msSecondSwitch)
EndIf
Procedure.i getDefaultConfig()
Protected *config.sConfig
*config = AllocateStructure(sConfig)
*config\canvas = -1
*config\image = -1
*config\colorBackground = $ffffffff
*config\colorClockFill = $ffdddddd
*config\colorClockRim = $ff444444
*config\colorTick = $ff444444
*config\colorTick5th = $ff333333
*config\colorTick15th = $ff222222
*config\colorHourHand = $ff444444
*config\colorMinuteHand = $ff444444
*config\colorSecondHand = $ff444444
*config\radiusClockRim = 0.9
*config\radiusHourHand = 0.45
*config\radiusMinuteHand = 0.8
*config\radiusSecondHand = 0.9
*config\radiusSecondHand = 0.85
*config\radiusTickFrom = 0.95
*config\radiusTickTo = 0.96
*config\radiusTick5thFrom = 0.92
*config\radiusTick5thTo = 0.96
*config\radiusTick15thFrom = 0.90
*config\radiusTick15thTo = 0.96
*config\lineWidthClockRim = 6.0
*config\lineWidthHourHand = 8.0
*config\lineWidthMinuteHand = 5.0
*config\lineWidthSecondHand = 3.0
*config\lineWidthTick = 3.0
*config\lineWidthTick5th = 4.0
*config\lineWidthTick15th = 5.0
*config\roundCaps = #True
*config\smoothHours = #False
*config\smoothMinutes = #False
*config\smoothSeconds = #False
*config\smootherSeconds = #False
ProcedureReturn *config
EndProcedure
Procedure.f easeInOut(x.f)
If x < 0.5
; [0 .. 0.5] --> [0 .. 1]
x * 2.0
ProcedureReturn 0.5 * ((x) * Pow(x, 2))
Else
; [0.5 .. 1.0] --> [0 .. 1]
x = (x - 0.5) * 2.0
; 1-x = flip left/right
; 1 - .. = flip top/bottom
ProcedureReturn 0.5 + 0.5 * (1 - (1-x) * Pow(1-x, 2))
EndIf
EndProcedure
Procedure update(*config.sConfig, date = -1)
Protected h, m, s, ms, msFact.f
Protected width, height, smallerSize, centerX, centerY, caps
Protected radiusMax.f, radiusRim.f, radius.f, angle.f
Protected c, context
Shared mutex, msSecondSwitch
If date = -1
date = Date()
EndIf
h = Hour(date)
m = Minute(date)
s = Second(date)
; loop 2 times, to check for canvas or image (or both)
For c=0 To 1
context = 0
If (c = 0) And (*config\canvas >= 0)
context = StartVectorDrawing(CanvasVectorOutput(*config\canvas))
ElseIf (c = 1) And (*config\image >= 0)
context = StartVectorDrawing(ImageVectorOutput(*config\image))
EndIf
If context
width = VectorOutputWidth()
height = VectorOutputHeight()
smallerSize = width
If height < smallerSize
smallerSize = height
EndIf
radiusMax = smallerSize / 2
centerX = width / 2
centerY = height / 2
caps = #PB_Path_SquareEnd
If *config\roundCaps
caps = #PB_Path_RoundEnd
EndIf
; background
VectorSourceColor(*config\colorBackground)
FillVectorOutput()
; clock rim/fill
radiusRim = *config\radiusClockRim * radiusMax
AddPathCircle(centerX, centerY, radiusRim, 0, 360)
VectorSourceColor(*config\colorClockFill)
FillPath(#PB_Path_Preserve)
VectorSourceColor(*config\colorClockRim)
StrokePath(*config\lineWidthClockRim)
; ticks
Protected t, rFrom, rTo, color, lineWidth
For t=0 To 59
angle = -Radian(90) + Radian(t * (360/60))
If t%15 = 0
; 15 minutes ticks
rFrom = radiusRim * *config\radiusTick15thFrom
rTo = radiusRim * *config\radiusTick15thTo
color = *config\colorTick15th
lineWidth = *config\lineWidthTick15th
ElseIf t%5 = 0
; 5 minute ticks
rFrom = radiusRim * *config\radiusTick5thFrom
rTo = radiusRim * *config\radiusTick5thTo
color = *config\colorTick5th
lineWidth = *config\lineWidthTick5th
Else
; normal minute ticks
rFrom = radiusRim * *config\radiusTickFrom
rTo = radiusRim * *config\radiusTickTo
color = *config\colorTick
lineWidth = *config\lineWidthTick
EndIf
MovePathCursor(centerX + rFrom * Cos(angle), centerY + rFrom * Sin(angle))
AddPathLine(centerX + rTo * Cos(angle), centerY + rTo * Sin(angle))
VectorSourceColor(color)
StrokePath(lineWidth, caps)
Next
; hour hand
angle = -Radian(90) + Radian(h * (360/ 12))
If *config\smoothHours
angle + Radian(m * (360 / 60) / 12)
EndIf
radius = *config\radiusHourHand * radiusRim
MovePathCursor(centerX, centerY)
AddPathLine(radius * Cos(angle), radius * Sin(angle), #PB_Path_Relative)
VectorSourceColor(*config\colorHourHand)
StrokePath(*config\lineWidthHourHand, caps)
; minute hand
angle = -Radian(90) + Radian(m * (360 / 60))
If *config\smoothMinutes
angle + Radian(s * (360 / 60) / 60)
EndIf
radius = *config\radiusMinuteHand * radiusRim
MovePathCursor(centerX, centerY)
AddPathLine(radius * Cos(angle), radius * Sin(angle), #PB_Path_Relative)
VectorSourceColor(*config\colorMinuteHand)
StrokePath(*config\lineWidthMinuteHand, caps)
; second hand
angle = -Radian(90) + Radian(s * (360 / 60))
; smooth seconds only if the thread is done
If (*config\smoothSeconds Or *config\smootherSeconds) And TryLockMutex(mutex)
; just wanted to know if the thread is done, we dont really need the mutex for protection.
UnlockMutex(mutex)
; get how many milliseconds we are into the current second by removing any full seconds since our second switch.
ms = (ElapsedMilliseconds() - msSecondSwitch) % 1000
; our ms value (from ElapsedMilliseconds()) and our s value (from Date()) can be slightly
; off and not be 100% aligned to each other, so it could happen for example that the ms
; resets from 999 to 0 while the second is still the same and will only increases in a following
; frame, causing the second hand to jump back for a short moment. We fix that by using an older
; ms value if the second did not change yet.
If (ms < *config\_last_ms) And (s = *config\_last_s)
ms = *config\_last_ms
EndIf
; similarly, if the ms still increased while the second already proceeded, we reset the ms manually.
If (ms > *config\_last_ms) And (s > *config\_last_s)
ms = 0
EndIf
; smoother seconds movement
If *config\smootherSeconds
msFact = ms / 1000.0 ; normalize to 0..1
msFact = easeInOut(msFact) ; ease
ms = 1000.0 * msFact ; convert back to ms
EndIf
; add smooth[er] part to seconds angle
angle + Radian(ms * (360 / 60) / 1000)
*config\_last_s = s
*config\_last_ms = ms
EndIf
radius = *config\radiusSecondHand * radiusRim
MovePathCursor(centerX, centerY)
AddPathLine(radius * Cos(angle), radius * Sin(angle), #PB_Path_Relative)
VectorSourceColor(*config\colorSecondHand)
StrokePath(*config\lineWidthSecondHand, caps)
StopVectorDrawing()
EndIf
Next
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
Define ww, wh, event, quit
Define win1, canvas1
Define win2, image2, img2
Define win3, canvas3
Define *clockConfig1.vectorDrawingClock::sConfig
Define *clockConfig2.vectorDrawingClock::sConfig
Define *clockConfig3.vectorDrawingClock::sConfig
; ----------------------------------------------------------------------
; default clock on a canvas
ww=600
wh=400
win1 = OpenWindow(#PB_Any, 100, 100, ww, wh, "1, default", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
canvas1 = CanvasGadget(#PB_Any, 0, 0, ww, wh)
AddKeyboardShortcut(win1, #PB_Shortcut_Escape, 10)
*clockConfig1 = vectorDrawingClock::getDefaultConfig()
*clockConfig1\canvas = canvas1
Procedure updateClock1()
Shared *clockConfig1
vectorDrawingClock::update(*clockConfig1, Date())
EndProcedure
Procedure resize1()
Shared win1, canvas1
ResizeGadget(canvas1, 0, 0, WindowWidth(win1), WindowHeight(win1))
updateClock1()
EndProcedure
BindEvent(#PB_Event_SizeWindow, @ resize1(), win1)
AddWindowTimer(win1, 1, 100)
BindEvent(#PB_Event_Timer, @ updateClock1(), win1, 1)
; ----------------------------------------------------------------------
; randomized clock on an image
ww=400
wh=600
win2 = OpenWindow(#PB_Any, 720, 100, ww, wh, "2, randomized", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
img2 = CreateImage(#PB_Any, ww, wh)
image2 = ImageGadget(#PB_Any, 0, 0, ww, wh, ImageID(img2))
AddKeyboardShortcut(win2, #PB_Shortcut_Escape, 10)
*clockConfig2 = vectorDrawingClock::getDefaultConfig()
*clockConfig2\image = img2
Procedure updateClock2()
Shared image2, img2, *clockConfig2
vectorDrawingClock::update(*clockConfig2, Date())
SetGadgetState(image2, ImageID(img2))
EndProcedure
Procedure resize2()
Shared win2, image2
ResizeGadget(image2, 0, 0, WindowWidth(win2), WindowHeight(win2))
updateClock2()
EndProcedure
Procedure randomizeConfig2()
Shared *clockConfig2
*clockConfig2\colorBackground = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorClockFill = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorClockRim = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorTick = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorTick5th = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorTick15th = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorHourHand = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorMinuteHand = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\colorSecondHand = RGBA(Random(255), Random(255), Random(255), Random(255))
*clockConfig2\radiusClockRim = 0.4 + 0.01 * Random(60)
*clockConfig2\radiusHourHand = 0.4 + 0.01 * Random(30)
*clockConfig2\radiusMinuteHand = 0.4 + 0.01 * Random(30)
*clockConfig2\radiusSecondHand = 0.4 + 0.01 * Random(30)
*clockConfig2\radiusTickFrom = 0.8 + 0.01 * Random(10)
*clockConfig2\radiusTickTo = 0.8 + 0.01 * Random(10)
*clockConfig2\radiusTick5thFrom = 0.8 + 0.01 * Random(10)
*clockConfig2\radiusTick5thTo = 0.8 + 0.01 * Random(10)
*clockConfig2\radiusTick15thFrom = 0.8 + 0.01 * Random(10)
*clockConfig2\radiusTick15thTo = 0.8 + 0.01 * Random(10)
*clockConfig2\lineWidthClockRim = 1.0 + Random(30)
*clockConfig2\lineWidthHourHand = 1.0 + Random(30)
*clockConfig2\lineWidthMinuteHand = 1.0 + Random(30)
*clockConfig2\lineWidthSecondHand = 1.0 + Random(30)
*clockConfig2\lineWidthTick = 1.0 + Random(12)
*clockConfig2\lineWidthTick5th = 1.0 + Random(12)
*clockConfig2\lineWidthTick15th = 1.0 + Random(12)
*clockConfig2\roundCaps = Bool(Random(1))
EndProcedure
BindEvent(#PB_Event_SizeWindow, @ resize2(), win2)
AddWindowTimer(win2, 21, 100)
BindEvent(#PB_Event_Timer, @ updateClock2(), win2, 21)
AddWindowTimer(win2, 22, 1700)
BindEvent(#PB_Event_Timer, @ randomizeConfig2(), win2, 22)
; ----------------------------------------------------------------------
; smooth hand movement.
; see the select below for continuous or natural second hand movement.
ww=300
wh=200
win3 = OpenWindow(#PB_Any, 100, 550, ww, wh, "3, smooth movement", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget)
canvas3 = CanvasGadget(#PB_Any, 0, 0, ww, wh)
AddKeyboardShortcut(win3, #PB_Shortcut_Escape, 10)
*clockConfig3 = vectorDrawingClock::getDefaultConfig()
*clockConfig3\canvas = canvas3
*clockConfig3\smoothHours = #True
*clockConfig3\smoothMinutes = #True
Select 2
Case 1 : *clockConfig3\smoothSeconds = #True
Case 2 : *clockConfig3\smootherSeconds = #True
EndSelect
Procedure updateClock3()
Shared *clockConfig3
vectorDrawingClock::update(*clockConfig3, Date())
EndProcedure
Procedure resize3()
Shared win3, canvas3
ResizeGadget(canvas3, 0, 0, WindowWidth(win3), WindowHeight(win3))
updateClock3()
EndProcedure
BindEvent(#PB_Event_SizeWindow, @ resize3(), win3)
AddWindowTimer(win3, 3, 100)
BindEvent(#PB_Event_Timer, @ updateClock3(), win3, 3)
; ----------------------------------------------------------------------
Repeat
event = WaitWindowEvent(10)
Select event
Case #PB_Event_CloseWindow
quit = #True
Case #PB_Event_Menu
Select EventMenu()
Case 10
quit = #True
EndSelect
EndSelect
Until quit
CompilerEndIf
; configs are allocated and should be freed in case the program does not end
FreeStructure(*clockConfig1)
*clockConfig1 = 0
FreeStructure(*clockConfig2)
*clockConfig2 = 0
FreeStructure(*clockConfig3)
*clockConfig3 = 0
Re: DrawVector RotateCoordinates, Box drehen + Ecken berechn
Hat dieses "Uhr-Thema" etwas mit dem Titel und dem ersten Beitrag was gemeinsames?
Vielleicht mag ein Forum-Admin das auftrennen?
Vielleicht mag ein Forum-Admin das auftrennen?
Siehste! Geht doch....?!
PB*, *4PB, PetriDish, Movie2Image, PictureManager, TrainYourBrain, ...
PB*, *4PB, PetriDish, Movie2Image, PictureManager, TrainYourBrain, ...