Raw File
GraphicsData.cs
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows;

namespace Puppy
{
    public class GraphicsData
    {
        public bool drawArrow = false;
        public bool drawTangent = false;
        public bool drawNormal = false;
        public double normalX = -1;

        private TrackForm tf;
        private Vector center;

        private double tfScale;
        private double drawScale;
        private double featureScale;
        public double pfScale = 1;
        public double pfDiagramScale = 1;
        public double hfScale = 1;
        public double hfDiagramScale = 1;

        private Bitmap hBitmap = new Bitmap("h.png");
        private Bitmap pBitmap = new Bitmap("p.png");
        private double bitmapSize;

        private Pen linePen = new Pen(Program.TRACK_COLOR);
        private Pen dashPenT = new Pen(Program.TANGENT_COLOR);
        private Pen dashPenN = new Pen(Program.NORMAL_COLOR);
        private AdjustableArrowCap arrowCap;

        private Pen diagramPen = new Pen(Program.STABLE_COLOR);
        private SolidBrush circleBrush = new SolidBrush(Program.NORMAL_CIRCLE_COLOR);

        public bool refreshingTf = false;
        public bool refreshingPf = false;
        public bool refreshingHf = false;

        /*        private Font tokenFont;
                private Brush tokenFontBrush = new SolidBrush(Color.Black);
                private StringFormat tokenFormat = new StringFormat()
                {
                    Alignment = StringAlignment.Center,
                    LineAlignment = StringAlignment.Center,
                };*/

        /*private double arrowLength;
        private double arrowWidth;
        private Brush arrowBrush = new SolidBrush(Color.Green);*/

        public GraphicsData(TrackForm tf)
        {
            this.tf = tf;
            UpdateSize();
            SetFeatureScale(Program.INITIAL_FEATURE_SCALE);
            SetScale(Program.INITIAL_TRACK_SCALE);
            linePen.LineJoin = LineJoin.Round;
            dashPenT.SetLineCap(LineCap.Flat, LineCap.Flat, DashCap.Flat);
            dashPenT.DashPattern = new float[] { 2, 2 };
            dashPenN.SetLineCap(LineCap.Flat, LineCap.Flat, DashCap.Flat);
            dashPenN.DashPattern = new float[] { 2, 2 };
            diagramPen.SetLineCap(LineCap.Round, LineCap.Round, DashCap.Flat);
            arrowCap = new AdjustableArrowCap((float)(Program.ARROW_W_SIZE / Program.ARROW_LINE_THICKNESS), (float)(Program.ARROW_H_SIZE / Program.ARROW_LINE_THICKNESS));
        }

        public void UpdateSize()
        {
            int w = tf.ClientSize.Width;
            int h = tf.ClientSize.Height;
            center = new Vector(w * 0.5, h * 0.5); // consider margins
            Vector avail = new Vector(w, h); // subtract margins
            if (avail.X <= 0) avail.X = 0;
            if (avail.Y <= 0) avail.Y = 0;
            Vector draw = tf.t.size; // size of drawing in drawing space
            drawScale = draw.X * avail.Y > avail.X * draw.Y ? avail.X / draw.X : avail.Y / draw.Y;
            drawScale *= tfScale;
            UpdateFeatureScale();
        }

        public void SetScale(double s)
        {
            tfScale = s;
            //tokenFont = new Font("Verdana", (float)(50 * s), FontStyle.Regular, GraphicsUnit.Pixel);
            UpdateLayout();
        }

        public void UpdateFeatureScale()
        {
            double s = featureScale * drawScale;
            linePen.Width = (float)(Program.TRACK_LINE_THICKNESS * s);
            dashPenT.Width = (float)(Program.ARROW_LINE_THICKNESS * s);
            dashPenN.Width = (float)(Program.NORMAL_LINE_THICKNESS * s);
            bitmapSize = Program.TRACK_PORTRAIT_SIZE * s;
        }

        public void SetFeatureScale(double s)
        {
            featureScale = s;
            UpdateFeatureScale();
            Refresh(true, false, false);
        }

