[chronojump] Run execute double contacts revamped for 1.8.1



commit 43e9723db1e6db67ab83089108bc4f75c32377f7
Author: Xavier de Blas <xaviblas gmail com>
Date:   Mon Mar 26 18:36:48 2018 +0200

    Run execute double contacts revamped for 1.8.1

 src/Makefile.am           |    1 +
 src/constants.cs          |   11 +-
 src/execute/event.cs      |   73 +++++++-
 src/execute/run.cs        |  461 ++++++++++++++++++++-------------------------
 src/execute/runObjects.cs |  376 ++++++++++++++++++++++++++++++++++++
 src/gui/chronojump.cs     |    4 +-
 src/gui/eventExecute.cs   |   28 +++-
 7 files changed, 694 insertions(+), 260 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index cefe1ec..547d8c1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -134,6 +134,7 @@ SOURCES = \
        execute/event.cs\
        execute/jump.cs\
        execute/run.cs\
+       execute/runObjects.cs\
        execute/pulse.cs\
        execute/reactionTime.cs\
        execute/multiChronopic.cs\
diff --git a/src/constants.cs b/src/constants.cs
index a85ba69..2e2af53 100644
--- a/src/constants.cs
+++ b/src/constants.cs
@@ -926,8 +926,17 @@ public class Constants
        
        public enum EncoderAutoSaveCurve { ALL, NONE, BEST, FROM4TOPENULTIMATE }
 
+       //BIGGEST_TC will be the default mode.
+       // - at END of each track: track ends before the biggest TC (just before the trunk arrives)
+       // - at START of each track:
+       //      - if starting on contact:
+       //              time starts when leaving it. Usually will be with the biggest part (trunk),
+       //              and maybe later there's a foot, so leaving the contact on the first time is the 
beginning.
+       //      - on speed start, if there are double contacts,
+       //              - if "race starts at arriving at platform", then race will start before big tc (trunk)
+       //              - else, race will start after big tc (trunk)
        public enum DoubleContact {
-               NONE, FIRST, AVERAGE, LAST
+               NONE, FIRST, AVERAGE, LAST, BIGGEST_TC
        }
        
        //DISPLACED means: total
diff --git a/src/execute/event.cs b/src/execute/event.cs
index f238086..cfd3874 100644
--- a/src/execute/event.cs
+++ b/src/execute/event.cs
@@ -57,6 +57,8 @@ public class EventExecute
        }
        protected eventType needUpdateGraphType;
        
+       protected bool needCallTrackDone;
+       protected bool needCheckIfTrackEnded; //Races with double contacts wait some ms to see if other 
contact appears
        protected bool needShowCountDown;       //RSA
 
        //protected string syncMessage;
@@ -82,6 +84,8 @@ public class EventExecute
 
        protected ExecutingGraphData egd;
        
+       //for runs
+       public RunPhaseTimeList runPTL;
 
 
        //better as private and don't inherit, don't know why
@@ -312,7 +316,22 @@ public class EventExecute
                        egd.Button_finish.Sensitive = true;
                        needSensitiveButtonFinish = false;
                }
-               
+
+               // races specific --------------------------------->
+
+               //Race track with DoubleContacts mode NONE
+               if(needCallTrackDone)
+               {
+                       trackDone();
+                       needCallTrackDone = false;
+               }
+               //Race track with DoubleContacts mode != NONE
+               if(needCheckIfTrackEnded && lastTfCheckTimeEnded())
+               {
+                       trackDone();
+                       needCheckIfTrackEnded = false;
+               }
+
                //RSA
                if(needShowCountDown) 
                {
@@ -325,6 +344,7 @@ public class EventExecute
                        needShowFeedbackMessage = false;
                }
                
+               // <-------------------------- end of races specific
                
                //check if it should finish by time
                if(shouldFinishByTime()) {
@@ -333,6 +353,8 @@ public class EventExecute
                } 
        }
        
+       // races specific --------------------------------->
+
        private void runATouchPlatform() {
                UtilGtk.PrintLabelWithTooltip(egd.Label_message, feedbackMessage);
        }
@@ -340,7 +362,18 @@ public class EventExecute
        public void RunANoStrides() {
                UtilGtk.PrintLabelWithTooltip(egd.Label_message, feedbackMessage);
        }
-       
+
+       protected virtual bool lastTfCheckTimeEnded()
+       {
+               return true;
+       }
+
+       protected virtual void trackDone()
+       {
+       }
+
+       // <-------------------------- end of races specific
+
        protected void progressBarEventOrTimePreExecution (bool isEvent, bool percentageMode, double events) 
        {
                if (isEvent) 
@@ -477,6 +510,11 @@ public class EventExecute
                return "";
        }
 
+       public RunPhaseTimeList RunPTL
+       {
+               get { return runPTL; }
+       }
+
        //from confirm_window cancel button (thread has not started)
        //this is NOT called when a event has started and user click on "Cancel"
        protected void cancel_event_before_start(object o, EventArgs args)
@@ -548,6 +586,37 @@ public class EventExecute
           
 }
 
