none
List, for и события RRS feed

  • Вопрос

  • В событии постоянно приходят новые данные:

      private void SmartServer_AddTick(string symbol, System.DateTime datetime, double price, double volume, string tradeno, StClientLib.StOrder_Action action)
      {
      AllTicks.Add(new Tick(datetime, price, volume, tradeno, action));
      }
    Я их добавляю в список AllTicks. Каждое значение Price из этих данных рисую на экране в виде точки:
    if (AllTicks.Count > 0)
       {
        Gl.glBegin(Gl.GL_POINTS);
        for (int x = 1518, i = AllTicks.Count - 1; (i > AllTicks.Count - 1519) && (i >= 0); x--, i--)
        {
         Gl.glVertex2i(x, (int)AllTicks[i].Price - ScaleCor);
        }
        Gl.glEnd();
       }

    В итоге график рисуется не точный. Т.е. по идее, каждому значению координаты X должно соответствовать только одно значение Price. На графике же видно, что в некоторых местах координате X не соответствует ни одного значения Price, а в соседней координате X рисуется сразу 2 значения Price. Визуально график двигается с права налево частями, а должен двигаться не меняя расстояние между точками.

    Будьте любезны, подскажите как это можно побороть.

Ответы

  • После долгих мытарств найдена логика. Нужно делать так, в любом другом случае будут искажения масштаба на экране:
          Gl.glViewport(0, 0, TaoWin.Width + 1, TaoWin.Height + 1);
          // устанавливаем проекционную матрицу
          Gl.glMatrixMode(Gl.GL_PROJECTION);
          // очищаем ее
          Gl.glLoadIdentity();
          // Вычисляем новые геометрические размеры сцены;
          Glu.gluOrtho2D(0.0, TaoWin.Width, 0.0, TaoWin.Height);
          // переходим к объектно-видовой матрице
          Gl.glMatrixMode(Gl.GL_MODELVIEW);
          Gl.glLoadIdentity();
    • Помечено в качестве ответа 4dimuser 29 мая 2011 г. 9:56

