Нарисуйте изогнутую линию от края дуги

Вот скриншот того, что я делаю. В настоящее время я не могу нарисовать изогнутые границы в этом прямоугольнике.

Неее

Моим первым решением было: нарисовать четверть круга за прямоугольником, но если я отрегулирую непрозрачность фигуры, как вы можете видеть, четверть круга будет показана.

neeh

Я знаю, это довольно просто для вас, ребята, но я не очень хорош в математике.

Я попытался повторно использовать вычисленные ребра дуги и добавить размер границы, но в результате получил это.

niih

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

Вот код, как я рисую внутренний круг, и я думаю, что я могу просто использовать его снова.

void drawArc(int x, int y,
int startAngle, int endAngle,
uint32_t radiusX, uint32_t radiusY,
int border_x, int border_y,
const rgb color,
const rgb bcX, const rgb bcY,
uint8_t opacity)
{
if (radiusX <= 0 || radiusY <= 0) return;

static constexpr float DTR = 3.14159 / 180;

float cx, cy;
int step;

static std::vector<float> verts;
static std::vector<uint8_t> colors;

if (startAngle < endAngle)
{
step = +1;
++ endAngle;
} else
{
step = -1;
-- endAngle;
}

verts.clear();
colors.clear();

verts.push_back(x);
verts.push_back(y);

colors.push_back(color[R]);
colors.push_back(color[G]);
colors.push_back(color[B]);
colors.push_back(opacity);

while (startAngle != endAngle)
{
cx = cos(DTR * startAngle) * radiusX;
cy = sin(DTR * startAngle) * radiusY;

verts.push_back(x + cx);
verts.push_back(y - cy);

colors.push_back(color[R]);
colors.push_back(color[G]);
colors.push_back(color[B]);
colors.push_back(opacity);

startAngle += step;
}

drawElements(GL_POLYGON, sizeof(arcIndices) / sizeof(arcIndices[0]), GL_FLOAT,
&verts[0], &colors[0], &arcIndices[0]);

if (border_x != 0 || border_y != 0)
{
//remove (x, y)
verts.erase(verts.begin(), verts.begin() + 2);

//        float px, py;
//
//        px = *(verts.begin() + 0);
//        py = *(verts.begin() + 1);
//
//        glPointSize(5);
//
//        glBegin(GL_POINTS);
//
//        glColor3ub(0,0,255);
//        glVertex2i(px, py);
//
//        px = *(verts.end() - 2);
//        py = *(verts.end() - 1);
//
//        glColor3ub(255,0,0);
//        glVertex2i(px , py);
//        glEnd();

//attempting to reuse the edges
//I think the last vertices are opposed
//that's why I got a crossed out lines??
for (int i = 0;i <= 90; ++i)
{
verts.push_back(verts[i + 0] + border_x);
verts.push_back(verts[i + 1] + border_y);

colors.push_back(bcX[R]);
colors.push_back(bcX[G]);
colors.push_back(bcX[B]);
colors.push_back(opacity);
}

//91 = steps from 0-90 degree revolution
//182 = 91 * 2
unsigned int index[182 + 91 * 2];
for (int i = 0;i < 182 + 91 * 2; ++i)
index[i] = i;

drawElements(GL_LINE_LOOP, verts.size() / 2, GL_FLOAT,
&verts[0], &colors[0], &index[0]);
}

}

Редактировать:

Разве я не могу просто использовать предварительно рассчитанный (x, y) раньше?

Нух

Извините за слишком большое использование фотографий

Красные точки предварительно рассчитаны (x, y), о которых я говорю, и просто добавьте следующую базу дуг к этому.

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

Обновить:

И вот результат, который я получил от использования stencil buffer как, что Андон М. Коулман предложил:

nuuh

Кстати, как вы можете видеть, я пытаюсь эмулировать свой собственный интерфейс с помощью OpenGL: D

1

Решение

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

glClearStencil (0x0);
glClear        (GL_STENCIL_BUFFER_BIT);

glEnable       (GL_STENCIL_TEST);
glStencilFunc  (GL_ALWAYS, 0x0, 0x0);

// Add 1 to stencil buffer at every location the object to be bordered is visible
glStencilOp    (GL_KEEP, GL_KEEP, GL_INCR);

// Draw your grey object

// Only draw the red border where the grey object was never drawn (stencil = 0x0)
glStencilFunc  (GL_EQUAL, 0x0, 0xff);

// Draw your red quarter circles

glDisable     (GL_STENCIL_TEST);

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

Конечно, чтобы это работало, ваш формат пикселей должен иметь трафаретный буфер. Мне придется оставить эту часть на ваше усмотрение, потому что процесс ее настройки зависит от конкретной реализации.

1

Другие решения

GL_POLYGON только для выпуклый многоугольники.

Соедините вершины на вашем внутреннем и внешнем радиусах, чтобы сформировать четырехугольники / треугольники:

частичный тор

#include <GL/glut.h>
#include <cmath>

void Torus2d
(
float angle,            // starting angle in radians
float length,           // length of arc in radians, >0
float radius,           // inner radius, >0
float width,            // width of torus, >0
unsigned int samples    // number of circle samples, >=3
)
{
if( samples < 3 ) samples = 3;
const float outer = radius + width;
glBegin( GL_QUAD_STRIP );
for( unsigned int i = 0; i <= samples; ++i )
{
float a = angle + ( i / (float)samples ) * length;
glVertex2f( radius * cos( a ), radius * sin( a ) );
glVertex2f( outer * cos( a ), outer * sin( a ) );
}
glEnd();
}

void display()
{
glClear( GL_COLOR_BUFFER_BIT );

glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
double ar = w / h;
glOrtho( -4 * ar, 4 * ar, -4, 4, -1, 1);

glMatrixMode( GL_MODELVIEW );
glLoadIdentity();

glColor3ub( 255, 0, 0 );
Torus2d( 0, 1.57079633, 2, 1, 20 );

glutSwapBuffers();
}

int main( int argc, char **argv )
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutInitWindowSize( 640, 480 );
glutCreateWindow( "GLUT" );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
1

По вопросам рекламы [email protected]