CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - Wykresy - Chart
Strona 1 z 1

Wykresy - Chart

Nowy postNapisane: środa, 13 kwietnia 2011, 16:02
przez Gazunio
Witam. Tworzę obecnie program dotyczący kinematyki. Na pierwszy ogień poszedł ruch jednostajny prostoliniowy. Mam trzy pola tekstowe - czas, droga i szybkosc. Ładnie generuję wykres szybkości od czasu:
KOD cpp:     UKRYJ  
 int v = StrToInt(szybkosc->Text);
 int s = StrToInt(droga->Text);
 int t = StrToInt(czas->Text);

 for(int i = 0; i <= t; i++)
 {
  TColor color = (TColor)255;
  Chart1->Series[0]->Add(v, i, color);
 }
Wykres powinien przedstawiać linię poziomą, bo przecież prędkość jest stała. I tak jest. Ale jest problem taki, że nie ma siatki poziomej - na wykresie jest tylko linia z wartością podaną w polu szybkość. A chciałbym, by były także linie pomocnicze. Wykres zaczynał się od zera i w pionie i w poziomie.

Tak to wygląda:
wykres.JPG


Dodam, że w przypadku drugiego wykresu, drogi od czasu wszystko jest w porządku. Tak więc chcę się dowiedzieć, jak wymusić, bo były te linie pomocnicze i wykres zaczynał się od zera?

Re: Wykresy - Chart

Nowy postNapisane: czwartek, 14 kwietnia 2011, 09:03
przez Cyfrowy Baron
Dla osi Left Axis musisz określić Minimum - minimalną wartość na osi Y (lewy pion), Maximum - maksymalną wartość dla osi Y i Increment - częstotliwość zwiększania argumentu. Można to ustawić na sztywno w edytorze wykresu:

axischart.png


Może się jednak okazać, że chcesz wyświetlać rozmiar siatki zależny od wartości linii, w takiej sytuacji możesz sterować maksymalna wartością osi w kodzie:

KOD cpp:     UKRYJ  
 int v = StrToInt(szybkosc->Text);
 int s = StrToInt(droga->Text);
 int t = StrToInt(czas->Text);

 for(int i = 0; i <= 10; i++)
 {
  TColor color = (TColor)255;
  Chart1->Series[0]->Add(v, i, color);

  Chart1->LeftAxis->Maximum = v * 2;
 }

Re: Wykresy - Chart

Nowy postNapisane: piątek, 15 kwietnia 2011, 21:18
przez Gazunio
Dziękuję za odpowiedź. To rozwiązanie działa dobrze.
Mam jeszcze jedno pytanie. Chciałbym "zobrazować", jak poruszać się będzie dany obiekt w określonym ruchu(jednostajny, przyspieszony, opóźniony).
I tak, w ruchu jednostajnym mi się jakoś udało (wiem, że to niezbyt "profesjonalne ;) )

KOD cpp:     UKRYJ  
for(int i = 0;i<500;i++)
{
        ListBox1->Left = ListBox1->Left+1;
        Sleep(5);  }


Szybkość mogę regulować Sleepem.
Ale jak tutaj to wykonać w ruchu przyspieszonym, czyli aby zwiększała się szybkość. Albo, czy jest jakaś bardziej profesjonalna metoda takiej animacji?

Re: Wykresy - Chart

Nowy postNapisane: sobota, 16 kwietnia 2011, 10:28
przez Cyfrowy Baron
Funkcja Sleep generuje opóźnienie poprzez wstrzymanie aplikacji i nie jest to dobre rozwiązanie do tworzenia animacji, lepiej posłużyć się zegarem TTimer. Umieszczasz kod w zdarzeniu OnTimer tegoż obiektu. Zegar włączasz ustawiając jego właściwość Enabled na true, a szybkością zegara sterujesz zmieniając jego właściwość Interval, gdzie 1000 = 1 sekunda. Dla kodu który tutaj przedstawiłeś mogłoby to wyglądać tak:
KOD cpp:     UKRYJ  
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  /* ustawienie początkowej częstotliwości pracy zegara czyli zdarzenie OnTimer wywoływane jest z częstotliwością 1 sekundy */
  Timer1->Interval = 1000;
  Timer1->Enabled = true; /* włączenie zegara = uruchomienie zdarzenie OnTimer */
}
//--------------------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  static int i = 0; /* zmienna statyczna zachowuje się jak zmienna globalna */
  static int left = ListBox1->Left; /* zmienna statyczna przechowuje pierwotną pozycję obiektu */
 
  if( i < 500 ) ListBox1->Left = left + 1;
  else
  {
    Timer1->Enabled = false; /* wyłączenie zegara = zatrzymanie zdarzenie OnTimer */
    i = 0; /* wyzerowanie zmiennej statycznej, by po ponownym uruchomieniu zegara liczyła od 0 */
    ListBox1->Left = left; /* przywrócenie obiektu na pierwotną pozycję */
  }

  i++;
  Timer1->Interval -= 2; /* przyspieszanie zegara z każdym cyklem pracuje o 2 milisekundy szybciej */
}

Re: Wykresy - Chart

Nowy postNapisane: poniedziałek, 2 maja 2011, 15:57
przez Gazunio
Dziękuję za pomoc. Działa bardzo dobrze ;)
Teraz próbuję tutaj zastosować wzory z ruchu przyspieszonego( v=a/t oraz s=(a*t^2)/2 )
Drogę prosto dodałem - w tym poprzednim kodzie dodałem
KOD cpp:     UKRYJ  
  Label1->Caption = IntToStr(ListBox1->Left);

, i za każdym ruchem pokazuje poprawną drogę w Labelu.
Problem mam z czasem - ma być liczony i pokazywany w np. Label2 na bieżąco, od momentu zainicjowania licznika do momentu osiągnięcia końcowego punktu.
Czytałem o mierzeniu czasu, i skorzystałem z funkcji:
KOD cpp:     UKRYJ  
 static int czas = GetTickCount();

a w momencie zatrzymania się "pojazdu" korzystam z :
KOD cpp:     UKRYJ  
  czas = GetTickCount()-czas;
  Label2->Caption = IntToStr(czas);


Ale to daje za każdym razem inny wynik niestety, który różni się znacząco. Co innego mogę tutaj zastosować?

Re: Wykresy - Chart

Nowy postNapisane: poniedziałek, 2 maja 2011, 22:34
przez Gazunio
Przepraszam za post pod postem. Rozwiązałem problem z brakiem odpowiedniego czasu. Dodałem drugi Timer, z interwałem 1ms, który ma taki kod:
KOD cpp:     UKRYJ  
static int czas = 0;
czas++;
float sek = czas/100;
Label2->Caption = FloatToStr(sek);

Wyświetla się teraz czas poprawnie, ale i tak chyba muszę zrezygnować z tej opcji. Ustawienie tutaj odpowiedniego przyspieszenia jest dla mnie zbyt trudne. Modyfikacja wartości w trzech miejscach kodu wpływa na czas pokonania trasy, ale nie wiem jak tutaj wyznaczyć przyspieszenie, by można je było podstawić np, z Edita.

Re: Wykresy - Chart

Nowy postNapisane: wtorek, 3 maja 2011, 09:21
przez Cyfrowy Baron
Zadajesz pytania w taki sposób jakbyś rozmawiał sam ze sobą, przez co nie wiadomo o co Tobie dokładnie chodzi.

Co się tyczy problemu to powinieneś wiedzieć, że zegary (TTimer) nie działają w oddzielnych wątkach, więc dwa zegary działające w jednym czasie wchodzą sobie w paradę. Dlatego w jednym czasie powinien działać tylko jeden zegar.

Jeżeli oprócz przyspieszenia chcesz pokazywać w obiekcie Label również czas w jakim to przyspieszenie jest realizowane?! Tak to rozumiem.

Oczywiście żadne pętle nie wchodzą tutaj w grę, żadne opóźniacze typu Sleep również. Poza tym trzeba wprowadzić synchronizację zegara, gdyż operacje wykonywane w programie jak i w systemie wpływają na jego pracę i mogą powodować chwilowe wstrzymania, rzędu kilku milisekund.
Synchronizacja zegara umożliwia jednak tylko dokładne odmierzenie czasu pomiędzy uruchomienie tegoż zegara, a jego zatrzymaniem. Do synchronizacji można posłużyć się funkcją GetTickCount().

Problem w tym, że obiekt przesuwany po formularzu jest odświeżany i podobnie jak ma to miejsce w przypadku zegara, tak i w tym przypadku operacje wykonywane w programie jak i w systemie wpływają na szybkość tego odświeżania, co niestety przekłada się również na czas w jakim obiekt jest przesuwany.

W tej sytuacji należałoby zsynchronizować pracę zegara z przesuwanym obiektem, jednak jak wykazują testy i to nie daje precyzyjnego pomiaru i wyniki pomiędzy kolejnymi uruchomieniami mogą się różnić o kilka milisekund.
Niestety Timer nie jest najdokładniejszy i tych milisekundowych różnic nie da się chyba wyeliminować:

KOD cpp:     UKRYJ  
int  iElapsTime, iStartTime;
void __fastcall TForm1::Button1Click(TObject *Sender)
{
 ListBox1->Left = 8;

  if( Timer1->Enabled )
  { /* zatrzymanie zegara */
        Timer1->Enabled = false;
  }
  else
  { /* uruchomienie zegara */
        iStartTime = GetTickCount();
        iElapsTime = 0;
        Timer1->Interval = 10;
        Timer1->Enabled = true;
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  static float i = 0.0;

  if( ListBox1->Left < this->ClientWidth - ListBox1->Width)
  {
   ListBox1->Left = ListBox1->Left + i;
  }
  else
  {
        Timer1->Enabled = false;
        Caption = (String)i;
        i = 0.0;
  }

  iElapsTime = GetTickCount() - iStartTime;
  Label1->Caption = FloatToStrF( ((float)iElapsTime)/1000.0, ffFixed, 7, 3) + " sec.";

  i = ((float)iElapsTime/100.0);
}
//---------------------------------------------------------------------------