Проблема распределения сетки при масштабировании пользовательского графика с использованием C# - PullRequest
0 голосов
/ 08 января 2020

Основная проблема заключается в том, что график, с которым я работаю, не является стандартным элементом управления Visual Studio, а является пользовательским. Не все функции были разработаны и документация не была предоставлена. Прямо сейчас я вроде понимаю, как это работает, но я думаю, что я застрял здесь с математической задачей.

Описание: У нас есть график с n кривыми, где 0 . Каждая кривая имеет свой масштаб, поэтому значения осей X и Y меняются. Пример кривых, которые обычно отображаются на графике

Ввод: TotalYLength, TotalValue, DivisionValue .

Где: TotalYLength - это разница между нижней и верхней сторонами отображаемой области (я полагаю).

TotalValue - длина оси Y текущей кривой.

DivisionValue - шаг сетки (значение по умолчанию жестко задано как 200, но может быть изменено).

Существует также StartValue , которая является первой точкой Y кривой, но она не использовалась в приведенной ниже формуле.

Существующее решение:

float newDivitionPixels = (float) ((totalYLength * _divisionValue) / TotalValue);

Например: 343 * 200/1000 = 68,6

После одного уменьшения: 343 * 200/2000 = 34,3

После двух уменьшений: 343 * 200/4000 = 17,15

Масштабирование график вместе со значениями сетки: чем больше мы уменьшаем масштаб - тем больше сеток мы получаем на экране.

Выпуск: Количество масштабирования s out неограничен, и это нормально, но сетки продолжают добавляться, делая этот нечитабельный вывод и останавливая приложение, когда их слишком много.

нечитаемые значения после нескольких уменьшений

Задача: Найдите формулу, которая будет корректировать масштабирование для каждой конкретной кривой с ограниченным увеличением линий сетки слева или без изменения их числа вообще.

Я пытался присвоить число 45 переменной newDivitionPixels (я нашел это число экспериментально. Выдает ровно одиннадцать значений сетки). А также логарифмы, такие как:

        TotalYLength * Math.Log(TotalYLength);

        (TotalYLength * Math.Log(TotalYLength)) / TotalValue;

        Math.Log(45, TotalYLength);

        (totalYLength / Math.Log(TotalValue));

и так далее. Последний даже решил проблему с сетками, но вывел неверные значения масштабирования. Я считаю, что мне просто нужна точная математическая формула, которая будет отображать как правильные значения, так и ограниченное количество сеток. Но я предполагаю, что могло бы быть решение алгоритми c я не вижу. Буду благодарен за любые рабочие предложения, так как я уже потратил недели на то, чтобы найти и поэкспериментировать с этой частью. Вот код метода, который задает aws линии сетки.