Все ответы

  • Это нужно просто пощагово щупать, что входит, где и как проходит, и что получается.
    Если ошибки возникают синхронно, т.е. на одних и тех же данных,
    то в тексте программы нужно попытаться сформулировать условие ошибки
    и пометить это место точкой останова.

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

    При каждом добавлении тика перерисовывается весь список, причем в обратном порядке?
    Это нелогично. 

    Событий здесь я не вижу - Вы поймали тик по какому-то событию,
    а здесь пытаетесь этот тик нарисовать. 

  • После AllTicks.Add данные добавляются корректно. Пробовал выводить на экран в виде текста последний тик AllTicks[AllTicks.Count - 1].Price, все выводится точно, никаких ошибок. OpenGL тоже корректно работает. Ошибка именно в for.

    1. Вы говорили про простые структуры, это что такое?

    2. Почему не логично перерисовывать список в обратном порядке? Начало координат (0;0) - левый нижний угол. Правый верхний угол (1919;1079). Я вывожу только последние 1518 тиков от i = AllTicks.Count - 1 до i > AllTicks.Count - 1519. X при этом от 1518 до 0. Есть другие варианты?

  • "Ошибка именно в for"- возможно.
    В операторе for используется обычно только счетчик циклов,
    т.е. вы должны сформулировать, сколько итераций вам нужно произвести.
    Формирование номера точки я бы привязал к счетчику и расположил бы в теле цикла,
    в фигурных скобках.

    "Почему не логично перерисовывать список в обратном порядке?"
    Да. Можно и так, это я привык обходиться без перерисовок,
    поэтому глаз и цепляется.

    В общем, нужно определить какие точки выпадают,
    тогда и решение придет само собой 

  • Когда Вы говорили про простые структуры, Вы что имели в виду, Do while? Какие простые структуры существуют для отслеживания двух переменных?
  • Нет, я имел в виду, более простой for - это ведь только цикл со своим счетчиком, не более.
    Все остальное отвлекает.
  • Переделал так

    int x = 1518, i = AllTicks.Count - 1;
            do
            {
              Gl.glVertex2i(x, (int)AllTicks[i].Price - ScaleCor);
              x--;
              i--;
            }
            while ((i > AllTicks.Count - 1519) && (i >= 0));
    Все равно тоже самое. Если перестать записывать новые тики в список, то ошибка остается. Как же мне сделать более простой for, если необходимо отслеживать две переменные.

  • Сейчас попробовал перейти в полноэкранный режим и проблема исчезла, а в оконном режиме проблема остается. Значит это не for.

    Прям полтергейст какой-то. Может кто может сказать в чем причина сего действа?

    public FormFS()
     {
      InitializeComponent();
      // Инициализируем работу TaoWin;
      TaoWin.InitializeContexts();
      // Инициализация OpenGL
      // !!!Последовательность строк имеет значение!!!
      InitGL();
      ResizeGlScene();
     }
    
     public FormFS(bool fullscreen)
     {
      InitializeComponent();
      // Инициализируем работу TaoWin;
      TaoWin.InitializeContexts();
      // Инициализация OpenGL
      // !!!Последовательность строк имеет значение!!!
      InitGL();
      ResizeGlScene();
     }
    
     // Инициализация OpenGL
     private void InitGL()
     {
      Glut.glutInit();
      Glut.glutInitDisplayMode(Glut.GLUT_RGB | Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
     }
    
     // Изменение размеров окна OpenGL
     void ResizeGlScene()
     {
      // очитка окна черным цветом
      Gl.glClearColor(0, 0, 0, 1);
      // Сбрасываем текущую область просмотра;
      Gl.glViewport(0, 0, TaoWin.Width, TaoWin.Height);
      // Выбираем матрицу проекций;
      Gl.glMatrixMode(Gl.GL_PROJECTION);
      // Сбрасываем выбранную матрицу;
      Gl.glLoadIdentity();
      // Вычисляем новые геометрические размеры сцены;
      Glu.gluOrtho2D(0.0, TaoWin.Width, 0.0, TaoWin.Height);
      // Выбираем матрицу вида модели;
      Gl.glMatrixMode(Gl.GL_MODELVIEW);
      // Сбрасываем ее;
      Gl.glLoadIdentity();
     }
    
     //РИСОВАНИЕ СЦЕНЫ
     private void DrawGlScene()
     {
      // Очищаем экран выбранным цветом;
      Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
      // Сбрасываем текущую матрицу проекций;
      Gl.glLoadIdentity();
    
      // утснаовка зеленого цвета
      Gl.glColor3f(0, 255, 0);
    
      // Текст цены и объема первого бида стакана
      PrintText2D(1560, (int)Glassful[0].Bid - ScaleCor - 3, Glassful[0].Bid.ToString());
      PrintText2D(1540, (int)Glassful[0].Bid - ScaleCor - 3, Glassful[0].Bidsize.ToString());
      //Линия объема первого бида стакана
      Gl.glBegin(Gl.GL_LINES);
      Gl.glVertex2i(1520, (int)Glassful[0].Bid - ScaleCor);
      Gl.glVertex2i(1520 + (int)Glassful[0].Bidsize, (int)Glassful[0].Bid - ScaleCor);
      Gl.glEnd();
    
      // утснаовка красного цвета
      Gl.glColor3f(255, 0, 0);
    
      // Текст цены и объема первого аска стакана
      PrintText2D(1560, (int)Glassful[0].Ask - ScaleCor - 3, Glassful[0].Ask.ToString());
      PrintText2D(1540, (int)Glassful[0].Ask - ScaleCor - 3, Glassful[0].Asksize.ToString());
      //Линия объема первого аска стакана
      Gl.glBegin(Gl.GL_LINES);
      Gl.glVertex2i(1520, (int)Glassful[0].Ask - ScaleCor);
      Gl.glVertex2i(1520 + (int)Glassful[0].Asksize, (int)Glassful[0].Ask - ScaleCor);
      Gl.glEnd();
    
      // утснаовка белого цвета
      Gl.glColor3f(255, 255, 255);
    
      // Линии от курсора
      Gl.glBegin(Gl.GL_LINES);
      Gl.glVertex2i(2, 30);
      Gl.glVertex2i(1918, 30); // 1917+1
    
      Gl.glVertex2i(30, 2);
      Gl.glVertex2i(30, 1078); // 1077+1
    
      
      Gl.glVertex2i(0, 120); // 119+1
      Gl.glVertex2i(0, 20);  
      Gl.glVertex2i(1919, 120); // 119+1
      Gl.glVertex2i(1919, 20);
    
      Gl.glVertex2i(20, 0);
      Gl.glVertex2i(120, 0); // 119+1
      Gl.glVertex2i(20, 1079);
      Gl.glVertex2i(120, 1079); // 119+1
    
      Gl.glVertex2i(Mcoord_X, 1080); // 1079+1
      Gl.glVertex2i(Mcoord_X, 0);  
      Gl.glVertex2i(0, Mcoord_Y);
      Gl.glVertex2i(1920, Mcoord_Y);
    
      Gl.glEnd();
    
      Gl.glBegin(Gl.GL_POINTS);
      Gl.glVertex2i(0, 0);
      Gl.glVertex2i(1, 1);
      Gl.glVertex2i(2, 2);
      Gl.glVertex2i(1919, 1079);
      Gl.glVertex2i(1918, 1078);
      Gl.glVertex2i(1917, 1077);
      Gl.glEnd();
    
      if (AllTicks.Count > 0)
      {
      Gl.glBegin(Gl.GL_POINTS);
      int x = 1518, i = AllTicks.Count - 1;
      do
      {
       Gl.glVertex2i(x, (int)AllTicks[i].Price - ScaleCor);
       x--;
       i--;
      }
      while ((i > AllTicks.Count - 1519) && (i >= 0));
      Gl.glEnd();
    
      // утснаовка белого цвета
      Gl.glColor3f(255, 255, 255);
    
      PrintText2D(1400, 550, AllTicks[AllTicks.Count - 1].Price.ToString());
      }
      
      // выводим текст со значением координаты Y
      if (Mcoord_Y < 1060)
      PrintText2D(1679, Mcoord_Y + 6, Mcoord_X.ToString() + ";" + Mcoord_Y.ToString());
      else
      if (Mcoord_Y >= 1060)
       PrintText2D(1679, Mcoord_Y - 17, Mcoord_X.ToString() + ";" + Mcoord_Y.ToString());
    
      Gl.glFlush();
      TaoWin.Invalidate();
     }
    
     // Обработчик события изменения размеров формы;
     private void FormFS_Resize(object sender, EventArgs e)
     {
      // Вначале изменим размеры сцены;
      ResizeGlScene();
      // А потом перерисуем;
      DrawGlScene();
     }
    
     // Смена режима (Fullscreen/Window)
     private void ScreenMode(bool fullscreen)
     {
      // Присваиваем значение "глобальной" переменной;
      FS = fullscreen;
    
      if (FS)
      { // *** ПОЛНОЭКРАННЫЙ РЕЖИМ ***
      // Скрываем рамку окна;
      this.FormBorderStyle = FormBorderStyle.None;
      // Разворачиваем окно;
      this.WindowState = FormWindowState.Maximized;
      }
      else
      { // *** ОКОННЫЙ РЕЖИМ ***
      // Возвращаем состояние окна;
      this.WindowState = FormWindowState.Normal;
      // Показываем масштабируемую рамку окна;
      this.FormBorderStyle = FormBorderStyle.None;
      }
      ResizeGlScene();
     }
    
     private void FormFS_KeyDown(object sender, KeyEventArgs e)
     {
      // Нажата клавиша ЕSCAPE;
      if (e.KeyCode == Keys.Escape)
      {
      // Отключаемся
      Disconnect();
    
      // Завершим приложение;
      this.Close();
      }
      // Нажата клавиша F2;
      if (!FS && e.KeyCode == Keys.F2)
      {
      // Изменяем режим на ПОЛНОЭКРАННЫЙ;
      ScreenMode(true);
      // Прячем курсор;
      Cursor.Hide();
      }
      // Нажата клавиша F1;
      if (FS && e.KeyCode == Keys.F1)
      {
      // Изменяем режим на оконный;
      ScreenMode(false);
      // Показываем курсор;
      Cursor.Hide();
      }
     }
    
     private void RefreshTimer_Tick(object sender, EventArgs e)
     {
      DrawGlScene();
     }
    
     private void TaoWin_MouseMove(object sender, MouseEventArgs e)
     {
      // вычисляем параметры для будующей дорисовке линий от указателя мыши к координатным осям.
      Mcoord_X = e.X;
      Mcoord_Y = (int)(TaoWin.Height - e.Y - 1);
     }
    
     private void PrintText2D(int x, int y, string text)
     {
      // устанавливаем позицию вывода растровых символов
      // в переданных координатах x и y.
      Gl.glRasterPos2i(x, y);
    
      // в цикле foreach перебираем значения из массива text,
      // который содержит значение строки для визуализации
      foreach (char char_for_draw in text)
      {
      // визуализируем символ c, с помощью функции glutBitmapCharacter, используя шрифт GLUT_BITMAP_HELVETICA_10.
      Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_HELVETICA_10, char_for_draw);
      }
     }

    Извините за длинный текст

  • Может быть, как я уже говорил, Ваш график ограничен снизу и сверху, и пропуски - это значения выше или ниже ограничений.
    Полтергейст - это нормальное явление в программировании. 
  • Это исключено. Каждое следующее значение отличается от предыдущего на очень маленькую величину. К тому же у меня на экран в виде цифры выдается это значение, поэтому я бы заметил.

    Еще я заметил, что если навести курсор мыши на место пропусков, то таким же образом не отображается линия, идущая от верхней границы монитора к нижней через курсор мыши. Хотя, во всех других точках экрана линия, проходящая через курсор мыши отображается корректно.

  • Тогда нужно ловить эти точки и смотреть, что происходит.
    Еще может быть ситуация, когда дискрет графика по x не вполне соответствует сумме пикселей,
    например, 1 минута - это не строго 10, а 10.05 или 9.95 пикселей, тогда ошибка будет накапливаться и 
    в какой-то момент будет перескок. 
  • С точками, как оказалось, все в порядке. В полноэкранном режиме все отображается корректно, а в оконном не корректно. Здесь что-то с OpenGL, код рисующий все ведь один и для полноэкранного режима и для оконного.
  • OpenGL - это для меня темный лес
  • Можно еще попробовать следующий прием.
    Привязать график к форме, чтобы график увеличивался или уменьшался с изменением размера формы.
    и посмотреть, будет ли что-либо меняться.
    • Помечено в качестве ответа Abolmasov Dmitry 27 мая 2011 г. 5:47
    • Снята пометка об ответе 4dimuser 29 мая 2011 г. 9:57
  • Уважаемый пользователь, пожалуйста, не забудьте отметить ответ/ответы, которые решили вашу проблему. Для этого под каждым сообщением есть кнопка 'Пометить как ответ'. Спасибо.
    Для связи [mail]
  • Я бы с радостью, но проблема не решена. Данный код абсолютно корректно выводит график в полноэкранном режиме, А в оконном режиме некоторые точки графика не прорисовываются. Видимо проблема в OpenGL, но где именно понять не могу. Очень надеюсь на ваш совет.
  • Если без деталей - я думаю, проблема решиться если отделить цепочку событий (поток), в который данные накапливаются от другого потока (посмотрите к примеру в сторону BackgroundWorker класса и прочей организации многопоточности), в котором имеет смысл организовать отрисовку.

    Вариантов как это сделать - масса. Общую мысль я изложил. Дерзайте!


    Don't forget to vote for useful replies and/or mark answers for your questions - that helps other guys to find the answer faster.
    • Помечено в качестве ответа Abolmasov Dmitry 27 мая 2011 г. 5:43
    • Снята пометка об ответе 4dimuser 29 мая 2011 г. 9:57
  • Проблему решил. Может кому пригодится. Просто слов нет от тупости OpenGL.

    Если размер окна 1575; 1078, то плоскость почему-то надо задавать именно так:

    Gl.glViewport(0, 0, TaoWin.Width, TaoWin.Height);
    Glu.gluOrtho2D(0.0, 1574, 0.0, TaoWin.Height);

    Искажения возникали из-за того, что вместо цифры 1574 стояла TaoWin.Width, равная 1575.

    Почему таким же образом не надо вместо TaoWin.Height не надо ставить 1077 одному богу известно.

  • После долгих мытарств найдена логика. Нужно делать так, в любом другом случае будут искажения масштаба на экране:
          Gl.glViewport(0, 0, TaoWin.Width + 1, TaoWin.Height + 1);
          // устанавливаем проекционную матрицу
          Gl.glMatrixMode(Gl.GL_PROJECTION);
          // очищаем ее
          Gl.glLoadIdentity();
          // Вычисляем новые геометрические размеры сцены;
          Glu.gluOrtho2D(0.0, TaoWin.Width, 0.0, TaoWin.Height);
          // переходим к объектно-видовой матрице
          Gl.glMatrixMode(Gl.GL_MODELVIEW);
          Gl.glLoadIdentity();
    • Помечено в качестве ответа 4dimuser 29 мая 2011 г. 9:56
  • Какая фигня, я и слова-то эти уже позабыл...
    А все потому, что Вы решили  вместо графиков рисовать мультики