+public class PhaseTime
+{
+       private bool contactIn;
+       private double duration;
+
+       public PhaseTime (bool contactIn, double duration)
+       {
+               this.contactIn = contactIn;
+               this.duration = duration;
+       }
+
+       public override string ToString()
+       {
+               string strMode = "IN";
+               if(! contactIn)
+                       strMode = "OUT";
+
+               //TODO: use a printf mode to have always same digits
+               return "\n" + Math.Round(Util.DivideSafe(duration, 1000.0), 3) + " - " + strMode;
+       }
+
+       public bool IsContact
+       {
+               get { return contactIn; }
+       }
+       public double Duration
+       {
+               get { return duration; }
+       }
+}
+
 public class InOut
 {
        private bool contactIn;
diff --git a/src/execute/run.cs b/src/execute/run.cs
index f72bba4..ce38782 100644
--- a/src/execute/run.cs
+++ b/src/execute/run.cs
@@ -56,8 +56,11 @@ public class RunExecute : EventExecute
        protected double timestampDCContactTimes;       //sum of the contact times that happen in small time
        protected double timestampDCn;                  //number of flight times in double contacts period
 
+       //static because they are used on both threads at the same time
        protected static RunExecuteInspector runEI;
-
+       protected static RunDoubleContact runDC;
+       //protected static RunPhaseTimeList runPTL;
+       protected static bool success;
 
        public RunExecute() {
        }
@@ -208,7 +211,7 @@ public class RunExecute : EventExecute
 
                timestampDCInitValues();
 
-               bool success = false;
+               success = false;
                bool ok;
 
                //prepare variables to allow being cancelled or finished
@@ -230,12 +233,8 @@ public class RunExecute : EventExecute
                        
                        if (ok && !cancel) {
                                //LogB.Information("timestamp:" + timestamp);
-                               if (platformState == Chronopic.Plataforma.ON && loggedState == States.OFF)
+                               if (has_arrived()) // timestamp is tf
                                {
-                                       /*
-                                        * ---------------------------- has arrived ---------------------
-                                        */
-
                                        loggedState = States.ON;
                                        
                                        if(runPhase == runPhases.PRE_RUNNING) {
@@ -366,14 +365,10 @@ public class RunExecute : EventExecute
                                                }
                                        }
                                }
-                               else if (platformState == Chronopic.Plataforma.OFF && loggedState == 
States.ON)
+                               else if (has_lifted()) // timestamp is tc
                                {
-                                       /*
-                                        * ------------------it's out has abandoned photocell 
----------------------
-                                        */
                                        //don't record time
                                                
-                                       //change the automata state
                                        loggedState = States.OFF;
 
                                        if(checkDoubleContactMode != Constants.DoubleContact.NONE && 
timestampDCn > 0)
@@ -413,6 +408,15 @@ public class RunExecute : EventExecute
                } while ( ! success && ! cancel );
                runEI.ChangePhase(RunExecuteInspector.Phases.END);
        }
+
+       protected bool has_arrived()
+       {
+               return (platformState == Chronopic.Plataforma.ON && loggedState == States.OFF);
+       }
+       protected bool has_lifted()
+       {
+               return (platformState == Chronopic.Plataforma.OFF && loggedState == States.ON);
+       }
        
        protected override bool shouldFinishByTime() {
                return false; //this kind of events (simple runs) cannot be finished by time
@@ -530,7 +534,10 @@ public class RunExecute : EventExecute
 
        public override string GetInspectorMessages()
        {
-               return runEI.ToString();
+               if(runPTL != null)
+                       return runEI.ToString() + "\n\n" + runPTL.ToString() + "\n\n" + 
runPTL.InListForPaintingToString();
+               else
+                       return runEI.ToString();
        }
 
        public string RunnerName
@@ -547,16 +554,20 @@ public class RunIntervalExecute : RunExecute
        double distanceTotal;
        double timeTotal;
        double distanceInterval;
-       string intervalTimesString;
-       double tracks; //double because if we limit by time (runType tracksLimited false), we do n.nn tracks
        string limited; //the teorically values, eleven runs: "11=R" (time recorded in "time"), 10 seconds: 
"10=T" (tracks recorded in tracks)
        double limitAsDouble;   //-1 for non limited (unlimited repetitive run until "finish" is clicked)
        bool tracksLimited;
 
-
        string distancesString; //if distances are variable (distanceInterval == -1), this is used
        double distanceIntervalFixed; //if distanceInterval == -1, then Fixed is the corresponding base on 
distancesString
-       double lastTc;          //useful to know time on contact platform because intervalTimesString does 
not differentiate
+
+       //static because they are used on both threads at the same time
+       static double tracks; //double because if we limit by time (runType tracksLimited false), we do n.nn 
tracks
+       static string intervalTimesString;
+       //since trackDone is called by PulseGTK (onTimer)
+       static double lastTc;           //useful to know time on contact platform because intervalTimesString 
does not differentiate
+       static double lastTf;           //used when no double contacts mode
+       static DateTime timerLastTf; //this two will be protected and in runSimpleExecute
                                                        
        bool RSABellDone;
 
@@ -625,7 +636,9 @@ public class RunIntervalExecute : RunExecute
                
                needUpdateEventProgressBar = false;
                needUpdateGraph = false;
-               
+               needCallTrackDone = false;
+               needCheckIfTrackEnded = false;
+
                timesForSavingRepetitive = 1; //number of times that this repetive event needs for being 
recorded in temporal table
 
                //initialize eventDone as a RunInterval
@@ -633,11 +646,13 @@ public class RunIntervalExecute : RunExecute
        }
 
 
+       private string equal;
+       private int countForSavingTempTable;
        protected override void waitEvent ()
        {
                double timestamp = 0;
-               bool success = false;
-               string equal = "";
+               success = false;
+               equal = "";
                
                //initialize variables
                intervalTimesString = "";
@@ -645,12 +660,14 @@ public class RunIntervalExecute : RunExecute
                bool ok;
                timerCount = 0;
                //bool initialized = false;
-               int countForSavingTempTable = 0;
+               countForSavingTempTable = 0;
+
                lastTc = 0;
                distanceIntervalFixed = distanceInterval;
 
                timestampDCInitValues();
-               
+               timerLastTf = DateTime.MinValue;
+
                //prepare variables to allow being cancelled or finished
                if(! simulated)
                        Chronopic.InitCancelAndFinish();
@@ -662,23 +679,33 @@ public class RunIntervalExecute : RunExecute
                                checkDoubleContactTime
                                );
                runEI.ChangePhase(RunExecuteInspector.Phases.START);
