3

I want to draw tow circles with the same radii but exclude the overlapped area when drawing.

enter image description here

I want to draw or set dots on gray area.

I implement the mathematical aspect behind it and here is my code:

void draw_venn(){   
        
float radian_to_degree_theta=2 * 3.14 / 360,
          r = 0.5,
          distance=0.3,
          theta=0.0,
          theta2=0.0,
          xR=0.0,
          yR=0.0,
          xG=0.0,
          yG=0.0,
          sum_radii=0,
          dis=0.0;

    sum_radii=r+r;
    for (r = 0.5; r >=0; r-=0.001)
    {
        for (float degree = 0; degree < 361; degree+=0.1)   
        {   
            theta =degree*radian_to_degree_theta;   
            xR=r*cos(theta)+distance;
            yR=r*sin(theta);
            
            xG=r*cos(theta)-distance;
            yG=r*sin(theta);

            dis=sqrt(pow(xR-xG,2) + pow(yR-yG,2));  
            if (dis <= sum_radii)   
            {
                set_point(xR,yR,0.1,1,0,0);
                set_point(xG,yG,0.1,0,1,0);
            }           
            
        }
    }
}
void set_point(float x,float y,float size,float R,float G,float B){
    glPointSize(size);
    glBegin (GL_POINTS);
    glColor3f (R, G, B);
    glVertex2f(x, y);   
    glEnd ();
}
void draw(void)
{
    glClearColor (1, 1, 1, 0);
    glClear (GL_COLOR_BUFFER_BIT);
   
    glPushMatrix(); 

    draw_ven();

    glPopMatrix ();     

    glFlush();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE);
    glutInitWindowSize(1400, 1400);
    glutInitWindowPosition(700, 500);
    glutCreateWindow("GL Sample");
    glutDisplayFunc(draw);
    glutMainLoop();
    return 0;
}

and here is the result:

enter image description here

How can I find if a point is inside the overlapping area?