        public void SetPScale(double s)
        {
            pfScale = s;
            UpdatePDiagramScale();
        }

        public void UpdatePDiagramScale()
        {
            //double s = pfDiagramScale * pfScale;
            Refresh(false, true, false);
        }

        public void SetPDiagramScale(double s)
        {
            pfDiagramScale = s;
            UpdatePDiagramScale();
        }

        public void SetHScale(double s)
        {
            hfScale = s;
            UpdateHDiagramScale();
        }

        public void UpdateHDiagramScale()
        {
            //double s = hfDiagramScale * hfScale;
            Refresh(false, false, true);
        }

        public void SetHDiagramScale(double s)
        {
            hfDiagramScale = s;
            UpdateHDiagramScale();
        }

        public void ScaleUp() => SetScale(tfScale * Program.TRACK_RESIZE_FACTOR);

        public void ScaleDown() => SetScale(tfScale / Program.TRACK_RESIZE_FACTOR);

        public void FeatureScaleUp() => SetFeatureScale(featureScale * Program.FEATURE_RESIZE_FACTOR);

        public void FeatureScaleDown() => SetFeatureScale(featureScale / Program.FEATURE_RESIZE_FACTOR);

        public void PDiagramScaleUp() => SetPDiagramScale(pfDiagramScale * Program.FEATURE_RESIZE_FACTOR);

        public void PDiagramScaleDown() => SetPDiagramScale(pfDiagramScale / Program.FEATURE_RESIZE_FACTOR);

        public void HDiagramScaleUp() => SetHDiagramScale(hfDiagramScale * Program.FEATURE_RESIZE_FACTOR);

        public void HDiagramScaleDown() => SetHDiagramScale(hfDiagramScale / Program.FEATURE_RESIZE_FACTOR);

        public void UpdateLayout()
        {
            UpdateSize();

            /*            button1.Size = new Size(buttonWidth, buttonHeight);

                        button1.Location = new Point(buttonMargin, h - button1.Size.Height - buttonMargin);*/

            Refresh(true, false, false);
        }

        private Vector Trans(Vector v)
        {
            return Vector.Add(Vector.Multiply(v, drawScale), center);
        }

        public Vector InvTrans(Vector v)
        {
            return Vector.Divide(Vector.Subtract(v, center), drawScale);
        }

        public void DrawLine(Graphics g, Vector p1, Vector p2) => g.DrawLine(linePen, Trans(p1).ToPointF(), Trans(p2).ToPointF());

        public void DrawPolygon(Graphics g, List<Vector> p)
        {
            PointF[] q = new PointF[p.Count];
            for (int i = 0; i < p.Count; i++) q[i] = Trans(p[i]).ToPointF();
            g.DrawPolygon(linePen, q);
        }

        public void DiagramCircle(Graphics g, Vector p)
        {
            float r = (float)(Program.DIAGRAM_CIRCLE_SIZE * pfDiagramScale * pfScale);
            float d = r * 2;
            RectangleF a = new RectangleF(Vector.Subtract(p, new Vector(r, r)).ToPointF(), new SizeF(d, d));
            circleBrush.Color = Program.PUPPY_CIRCLE_COLOR;
            g.FillEllipse(circleBrush, a);
        }

        /*        public void DrawToken(double x, double y, int num)
                {
                    Rectangle r = new Rectangle((int)(x - tokenSize), (int)(y - tokenSize), (int)(tokenSize * 2), (int)(tokenSize * 2));
                    g.FillEllipse(tokenBrush, r);
                    g.DrawEllipse(tokenPen, r);
                    g.DrawString(num.ToString(), tokenFont, tokenFontBrush, x, y, tokenFormat);
                }*/

        public void DrawPuppy(Graphics g, Vector p)
        {
            p = Trans(p);
            double sizey = bitmapSize;
            double sizex = sizey * pBitmap.Width / pBitmap.Height;
            RectangleF dest = new RectangleF((float)(p.X - sizex / 2 + sizex * Program.PUPPY_PORTRAIT_OFFSET), (float)(p.Y - sizex / 2), (float)(sizex), (float)(sizey));
            g.DrawImage(pBitmap, dest);
        }

