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

Продолжаю начатую серию заметок о построении графиков в C++ Builder. В этой серии уже имеются такие записи:

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

На сей раз (если вы еще не догадались) речь пойдет о котангенсах (ctg). Строить будем график вида: y = a * ctg(x) + k.

Построение линий сетки я рассматривала в первом посте серии (в построении косинусов), там же поясняла большинство обозначений (если не разберетесь – всегда можно спросить в комментариях).

Отмечу, что константы a и k должны быть заданы. Также важным моментом является таковой: в C++ Builder отсутствует функция получения котангенса (ctg). Для этих целей можно воспользоваться тригонометрическим выражением ctg(x)= cos(x)/sin(x).

Кроме того, следует учитывать и тот факт, что в некоторых точках котангенса функции просто не существует (в точках, где sin(x) = 0).

В общем, перейдем непосредственно к построению графика.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// делаем объект Image1 видимым
  Image1->Visible=true;
 
// циклически определяем максимальное и 
// минимальное значения Y
 for (X=Xmin;X<=Xmax;X+=dX)
  {
     if (sin(X)==0) X+=dX;
  Y=a*cos(X)/sin(X)+k;
   if(Ymax<Y) Ymax=Y;
   if(Ymin>Y) Ymin=Y;
  }
 
// задаем масштаб по оси Y
  if((Ymax-Ymin)==0) MasY=LY-40;
  else MasY=(LY-40)/(Ymax-Ymin);
 
// циклически проставляем значения по шкале Y
 float B[11];
 for (i=0;i<=10;i++)
{
 B[i]=50+LY/11*i;
 AnsiString S = FloatToStrF(Ymax-((Ymax-Ymin)/10)*i,ffFixed,5,2);
 Image1->Canvas->TextOutA(20,B[i]-15,S);
}
 
// на 0 делить нельзя
if (sin(Xmin)==0) Image1->Canvas->MoveTo(50,LY-(Ymin*(-1)+a*sin(Xmin+dX)/cos(Xmin+dX))*MasY);
else Image1->Canvas->MoveTo(50,LY-(Ymin*(-1)+a*cos(Xmin)/sin(Xmin))*MasY);
 
// непосредственно построение графика функции
 for (X=Xmin;X<=Xmax;X+=dX)
  {
    if (sin(X)==0) X+=dX;
   Y=a*cos(X)/sin(X)+k;
   PY=LY-(Ymin*(-1)+Y)*MasY;
       PX=X*MasX+50;
   Image1->Canvas->LineTo(PX-Xmin*MasX,PY);
  }

При заданных значениях Xmin=0, Xmax=10, dX=0.02, a=1, k=0 получился вот такой график.

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

  1. построила график с помощью Chart, а по одной оси значения ставят не по возрастанию, а наоборот, как это изменить?

    1. Снять галочку Inverted на вкладке Axis. Если все равное не получится — пишите в комментах к статье о чарте. Вот тут, вдруг кому-то еще понадобиться.

  2. Как хорошо написано, кратенько, без занудства. Прям хочется читать…
    Но я не просто так, у меня вопрос)).
    Можно ли как-нибудь сделать возможность выбора переменной, для которой будет создаваться массив значений (для функции нескольких переменных)?
    Что-то вроде:
    if (v==b)
    for (x=Xmin; x<Xmax; x+=dX)
    y = a * ctg(x) + k.

    if (v==c)
    for (a=Amin; a<Amax; a+=dA)
    y = a * ctg(x) + k.

    1. Конечно же да.
      Тот код, который привели вы, будет работать (если ; в конце y = a * ctg(x) + k поставить =)
      Но я бы пользовала else (если есть риск того, что b будет равно c).
      Ну и {} обязательно
      т.е.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      
      if (v==b)
      {
      for (x=Xmin; x<Xmax; x+=dX)
      y = a * ctg(x) + k;
      }
      else if (v==c)
      {
      for (a=Amin; a<Amax; a+=dA)
      y = a * ctg(x) + k;
      }
      1. Я немного неправильно написал код. Я имел ввиду можно ли так сделать для одного и того же «куска» кода.

        1
        2
        3
        4
        5
        6
        7
        8
        9
        
        if (v==b)
        for (x=Xmin; x&lt;Xmax; x+=dX)
         
        else 
         
        for (a=Amin; a&lt;Amax; a+=dA)
        {
        y = a * ctg(x) + k;
        }

        Но такой номер, естественно, не проходит.
        У меня есть большущий расчет и в конце нужны графики зависимости результата от разных переменных. Можно, конечно, сразу посчитать массивы от всех переменных, но это будет долго (от одной только переменной считается 2-3 сек.) и может быть не нужно одновременно. Уф.

        1. В приведенном вами коде ничего не поняла %|
          Вам нужно циклически менять х или а? Или и то, и другое, но в разных ситуациях?
          Конечно, так, как вы привели работать не будет.
          ЗЫ: Считать, конечно же, нужно только то, что интересно глядеть конечному пользователю…

          1. И х и а, но по желанию пользователя. Например, он в RadioGroup’е выбирает «х», нажимает кнопку «Построить» и строится график y = f(х), а выбирает «а» — строится y = f(а).
            Не могу сделать этот выбор. Много чего перепробовал уже(.
            Можно, конечно, как в первом случае — скопировать сам расчет под каждый счетчик (с современными мегагерцами гигабайтами это не проблема), но хочется как-то пофункциональнее ;).

            1. Я не очень понимаю в чем именно сложность. Введите переменную, к примеру, ах и копируйте в нее значения а или х, в зависимости от того, что там выбрал пользователь. После стройте график у = f(ax) и все дела… ммм?

              1. Теперь уже я не понимаю).
                Если взять нашу любимую функцию y = a * ctg(x) + k,
                то график от а будет прямой линией, а от х — соответствующей кривой. Это же разные переменные. Как их можно объединить в одну?
                Или я туплю?

                1. В приведенном вами примере можно и не объединять )))
                  Если пользователь выбрал график от х, то а = 1, если наоборот, то х = 45 градусам.
                  Просто сделать заюзать if {} else {} при определении значений переменных, а непосредственно расчет сделать общим для всех вариантов.

                  1. Сделал! Таанцуююю! Спасибо за помощь!!
                    Код, если интересно:

                    1
                    2
                    3
                    4
                    
                    float Fsum(float a, float x, float k)
                    {
                     return a * tan(x) + k;
                    }

                    Это в самом начале после includ’ов. Ну а дальше «на кнопке» уже просто:

                    1
                    2
                    3
                    4
                    5
                    6
                    7
                    8
                    9
                    10
                    11
                    12
                    13
                    
                    float d;
                    if (RG-&gt;ItemIndex==0)
                    {
                     Series1-&gt;Clear();
                     for (float x1=1;x1AddXY(x1,d);
                     }
                    }
                    else
                    {
                     Series1-&gt;Clear();
                     for (float x2=1; x2AddXY(x2,d);
                     }
                    }

                    Ещё раз спасибо!

                    1. Потерялись строки:

                      if (RG->ItemIndex==0)
                      {
                      for (float x1=1; x2AddXY(x1,d);
                        }
                      }

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

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