+
+               //initialize runDC
+               runDC = new RunDoubleContact(
+                               checkDoubleContactMode,
+                               checkDoubleContactTime
+                               );
+               runPTL = new RunPhaseTimeList();
+
+               bool exitWaitEventBucle = false;
+               int countBucle = 0; //just for debug now
                do {
                        if(simulated) 
                                ok = true;
                        else 
                                ok = cp.Read_event(out timestamp, out platformState);
-               
-       
-                       if (ok && !cancel && !finish) {
+
+                       LogB.Information(string.Format("countBucle = {0}; platformState = {1}; lastTc = {2}; 
lastTf = {3}", countBucle, platformState, lastTc, lastTf));
+                       countBucle ++;
+
+
+                       if (ok && ! cancel && ! finish)
+                       {
                                if(distanceInterval == -1)
                                        distanceIntervalFixed = 
Util.GetRunIVariableDistancesStringRow(distancesString, (int) tracks);
 
-                               if (platformState == Chronopic.Plataforma.ON && loggedState == States.OFF)
+                               if (has_arrived()) //timestamp is TF
                                {
-                                       /*
-                                        * ---------------------------- has arrived ---------------------
-                                        */
-
                                        loggedState = States.ON;
                                        
                                        //show RSA count down only on air               
@@ -714,156 +741,24 @@ public class RunIntervalExecute : RunExecute
                                                if(simulated)
                                                        timestamp = simulatedTimeLast * 1000; //conversion to 
milliseconds
 
-                                               //prevent double contact stuff
-                                               string runEIString = "";
-                                               if(checkDoubleContactMode != Constants.DoubleContact.NONE) {
-                                                       if(timestamp <= checkDoubleContactTime) {
-                                                               /*
-                                                                  when checking double contact
-                                                                  first time that timestamp < 
checkDoubleContactTime
-                                                                  and we arrived (it's a flight time)
-                                                                  record this time as timestampDCFlightTimes
-                                                                */
-                                                               timestampDCn ++;
-                                                               timestampDCFlightTimes += timestamp;
-                                                               
runEI.ChangePhase(RunExecuteInspector.Phases.IN,
-                                                                       string.Format("RUNNING, 
DOUBLECONTACT, timestamp: {0}, " +
-                                                                               "has been added to 
timestampDCFlightTimes: {1}",
-                                                                               Math.Round(timestamp/1000.0, 
3),
-                                                                               
Math.Round(timestampDCFlightTimes/1000.0, 3)
-                                                                               ));
-
-                                                               continue;
-                                                       }
-                                                       else {
-                                                               if(timestampDCn > 0) {
-                                                                       if(checkDoubleContactMode == 
-                                                                                       
Constants.DoubleContact.FIRST) {
-                                                                               /* user want first flight 
time,
-                                                                                  then add all DC times*/
-
-                                                                               double timestampTemp = 
timestamp;
-                                                                               timestamp += 
timestampDCFlightTimes + 
-                                                                                       
timestampDCContactTimes;
-
-                                                                               runEIString = 
string.Format("RUNNING, DoubleContactMode.FIRST, timestamp was: {0} " +
-                                                                                               "added 
DCFlightTimes: {1} and DCContactTimes: {2}, " +
-                                                                                               "now 
timestamp is: {3}",
-                                                                                               
Math.Round(timestampTemp/1000.0, 3), Math.Round(timestampDCFlightTimes/1000.0, 3),
-                                                                                               
Math.Round(timestampDCContactTimes/1000.0, 3), Math.Round(timestamp/1000.0, 3));
-                                                                       }
-                                                                       else if(checkDoubleContactMode == 
-                                                                                       
Constants.DoubleContact.LAST) {
-                                                                               //user want last flight time, 
take that
-                                                                               // so we don't need to change 
timestamp. Or we could do (it triggers a warning):
-                                                                               // timestamp = timestamp;
-
-                                                                               runEIString = 
string.Format("RUNNING, DoubleContactMode.LAST " +
-                                                                                               "do not 
change timestamp, timestamp is: {0}", timestamp/1000.0);
-                                                                       }
-                                                                       else {  // checkDoubleContactMode == 
AVERAGE
-                                                                               /* do the avg of all flights 
and contacts
-                                                                                  then add to last timestamp 
*/
-                                                                               double timestampTemp = 
timestamp;
-                                                                               timestamp += 
-                                                                                       
(timestampDCFlightTimes + 
-                                                                                        
timestampDCContactTimes) 
-                                                                                       / timestampDCn;
-
-                                                                               runEIString = 
string.Format("RUNNING, DoubleContactMode.AVERAGE, timestamp was: {0} " +
-                                                                                               "added 
(DCFlightTimes: {1} + DCContactTimes: {2}) / n: {3}, " +
-                                                                                               "now 
timestamp is: {4}",
-                                                                                               
Math.Round(timestampTemp/1000.0, 3), Math.Round(timestampDCFlightTimes/1000.0, 3),
-                                                                                               
Math.Round(timestampDCContactTimes/1000.0, 3), timestampDCn,
-                                                                                               
Math.Round(timestamp/1000.0, 3));
-                                                                       }
-
-                                                                       //init values of timestampDC for next 
track
-                                                                       timestampDCInitValues();
-                                                               }
-                                                       }
-                                               }
-
-                                               //note in double contacts mode timestamp can have added 
DCFlightTimes and DCContactTimes. So contact time is not only on lastTc
-                                               double myRaceTime = lastTc + timestamp/1000.0;
-
-                                               runEI.ChangePhase(RunExecuteInspector.Phases.IN, runEIString +
-                                                               string.Format("; timestamp: {0}; 
<b>trackTime: {1}</b>",
-                                                                       Math.Round(timestamp/1000.0, 3), 
Math.Round(myRaceTime, 3)));
-
-                                               LogB.Information(string.Format("RACE ({0}) TC: {1}; TV: {2}; 
TOTALTIME: {3}", tracks, lastTc, timestamp/1000.0, myRaceTime));
-
-                                               if(intervalTimesString.Length > 0) { equal = "="; }
-                                               intervalTimesString = intervalTimesString + equal + 
myRaceTime.ToString();
-                                               updateTimerCountWithChronopicData(intervalTimesString);
-                                               tracks ++;      
-
-                                               //save temp table if needed
-                                               countForSavingTempTable ++;
-                                               if(countForSavingTempTable == timesForSavingRepetitive) {
-                                                               writeRunInterval(true); //tempTable
-                                                               countForSavingTempTable = 0;
-                                               }
-                                       
-                                               if(limitAsDouble == -1) {
-                                                       //has arrived, unlimited
-                                                       updateProgressBar= new UpdateProgressBar (
-                                                                       true, //isEvent
-                                                                       true, //unlimited: activity mode
-                                                                       tracks
-                                                                       );  
-                                                       needUpdateEventProgressBar = true;
-                                               }
-                                               else {
-                                                       //has arrived, limited
-                                                       if (tracksLimited) {
-                                                               //has arrived, limited by tracks
-                                                               if(tracks >= limitAsDouble) 
-                                                               {
-                                                                       runPhase = runPhases.PLATFORM_END;
-
-                                                                       //finished
-                                                                       writeRunInterval(false); //tempTable 
= false
-                                                                       success = true;
-                                                               }
-                                                               //progressBarEventOrTimePreExecution(
-                                                               updateProgressBar= new UpdateProgressBar (
-                                                                               true, //isEvent
-                                                                               true, //tracksLimited: 
percentageMode
-                                                                               tracks
-                                                                               );  
-                                                               needUpdateEventProgressBar = true;
-                                                       } else {
-                                                               //has arrived, limited by time
-                                                               updateProgressBar= new UpdateProgressBar (
-                                                                               true, //isEvent
-                                                                               false, //timeLimited: 
activity mode
-                                                                               tracks
-                                                                               );  
-                                                               needUpdateEventProgressBar = true;
-                                                       }
+                                               if(runDC.UseDoubleContacts())
+                                               {
+                                                       runDC.DoneTF (timestamp);
+                                                       timerLastTf = DateTime.Now;
+                                                       needCheckIfTrackEnded = true;
+                                               } else
+                                               {
+                                                       lastTf = timestamp;
+                                                       //trackDone();
+                                                       needCallTrackDone = true;
                                                }
 
-                                               distanceTotal = Util.GetRunITotalDistance(distanceInterval, 
distancesString, tracks);
-
-                                               //update graph
-                                               PrepareEventGraphRunIntervalObject = new 
PrepareEventGraphRunInterval(
-                                                               distanceIntervalFixed, myRaceTime, 
intervalTimesString, 
-                                                               distanceTotal, distancesString, startIn);
-
-                                               needUpdateGraphType = eventType.RUNINTERVAL;
-                                               needUpdateGraph = true;
-
-                                               //put button_finish as sensitive when first jump is done 
(there's something recordable)
-                                               if(tracks == 1)
-                                                       needSensitiveButtonFinish = true;
+                                               runPTL.AddTF(timestamp);
                                        }
                                }
-                               else if (platformState == Chronopic.Plataforma.OFF && loggedState == 
States.ON)
+                               else if (has_lifted()) //timestamp is TC
                                {
-                                       /*
-                                        * ------------------it's out has abandoned photocell 
----------------------
-                                        */
+                                       loggedState = States.OFF;
 
                                        lastTc = 0;
                                        if(runPhase == runPhases.PLATFORM_INI_NO_TIME) {
@@ -884,22 +779,23 @@ public class RunIntervalExecute : RunExecute
                                                        lastTc = timestamp / 1000.0;
                                                        runEI.ChangePhase(RunExecuteInspector.Phases.OUT,
                                                                string.Format("SpeedStartArrival, tc = {0}", 
Math.Round(lastTc, 3)));
+                                                       runPTL.AddTC(timestamp);
                                                }
 
                                                feedbackMessage = "";
                                                needShowFeedbackMessage = true; 
                                        } else {
-                                               if(checkDoubleContactMode != Constants.DoubleContact.NONE && 
timestampDCn > 0)
+                                               runEI.ChangePhase(RunExecuteInspector.Phases.OUT,
+                                                               string.Format("SpeedStartArrival, timestamp = 
{0}", timestamp));
+
+                                               if(runDC.UseDoubleContacts())
                                                {
-                                                       timestampDCContactTimes += timestamp;
-                                                       runEI.ChangePhase(RunExecuteInspector.Phases.OUT,
-                                                               string.Format("RUNNING double contact, 
timestampDCContactTimes = {0}", Math.Round(timestampDCContactTimes/1000.0, 3)));
+                                                       runDC.DoneTC(timestamp);
                                                }
                                                else {
                                                        lastTc = timestamp / 1000.0;
-                                                       runEI.ChangePhase(RunExecuteInspector.Phases.OUT,
-                                                               string.Format("RUNNING, tc = {0}", 
Math.Round(lastTc, 3)));
                                                }
+                                               runPTL.AddTC(timestamp);
                                                
                                                
                                                //RSA
@@ -916,14 +812,30 @@ public class RunIntervalExecute : RunExecute
 
                                        }
 
-                                               
                                        runPhase = runPhases.RUNNING;
+                               }
+                       }
 
-                                       //change the automata state
-                                       loggedState = States.OFF;
+                       exitWaitEventBucle = false;
+                       if(success || cancel || finish)
+                       {
+                               if(runDC.UseDoubleContacts())
+                               {
+                                       LogB.Information(string.Format("success: {0}, cancel: {1}, finish: 
{2}", success, cancel, finish));
+                                       while(needCheckIfTrackEnded)
+                                       {
+                                               LogB.Information("WAITING 100 MS TO EXIT BUCLE");
+                                               //TODO: checks what happens with cancel... in the pulse 
thread, will change this boolean? needCheckIfTrackEnded
+                                               Thread.Sleep(100);
+                                       }
+
+                                       exitWaitEventBucle = true;
                                }
+                               else
+                                       exitWaitEventBucle = true;
                        }
-               } while ( ! success && ! cancel && ! finish );
+
+               } while ( ! exitWaitEventBucle );
                runEI.ChangePhase(RunExecuteInspector.Phases.END);
 
                if (finish) {
@@ -940,6 +852,116 @@ public class RunIntervalExecute : RunExecute
                }
        }
 
+       //this will be protected and in run simple execute class
+       protected override bool lastTfCheckTimeEnded()
+       {
+               TimeSpan span = DateTime.Now - timerLastTf;
+               if(span.TotalMilliseconds > checkDoubleContactTime * 1.5)
+               {
+                       timerLastTf = DateTime.Now;
+                       return true;
+               }
+               return false;
+       }
+
+       //this will be protected and in run simple execute class
+       //big change in 1.8.1: this will be called from GTK thread
+       //so don't write to SQL here
+       //and use static variables where needed
+       protected override void trackDone()
+       {
+               double myTrackTime = 0;
+               if(runDC.UseDoubleContacts())
+                       myTrackTime = runDC.GetTrackTimeInSecondsAndEmptyLists(); //will come in seconds
+               else {
+                       //note in double contacts mode timestamp can have added DCFlightTimes and 
DCContactTimes. So contact time is not only on lastTc
+                       myTrackTime = lastTc + lastTf/1000.0;
+               }
+
+               //runEI.ChangePhase(RunExecuteInspector.Phases.IN, runEIString +
+               runEI.ChangePhase(RunExecuteInspector.Phases.IN, //runEIString +
+                               string.Format("; timestamp: {0}; <b>trackTime: {1}</b>",
+                                       Math.Round(lastTf/1000.0, 3), Math.Round(myTrackTime, 3)));
+
+               LogB.Information(string.Format("RACE ({0}) TC: {1}; TV: {2}; TOTALTIME: {3}", tracks, lastTc, 
lastTf/1000.0, myTrackTime));
+
+               if(intervalTimesString.Length > 0) { equal = "="; }
+               intervalTimesString = intervalTimesString + equal + myTrackTime.ToString();
+               updateTimerCountWithChronopicData(intervalTimesString);
+               tracks ++;
+
+               /*
+                * Attention:
+                * don't do this because we are on GTK thread right now
+                * and here we are touching SQL
+                *
+               //save temp table if needed
+               countForSavingTempTable ++;
+               if(countForSavingTempTable == timesForSavingRepetitive) {
+                       writeRunInterval(true); //tempTable
+                       countForSavingTempTable = 0;
+               }
+               */
+
+               if(limitAsDouble == -1) {
+                       //has arrived, unlimited
+                       updateProgressBar= new UpdateProgressBar (
+                                       true, //isEvent
+                                       true, //unlimited: activity mode
+                                       tracks
+                                       );
+                       needUpdateEventProgressBar = true;
+               }
+               else {
+                       //has arrived, limited
+                       if (tracksLimited) {
+                               //has arrived, limited by tracks
+                               if(tracks >= limitAsDouble) 
+                               {
+                                       runPhase = runPhases.PLATFORM_END;
+
+                                       //finished
+                                       writeRunInterval(false); //tempTable = false
+                                       success = true;
+
+                                       //as we will be on waitEvent do { ok = cp.Read_event ... }
+                                       //call this to end Read_cambio called by Read_event
+                                       Chronopic.FinishDo();
+                               }
+                               //progressBarEventOrTimePreExecution(
+                               updateProgressBar= new UpdateProgressBar (
+                                               true, //isEvent
+                                               true, //tracksLimited: percentageMode
+                                               tracks
+                                               );
+                               needUpdateEventProgressBar = true;
+                       } else {
+                               //has arrived, limited by time
+                               updateProgressBar= new UpdateProgressBar (
+                                               true, //isEvent
+                                               false, //timeLimited: activity mode
+                                               tracks
+                                               );
+                               needUpdateEventProgressBar = true;
+                       }
+               }
+
+               distanceTotal = Util.GetRunITotalDistance(distanceInterval, distancesString, tracks);
+
+               //update graph
+               PrepareEventGraphRunIntervalObject = new PrepareEventGraphRunInterval(
+                               distanceIntervalFixed, myTrackTime, intervalTimesString,
+                               distanceTotal, distancesString, startIn);
+
+               needUpdateGraphType = eventType.RUNINTERVAL;
+               needUpdateGraph = true;
+
+               //put button_finish as sensitive when first jump is done (there's something recordable)
+               if(tracks == 1)
+                       needSensitiveButtonFinish = true;
+       }
+
+
        protected override string countDownMessage() {
                double waitSeconds = Util.GetRunIVariableDistancesThisRowIsRSA(distancesString, 
Convert.ToInt32(tracks))
                         - (timerCount - Util.GetTotalTime(intervalTimesString) - lastTc);
@@ -1119,7 +1141,8 @@ public class RunIntervalExecute : RunExecute
                                        );
 
                        //define the created object
-                       eventDone = new RunInterval(uniqueID, personID, sessionID, type, distanceTotal, 
timeTotal, distanceInterval, intervalTimesString, tracksHere, description, limitString, 
Util.BoolToNegativeInt(simulated), !startIn); 
+                       eventDone = new RunInterval(uniqueID, personID, sessionID, type, distanceTotal, 
timeTotal, distanceInterval, intervalTimesString,
+                                       tracksHere, description, limitString, 
Util.BoolToNegativeInt(simulated), !startIn); 
 
                        /*
                        string tempValuesString;
@@ -1207,69 +1230,3 @@ public class RunIntervalExecute : RunExecute
                
        ~RunIntervalExecute() {}
 }
-
-public class RunExecuteInspector
-{
-       public enum Types { RUN_SIMPLE, RUN_INTERVAL }
-       private Types type;
-
-       public enum Phases { START, IN, OUT, END }
-       private DateTime dtStarted;
-       private DateTime dtEnded;
-
-       private bool speedStartArrival;
-       Constants.DoubleContact checkDoubleContactMode;
-       int checkDoubleContactTime;
-
-       private List<InOut> listInOut;
-
-
-       //constructor
-       public RunExecuteInspector(Types type, bool speedStartArrival,
-                       Constants.DoubleContact checkDoubleContactMode, int checkDoubleContactTime)
-       {
-               this.type = type;
-               this.speedStartArrival = speedStartArrival;
-               this.checkDoubleContactMode = checkDoubleContactMode;
-               this.checkDoubleContactTime = checkDoubleContactTime;
-
-               listInOut = new List<InOut>();
-       }
-
-       //public methods
-
-       public void ChangePhase(Phases phase)
-       {
-               ChangePhase(phase, "");
-       }
-       public void ChangePhase(Phases phase, string message)
-       {
-               DateTime dt = DateTime.Now;
-
-               if(phase == Phases.START)
-                       dtStarted = dt;
-               else if(phase == Phases.END)
-                       dtEnded = dt;
-               else // (phase == Phases.IN || phases == Phases.OUT)
-               {
-                       InOut inOut = new InOut(phase == Phases.IN, dt, message);
-                       listInOut.Add(inOut);
-                       //listInOut.Add(new InOut(phase == Phases.IN, dt, message));
-               }
-       }
-
-       public override string ToString()
-       {
-               string report = string.Format("Report of race started at: {0}; ended at: {1}", 
dtStarted.ToShortTimeString(), dtEnded.ToShortTimeString());
-               report += "\n" + "Type: " + type.ToString();
-               report += "\n" + "SpeedStartArrival: " + speedStartArrival;
-               report += "\n" + "CheckDoubleContactMode: " + checkDoubleContactMode;
-               report += "\n" + "CheckDoubleContactTime: " + checkDoubleContactTime;
-               report += "\n" + "Chronopic changes:";
-               foreach(InOut inOut in listInOut)
-               {
-                       report += inOut.ToString();
-               }
-               return report;
-       }
-}
diff --git a/src/execute/runObjects.cs b/src/execute/runObjects.cs
new file mode 100644
index 0000000..9919b66
--- /dev/null
+++ b/src/execute/runObjects.cs
@@ -0,0 +1,376 @@
+/*
+ * This file is part of ChronoJump
+ *
+ * ChronoJump is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or   
+ *    (at your option) any later version.
+ *    
+ * ChronoJump is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ *    GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Copyright (C) 2018  Xavier de Blas <xaviblas gmail com> 
+ */
+
+using System;
+using System.Data;
+using System.Collections.Generic; //List
+
+//contains for each phase: isContact? startMSInSequence duration
+public class RunPhaseInfo
+{
+       public enum Types { CONTACT, FLIGHT }
+
+       public Types type;
+       public double startMSInSequence; //unused right now
+       public double duration;
+
+       public RunPhaseInfo (Types type, double startMSInSequence, double duration)
+       {
+               this.type = type;
+               this.startMSInSequence = startMSInSequence;
+               this.duration = duration;
+       }
+
+       public bool IsContact()
+       {
+               return type == Types.CONTACT;
+       }
+
+       public double Duration {
+               get { return duration; }
+       }
+
+       public override string ToString()
+       {
+               return string.Format("type: {0}, startMSInSequence: {1}, duration: {2}",
+                               type, startMSInSequence, duration);
+       }
+
+}
+//manage RunPhaseInfo list
+public class RunPhaseInfoManage
+{
+       private List<RunPhaseInfo> list;
+
+       public RunPhaseInfoManage ()
+       {
+               list = new List<RunPhaseInfo>();
+       }
+               
+       public void Add (RunPhaseInfo rpi)
+       {
+               list.Add(rpi);
+       }
+
+       public int GetPosOfBiggestTC ()
+       {
+               //if there's no tc, return -1, track duration will be tf duration
+               //if there's one tc, return -1, track duration will be tc+tf duration
+               if(countTCs() < 2)
+                       return -1;
+
+               //if there's more than one tc, return the pos of bigger tc,
+               //but first tc cannot be the biggest, because first tc will be always added (and first tf)
+               double max = 0;
+               int pos = 0;
+               int posBiggest = 0;
+               foreach(RunPhaseInfo rpi in list)
+               {
+                       if(pos > 0 && rpi.IsContact() && rpi.Duration > max) //pos > 0 to not allow first tc 
to be the biggest
+                       {
+                               max = rpi.Duration;
+                               posBiggest = pos;
+                       }
+
+                       pos ++;
+               }
+               return posBiggest;
+       }
+
+       //if pos == -1 return all
+       public double SumUntilPos(int pos)
+       {
+               double sum = 0;
+
+               if(pos == -1) {
+                       foreach(RunPhaseInfo rpi in list)
+                               sum += rpi.Duration;
+               } else {
+                       int count = 0;
+                       foreach(RunPhaseInfo rpi in list)
+                               if(count ++ < pos)
+                                       sum += rpi.Duration;
+               }
+
+               return sum;
+       }
+       
+       //if pos == -1 empty all
+       public void EmtpyListUntilPos(int pos)
+       {
+               if(pos == -1)
+                       list = new List<RunPhaseInfo>();
+               else {
+                       List<RunPhaseInfo> listNew = new List<RunPhaseInfo>();
+                       int count = 0;
+                       foreach(RunPhaseInfo rpi in list)
+                               if(count ++ >= pos)
+                                       listNew.Add(rpi);
+
+                       list = listNew;
+               }
+       }
+                       
+       public string PrintList()
+       {
+               string str = "\n";
+               foreach(RunPhaseInfo rpi in list)
+                       str += "\n" + rpi.ToString();
+
+               return str;
+       }
+
+       private int countTCs()
+       {
+               int count = 0;
+               foreach(RunPhaseInfo rpi in list)
+                       if(rpi.IsContact())
+                               count ++;
+
+               return count;
+       }
+
+       public int LastPositionOfList {
+               get { return list.Count -1; }
+       }
+}
+
+//manage double contacts in runs
+public class RunDoubleContact
+{
+       private Constants.DoubleContact mode;
+       private int checkTime;
+
+       private RunPhaseInfoManage rpim;
+
+       //these are used also to know track time if there are no double contacts
+       private double lastTc; //important to check lastTc and currentTF to measure if they are above or not 
checkTime
+       
+       private double timeAcumulated;
+
+       //constructor ------------------------------------------
+       public RunDoubleContact (Constants.DoubleContact mode, int checkTime)
+       {
+               this.mode = mode;
+               this.checkTime = checkTime;
+
+               lastTc = 0;
+               timeAcumulated = 0;
+               rpim = new RunPhaseInfoManage();
+       }
+
+       //public methods ---------------------------------------
+
+       public bool UseDoubleContacts ()
+       {
+               return (mode != Constants.DoubleContact.NONE);
+       }
+
+       public void DoneTC (double timestamp)
+       {
+               lastTc = timestamp;
+               rpim.Add(new RunPhaseInfo(RunPhaseInfo.Types.CONTACT, timeAcumulated, timestamp));
+               timeAcumulated += timestamp;
+               LogB.Information(string.Format("DoneTC -> lastTc: {0}", lastTc));
+       }
+
+       public void DoneTF (double timestamp)
+       {
+               LogB.Information(string.Format(
+                                       "lastTc + timestamp <= checkTime ?, lastTc: {0}; timestamp: {1}; 
checkTime: {2}",
+                                       lastTc, timestamp, checkTime));
+
+               rpim.Add(new RunPhaseInfo(RunPhaseInfo.Types.FLIGHT, timeAcumulated, timestamp));
+               timeAcumulated += timestamp;
+       }
+
+       //this wait will be done by C#
+       public double GetTrackTimeInSecondsAndEmptyLists()
+       {
+               double trackTime = 0;
+               /*
+               if(mode == Constants.FoubleContact.FIRST)
+                       timestamp = getDCFirst();
+               else if(mode == Constants.FoubleContact.LAST)
+                       timestamp = getDCLast();
+               else if(mode == Constants.FoubleContact.AVERAGE)
+                       timestamp = getDCAverage();
+               else // if(mode == Constants.FoubleContact.BIGGEST_TC)
+               */
+                       trackTime = getDCBiggestTC(); //superhardcoded
+
+               //in seconds
+               if(trackTime > 0)
+                       trackTime /= 1000.0;
+
+               return trackTime;
+       }
+
+       //private methods --------------------------------------
+       
+       private double getDCBiggestTC()
+       {
+               int bigTCPosition = rpim.GetPosOfBiggestTC();
+               double sum = rpim.SumUntilPos(bigTCPosition);
+
+               LogB.Information(string.Format("\n----------------\ngetDCBiggestTC, list: {0}, bigTCPosition: 
{1}, sum: {2}", rpim.PrintList(), bigTCPosition, sum));
+
+               if(sum < checkTime)
+               {
+                       while (sum < checkTime && bigTCPosition +2 <= rpim.LastPositionOfList)
+                       {
+                               bigTCPosition += 2;
+                               sum = rpim.SumUntilPos(bigTCPosition);
+                               LogB.Information(string.Format("SUM was < checkTime. New bigTCPosition: {0}, 
New Sum: {1}", bigTCPosition, sum));
+                       }
+               }
+
+               rpim.EmtpyListUntilPos(bigTCPosition);
+
+               return sum;
+       }
+}
+
+//decide if use this or inspector
+public class RunPhaseTimeList
+{
+       private List<PhaseTime> listPhaseTime;
+
+       public RunPhaseTimeList()
+       {
+               listPhaseTime = new List<PhaseTime>();
+       }
+       
+       public void AddTC(double timestamp)
+       {
+               listPhaseTime.Add(new PhaseTime(true, timestamp));
+       }
+
+       public void AddTF(double timestamp)
+       {
+               listPhaseTime.Add(new PhaseTime(false, timestamp));
+       }
+
+       public override string ToString()
+       {
+               string str = "";
+               foreach(PhaseTime pt in listPhaseTime)
+                       str += pt.ToString();
+
+               return str;
+       }
+
+       public List<string> InListForPainting()
+       {
+               List<string> list_in = new List<string>();
+               int currentMS = 0;
+               int startInMS = -1;
+               foreach(PhaseTime pt in listPhaseTime)
+               {
+                       if(pt.IsContact)
+                               startInMS = currentMS;
+                       else if(startInMS >= 0)
+                               list_in.Add(startInMS/1000.0 + ":" + currentMS/1000.0); //in seconds
+
+                       currentMS += Convert.ToInt32(pt.Duration);
+               }
+
+               return list_in;
+       }
+
+       //Debug
+       public string InListForPaintingToString()
+       {
+               string str = "Contact in time list:\n";
+               List<string> list_in = InListForPainting();
+               foreach(string s in list_in)
+                       str += s + "\n";
+
+               return str;
+       }
+
+}
+
+//currently used for simple runs
+public class RunExecuteInspector
+{
+       public enum Types { RUN_SIMPLE, RUN_INTERVAL }
+       private Types type;
+
+       public enum Phases { START, IN, OUT, END }
+       private DateTime dtStarted;
+       private DateTime dtEnded;
+
+       private bool speedStartArrival;
+       Constants.DoubleContact checkDoubleContactMode;
+       int checkDoubleContactTime;
+
+       private List<InOut> listInOut;
+
+
+       //constructor
+       public RunExecuteInspector(Types type, bool speedStartArrival,
+                       Constants.DoubleContact checkDoubleContactMode, int checkDoubleContactTime)
+       {
+               this.type = type;
+               this.speedStartArrival = speedStartArrival;
+               this.checkDoubleContactMode = checkDoubleContactMode;
+               this.checkDoubleContactTime = checkDoubleContactTime;
+
+               listInOut = new List<InOut>();
+       }
+
+       //public methods
+
+       public void ChangePhase(Phases phase)
+       {
+               ChangePhase(phase, "");
+       }
+       public void ChangePhase(Phases phase, string message)
+       {
+               DateTime dt = DateTime.Now;
+
+               if(phase == Phases.START)
+                       dtStarted = dt;
+               else if(phase == Phases.END)
+                       dtEnded = dt;
+               else // (phase == Phases.IN || phases == Phases.OUT)
+               {
+                       InOut inOut = new InOut(phase == Phases.IN, dt, message);
+                       listInOut.Add(inOut);
+                       //listInOut.Add(new InOut(phase == Phases.IN, dt, message));
+               }
+       }
+
+       public override string ToString()
+       {
+               string report = string.Format("Report of race started at: {0}; ended at: {1}", 
dtStarted.ToShortTimeString(), dtEnded.ToShortTimeString());
+               report += "\n" + "Type: " + type.ToString();
+               report += "\n" + "SpeedStartArrival: " + speedStartArrival;
+               report += "\n" + "CheckDoubleContactMode: " + checkDoubleContactMode;
+               report += "\n" + "CheckDoubleContactTime: " + checkDoubleContactTime;
+               report += "\n" + "Chronopic changes:";
+               foreach(InOut inOut in listInOut)
+               {
+                       report += inOut.ToString();
+               }
+               return report;
+       }
+}
diff --git a/src/gui/chronojump.cs b/src/gui/chronojump.cs
index ef32f55..e2686e5 100644
--- a/src/gui/chronojump.cs
+++ b/src/gui/chronojump.cs
@@ -5443,7 +5443,9 @@ LogB.Debug("X");
                                                                distanceTotal,
                                                                runType.DistancesString,
                                                                currentRunInterval.StartIn,
-                                                               preferences.volumeOn, preferences.gstreamer, 
repetitiveConditionsWin);
+                                                               preferences.volumeOn, preferences.gstreamer, 
repetitiveConditionsWin,
+                                                               currentEventExecute.RunPTL
+                                                               );
                                        }
                                        break;
                                case EventType.Types.FORCESENSOR:
diff --git a/src/gui/eventExecute.cs b/src/gui/eventExecute.cs
index b8a3a84..0b70793 100644
--- a/src/gui/eventExecute.cs
+++ b/src/gui/eventExecute.cs
@@ -707,7 +707,7 @@ public partial class ChronoJumpWindow
        public void PrepareRunIntervalGraph(double distance, double lastTime, string timesString,
                        double distanceTotal, string distancesString,
                        bool startIn, bool volumeOn, Preferences.GstreamerTypes gstreamer,
-                       RepetitiveConditionsWindow repetitiveConditionsWin)
+                       RepetitiveConditionsWindow repetitiveConditionsWin, RunPhaseTimeList runPTL)
        {
                //check graph properties window is not null (propably user has closed it with the DeleteEvent
                //then create it, but not show it
@@ -750,7 +750,7 @@ public partial class ChronoJumpWindow
                                lastTime, timesString, Util.GetAverage(timesString), 
                                maxValue, minValue, tracks, topMargin, bottomMargin,
                                Util.GetPosMax(timesString), Util.GetPosMin(timesString), startIn,
-                               volumeOn, gstreamer, repetitiveConditionsWin);
+                               volumeOn, gstreamer, repetitiveConditionsWin, runPTL);
                
                // -- refresh
                event_execute_drawingarea.QueueDraw();
@@ -1435,7 +1435,7 @@ public partial class ChronoJumpWindow
                        double maxValue, double minValue, int tracks, int topMargin, int bottomMargin, 
                        int hightValuePosition, int lowValuePosition, bool startIn,
                        bool volumeOn, Preferences.GstreamerTypes gstreamer,
-                       RepetitiveConditionsWindow repetitiveConditionsWin)
+                       RepetitiveConditionsWindow repetitiveConditionsWin, RunPhaseTimeList runPTL)
        {
                //int topMargin = 10; 
                int ancho=drawingarea.Allocation.Width;
@@ -1478,8 +1478,24 @@ public partial class ChronoJumpWindow
                        Gdk.GC myPen = pen_rojo; //default value
                        double myValue = 0;
 
+                       foreach (string inPTL in runPTL.InListForPainting())
+                       {
+                               string [] inPTLFull = inPTL.Split(new char[] {':'});
+                               int xStart = event_execute_rightMargin + Convert.ToInt32((ancho - 
2*event_execute_rightMargin) *
+                                                       (Convert.ToDouble(inPTLFull[0]) / timeTotal));
+
+                               int xEnd = event_execute_rightMargin + Convert.ToInt32((ancho - 
2*event_execute_rightMargin) *
+                                               (Convert.ToDouble(inPTLFull[1]) / timeTotal));
+
+                               //don't plot the TCs after current track
+                               if(Convert.ToDouble(inPTLFull[0]) < timeTotal)
+                                       event_execute_pixmap.DrawRectangle(pen_gris, true,
+                                                       new Rectangle (xStart, alto-bottomMargin-4, 
xEnd-xStart, 4));
+                       }
+
                        foreach (string myTime in myTimesStringFull) 
                        {
+                               LogB.Information(myTime.ToString());
                                myTimeDouble = Convert.ToDouble(myTime);
                                if(myTimeDouble < 0)
                                        myTimeDouble = 0;
@@ -1979,13 +1995,17 @@ public partial class ChronoJumpWindow
                                                volumeOnHere = false;
 
                                        PrepareRunIntervalGraph(
+                                                       //TODO: pass most of this as (including RunPTL)
+                                                       //new PrepareEventGraphRunIntervalObject(distance, 
lastTime, ...)
                                                        
currentEventExecute.PrepareEventGraphRunIntervalObject.distance, 
                                                        
currentEventExecute.PrepareEventGraphRunIntervalObject.lastTime,
                                                        
currentEventExecute.PrepareEventGraphRunIntervalObject.timesString,
                                                        
currentEventExecute.PrepareEventGraphRunIntervalObject.distanceTotal,
                                                        
currentEventExecute.PrepareEventGraphRunIntervalObject.distancesString,
                                                        
currentEventExecute.PrepareEventGraphRunIntervalObject.startIn,
-                                                       volumeOnHere, preferences.gstreamer, 
repetitiveConditionsWin);
+                                                       volumeOnHere, preferences.gstreamer, 
repetitiveConditionsWin,
+                                                       currentEventExecute.RunPTL
+                                                       );
                                }
                                break;
                        case EventType.Types.REACTIONTIME:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]