Home > Enterprise >  Is there a way to make a circle cover up another circle inside when I shrink the outer circle
Is there a way to make a circle cover up another circle inside when I shrink the outer circle

Time:09-17

I'm trying to make an eye because why not, so I am trying to make a blinking animation.

Instead of closing the "eyelid" circle, I have chosen to shrink sclera (white bit) along the y-axis so it looks like the eye is closing.

Now I am adding the colored cornea in the center, but when I try to shrink the cornea when the yvalues of the sclera and cornea meet, the cornea looks weird like it is being squished.

Is the any method that would make it so that when I shrink the sclera-circle, the cornea circle would disappear when the bounds of the outer circle are smaller than the inner circle?

Basically like what happens when you resize a JPanel to be smaller than the components. They just disappear under the border of the frame rather than appear outside it.

Code: class for panel:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class EyePanel extends JPanel implements ActionListener{

    private int width;
    private int height;

    private int timeStep = 10;
    
    private Timer timer;
    private Random random;
    
    Eye eye;
    
    EyePanel(int width, int height){
        this.width = width;
        this.height = height;
        
        eye = new Eye(width, height, timeStep);
        
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        this.setPreferredSize(new Dimension(width, height));
        
        
        frame.add(this);
        frame.pack();
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        
        
        timer = new Timer(timeStep, this);
        random = new Random();
        
        timer.start();
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        this.setBackground(new Color(255,255,255));
        
        draw(g);
    }
    
    public void draw(Graphics g) {
        eye.draw(g);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        repaint();
    }
}

class for eye:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.*;
import javax.swing.*;

public class Eye {

    private int width;
    private int height;
    private int timeStep;
    private int lidDiameter;
    private int sclDiameter;
    private int corDiameter;

    //lid coordinates
    private int lidX;
    private int lidY;

    //sclera coordinates
    private int sclX;
    private int sclY;
    private int sclU;           //upper level
    private int sclB;           //bottom level
    private int sclC;           //y-level at which eyes are closed

    //cornea coordinates
    private int corX;
    private int corY;
    private int corU;           //upper level
    private int corB;           //bottom level
    private int corC;           //y-level at which eyes are closed

    private int blinkDelay = 3; //delay in seconds preset
    private int blinkTime;      //time till next blink
    private int rate = 20;          //rate of eye close&open

    private boolean closed = false;

    Eye(int width, int height, int timeStep){
        this.width = width;
        this.height = height;
        this.timeStep = timeStep;

        blinkTime = blinkDelay*(1000/timeStep);

        //setup eye variables
        if(width>height)        lidDiameter = height - (height/10);
        else if(height>width)   lidDiameter = width - (width/10);
        else                    lidDiameter = width - (height/10);
        
        sclDiameter = lidDiameter-(lidDiameter/10);
        corDiameter = sclDiameter/3;

        //lid location
        lidX = (int)((width-lidDiameter)/2);
        lidY = (int)((height-lidDiameter)/2);
        //lid location
        
        //sclera location
        sclX = (int)(lidX   (lidDiameter-sclDiameter)/2);
        sclY = (int)(lidY   (lidDiameter-sclDiameter)/2);
        sclU = sclY;
        sclB = sclDiameter;
        sclC = (int)(sclY sclDiameter/2);
        //sclera location
        
        //cornea location
        corX = (int)(sclX   (sclDiameter-corDiameter)/10);
        corY = (int)(sclY   (sclDiameter-corDiameter)/10);
        corU = corY;
        corB = corDiameter;
        corC = (int)(corY corDiameter/2);
        //cornea location
        
        //setup eye variables
    }

    public void close() {
        if(sclU != sclC)
            sclU = rate;

        if(sclB != sclC)
            sclB-= rate*2;          //bottom limit must rise by (required amt   rate of upper limit fall)

        if(sclU >= sclC && sclB <= sclC)
            closed = true;
    }

    public void open() {
        if(sclU != sclY)
            sclU = -rate;

        if(sclB != sclDiameter)
            sclB-= -rate*2;         //bottom limit must rise by (required amt   rate of upper limit fall)

        if(sclU == sclY && sclB == sclDiameter) {
            closed = false;
            blinkTime = blinkDelay*(1000/timeStep);
        }
    }

    public void blink() {
        if(blinkTime == 0) {
            if(!closed)
                close();
            if(closed)
                open();
        }
        else
            blinkTime--;
    }

    public void draw (Graphics g) {
        Graphics2D g2d = (Graphics2D) g;

        //eyelid
        g2d.setColor(Color.pink);
        g2d.fillOval(lidX, lidY, lidDiameter, lidDiameter);

        //sclera
        g2d.setColor(Color.white);
        g2d.fillOval(sclX, sclU, sclDiameter, sclB);

        g2d.setColor(Color.black);
        g2d.drawLine(sclX, sclC, sclX   sclDiameter, sclC);

        //cornea
        g2d.setColor(Color.cyan);
        g2d.fillOval(corX, corU, corDiameter, corB);

        g2d.setColor(Color.red);
        g2d.drawLine(corX, corC, corX   corDiameter, corC);

        //trigger blink
        blink();
    }
}

Main class that starts everything:

public class Main {

    public static void main(String[] args) {
        new EyePanel(600, 600);
    }
}

CodePudding user response:

Under no circumstances should a painting method call any form of logic that alters object state. Painting is triggered by system events and you have very little control over its timing. (Examples of such events are a user moving the window, lowering or raising the window, deiconifying the window, unlocking the screen, and even moving the mouse over the window.)

So, the first thing you want to do is remove this from the Eye class:

//trigger blink
blink();

…and add it to your actionPerformed method:

@Override
public void actionPerformed(ActionEvent e) {
    eye.blink();
    repaint();
}

Nearly all Swing methods and constructors must be run on the AWT event dispatch thread, so change your main method to do that:

public static void main(String[] args) {
    EventQueue.invokeLater(() -> new EyePanel(600, 600));
}

Your code doesn’t do exactly what you claim (the cornea/iris is not in the center), but I think your question is answerable. The Area class can be used to check whether shapes intersect:

public void draw (Graphics g) {
    Graphics2D g2d = (Graphics2D) g;

    //eyelid
    g2d.setColor(Color.pink);
    g2d.fillOval(lidX, lidY, lidDiameter, lidDiameter);

    //sclera
    Area sclera = new Area(
        new Ellipse2D.Float(sclX, sclU, sclDiameter, sclB));
    g2d.setColor(Color.white);
    g2d.fill(sclera);

    g2d.setColor(Color.black);
    g2d.drawLine(sclX, sclC, sclX   sclDiameter, sclC);

    //cornea
    Area cornea = new Area(
        new Ellipse2D.Float(corX, corU, corDiameter, corB));
    Area hiddenCornea = (Area) cornea.clone();
    hiddenCornea.subtract(sclera);
    if (hiddenCornea.isEmpty()) {
        g2d.setColor(Color.cyan);
        g2d.fill(cornea);

        g2d.setColor(Color.red);
        g2d.drawLine(corX, corC, corX   corDiameter, corC);
    }
}

This will skip drawing the cornea if any part of the cornea is hidden (does not intersect the sclera).

  • Related