2015-12-09 3 views
3

Я хочу нарисовать дугу, используя центральную точку, начальную точку, конечную точку на opengl surfaceview. Я пробовал это ниже под кодом. Эта функция рисует ожидаемую дугу, если мы даем значение для start_line_angle и end_line_angle вручную (как start_line_angle = 0 и end_line_angle = 90) в градусах.Нарисуйте дугу в opengl GL10

Но мне нужно, чтобы нарисовать дугу с заданными координатами (центральную точку, начальную точку, конечную точку) и вычисляя start_line_angle и end_line_angle программно. Эта функция рисует дугу с заданными параметрами, но не дает результат желания. Я потратил 2 дня на это. Заранее спасибо.

private void drawArc(GL10 gl, float radius, float cx, float cy, float start_point_x, float start_point_y, float end_point_x, float end_point_y) { 
     gl.glLineWidth(1); 
     int start_line_angle; 
     double sLine = Math.toDegrees(Math.atan((cy - start_point_y)/(cx - start_point_x))); //normal trigonometry slope = tan^-1(y2-y1)/(x2-x1) for line first 
     double eLine = Math.toDegrees(Math.atan((cy - end_point_y)/(cx - end_point_x)));   //normal trigonometry slope = tan^-1(y2-y1)/(x2-x1) for line second 

     //cast from double to int after round 
     int start_line_Slope = (int) (sLine + 0.5); 


     /** 
     * mapping the tiriogonometric angle system to glsurfaceview angle system 
     * since angle system in trigonometric system starts in anti clockwise 
     * but in opengl glsurfaceview angle system starts in clock wise and the starting angle is 90 degree of general trigonometric angle system 
     **/ 
     if (start_line_Slope <= 90) { 
      start_line_angle = 90 - start_line_Slope; 
     } else { 
      start_line_angle = 360 - start_line_Slope + 90; 
     } 

//  int start_line_angle = 270; 
//  int end_line_angle = 36; 

     //casting from double to int 
     int end_line_angle = (int) (eLine + 0.5); 

     if (start_line_angle > end_line_angle) { 
      start_line_angle = start_line_angle - 360; 

     } 
     int nCount = 0; 

     float[] stVertexArray = new float[2 * (end_line_angle - start_line_angle)]; 

     float[] newStVertextArray; 
     FloatBuffer sampleBuffer; 

//  stVertexArray[0] = cx; 
//  stVertexArray[1] = cy; 

     for (int nR = start_line_angle; nR < end_line_angle; nR++) { 
      float fX = (float) (cx + radius * Math.sin((float) nR * (1 * (Math.PI/180)))); 
      float fY = (float) (cy + radius * Math.cos((float) nR * (1 * (Math.PI/180)))); 

      stVertexArray[nCount * 2] = fX; 
      stVertexArray[nCount * 2 + 1] = fY; 
      nCount++; 
     } 

     //taking making the stVertextArray's data in reverse order 
     reverseArray = new float[stVertexArray.length];//-2 so that no repeatation occurs of first value and end value 
     int count = 0; 


     for (int i = (stVertexArray.length)/2; i > 0; i--) { 
      reverseArray[count] = stVertexArray[(i - 1) * 2 + 0]; 
      count++; 
      reverseArray[count] = stVertexArray[(i - 1) * 2 + 1]; 
      count++; 
     } 

     //reseting the counter to initial value 
     count = 0; 
     int finalArraySize = stVertexArray.length + reverseArray.length; 
     newStVertextArray = new float[finalArraySize]; 

     /**Now adding all the values to the single newStVertextArray to draw an arc**/ 

     //adding stVertextArray to newStVertextArray 
     for (float d : stVertexArray) { 
      newStVertextArray[count++] = d; 
     } 

     //adding reverseArray to newStVertextArray 
     for (float d : reverseArray) { 
      newStVertextArray[count++] = d; 
     } 

     Log.d("stArray", stVertexArray.length + ""); 
     Log.d("reverseArray", reverseArray.length + ""); 
     Log.d("newStArray", newStVertextArray.length + ""); 

     ByteBuffer bBuff = ByteBuffer.allocateDirect(newStVertextArray.length * 4); 
     bBuff.order(ByteOrder.nativeOrder()); 
     sampleBuffer = bBuff.asFloatBuffer(); 
     sampleBuffer.put(newStVertextArray); 
     sampleBuffer.position(0); 

     gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); 
     gl.glVertexPointer(2, GL10.GL_FLOAT, 0, sampleBuffer); 
     gl.glDrawArrays(GL10.GL_LINE_LOOP, 0, nCount * 2); 
     gl.glLineWidth(1); 
    } 
+0

