Hi, folks.
I am looking for a better and simpler solution to this problem, as what exists seems unnecessarily complicated and inconvenient to me.
The essence of the task:
There are some control points that are defined in advance and do not change. Next, a specific value is entered that falls exactly within the range of all control points. It will never be outside this range. What interests me in the end ? This is the interval (between which control points) in which the entered value lies.
Thanks in advance!
P.S. Sorry, I forgot to write... all values are whole natural numbers !
The problem of finding an interval and the closest points.
Re: The problem of finding an interval and the closest points.
Are we talking 1D, 2D or 3D points here? How many control points are there likely to be? 10's, 100's or 1000's
Re: The problem of finding an interval and the closest points.
Good time, spikey !
Everything is much simpler ! I just want to make a timer.
Okay. This is how I have it done now. But I will have to do the calculations many times and I would like to take this out into a separate procedure. Now you can see a checkpoint ahead. Only forward. But sometimes I also need to get a point that is behind the given value.
So I ask professionals how they would do it.
Thanks in advance to everyone who responds.
Sorry, I expressed myself incorrectly. According to your classification, it will be one ! DAre we talking 1D, 2D or 3D points here?
Just four !How many control points are there likely to be?
Everything is much simpler ! I just want to make a timer.
Okay. This is how I have it done now. But I will have to do the calculations many times and I would like to take this out into a separate procedure. Now you can see a checkpoint ahead. Only forward. But sometimes I also need to get a point that is behind the given value.
So I ask professionals how they would do it.
Code: Select all
Structure Task
timer.i
value.i
wait_for_n_min.i
schedule_nr.i
schedule_str1$
schedule_str2$
EndStructure
Procedure.s ConvertMinutes(NbMinutes)
Protected divisor = 60 ; minutes in an hour
Protected hours, minutes
Protected result$ = ""
hours = NbMinutes / divisor
minutes = NbMinutes % divisor
If hours > 0
result$ + Str(hours) + " h."
EndIf
If minutes > 0
If hours > 0
result$ + " "
EndIf
result$ + Str(minutes) + " min."
EndIf
ProcedureReturn result$
EndProcedure
Procedure.s Get_Timetable(value)
Protected result$
If value = 1
result$ = "05:00"
ElseIf value = 2
result$ = "11:00"
ElseIf value = 3
result$ = "17:00"
ElseIf value = 4
result$ = "23:00"
EndIf
ProcedureReturn result$
EndProcedure
Procedure Calculate_TriggerTime(*Task.Task)
Protected CurrentTime = Date()
Protected CurrentTimeHour = 22;Hour(CurrentTime)
Protected CurrentTimeMinute = 59;Minute(CurrentTime)
Protected inpval = (CurrentTimeHour * 60) + CurrentTimeMinute
Protected i=1, found=0, Index, _timer, wait_for_n_min
*Task\schedule_nr = *Task\schedule_nr + 1
NewList Timer.i()
Dim *Pointers(0)
; values of checkpoints in minutes
AddElement(Timer())
Timer() = 300 ; minutes = 05:00 AM etc...
AddElement(Timer())
Timer() = 660
AddElement(Timer())
Timer() = 1020
AddElement(Timer())
Timer() = 1380
ForEach Timer()
If Timer() = inpval
found=1
Break
EndIf
i+1
Next
If found ; execute immediately !
If i = 4
*Task\value = 1
Else
*Task\value = i+1
EndIf
*Task\wait_for_n_min = 360
*Task\schedule_str1$ = Get_Timetable(*Task\value)
*Task\schedule_str2$ = ConvertMinutes(*Task\wait_for_n_min)
;PostEvent(#print_estimated_time) ; send a command to the main loop
Else
AddElement(Timer())
Timer() = inpval
SortList(Timer(), #PB_Sort_Ascending)
ReDim *Pointers(ListSize(Timer()))
ForEach Timer()
*Pointers(ListIndex(Timer())) = @Timer()
Next
i=1
ForEach Timer()
If Timer() = inpval
Break
EndIf
i+1
Next
If i=5
i=1
EndIf
Index = i
;ResetList(Timer())
ChangeCurrentElement(Timer(), *Pointers(Index))
_timer = Timer()
If inpval > 1380 ; if inpval > 23:00
wait_for_n_min = (1440 - inpval) + 300
Else
wait_for_n_min = _timer - inpval
EndIf
*Task\value = i
*Task\wait_for_n_min = wait_for_n_min
*Task\schedule_str1$ = Get_Timetable(i)
*Task\schedule_str2$ = ConvertMinutes(wait_for_n_min)
;PostEvent(#print_estimated_time) ; send a command to the main loop
EndIf
EndProcedure
Define Task.Task
Calculate_TriggerTime(@Task)
Debug "Task # " + Str(Task\schedule_nr)
Debug ""
text$ = "scheduled for " + Task\schedule_str1$ + #CRLF$ + Task\schedule_str2$ + " left"
Debug text$Re: The problem of finding an interval and the closest points.
If you always have four time slots you don't need to muck about with a list. Each task can have a fixed sized array.
I would also store Unix epoch timestamps (i.e. Q values from the Date() function) of the next event time in the array. Then you can also take advantage of the AddDate() function too.
When the timer procedure 'ticks' at its resolution, I'd check to see if any of the timestamps have passed and so the event is due and needs triggering. Then recalculating the next time to trigger. Something like this:
(this particular code may not work properly if you start it up in the 59th minute of the hour, so don't - but you get the idea, I hope).
It depends, however, on how long tasks might take to execute, how accurate start times must be and if tasks must execute concurrently. If tasks are long, start times must be accurate and concurrent then I'd be looking at a timer thread and a number of executive threads to do the work.
I would also store Unix epoch timestamps (i.e. Q values from the Date() function) of the next event time in the array. Then you can also take advantage of the AddDate() function too.
When the timer procedure 'ticks' at its resolution, I'd check to see if any of the timestamps have passed and so the event is due and needs triggering. Then recalculating the next time to trigger. Something like this:
(this particular code may not work properly if you start it up in the 59th minute of the hour, so don't - but you get the idea, I hope).
Code: Select all
Structure TASK
Name.S
Times.Q[4]
Sequence.B
; ...
EndStructure
NewList Tasks.TASK()
Define.W Yr = Year(Date()), Mn = Month(Date()), Dy = Day(Date()), Hr = Hour(Date()), Mt = Minute(Date())
AddElement(Tasks())
Tasks()\Name = "First task"
Tasks()\Times[0] = Date(Yr, Mn, Dy, Hr, Mt + 1, 00)
Tasks()\Times[1] = Date(Yr, Mn, Dy, Hr, Mt + 1, 15)
Tasks()\Times[2] = Date(Yr, Mn, Dy, Hr, Mt + 1, 30)
Tasks()\Times[3] = Date(Yr, Mn, Dy, Hr, Mt + 1, 45)
AddElement(Tasks())
Tasks()\Name = "Second task"
Tasks()\Times[0] = Date(Yr, Mn, Dy, Hr, Mt + 1, 10)
Tasks()\Times[1] = Date(Yr, Mn, Dy, Hr, Mt + 1, 25)
Tasks()\Times[2] = Date(Yr, Mn, Dy, Hr, Mt + 1, 35)
Tasks()\Times[3] = Date(Yr, Mn, Dy, Hr, Mt + 1, 55)
Debug "Started, waiting for a trigger..."
Repeat
ForEach Tasks()
For i = 0 To 3
If Date() >= Tasks()\Times[i]
; Task is due.
Tasks()\Sequence = i
Debug Tasks()\Name + " triggered at " + FormatDate("%dd/%mm/%yy %hh:%ii:%ss", Tasks()\Times[i]) + " #" + Str(Tasks()\Sequence) + "."
; Recalculate next Tasks()\Times[i].
Tasks()\Times[i] = AddDate(Tasks()\Times[i], #PB_Date_Minute, 1)
Debug "Next trigger will be " + FormatDate("%dd/%mm/%yy %hh:%ii:%ss", Tasks()\Times[i]) + " #" + Str(Tasks()\Sequence) + "."
; Do task...
Break
EndIf
Next i
Next Tasks()
; Whatever timer resolution makes sense.
Delay(500)
ForEverRe: The problem of finding an interval and the closest points.
spikey, thanks for your version and explanations.
