C++ Builder: построение графиков. Часть 1. Косинусы (cos)

Начинаю серию заметок о построении графиков средствами C++ Builder. Сначала, пожалуй, напишу о «прорисовке» графика на компоненте Image. А потом, если кому-то будет интересно, поговорим о компоненте Chart (жутко полезная штука, я вам скажу).

В серию о построении графиков в C++ Builder уже вошли такие посты:

  1. Построение косинусов (cos);
  2. Построение синусов (sin);
  3. Построение тангенсов (tg);
  4. Построение котангенсов (ctg).

В общем, этот пост посвящен построению графика косинуса (cos). Функция при этом имеет вид cos(X) или cos(X)+k, или даже такой a*cos(X)+k.

Первым делом нам понадобится установить компонент Image на форму. Далее можно переходить непосредственно к «прорисовке». Для начала нам понадобится нарисовать градацию. Это можно сделать так:

// выделяем область, на которой будем рисовать 
// (при этом оставив небольшие поля по краям)
LX=Image1->Width-50;
LY=Image1->Height-30;
 
//примем ориентировочные значения максимума и минимума 
// (понадобятся для выделения максимума и минимума функции)
  Ymax=-100;
  Ymin=100;
 
//устанавливаем голубой цвет кисти и рисуем прямоугольник
Image1->Canvas->Pen->Color=clBlue;
Image1->Canvas->Rectangle(50,40,LX,LY);
 
//устанавливаем серый цвет кисти (прерывистая линия)
Image1->Canvas->Pen->Color=clGray;
Image1->Canvas->Pen->Style=psDash;
 
//циклически прорисовываем девять линий градации
for (i=1;i<=9;i++) { A[i]=50+LX/11*i; Image1->Canvas->MoveTo(A[i],40);
 Image1->Canvas->LineTo(A[i],LY);
}
 
//циклически выводим значения возле прорисованной линии
 float C[11];
 for (i=0;i<=10;i++) { C[i]=50+LX/11*i; AnsiString S1 = FloatToStrF(Xmin+((Xmax-Xmin)/10)*i,ffFixed,5,2); Image1->Canvas->TextOutA(C[i]-10,LY+5,S1);
}
 
//циклически прорисовываем девять линий градации
for (i=1;i<=9;i++) { A[i]=50+LY/11*i; Image1->Canvas->MoveTo(50,A[i]-10);
 Image1->Canvas->LineTo(LX,A[i]-10);
}
 
//устанавливаем красный цвет кисти (сплошная линия)
Image1->Canvas->Pen->Style=psSolid;
Image1->Canvas->Pen->Color=clRed;
 
//определяем масштаб по оси X 
if ((Xmax-Xmin)==0) MasX=LX-50;
else MasX=(LX-50)/(Xmax-Xmin);
 
//делаем рисунок видимым
Image1->Visible=true;

Учтите, что Xmax (максимальное значение по X) и Xmin (минимальное значение по X) необходимо задать заранее. Также следует задать величину шага – dX. Кроме того, можно задать константу k (в случае, если функция имеет вид cos(X)+k) и a (в случае, если функция имеет вид a*cos(X)+k).

После этого можно перейти непосредственно к построению графика функции. Я делала это так:

//циклически рассчитываем значения функции и определяем 
// ее максимум и минимум)
for (X=Xmin;X<=Xmax;X+=dX)
  {
   Y=a*cos(X)+k;
   if(Ymax<Y) Ymax=Y; if(Ymin>Y) Ymin=Y;
  }
 
//определяем масштаб по оси Y
 MasY=(LY-40)/(Ymax-Ymin);
 
//циклически выводим числовые значения возле прорисованных 
// градационных линий
 float B[11];
 for (i=0;i<=10;i++) { B[i]=35+LY/11*i; AnsiString S = FloatToStrF(Ymax-((Ymax-Ymin)/10)*i,ffFixed,5,2); Image1->Canvas->TextOutA(20,B[i],S);
}
 
// и вот теперь переходим непосредственно к рисованию
Image1->Canvas->MoveTo(50,LY-(Ymin*(-1)+a*cos(Xmin))*MasY);
 
 for (X=Xmin;X<=Xmax;X+=dX) { Y=a*cos(X); PY=LY-(Ymin*(-1)+Y)*MasY; PX=X*MasX+50; Image1->Canvas->LineTo(PX-Xmin*MasX,PY);
  }

Результат работы программы представлен ниже (установленные параметры: Xmax=10, Xmin=0, dX=0.2, a=1, k=0).