fbarikzehy
  • 4,885
  • 2
  • 33
  • 39
  • Are you looking for a parity of [winding number](https://en.wikipedia.org/wiki/Winding_number) approach? – Neil Jun 18 '22 at 18:01
  • Could you include your "main" function as well that calls the "draw_venn()" function? – NoDakker Jun 18 '22 at 19:18
  • @neil no.its just a simple circle overlapping points – fbarikzehy Jun 18 '22 at 19:39
  • @httpdigest cleaned and edited the code. – fbarikzehy Jun 18 '22 at 20:03
  • 1
    sounds like task for Stencil buffer ... see [I have an OpenGL Tessellated Sphere and I want to cut a cylindrical hole in it](https://stackoverflow.com/a/39466130/2521214) so clear stencil, then increment stencil while rendering circles (with disabled color) and then render again (with enabled color) but only if stencil is `1` ... – Spektre Jun 19 '22 at 03:17
  • @Spektre no.i want a condition to find out if a point is in both circle on not. – fbarikzehy Jun 19 '22 at 13:05
  • @FereydoonBarikzehy I created answer with working C++ code ... – Spektre Jun 19 '22 at 13:48

2 Answers2

1

I reviewed and tested out your code. Trigonometry can get a bit tricky. Following is the "draw_venn" function with some refinements to produce an overlap effect.

void draw_venn()
{
    float   radian_to_degree_theta=2 * 3.141 / 360, 
            r = 0.5, 
            distance=0.3, 
            theta=0.0,
            theta2 = 0.0, 
            xR=0.0, 
            yR=0.0,
            xG=0.0, 
            yG=0.0,
            dis=0.0;

    glPointSize(1);
    glColor3f(1,0,0);
    glBegin(GL_POINTS);
    
    for (r = 0.5; r >=0; r-=0.001)
    {
        for (float degree = 0; degree < 361; degree+=0.1)
        {
            theta =degree*radian_to_degree_theta;
            theta2 = (180.0 - degree) * radian_to_degree_theta;
            xR=r*cos(theta2)+distance;
            yR=r*sin(theta2);

            xG=r*cos(theta)-distance;
            yG=r*sin(theta);

            dis = sqrt(pow((distance - xG), 2) + pow(yG, 2));
 
            if (dis < 0.5)
            {
                set_point(xR,yR,0.1,0,0,1); /* Color the overlap blue */
                set_point(xG,yG,0.1,0,0,1); /* This works due to symmetry */
            }
            else
            {
                set_point(xR,yR,0.1,1,0,0); /* Set the symmetrical circle colors */
                set_point(xG,yG,0.1,0,1,0);
            }
        }
    }
    glEnd();
}

Pointing out the two significant revisions, first I derive a mirror image value for "theta" and place that into variable "theta2". That is used to draw the red circle. This assures that the circle images are being built in equal but opposite directions so that the coordinates are symmetrical. Second, I revised the formula for checking if the green image coordinates fall within the red circle's outermost radius. Using the Pythagorean theorem calculation for the hypotenuse, the formula determines if the hypotenuse value is smaller than the outermost radius length (0.5). If it is smaller make that point for the green circle blue, and since the circle points are being built and colored symmetrically, also make the corresponding point for the red circle blue.

The result of those revisions is a Venn Diagram showing an overlap.

Venn Diagram

I hope that helps and gives you a springboard to proceed.

Regards.

NoDakker
  • 3,390
  • 1
  • 10
  • 11
  • greate job.that helped very much.Tnx – fbarikzehy Jun 19 '22 at 13:52
  • @FereydoonBarikzehy this will be horribly slooooow because its rendering pixels instead of polygon. It will also create hole artifacts unless the step is too small which will cause that many points will be rendered more than once. This approach is better suitable for shaders. If you want to go this way and old GL api then compute the intersection points and construct the outlines polygons. and just render triangle fans. If you want to render by pixels then do it properly see [Is there a more efficient way of texturing a circle?](https://stackoverflow.com/a/61097673/2521214) – Spektre Jun 19 '22 at 17:16
  • @FereydoonBarikzehy do not forget to use pixel size as step ... I added much faster example than this using GL_POINTS to my answer – Spektre Jun 19 '22 at 17:51
  • @Spektre thank you very much.yes i optimized the code for large rendering also. – fbarikzehy Jun 19 '22 at 18:28
1
  1. Add 8bit Stencil Buffer to your context

    I do it by setting up pixelformat like this:

     PIXELFORMATDESCRIPTOR pfd;
     ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
     pfd.nSize = sizeof( pfd );
     pfd.nVersion = 1;
     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
     pfd.iPixelType = PFD_TYPE_RGBA;
     pfd.cColorBits = 24;
     pfd.cDepthBits = 24;
     pfd.cStencilBits = 8;
     pfd.iLayerType = PFD_MAIN_PLANE;
     SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
    
  2. Enable and Clear Stencil with 0 and setup it for incrementation

  3. Disable color and depth output

  4. Render circles

  5. Enable color and depth output

  6. Set up Stencil test to not equal 2

    You can also use equal to 1 in case you overlap more than just 2 objects

  7. Render circles

  8. Disable Stencil test

I see it like this:

//---------------------------------------------------------------------------
void glCircle(float x,float y,float r)
    {
    int e;
    float a,da=2.0*M_PI/72.0;
    glBegin(GL_TRIANGLE_FAN);
    glVertex2f(x,y);
    for (e=1,a=0.0;e;a+=da)
        {
        if (a>=2.0*M_PI) { e=0; a=0.0; }
        glVertex2f(x+(r*sin(a)),y+(r*cos(a)));
        }
    glEnd();
    }
//---------------------------------------------------------------------------
void gl_draw()
    {
    glClearColor(1.0,1.0,1.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT);

    float aspect=float(xs)/float(ys);   //xs,ys is screen resolution
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glScalef(1.0,aspect,1.0);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_TEXTURE_2D);

    // turn off color,depth
    glStencilMask(0xFF);
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
    glDepthMask(GL_FALSE);
    // clear stencil and setup it for increment
    glEnable(GL_STENCIL_TEST);
    glClearStencil(0);
    glClear(GL_STENCIL_BUFFER_BIT);
    glStencilFunc(GL_ALWAYS,1,0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
    // render stencil
    glCircle(-0.3,0.0,0.6);
    glCircle(+0.3,0.0,0.6);
    // turn on color,depth
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    glDepthMask(GL_TRUE);
    // render screen (where Stencil is not 2)
    glStencilFunc(GL_NOTEQUAL,2,0xFF);
    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
    glColor3f(1.0,0.0,0.0); glCircle(-0.3,0.0,0.6);
    glColor3f(0.0,1.0,0.0); glCircle(+0.3,0.0,0.6);
    glDisable(GL_STENCIL_TEST);

    glFlush();
    SwapBuffers(hdc);
    }
//---------------------------------------------------------------------------

And output:

preview

In case you also want to know if pixel is inside both circles you can use:

GLint a;
glReadPixels(X,ys-1-Y,1,1,GL_STENCIL_INDEX,GL_INT,&a);
if (a==2); // X,Y is inside both circles
else;      // X,Y is not inside both circles

In case You insist on rendering the stuff pixel by pixel then do it at least properly As your current approach is horibly slow for many reasons... For example you can do this like this:

glClearColor(1.0,1.0,1.0,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glTranslatef(-1.0,-1.0,0.0);
glScalef(2.0/xs,2.0/ys,1.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

int x0=(4*xs)/10,y0=ys/2,r0=xs/4;   // circle0
int x1=(6*xs)/10,y1=ys/2,r1=xs/4;   // circle1
int x,y,xx0,xx1,yy0,yy1,rr0=r0*r0,rr1=r1*r1;
glBegin(GL_POINTS);
glColor3f(1.0,0.0,0.0);
for (x=-r0;x<=r0;x++){ xx0=x; xx0*=xx0; xx1=x+x0-x1; xx1*=xx1;
 for (y=-r0;y<=r0;y++){ yy0=y; yy0*=yy0; yy1=y+y0-y1; yy1*=yy1;
  if (xx0+yy0<=rr0)
   if (xx1+yy1>=rr1)
    glVertex2i(x0+x,y0+y); }}
glColor3f(0.0,1.0,0.0);
for (x=-r1;x<=r1;x++){ xx1=x; xx1*=xx1; xx0=x+x1-x0; xx0*=xx0;
 for (y=-r1;y<=r1;y++){ yy1=y; yy1*=yy1; yy0=y+y1-y0; yy0*=yy0;
  if (xx1+yy1<=rr1)
   if (xx0+yy0>=rr0)
    glVertex2i(x1+x,y1+y); }}
glEnd();

glFlush();
SwapBuffers(hdc);

Where xs,ys is GL screen resolution.

See related:

Spektre
  • 49,595
  • 11
  • 110
  • 380