        public void DrawHuman(Graphics g, Vector p)
        {
            p = Trans(p);
            double sizey = bitmapSize;
            double sizex = sizey * hBitmap.Width / hBitmap.Height;
            RectangleF dest = new RectangleF((float)(p.X - sizex / 2), (float)(p.Y - sizex / 2), (float)(sizex), (float)(sizey));
            g.DrawImage(hBitmap, dest);
        }

        public void DrawArrowFrame(Graphics g, Vector p1, Vector p2, Color col)
        {
            double f = bitmapSize / (2 * drawScale);
            double d = p1.Distance(p2);
            if (d < f * 2) return;
            if (drawArrow)
            {
                dashPenT.Color = col;
                Vector p3 = Vector.Add(p1, Vector.Multiply(Vector.Subtract(p2, p1), (d - f) / d));
                dashPenT.CustomStartCap = arrowCap;
                g.DrawLine(dashPenT, Trans(p3).ToPointF(), Trans(p1).ToPointF());
                dashPenT.StartCap = LineCap.Flat;
            }
            if (drawTangent)
            {
                dashPenT.Color = col;
                Vector p3 = Vector.Multiply(new Vector(p1.Y - p2.Y, p2.X - p1.X), Program.TANGENT_LENGTH / d);
                g.DrawLine(dashPenT, Trans(Vector.Add(p1, p3)).ToPointF(), Trans(p1).ToPointF());
                g.DrawLine(dashPenT, Trans(Vector.Subtract(p1, p3)).ToPointF(), Trans(p1).ToPointF());
            }
        }

        public void DrawPSegmentList(Graphics g, List<Vector> p, double sw, double sh, Color col)
        {
            diagramPen.Color = col;
            diagramPen.Width = (float)(Program.DIAGRAM_LINE_THICKNESS * pfDiagramScale * pfScale);
            int i = 0;
            while (i < p.Count)
            {
                Vector p1 = new Vector(p[i].X * sw, (1 - p[i].Y) * sh);
                i++;
                Vector p2 = new Vector(p[i].X * sw, (1 - p[i].Y) * sh);
                i++;
                g.DrawLine(diagramPen, p1.ToPointF(), p2.ToPointF());
            }
        }

        public void DrawHSegmentList(Graphics g, List<Vector> p, double sw, double sh, Color col)
        {
            diagramPen.Color = col;
            diagramPen.Width = (float)(Program.DIAGRAM_LINE_THICKNESS * hfDiagramScale * hfScale);
            int i = 0;
            while (i < p.Count)
            {
                Vector p1 = new Vector(p[i].X * sw, (0.5 - p[i].Y * Program.HUMAN_DIAGRAM_H_SCALE) * sh);
                i++;
                Vector p2 = new Vector(p[i].X * sw, (0.5 - p[i].Y * Program.HUMAN_DIAGRAM_H_SCALE) * sh);
                i++;
                g.DrawLine(diagramPen, p1.ToPointF(), p2.ToPointF());
            }
        }

