[chronojump] JumpsDjOptimalFall Cairo graph WIP (cont)



commit e6c230f13dfd6e7eccfad3225f70c47263e06878
Author: Xavier de Blas <xaviblas gmail com>
Date:   Wed Dec 18 16:40:51 2019 +0100

    JumpsDjOptimalFall Cairo graph WIP (cont)

 src/gui/jumpsDjOptimalFall.cs | 229 ++++++++++++++++++++++++++++++++++++++++--
 src/jumpsDjOptimalFall.cs     |  42 ++++++--
 2 files changed, 256 insertions(+), 15 deletions(-)
---
diff --git a/src/gui/jumpsDjOptimalFall.cs b/src/gui/jumpsDjOptimalFall.cs
index b92ff2f5..56749672 100644
--- a/src/gui/jumpsDjOptimalFall.cs
+++ b/src/gui/jumpsDjOptimalFall.cs
@@ -26,8 +26,10 @@ using Cairo;
 
 public static class JumpsDjOptimalFallGraph
 {
-       public static void Do (List<Point> point_l, double pointsMaxY, DrawingArea area, string title, string 
date)
+       public static void Do (List<Point> point_l, double[] coefs, double xAtMaxY,
+                       double pointsMaxValue, DrawingArea area, string title, string date)
        {
+               LogB.Information("at JumpsDjOptimalFallGraph.Do");
                //1 create context
                Cairo.Context g = Gdk.CairoHelper.Create (area.GdkWindow);
                
@@ -35,12 +37,32 @@ public static class JumpsDjOptimalFallGraph
                g.SetSourceRGB(1,1,1);
                g.Paint();
 
+               int topMargin = 30;
+               int bottomMargin = 30;
+               int leftMargin = 30;
+               int rightMargin = 30;
+               //int leftAxis = 40;
+               //int bottomAxis = 40;
+               int graphWidth = 500; //in the future check this is not bigger than area widt
+               int axisDist = 40; //distance from margin to graph
+
+                //calculate separation between series and bar width
+                int distanceBetweenCols = Convert.ToInt32((graphWidth - rightMargin)*(1+.5)/point_l.Count) -
+                        Convert.ToInt32((graphWidth - rightMargin)*(0+.5)/point_l.Count);
+
+                int tctfSep = Convert.ToInt32(.3*distanceBetweenCols);
+                int barWidth = Convert.ToInt32(.3*distanceBetweenCols);
+                int barDesplLeft = Convert.ToInt32(.5*barWidth);
+
+               g.SetSourceRGB(0,0,0);
+               g.LineWidth = 2;
+
                //4 prepare font
                g.SelectFontFace("Helvetica", Cairo.FontSlant.Normal, Cairo.FontWeight.Normal);
                int textHeight = 12;
                g.SetFontSize(textHeight);
 
-               if(pointsMaxY == 0)
+               if(pointsMaxValue == 0)
                {
                        g.SetSourceRGB(0,0,0);
                        g.SetFontSize(16);
@@ -50,22 +72,215 @@ public static class JumpsDjOptimalFallGraph
                        return;
                }
 
-               Cairo.Color color = colorFromRGB(101,86,67);
+               Cairo.Color red = colorFromRGB(200,0,0);
+               Cairo.Color blue = colorFromRGB(178, 223, 238); //lightblue
+
+               /*
                int i = 10;
+               int count = 0;
+               //note p.X is jump fall and p.Y jump height
+               //TODO: maybe this will be for a legend, because the graph wants X,Y points
                foreach(Point p in point_l)
                {
-                       drawRoundedRectangle (0,  i , p.X, 20, 4, g, color);
-                       drawRoundedRectangle (10,  i+20 , p.Y, 20, 4, g, color);
-                       i+= 40;
+                       int x = Convert.ToInt32((graphWidth - 
rightMargin)*(count+.5)/point_l.Count)-barDesplLeft;
+                       int y = calculatePaintHeight(Convert.ToDouble(p.X), area.Allocation.Height, 
pointsMaxValue, 0, topMargin, bottomMargin + bottomAxis);
+
+                       LogB.Information(string.Format("red: {0}, {1}, {2}, {3}", Convert.ToDouble(p.X), 
area.Allocation.Height, pointsMaxValue, y));
+                       drawRoundedRectangle (x, y, barWidth, area.Allocation.Height - y, 4, g, red);
+
+                       x = Convert.ToInt32((graphWidth - 
rightMargin)*(count+.5)/point_l.Count)-barDesplLeft+tctfSep;
+                       y = calculatePaintHeight(Convert.ToDouble(p.Y), area.Allocation.Height, 
pointsMaxValue, 0, topMargin, bottomMargin + bottomAxis);
+
+                       LogB.Information(string.Format("blue: {0}, {1}, {2}, {3}", Convert.ToDouble(p.Y), 
area.Allocation.Height, pointsMaxValue, y));
+                       drawRoundedRectangle (x, y, barWidth, area.Allocation.Height -y, 4, g, blue);
+
+                       count ++;
+               }
+               */
+
+               LogB.Information(string.Format("coef length:{0}", coefs.Length));
+               if(coefs.Length == 3)
+               {
+                       double minX = 1000000;
+                       double maxX = 0;
+                       double minY = 1000000;
+                       int xgraph = 0;
+                       int ygraph = 0;
+
+                       foreach(Point p in point_l)
+                       {
+                               if(p.X < minX)
+                                       minX = p.X;
+                               if(p.X > maxX)
+                                       maxX = p.X;
+                               if(p.Y < minY)
+                                       minY = p.Y;
+                       }
+
+                       double absoluteMaxY = coefs[0] + coefs[1]*xAtMaxY + coefs[2]*Math.Pow(xAtMaxY,2);
+//                     g.Save ();
+
+                       //double xstart = minX - (maxX - minX);
+                       //TODO: use lineTo, and have (maybe) more than 20 points
+                       bool firstValue = false;
+                       for(double x = minX; x < maxX; x += (maxX-minX)/100)
+                       {
+                               xgraph = calculatePaintWidth(
+                                               ( x ),
+                                               graphWidth, maxX, minX, rightMargin, leftMargin + axisDist);
+                               ygraph = calculatePaintHeight(
+                                               ( coefs[0] + coefs[1]*x + coefs[2]*Math.Pow(x,2) ),
+                                               area.Allocation.Height, absoluteMaxY, minY, topMargin, 
bottomMargin + axisDist);
+
+                               if(! firstValue)        
+                                       g.LineTo(xgraph, ygraph);
+
+                               g.MoveTo(xgraph, ygraph);
+                               firstValue = false;
+                       }
+                       g.Stroke ();
+
+                       foreach(Point p in point_l)
+                       {
+                               xgraph = calculatePaintWidth(
+                                               ( p.X ),
+                                               graphWidth, maxX, minX, rightMargin, leftMargin + axisDist);
+                               ygraph = calculatePaintHeight(
+                                               ( p.Y ),
+                                               area.Allocation.Height, absoluteMaxY, minY, topMargin, 
bottomMargin + axisDist);
+                               g.MoveTo(xgraph+6, ygraph);
+                               g.Arc(xgraph, ygraph, 6.0, 0.0, 2.0 * Math.PI); //full circle
+                               g.Color = blue;
+                               g.FillPreserve();
+                               g.SetSourceRGB(0, 0, 0);
+                               g.Stroke ();
+
+                               /*
+                               //print X, Y of each point
+                               printText(xgraph, area.Allocation.Height - Convert.ToInt32(bottomMargin/2), 
0, textHeight, Util.TrimDecimals(p.X, 2), g, true);
+                               printText(Convert.ToInt32(leftMargin/2), ygraph, 0, textHeight, 
Util.TrimDecimals(p.Y, 2), g, true);
+                               */
+                       }
+
+                       xgraph = calculatePaintWidth(
+                                       ( xAtMaxY ),
+                                       graphWidth, maxX, minX, rightMargin, leftMargin + axisDist);
+                       ygraph = calculatePaintHeight(
+                                       absoluteMaxY,
+                                       area.Allocation.Height, absoluteMaxY, minY, topMargin, bottomMargin + 
axisDist);
+
+                       //paint axis
+                       g.MoveTo(leftMargin, topMargin);
+                       g.LineTo(leftMargin, area.Allocation.Height - bottomMargin);
+                       g.LineTo(graphWidth - rightMargin, area.Allocation.Height - bottomMargin);
+                       g.Stroke ();
+
+                       printText(2, Convert.ToInt32(topMargin/2), 0, textHeight, "Height (cm)", g, false);
+                       printText(graphWidth - Convert.ToInt32(rightMargin/2), area.Allocation.Height - 
bottomMargin, 0, textHeight, "Fall (cm)", g, false);
+
+                       //paint grid,
+                       //TODO: fer el grid abns que pintar els punts
+                       //horiz
+                       paintCairoGrid (Convert.ToInt32(minY), Convert.ToInt32(absoluteMaxY), 5, graphWidth, 
area.Allocation.Height, true,
+                                       leftMargin, rightMargin, topMargin, bottomMargin, axisDist, g, 
textHeight);
+                       //vertical
+                       paintCairoGrid (Convert.ToInt32(minX), Convert.ToInt32(maxX), 5, graphWidth, 
area.Allocation.Height, false,
+                                       leftMargin, rightMargin, topMargin, bottomMargin, axisDist, g, 
textHeight);
+
+                       /*
+                       //print X, Y of maxY
+                       //at axis
+                       g.Save();
+                       g.SetDash(new double[]{14, 6}, 0);
+                       g.MoveTo(xgraph, area.Allocation.Height - bottomMargin);
+                       g.LineTo(xgraph, ygraph);
+                       g.LineTo(leftMargin, ygraph);
+                       g.Stroke ();
+                       g.Restore();
+
+                       printText(xgraph, area.Allocation.Height - Convert.ToInt32(bottomMargin/2), 0, 
textHeight, Util.TrimDecimals(xAtMaxY, 2), g, true);
+                       printText(Convert.ToInt32(leftMargin/2), ygraph, 0, textHeight, Util.TrimDecimals(
+                                       absoluteMaxY, 2), g, true);
+                       */
+
+                       //at right
+                       printText(graphWidth + axisDist, Convert.ToInt32(area.Allocation.Height/2) - 
textHeight*2, 0, textHeight, "Optimal values:", g, false);
+                       printText(graphWidth + axisDist, Convert.ToInt32(area.Allocation.Height/2),      0, 
textHeight, "Fall: " + Util.TrimDecimals(xAtMaxY, 2) + " cm", g, false);
+                       printText(graphWidth + axisDist, Convert.ToInt32(area.Allocation.Height/2) + 
textHeight*2, 0, textHeight, "Jump height: " + Util.TrimDecimals(absoluteMaxY, 2) + " cm", g, false);
+
+                       g.MoveTo(xgraph+8, ygraph);
+                       g.Arc(xgraph, ygraph, 8.0, 0.0, 2.0 * Math.PI); //full circle
+                       g.Color = red;
+                       g.FillPreserve();
+                       g.SetSourceRGB(0, 0, 0);
+                       g.Stroke ();
                }
 
+
                //dispose
                g.GetTarget().Dispose ();
                g.Dispose ();
        }
 
+       private static void paintCairoGrid (int min, int max, int seps, int horizontalSize, int verticalSize, 
bool horiz,
+                       int leftMargin, int rightMargin, int topMargin, int bottomMargin, int axisDist, 
Cairo.Context g, int textHeight)
+       {
+               //show 5 steps positive, 5 negative (if possible)
+               int temp = Convert.ToInt32(Util.DivideSafe(max - min, seps));
+               int step = temp;
+
+               //to have values multiples than 10, 100 ...
+               if(step <= 10)
+                       step = temp;
+               else if(step <= 100)
+                       step = temp - (temp % 10);
+               else if(step <= 1000)
+                       step = temp - (temp % 100);
+               else if(step <= 10000)
+                       step = temp - (temp % 1000);
+               else //if(step <= 100000)
+                       step = temp - (temp % 10000);
+
+               //fix crash when no force
+               if(step == 0)
+                       step = 1;
+
+               List<int> l = new List<int>();
+               g.Save();
+               g.SetDash(new double[]{1, 2}, 0);
+               for(int i = min; i <= max ; i += step)//TODO, start at min+sep
+               {
+                       //LogB.Information("i: " + i.ToString());
+                       if(horiz)
+                       {
+                               int ytemp = calculatePaintHeight(i, verticalSize, max, min, topMargin, 
bottomMargin + axisDist);
+                               g.MoveTo(leftMargin, ytemp);
+                               g.LineTo(horizontalSize - rightMargin, ytemp);
+                               printText(Convert.ToInt32(leftMargin/2), ytemp, 0, textHeight, i.ToString(), 
g, true);
+                       } else {
+                               int xtemp = calculatePaintWidth(i, horizontalSize, max, min, rightMargin, 
leftMargin + axisDist);
+                               g.MoveTo(xtemp, verticalSize - bottomMargin);
+                               g.LineTo(xtemp, topMargin);
+                               printText(xtemp, verticalSize - Convert.ToInt32(bottomMargin/2), 0, 
textHeight, i.ToString(), g, true);
+                       }
+               }
+               g.Stroke ();
+               g.Restore();
+       }
+
+       private static int calculatePaintWidth(double currentValue, int ancho, double maxValue, double 
minValue, int rightMargin, int leftMargin)
+       {
+                return Convert.ToInt32(leftMargin + (currentValue - minValue) * (ancho - rightMargin - 
leftMargin) / (maxValue - minValue));
+        }
+
+       private static int calculatePaintHeight(double currentValue, int alto, double maxValue, double 
minValue, int topMargin, int bottomMargin)
+       {
+                return Convert.ToInt32(alto - bottomMargin - ((currentValue - minValue) * (alto - topMargin 
- bottomMargin) / (maxValue - minValue)));
+        }
+
        //TODO: inherit this
-       private static Cairo.Color colorFromRGB(int red, int green, int blue) {
+       private static Cairo.Color colorFromRGB(int red, int green, int blue)
+       {
                return new Cairo.Color(red/256.0, green/256.0, blue/256.0);
        }
 
diff --git a/src/jumpsDjOptimalFall.cs b/src/jumpsDjOptimalFall.cs
index 1455963e..cc32f40e 100644
--- a/src/jumpsDjOptimalFall.cs
+++ b/src/jumpsDjOptimalFall.cs
@@ -24,6 +24,7 @@ using System.Collections.Generic; //List
 public class JumpsDjOptimalFall
 {
        private List<Point> point_l;
+       LeastSquares ls;
 
        //constructor
        public JumpsDjOptimalFall()
@@ -45,7 +46,7 @@ public class JumpsDjOptimalFall
                                                ));
 
                //3 get LeastSquares
-               LeastSquares ls = new LeastSquares();
+               ls = new LeastSquares();
                ls.Calculate(point_l);
 
                //4 print data
@@ -53,22 +54,47 @@ public class JumpsDjOptimalFall
                        LogB.Information(string.Format("coef = {0} {1} {2}",
                                                ls.Coef[0], ls.Coef[1], ls.Coef[2]));
 
-               if(ls.CalculatedMaxY)
-                       LogB.Information(string.Format("MaxY = {0}", ls.MaxY));
+               if(ls.CalculatedXatMaxY)
+                       LogB.Information(string.Format("XatMaxY = {0}", ls.XatMaxY));
        }
 
-       public double GetMaxY()
+       public double GetMaxValue()
        {
-               double maxY = 0;
+               double maxValue = 0;
                 foreach(Point p in point_l)
-                       if(p.Y > maxY)
-                               maxY = p.Y;
+               {
+                       if(p.X > maxValue)
+                               maxValue = p.X;
+                       if(p.Y > maxValue)
+                               maxValue = p.Y;
+               }
 
-               return maxY;
+               return maxValue;
        }
 
        public List<Point> Point_l
        {
                get { return point_l; }
        }
+
+       public double[] Coefs
+       {
+               get {
+                       if(! ls.CalculatedCoef)
+                               return new double[0];
+
+                       LogB.Information(string.Format("coef0:{0}", ls.Coef[0]));
+                       return ls.Coef;
+               }
+       }
+
+       public double XatMaxY //model
+       {
+               get {
+                       if(! ls.CalculatedXatMaxY)
+                               return -1;
+
+                       return ls.XatMaxY;
+               }
+       }
 }


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