Какую дугу вы пытаетесь нарисовать, используя 3 очка? Это круговая дуга или овальная дуга? Или кривая Безье? Что именно? Я вижу, что вы проходите в радиусе; что, кажется, побеждает цель использования 3 очков. –

+0

честно говоря, я не хочу использовать радиус, потому что, если у нас есть начальная точка и центральная точка, мы также можем вычислить радиус. Мы можем игнорировать радиус, но в этой функции, вычисляя точки на окружности, нам нужен радиус, поэтому я использовал это. Мне нужна круговая дуга. Я не знаю, как добиться результата. и я новичок в opengl-es тоже :( –

+0

Часть OpenGL ES по существу не имеет значения, до тех пор, пока вы можете рисовать сегменты линии, вопрос заключается в том, какие сегменты линии рисовать для формирования вашей дуги. Проблема в том, что центр и 2 точки не образуют дугу * круговой *. Вам нужно было бы ограничить две точки, чтобы оба были на круге. –

ответ

0

Для начала тригонометрии вы не можете просто использовать atan найти степень угла. Вам нужно проверить, в каком квадранте находится вектор, и увеличить или уменьшить результат, полученный от atan. Еще лучше используйте atan2, который должен содержать как dx, так и dy и выполнить эту работу за вас.

Кажется, что вы создаете буфер так, чтобы точка создавалась на градус. Это не лучшее решение, так как для большого радиуса, который может быть слишком мал, и для малого радиуса это слишком много. Тесселяция должна также включать радиус, так что число точек N равно N = abs((int)(deltaAngle*radius*tessellationFactor)), затем используйте angleFragment = deltaAngle/N, но убедитесь, что N больше 0 (N = N?N:1). Размер буфера равен 2*(N+1) поплавков и итерации, если for(int i=0; i<=N; i++) angle = startAngle + angleFragment*i;.

Как уже указывалось, вам необходимо определить радиус дуги. Вполне нормально использовать внешний источник так, как вы делаете, и просто принудительно использовать его для этого значения, но используйте 3 точки для центра и двух границ. Некоторые другие варианты, которые обычно имеют смысл, являются:

  • получают радиус от линии старта
  • получают радиус от наименьшего из двух линий
  • получать среднее двух
  • интерполировать два чтобы получить эллиптический кривой (объяснено ниже)

чтобы интерполировать радиус вам нужно получить два радиусов startRadius и endRadius. Затем вам нужно найти общий радиус, который уже использовался как deltaAngle выше (смотрите при вычислении этого, это сложнее, как кажется, например, от 320 градусов до 10 градусов приводит к deltaAngle = 50). В любом случае радиус для конкретной точки тогда просто radius = startRadius + (endRadius-startRadius)*abs((angleFragment*i)/deltaAngle). Это представляет собой простую линейную интерполяцию в полярной системе координат, которая обычно используется для интерполяции вектора в матрицах и является основной функциональностью для получения приятных анимаций.

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

 vec2 start, end, center; // input values 
     float radius; // input value 

     // making the start and end relative to center 
     start -= center; 
     end -= center; 

     vec2 current = start/length(start) * radius; // current position starts in first vector 

     vec2 target = end/length(end) * radius; // should be the last point 

     outputBuffer[0] = current+center; // insert the first point 
     for(int i=1;; i++) { // "break" will need to exit the loop, we need index only for the buffer 
      vec2 step = vec2(current.y, -(current.x)); // a tangential vector from current start point according to center 
      step = step/length(step)/tessellationScale; // normalize and apply tessellation 

      vec2 next = current + step; // move tangentially 
      next = next/length(next) * radius; // normalize and set the 

      if(dot(current-target, next-target) > .0) { // when we passed the target vector 
       current = next; // set the current point 
       outputBuffer[i] = current+center; // insert into buffer 
      } 
      else { 
       current = target; // simply use the target now 
       outputBuffer[i] = current+center; // insert into buffer 
       break; // exit 
      } 
     } 
+0

Я решил проблему, просто изменив эти строки: double sLine = Math.abs (Math.toDegrees (Math.atan ((cy - start_point_y)/(cx - start_point_x)))); double eLine = Math.abs (Math.toDegrees (Math.atan ((cy - end_point_y)/(cx - end_point_x)))); int tStart = (int) (sLine + 0.5); int tEnd = (int) (eLine + 0.5); –

+0

и, наконец, это: int start_line_angle = 90 - tStart; int end_line_angle = 90 - tEnd; int temp = start_line_angle; /** * потому что угол смотрел всегда меньше, чем то угол */ окончание, если (start_line_angle> end_line_angle) { start_line_angle = end_line_angle; end_line_angle = temp; } –

+0

Ну, надеюсь, вы выполнили тесты для всех квадрантов .. Например start = (-.1, -1.0) end = (-.1, 1.0) center = (0,0) –

Смежные вопросы