public void DrawAxis(Graphics graphics, Rectangle rectangle)
    {
        PointF pt1 = new PointF(XGap, YGap1);
        PointF pt2 = new PointF(XGap, rectangle.Height - YGap1);
        graphics.DrawLine(Pen, pt1, pt2); //Draws a vertical line across the Y-axis grids
        log.Debug("Draw a line from pt1 {0} to pt2 {1}", pt1.Y.ToString(), pt2.Y);

        float totalYLength = pt2.Y - pt1.Y;
        if (totalYLength < 0)
        {
            totalYLength = totalYLength * -1;
        }

        float newDivitionPixels = (float) ((totalYLength * _divisionValue) / TotalValue);
        _divisionDst = newDivitionPixels;
        if (_selected)
        {
            PointF ptOrigin = pt2;
            float ptFirstDivY = pt2.Y - ((float)((newDivitionPixels * (StartValue - Origin)) / _divisionValue));
            PointF ptFisrtDiv = ptOrigin;
            ptFisrtDiv.Y = ptFirstDivY;

            // Draw first division
            PointF ptFisrtDiv1 = ptFisrtDiv;
            ptFisrtDiv1.X = ptFisrtDiv1.X - 6;
            graphics.DrawLine(Pen, ptFisrtDiv1, ptFisrtDiv);
            log.Debug("Draw a line from ptFisrtDiv1 {0} to ptFisrtDiv {1}", ptFisrtDiv1, ptFisrtDiv);

            // Draw grid lines
            float[] dashValues = { 3, 1 };
            Pen grayPen = new Pen(Color.Gray, 1);
            grayPen.DashPattern = dashValues;

            int tempX = (int)(ptFisrtDiv.X + _graphControl.UIControl.Width - _graphControl.XAxis.XGap1 - 20);
            PointF ptTop = new PointF(tempX, ptFisrtDiv.Y);
            graphics.DrawLine(grayPen, ptFisrtDiv, ptTop); //Draws longer lines for the enumerated grids
            log.Debug("Draw a line from ptFisrtDiv {0} to ptTop {1}", ptFisrtDiv, ptTop);
            //
            {
                // Draws divisions in -ve side
                PointF divPt1 = ptFisrtDiv1;
                PointF divPt2 = ptFisrtDiv;
                divPt1.X = divPt1.X + 4;
                for (int i = 1; i <= 4; i++) 
                {
                    divPt1.Y = divPt1.Y + newDivitionPixels / 5;
                    divPt2.Y = divPt2.Y + newDivitionPixels / 5;
                    if (divPt2.Y > ptOrigin.Y)
                    {
                        break;
                    }
                    graphics.DrawLine(Pen, divPt2, divPt1); //Draws four shorter lines for the grids between two numbers
                    log.Debug("Draw a line from divPt2 {0} to divPt1 {1}", divPt2, divPt1);
                }

                // Draws divisions in +ve side
                PointF tpPt1 = ptFisrtDiv1;
                tpPt1.X = tpPt1.X + 4;
                PointF tpPt2 = ptFisrtDiv;
                for (int i = 1; i <= 4; i++)
                {
                    tpPt1.Y = tpPt1.Y - newDivitionPixels / 5;
                    tpPt2.Y = tpPt2.Y - newDivitionPixels / 5;
                    if (tpPt1.Y < pt1.Y)
                    {
                        break;
                    }
                    graphics.DrawLine(Pen, tpPt1, tpPt2);
                    log.Debug("Draw a line from tpPt1 {0} to tpPt2 {1}", tpPt1, tpPt2);
                }

                PointF ptToDrawStr = ptFisrtDiv1;
                ptToDrawStr.X = ptToDrawStr.X - 40;
                string strToDraw = StartValue.ToString();
                strToDraw = GetTrimmedStr(strToDraw);
                graphics.DrawString(strToDraw, _graphControl.UIControl.Font, Pen.Brush, ptToDrawStr);
                log.Debug("Draw a string {0} at ptToDrawStr.Y {1}", strToDraw, ptToDrawStr);
            }
            {
                PointF divPt1 = ptFisrtDiv1;
                PointF divPt2 = ptFisrtDiv;
                double yAxisDivisionValue = StartValue;
                while (true)
                {
                    divPt2.Y = divPt2.Y - newDivitionPixels;
                    divPt1.Y = divPt1.Y - newDivitionPixels;
                    if (divPt1.Y < pt1.Y)
                    {
                        break;
                    }

                    yAxisDivisionValue = yAxisDivisionValue + _divisionValue;

                    graphics.DrawLine(Pen, divPt2, divPt1);
                    log.Debug("Draw a line from divPt2 {0} to divPt1 {1}", divPt2, divPt1);

                    // Draw grid lines
                    tempX = (int)(divPt2.X + _graphControl.UIControl.Width - _graphControl.XAxis.XGap1 - 20);
                    ptTop = new PointF(tempX, divPt2.Y);
                    graphics.DrawLine(grayPen, divPt2, ptTop);
                    log.Debug("Draw a line from divPt2 {0} to ptTop {1}", divPt2, ptTop);

                    // Draw small divisions
                    PointF tpPt1 = divPt1;
                    tpPt1.X = tpPt1.X + 4;
                    PointF tpPt2 = divPt2;

                    for (int i = 1; i <= 4; i++)
                    {
                        tpPt1.Y = tpPt1.Y - newDivitionPixels / 5;
                        tpPt2.Y = tpPt2.Y - newDivitionPixels / 5;
                        if (tpPt1.Y < pt1.Y)
                        {
                            break;
                        }
                        graphics.DrawLine(Pen, tpPt1, tpPt2);
                        log.Debug("Draw a line from tpPt1 {0} to tpPt2 {1}", tpPt1, tpPt2);
                    }

                    PointF ptToDrawStr = divPt1;
                    ptToDrawStr.X = ptToDrawStr.X - 40;
                    string strTemp = yAxisDivisionValue.ToString();
                    strTemp = GetTrimmedStr(strTemp);
                    graphics.DrawString(strTemp, _graphControl.UIControl.Font, Pen.Brush, ptToDrawStr);
                    log.Debug("Draw a string {0} at ptToDrawStr {1}", strTemp, ptToDrawStr);
                }
            }

            PointF ptDesc = new PointF();
            ptDesc.X = 20;
            ptDesc.Y = _graphControl.UIControl.Height / 3;
            System.Drawing.StringFormat drawFormat = new System.Drawing.StringFormat();
            drawFormat.FormatFlags = StringFormatFlags.DirectionVertical | StringFormatFlags.DirectionRightToLeft | StringFormatFlags.NoWrap;
            graphics.DrawString(AxisDescription, _graphControl.UIControl.Font, Pen.Brush, ptDesc, drawFormat);
        }

    }

PS На оси X этой проблемы нет, но ее формула не соответствует этому методу.

...