Построенный график функции a*cos(X)+k

Вроде ничего не забыла. Будут вопросы – прошу в комментарии.

0

Комментариев: 43 на “C++ Builder: построение графиков. Часть 1. Косинусы (cos)

  1. Хотелось бы узнать возможно ли построение графика функции при помощи компонента Chart так что бы промежуток «х» и шаг «х» (дельта) указывал сам пользователь программы (к примеру при помощи Edit).

    1. Естественно, можно. Так даже проще получится (не придется считать масштаб +
      часть настроек можно произвести в компоненте «руками» заранее).
      Само рисование делается так:

      1
      
      Series1->AddXY(X,Y,"",clRed);

      где Series1 — созданная в Chat’е «серия» (задан вариант графика)
      Х и Y — берем циклически (с учетом заданного шага).
      clRed — цвет линии.
      между «» можно вставить название функции.
      Вот и вся премудрость.
      Кстати, спасибо за идею — в ближайшем будущем напишу об этом постик =)

      1. Спасибо за ответ=)
        уже сделал с Chart’ом намного проще получается
        вот еще вопрос:
        возможно ли задать функцию переменной?
        я пытался сделать через преобразование StrToFloat, но у меня выводит ошибку.

        1
        2
        3
        4
        
        float q;
        q=StrToFloat(Edit1->Text);
        for(float x = k; x<j; x+=l)//k<xAddXY(x,y);
        }

        в Edit1 вводим функцию.

        Подскажите если есть какие то мысли по данному поводу =)
        Буду благодарен

        1. Нет, так не выйдет.
          если q — функция, то преобразовать ее из строки в вещественный тип данных не представляется возможным. Это раз. Два — подключать вообще не известную функцию «по горячему» тоже не получится. Тут варианта два: либо разбиение строки и сравнение ее с заранее заданной маской (разбивать можно с помощью функции SubString). После можно частично преобразовать полученный результат.
          Либо замена Эдита (компонента, в смысле) на Комбобокс с набором заранее введенных функций.
          Как-то так.

  2. Плохое описание, если в коде пытаешься что то изменить, то появляются сплошные ошибки. Не расписано, что и как нужно поменять, чтобы стало так то, так то. Приходится самому всё додумывать. зачем то представлен готовый код(не как обычно выкладывают на сайтах) ,но элементарно нет ввода переменных, т е нельзя просто взять копирнуть код и посмотреть что там такое. Нельзя побаловаться в таком коде. Ничего не упоминается о подключенных библиотеках — настоящие чайники не разберутся.

    Например : //циклически прорисовываем девять линий градации
    for (i=1;iCanvas->MoveTo(50,A[i]-10);
    Image1->Canvas->LineTo(LX,A[i]-10);
    }

    непонятно почему именно 9 линий, непонятно почему компилятор ругается на «A[i]» , так же не ясно почему я не могу изменить колличество этих линий и т д.

    ВСЁ нужно подкреплять хоть какими то словами ,а не Я РИСУЮ 9 линий…
    должна быть оговорка вы можете изменить 9 на 109 ,НО при этом нужно поменять там то ,там то, так как оно связано и т п. Понимаете?

    1. Понимаю. Но переписывать не буду. Если у вас есть какие-то конкретные вопросы по коду — я постараюсь ответить. Если получена какая-то ошибка, то лучше сразу приводите и ее текст, и код. Как-то так )

      1. Быстро отвечаете)
        Девушка, а нельзя вас немного о другом спросить?но тоже о построении графика в билдере не имеичке)
        нужна помощь )

        1. Сравнительно. Спрашивайте.
          Кстати, если речь о построение при помощи компонента чарт, то есть соответствующий постик…

          1. Хотелось бы поподробней о том, как связать свой график именно с размером имейджа.
            Не получается, у меня например параболическая функция и естественно она при определённых значениях выходит далеко за пределы.
            не могу понять и связать ваше построение со своим.
            И можно ли чтобы числа которые высчитываются для градаций, каждый раз менялись.
            Т е как бы подстраивались под мой график.
            Я вам вчера писал в «Написать мне» там подробнее описана моя проблема)

            1. Надеюсь, вы скопировали, то, что писали через обратную связь, т.к. я ничего не получила (скорее всего хостинг ступил и не отправил).

              По поводу ресайза: масштабировать рисунок надо, а не сам имейдж.
              В первом куске кода мы определяем масштаб по Х (строки 49-50), во втором (до 11 строки) определяем масштаб по игреку. Уже после этот масштаб используется для вмещения рисунка в отведенное поле.

              И можно ли чтобы числа которые высчитываются для градаций, каждый раз менялись.
              Т е как бы подстраивались под мой график.

              Приведенный код полностью этим требованиям соответствует. Почему вы не можете просто скопировать?

              1. Потому что просто скопировать не удаётся, компилятор ругаться начинает)
                И проблема в том что я не понимаю ваш код и по этой причине не могу подстроить его под себя. У меня например
                y=-((x*x*mp)/(e*134*2)); такая всё кроме иксов является константами которые берутся либо из эдитов,либо из трек бара.
                что мне за Хмин Хмакс обозначать я не понимаю.

                вот кнопка которая должна строить параболическую зависимость.
                мало того что она почему то рисует не линию, а как бы целую область закрашивает так и вылезает за область)

                если на моём примере сможете показать , то я пойму, т к ваш не понятен вообще(
                _____________________________
                int a=Image1->Width;
                int b=Image1->Height;
                int O=TrackBar1->Position;
                int y,x;
                int mp=TrackBar2->Position;
                int e=StrToInt ((Edit1->Text));

                for (x=0;xCanvas->Pen->Color = clRed;
                Image1->Canvas->Pen->Width=1;

                Image1->Canvas->MoveTo((a-a*0.9), (0.9*b));
                x++;

                y=-((x*x*mp)/(e*134*2));

                Image1->Canvas->LineTo((a-a*0.9+x),(0.9*b+y));

                }

                1. Вот этот кусок кода, это что:

                  1
                  
                  for (x=0;xCanvas->Pen->Color = clRed;

                  ?
                  Если у вас идет построение от 0 до какого-то конкретного числа, то это и есть ваши мин. и макс. по х.

                  В вашем примере нет масштабирования — нужно найти максимум и минимум функции, посчитать масштаб, а потом ее строить.

                  1. Смотрите, это код именно для прорисовки градаций.
                    который я пытался под свой максимум приспособить и миллион ошибок выдаёт этот код, хотя я лишь поставил чтобы Хмакс вводимый был и игрик макс
                    ____

                    {
                    int LX, LY, i, MasY, MasX;
                    int Ymin=0;

                    LX=Image1->Width*0.9;
                    LY=Image1->Height*0.9;

                    int mp=TrackBar2->Position;
                    int e=StrToInt ((Edit1->Text));

                    int O=TrackBar1->Position;
                    int KK=((O*O*mp)/(e*134*2));

                    Image1->Canvas->Pen->Color=clGray;
                    Image1->Canvas->Pen->Style=psDash;

                    int A[10];

                    for (i=1;iCanvas->MoveTo(A[i],40);
                    Image1->Canvas->LineTo(A[i],LY);
                    }

                    float C[11];
                    for (i=0;iCanvas->TextOutA(C[i]-4,LY+10,S1);
                    }

                    for (i=1;iCanvas->MoveTo(50,A[i]-10);
                    Image1->Canvas->LineTo(LX-20,A[i]-10);
                    }

                    Image1->Canvas->Pen->Style=psSolid;

                    //îïðåäåëÿåì ìàñøòàá ïî îñè X
                    if ((O)==0) MasX=LX-50;
                    else MasX=(LX-50)/(O);

                    float B[11];
                    for (i=0;iCanvas->TextOutA(20,B[i],S);
                    }

                    Image1->Visible=true;
                    }

                    1. Тааак)с градацией исправил , получилось.
                      сейчас если график не добью, то обращусь)
                      я вам уже надоел наверно?

  3. Можно с вами на 10 минут онлайн пообщаться как нибудь?если можно то на этих выходных бы, у меня московское время)

  4. вот эта штука должна переделана с вашей вроде всё верно, но график какой-то странный, не такой вообщем)и зачем вообще в этом коде переделываются значения по оси ординат?
    они становятся не верные и график все -равно не под размер(((
    ___

    void __fastcall TForm1::Button8Click(TObject *Sender)
    {
    int LX, LY, i, MasY, MasX;
    int Ymin=0;
    int Xmin=0;

    LX=Image1->Width*0.9;
    LY=Image1->Height*0.9;
    int mp=TrackBar2->Position;
    int e=StrToInt ((Edit1->Text));

    int O=TrackBar1->Position;
    int Xmax=TrackBar1->Position;
    int Ymax=((O*O*mp)/(e*134*2));

    int X, PX,PY;
    int Y;

    for (X=Xmin;X<=Xmax;X++)
    {
    Y=X*X*mp/e/134/2;
    if(YmaxY) Ymin=Y;
    }

    MasY=(LY-40)/(Ymax-Ymin);

    float B[11];
    for (i=0;iCanvas->TextOutA(20,B[i],S);
    }

    Image1->Canvas->MoveTo(LX-0.9*LX,LY*0.9);

    for (X=Xmin;XCanvas->LineTo(PX-Xmin*MasX,PY);

    } }

    1. Добрый вечер. Смотрю только последний код (это, я так понимаю, последний вариант).
      Первый вопрос: что это за способ определения Ymax — нужно перебрать все значения Y, а не забить первое попавшееся в максимум. Это раз. Два, что это за строка:

      if(YmaxY) Ymin=Y;

      Вы на пхп, чтоль пишете? — Билдеру такое не глотнуть (в том понимании, в котором его глотает пхп.

      1
      2
      3
      
      float B[11];
      for (i=0;iCanvas->TextOutA(20,B[i],S);
      }

      Это тоже какие-то непонятнки.
      И вот тут

      1
      2
      3
      
       for (X=Xmin;XCanvas->LineTo(PX-Xmin*MasX,PY);
       
      } }

      P.S.: «В форме комментирования есть тег «Код» — пользуйте, тогда проблем будет в разы меньше»

      По поводу поговорить онлайн — только поздней ночью (как сейчас) — раньше я постоянно занята. Если я онлайн — я обязательно читаю почту и отвечаю на комментарии )))

    2. Опять же: масштабирование! Ни по оси х, ни по оси у я его не вижу.
      Либо не весь код, либо вы просто умножаете на 0.

      Комментарии вам приходят (если вы на них подписаны) с моей почты: пришлите туда программу — так будет быстрее и эффективнее.

      1. Доброе утро)
        Нет , пишу то на с++) у меня в разных кнопочках пока маштабирование и график, чтобы по очереди всё наладить.

        «if(YmaxY) Ymin=Y;» это из вашего кода, при копировании знак > либи < какой там был пропал)

        Маштабирование получилось, поэтому его не кидаю. Кину вам весь весь код сейчас,- глянете)

          1. Код я посмотрела. Логических ошибок в нем не вижу. Результата тоже не вижу, т.к. у меня нет времени собирать конструктор (ведь просто скопировать это нельзя) — событие для каждого компонента должно быть создано средствами билдера, а не простым копированием.

            У вас вот здесь, кстати, правильный результат расчета

            1
            
            Y=X*X*mp/e/134/2;

            ?

            ЗЫ: чтоб ВП не удалял куски кода — следует использовать тег «Код» (кнопка над формой для комментариев).

  5. Подскажи пожалуйста как сделать что график можно было сделать
    объекте Chart ( можешь под Chart на писать код программы )??
    Заранее Спасибо!!

  6. Составил проект в виде текстового редактора. Все стандартные процедуры для текстового редактора сделал т.е. кнопки главного меню:Открыть, сохранить и т.д. Создал свою кнопку «ВЫЧИСЛИТЬ» в главном меню текстового редактора. Ввел Форму2.Проблема в том, что хочу с помощью нажатия кнопки «ВЫЧИСЛИТЬ» вызвать Форму2. Процедуру вызова одной формы из другой, с помощью Form2ShowModal(); мне понятна. Пробовал пойти по данному пути выдает ошибку. Если не трудно подскажите WAY. Заранее благодарю.

    1. В шапку проекта нужно добавить заглавный файл второй формы, например так:

      1
      
      #include "Unit2.h"

      А непосредственно вызов можно также сделать таковым:

      1
      
       Form2->Visible=true;
  7. Сделал. Не получается. Почему-то Unit2.h выделяет красным цветом:class TForm1 : public TForm. Если не трудно подскажите. Please PEAPLE.
    Вот мой код.
    #include
    #pragma hdrstop

    #include «Unit123.h»
    #include «Unit2.h»
    //—————————————————————————
    #pragma package(smart_init)
    #pragma resource «*.dfm»
    TForm1 *Form1;

    void __fastcall TForm1::N2Click(TObject *Sender) (это кнопка из главного меню текстового редактора)
    {
    Form2->Visible=true;
    }

  8. А как просто по набору точек построить график? можете примерно набросать?

    1. Набор точек у вас в массиве? Если да — просто циклически перебирайте элементы. Если нет — сначала нужно засунуть в массив, а потом перебирать. Не пойму, в чем конкретно возникает проблема?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *