Projekt wariometru

Projekt wariometru
P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

Witam,
Robię praktyczny model wariometru, który drogą radiową będzie przesyłał dane do komputera.
Na podstawie http://forum.atnel.pl/topic1226.html opracowałem terminal, który te dane odbiera i wyświetla. Chciałbym jednak aby oprócz wykresów i danych w labelach można było obejrzeć dane wyświetlane w postaci "wariometru analogowego"- graficznie.
Niestety moja znajomość C# opiera się głównie na wymienionym wcześniej a nie ma tam słowa o grafice.
Chodzi o to aby było w tym moim terminalu okno wyglądające mniej więcej jak to z załącznika (okrąg) gdzie przy przesłaniu z wariometru danej 3 m/s wskazówka z obrazka przesunęła się na wartość 3 m/s.

Próbowałem zrobić coś na wzór zegarka analogowego z http://www.centrumxp.pl/dotNet/1457,Analogowy-zegarek.aspx#komentarz_54805 , niestety nie udało mi się wykonać tej aplikacji - autor nie zamieścił całości kodu a z dostępnych fragmentów nie potrafię poskładać całości.
Czy ktoś mógłby mi doradzić jakiś fajny poradnik z rysowaniem prostych rzeczy w C# albo powiedzieć jak to zacząć?

Wiem, że muszę narysować okrąg, napisać na nim wartości (od -5 m/s do +5 m/s) a następnie narysować wskazówkę która zaczynała się będzie w środku okręgu a kończyła na x i y wyliczonym z cos i sin i danej odebranej z wariometru. Dobrze myślę? Jak wykonać to w praktyce?
Proszę o pomoc. W załącznikach kod mojego termianalu i prymitywny obrazek przedstawiający jak mniej więcej ma wyglądać ten mój analogowy wariometr.

Z góry dzięki za pomoc,
Picek

NE
  • Rejestracja:około 12 lat
  • Ostatnio:prawie 10 lat
  • Postów:22
1

Na prędce takie coś napisałem. value powinnieneś podawać znormalizowane od 0 do *_myRange

Kopiuj
 
        double _myRange = 10.0;
        Pen _myPen = new Pen(new SolidBrush(Color.Black), 2);

        private void Draw(double value)
        {
            System.Drawing.Graphics graphics = this.CreateGraphics();
            Point startOfBox = new Point(50, 50);
            Size boxSize= new Size(200,200);
            System.Drawing.Rectangle rectangle = new System.Drawing.Rectangle(
               startOfBox, boxSize);

            graphics.DrawArc(_myPen, rectangle, 180, 180);
            Point centerOfCircle = new Point(startOfBox.X + boxSize.Width/2, startOfBox.Y+boxSize.Height/2);
            
            double angle = GetAngle(value);
            double x2 = centerOfCircle.X - (Math.Cos(angle) * 100);
            double y2 = centerOfCircle.Y - (Math.Sin(angle) * 100);
            Point endPoint = new Point((int)x2, (int)y2);
            graphics.DrawLine(_myPen, centerOfCircle, endPoint);

        }

        private double GetAngle(double value)
        {
              return (Math.PI / _myRange) * value;
        }

edytowany 1x, ostatnio: nexodg
Azarien
graphicsa należy zwolnić, albo przez Dispose(), albo umieścić go w bloku using.
NE
ok, Jest jakiś hack/addin? Coby wiedzieć, które należy zwalniać a które nie? Bo sprawdzać każdą klasę w dokumentacji to jest trochę przerost formy nad treścią. Pewnie wiedza przyjdzie z doświadczeniem i czasem, ale nie chciałbym unikać takich baboli a pakować wszystko w using'a to jest trochę na wyrost.
Azarien
zwalniać należy klasy implementujace IDisposable. Pod IDE bez dodatków możesz łatwo sprawdzić czy ma metodę Dispose().
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 9 godzin
0

Wiem, że muszę narysować okrąg, napisać na nim wartości (od -5 m/s do +5 m/s) a następnie narysować wskazówkę która zaczynała się będzie w środku okręgu a kończyła na x i y wyliczonym z cos i sin i danej odebranej z wariometru. Dobrze myślę? Jak wykonać to w praktyce?

Musisz narysować okrąg, napisać na nim wartości, a następnie a następnie narysować wskazówkę która zaczynała się będzie w środku okręgu a kończyła na x i y wyliczonym z cos i sin i danej odebranej z wariometru.

Połóż panel i oprogramuj jego zdarzenie Paint:

Kopiuj
        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Control control = (Control)sender;
            using (Graphics g = control.CreateGraphics())
            {
                g.Clear(Color.Navy);
                g.DrawEllipse(Pens.Yellow, 0, 0, control.Width-1, control.Height-1);
            }
        }

Szczegóły w dokumentacji. Klawisz F1.

P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

Dzięki za odpowiedzi i podpowiedzi!
Pierwsze pytania:
1.(glupie) Jak wywołać twoją funkcję nexodg? Tzn wiem jak tylko nie wiem gdzie. Draw(moje zmienne) tylko gdzie? w zdarzeniu Paint panelu? Po kliknięciu button?
2. Twoja funkcja przyjmuje double a ja dane dostaje w stringu. System.Convert.ToDouble() nie działa. Jak zamienić w takim razie string na double?
3. Jeśli z wariometru dostaję dane, które teoretycznie mogą przyjmować jakiekolwiek wartości, to jak jest znormalizowac?

edytowany 1x, ostatnio: Picek91
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 9 godzin
0
  1. Twoja funkcja przyjmuje double a ja dane dostaje w stringu. System.Convert.ToDouble() nie działa. Jak zamienić w takim razie string na double?
Kopiuj
Convert.ToDouble("3.14", CultureInfo.InvariantCulture)
NE
  • Rejestracja:około 12 lat
  • Ostatnio:prawie 10 lat
  • Postów:22
1
Picek91 napisał(a):
  1. Jeśli z wariometru dostaję dane, które teoretycznie mogą przyjmować jakiekolwiek wartości, to jak jest znormalizowac?

Poza limitami odrzuć, sam limit przesuń.
Przykład zakres -5 -- 5,
wartość -3 --> 0.. 2 10.
wartość 3 --> 0.. 8 10.
wartość maksymalna 5 --> 0... 10.
wartośc poza zakresem 12 --> 10.
jeśli jednak chcesz by odpowiednio się skalowało tzn wykres był logarytmiczny coś w stylu:
wartość -100,-50,-30,-20,-15.. tu mega gęsto 0 tu dalej gesto +15, 20,30,50,100 to ja Ci już nie pomogę.

Kopiuj
 
 private double Normalize(double value, double min, double max)
        {
            if (value < min)
                return min;
            else if (value > max)
                return max;
            else
            {
               return value + Math.Abs(min);          
            }
        }
P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

@Azarien
Próbowałem przekonwertować tak jak powiedziałeś:

Error 1 The name 'CultureInfo' does not exist in the current context C:...\Terminal\Form1.cs 125 53 Terminal

Bez tego CultureInfo:
Nie można rzutować obiektu typu 'System.String[]' na typ 'System.IConvertible'.

Zatem w jaki sposób to przekonwertować?

Azarien
zobacz sobie w jakim namespace'ie jest klasa CultureInfo i dodaj odpowiedni using.
P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

Dzięki Azarien za pomoc.
Podczas kompilacji nie wyskakuje żaden błąd.
Funkcje wywoływałem pod buttonem i przy panel paint ale ani w jednym ani w drugim przypadku nic nie zaczęło się rysować. Jak wywołać tą funkcję?

Poza tym po rozłączeniu portu debuger wywala:
Nie można rzutować obiektu typu 'System.String[]' na typ 'System.IConvertible'.
więc chyba i tak coś jest nie tak z tą konwersją na duble...

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
0
Picek91 napisał(a):

Nie można rzutować obiektu typu 'System.String[]' na typ 'System.IConvertible'.

Wszystko się zgadza. String jest IConvertible, ale String[], czyli tablica stringów już nie. Czemu i na co chcesz konwertować tablicę stringów?

VarrComodoo
  • Rejestracja:około 14 lat
  • Ostatnio:14 dni
  • Lokalizacja:Bk
  • Postów:480
1

Chciałbym tylko wtrącić że zegarek z CentrumXP działa:


Sterczące kolce Pondijusa, ostre grzebienie Daktyloskopei, Trygla i latający Wieprzoryb są niczym wobec Bestii która nas gnębi...
P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

@somekind
Tablicę stringów chcę przekonwertować na double.
Tablicę stringów bo w takiej formie dostaję dane z Atmegi, na double, ponieważ taki typ przyjmuje f-ja Nexodg

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
0
Picek91 napisał(a):

Tablicę stringów chcę przekonwertować na double.

Ale tablicę napisów możesz skonwertować na tablicę liczb, a nie na jedną liczbę!

P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0
Kopiuj
printf("%0.1f,%0.2f,%0.1f,%0.1f,\r\n", (double)temperature/10,(double)pressure/100,(double)altitude,(double)velocity); 

W ten sposób wysyłam dane z Atmegi do termianala. Do mojego graficznego wariometru potrzebna mi dana po ostatnim przecinku i to chciałbym wrzucić do funkcji Nexodg

Kopiuj
 Draw(double value)

Jakiś pomysł jak to zrobić bo ja już się gubię.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
1

@Picek91, czyli masz liczby oddzielone przecinkami, tak?

Kopiuj
string[] dane = napisZAtmegi.Split(',');
for (int i = 0; i < dane.Length; i++)
{
    // tutaj konwersja z dane[i] na double i wywołanie funkcji przyjmującej double.
}
P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

Mam teraz coś takiego:

Kopiuj
 
       private void rx_parse(object sender, EventArgs e)
        {
 
            tab_size++;
 
            string[] dane = new string[5];
            dane = rx_str.Split(',');
 
            /**WYŚWIETLANIE WYNIKOW**/
 
            textBox1.Text = dane[0] + "°C";
            textBox2.Text = dane[1] + "hPa";
            textBox3.Text = dane[2] + "m";
            textBox4.Text = dane[3] + "m/s";
//-------------------------------------------------------------------------------------------------
            Draw(Normalize(Convert.ToDouble(dane[3], CultureInfo.InvariantCulture), -5, 5));    //F-ja o którą mi chodzi.
//-------------------------------------------------------------------------------------------------
            /**WYKRESY**/
            chart1.Series["Series1"].Points.AddY(dane[0]);
            chart2.Series["Series1"].Points.AddY(dane[1]);
            chart3.Series["Series1"].Points.AddY(dane[2]);
            chart4.Series["Series1"].Points.AddY(dane[3]);
            

            notifyIcon1.Text = "T: " + dane[0] + "P: " + dane[1] + "H: " + dane[2] + "V: " + dane[3];
 
            richTextBox1.AppendText(rx_str);

            



            Array.Resize(ref temperatura, tab_size); // Cykliczne powiększanie rozmiaru tablicy
            Array.Resize(ref cisnienie, tab_size); // j.w
            Array.Resize(ref wysokosc, tab_size);  // j.w
            Array.Resize(ref predkosc, tab_size); // j.w
   


            temperatura[index] = dane[0];
            cisnienie[index] = dane[1];
            wysokosc[index] = dane[2];
            predkosc[index] = dane[3];
            index++;

            for (int n = 0; n < tab_size; n++)
            {
                dataGridView1.Rows.Add(1);
                dataGridView1.Rows[n].Cells[0].Value = temperatura[n];
                dataGridView1.Rows[n].Cells[1].Value = cisnienie[n];
                dataGridView1.Rows[n].Cells[2].Value = wysokosc[n];
                dataGridView1.Rows[n].Cells[3].Value = predkosc[n];
            }



        }

Kompiluje się ładnie, wszystko gra, jednak nadal nic mi się nie wyświetla ani maluje. Wiem, że to na pewno jakieś głupstwo ale jak wywołać tą funkcję żeby namalowało mi ten wariometr? :/

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 13 godzin
  • Lokalizacja:Wrocław
0

@Picek91, czemu Ci nie rysuje to nie wiem. Mogę Ci tylko powiedzieć, że przez to, że nie programujesz obiektowo, ten kod jest strasznie zamotany. A już najgorsze jest chyba to Array.Resize. Użyj listy (typu List<T>) zamiast tablicy i nie kombinuj w ten sposób.

edytowany 1x, ostatnio: somekind
P9
  • Rejestracja:około 12 lat
  • Ostatnio:około 9 lat
  • Postów:22
0

Szczerze mówiąc to z programowania jestem zielony zupełnie... sam bym tego nie napisał i wszystko jest na wzór z http://forum.atnel.pl/topic1226.html ...
Nie mam pojęcia jak to zrobić żeby mi rysowało

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.