        public void DrawDiagramDiag(Graphics g, List<Vector> p, double sw, double sh, Color col, bool squareLayout, bool extendedDiagram)
        {
            diagramPen.Color = col;
            float pw = (float)(Program.DIAGRAM_LINE_THICKNESS * pfDiagramScale * pfScale * (squareLayout ? 1 : 2));
            diagramPen.Width = pw;
            pw *= 2;
            if (extendedDiagram) {
                int i = 0;
                while (i < p.Count)
                {
                    float x1 = (float)(p[i].X * sw);
                    float y1 = (float)((1 - p[i++].Y) * sh);
                    float x2 = (float)(p[i].X * sw);
                    float y2 = (float)((1 - p[i++].Y) * sh);
                    g.DrawLine(diagramPen, new PointF(x1, y1), new PointF(x2, y2));
                    if (!squareLayout)
                    {
                        if (x1 < pw) g.DrawLine(diagramPen, new PointF((float)(x1 + sw), y1), new PointF((float)(x2 + sw), y2));
                        if (x2 > 1 - pw) g.DrawLine(diagramPen, new PointF((float)(x1 - sw), y1), new PointF((float)(x2 - sw), y2));
                    }
                }
            }
            else
            {
                float ofs = squareLayout ? 0 : 0;
                g.DrawLine(diagramPen, new PointF(0, ofs + (float)sh), new PointF(ofs + (float)sw, 0));
                if (!squareLayout)
                {
                    g.DrawLine(diagramPen, new PointF(ofs - (float)sw, ofs + (float)sh), new PointF(ofs + (float)sw, ofs - (float)sh));
                    g.DrawLine(diagramPen, new PointF(0, ofs + (float)(sh * 2)), new PointF(ofs + (float)(sw * 2), 0));
                }
            }
        }

        public void DrawHNormal(Graphics g, int w, int h, Color col)
        {
            if (!drawNormal) return;
            diagramPen.Color = col;
            diagramPen.Width = (float)(Program.DIAGRAM_NORMAL_THICKNESS * hfDiagramScale * hfScale);
            float x = (float)(normalX * w);
            g.DrawLine(diagramPen, new PointF(x, 0), new PointF(x, h - 1));
        }

        public void DrawTNormal(Graphics g, Vector p, Vector nor, Color col)
        {
            if (!drawNormal) return;
            dashPenN.Color = col;
            nor = Vector.Multiply(nor, Program.NORMAL_LENGTH);
            g.DrawLine(dashPenN, Trans(Vector.Add(p, nor)).ToPointF(), Trans(p).ToPointF());
            g.DrawLine(dashPenN, Trans(Vector.Subtract(p, nor)).ToPointF(), Trans(p).ToPointF());
            float r = (float)(Program.TRACK_CIRCLE_SIZE * featureScale * drawScale);
            float d = (float)(r * 2);
            RectangleF a = new RectangleF(Vector.Subtract(Trans(p), new Vector(r, r)).ToPointF(), new SizeF(d, d));
            circleBrush.Color = Program.NORMAL_CIRCLE_COLOR;
            g.FillEllipse(circleBrush, a);
        }

        public void DrawHBitmaps(Graphics g, Vector pv, Vector hv, double ofs, double sw, double sh)
        {
            double px = (pv.X + ofs).Frac() * sw;
            double py = (0.5 - pv.Y * Program.HUMAN_DIAGRAM_H_SCALE) * sh;
            double sizey = Program.DIAGRAM_PORTRAIT_SIZE * hfDiagramScale * hfScale;
            double sizex = sizey * pBitmap.Width / pBitmap.Height;
            g.DrawImage(pBitmap, new RectangleF((float)(px - sizex / 2 + sizex * Program.PUPPY_PORTRAIT_OFFSET), (float)(py - sizex / 2), (float)(sizex), (float)(sizey)));
            if (tf.t.attract)
            {
                double hx = (hv.X + ofs).Frac() * sw;
                double hy = (0.5 - hv.Y * Program.HUMAN_DIAGRAM_H_SCALE) * sh;
                sizex = sizey * hBitmap.Width / hBitmap.Height;
                g.DrawImage(hBitmap, new RectangleF((float)(hx - sizex / 2), (float)(hy - sizex / 2), (float)(sizex), (float)(sizey)));
            }
        }

        public void Refresh(bool r1, bool r2, bool r3)
        {
            if (tf == null) return;
            if (r1 && !refreshingTf)
            {
                refreshingTf = true;
                tf.Invalidate(false);
            }
            if (r2 && !refreshingPf && tf.pf != null)
            {
                refreshingPf = true;
                tf.pf.Invalidate(false);
            }
            if (r3 && !refreshingHf && tf.hf != null)
            {
                refreshingHf = true;
                tf.hf.Invalidate(false);
            }
        }
    }
}
back to top