在opengl GL10中画一个圆弧

时间:2015-12-09 05:05:48

标签: java android opengl-es automatic-ref-counting

我想在opengl surfaceview上使用中心点,起点,终点绘制弧线。到目前为止,我已尝试过以下代码。如果我们手动给出 start_line_angle end_line_angle 的值,则此函数会绘制预期的弧(例如 start_line_angle = 0且 end_line_angle = 90)度。

但是我需要用给定的坐标绘制圆弧(中心点,起点,终点)并以编程方式计算 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);
    }

1 个答案:

答案 0 :(得分:0)

要从三角学开始,您可能不会简单地使用atan来查找角度。您需要检查向量所在的象限,并增加或减少从atan获得的结果。更好的是使用atan2,其中应包含dxdy并为您完成工作。

您似乎创建了缓冲区,以便按度数创建一个点。对于可能太小的大半径而言,这不是最佳解决方案,对于小半径而言,这太过分了。细分也应该包括半径,使点数NN = 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个点作为中心和两个边界。其他一些通常有意义的选择是:

  • 从起始线获取半径
  • 从两条线中较短的一条获得半径
  • 得到两个人的平均值
  • 插入两个以获得椭圆曲线(如下所述)

要插入半径,您需要获得两个半径startRadiusendRadius。然后你需要找到上面已经用作deltaAngle的整体半径(在计算这个时要注意,它看起来更复杂,例如从320度到10度绘制会产生{{1} })。无论如何,特定点的半径只是deltaAngle = 50。这表示极坐标系统中的简单线性插值,通常用于在矩阵中插入向量,是获得精美动画的核心功能。

还有其他一些方法可以获得更好的性能,但我不会建议它们,除非你需要优化你的代码,这应该是非常晚的生产。您可以简单地继续走向下一个点并修正半径(这只是一个概念):

radius = startRadius + (endRadius-startRadius)*abs((angleFragment*i)/deltaAngle)