Reputation: 145
I'm making a program that's a bit like Paint
light, and I've gotten to the point where I want the user to be able to select elliptical regions. My initial thought is that there must be some kind of equation that allows me to construct an ellipse based on the width and height of a rectangle. However, I've thus far not found anything quite so straight forward.
Here is my code for selecting a rectangular region when the user drags the mouse (this is located inside a MouseAdapter):
@Override
public void mouseDragged(MouseEvent e) {
dragPoint = e.getPoint();
if (selectionType.equalsIgnoreCase("Rectangle")) {
int width = dragPoint.x - mouseAnchor.x;
int height = dragPoint.y - mouseAnchor.y;
subHeight = height;
subWidth = width;
int x = mouseAnchor.x;
int y = mouseAnchor.y;
if (width < 0) {
x = dragPoint.x;
width *= -1;
}
if (height < 0) {
y = dragPoint.y;
height *= -1;
}
selectionPane.setBounds(x, y, width, height);
selectionPane.revalidate();
repaint();
}
}
SelectionPane
is an instance of a custom class that extends JPanel
. The idea is that I want to draw a filled ellipse from the selected region, so the user can see what they've selected.
The second part of this program is where I'm also hitting some confusion. After the user makes his or her selection, I want to apply a mask to the image bits using the selected region as a guide. So I'm also working with byte arrays. How do I find which bytes are encompassed in a calculated oval based on the width, height, and origin of the sub image? Below is the code where I get the sub image based on a rectangular selection (for reference):
@Override
public void mouseReleased(MouseEvent e) {
if (subWidth != 0 && subHeight != 0) {
try {
//numCols * (numRows - 1) + xPos
int startPos = img.getWidth() * (img.getHeight() - 1) + mouseAnchor.x;//the starting position for the total byte array of the original image. The mask will start here.
Main.setStartingPos(startPos);
Main.setSubImage(img.getSubimage(mouseAnchor.x, mouseAnchor.y, Math.abs(subWidth), Math.abs(subHeight)));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(Main.getSubImage(), "bmp", baos);
Main.setImageRegion(baos.toByteArray()); //sets the region bytes in the Main class
Main.generateImageMask();//generates the mask after everything's been calculated.
} catch (IOException ex) {
Logger.getLogger(SelectionRectangle.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Let me know if there's any way I can make my question more clear.
Upvotes: 0
Views: 491
Reputation: 2682
You can get the ellipse from the rectangle as follows:
Ellispe2D.Double el=new Ellispe2D.Double(x, y, width, height);
Then you can mask the positions covered under the ellipse as follows:
Rectangle r=el.getBounds();
for(i=0; i<r.width; i++)
for(j=0; j<r.height; j++)
if(el.contains(r.x+i, r.y+j)) ... do whatever with this pixel add it to a list etc
--
For pixel r.x+i, r.y+j you can get the RGB and from this the individual bytes:
int pixel=image.getRGB(r.x+i, r.y+j);
int red=(pixel&0x00ff0000)>>16, green=(pixel&0x0000ff00)>>8, blue=pixel&0x000000ff;
Upvotes: 1
Reputation: 51845
for axis alligned ellipse use parametric equation (centric)
x = x0 + rx*cos(a)
y = y0 + ry*sin(a)
x0,y0
is ellipse center
rx,ry
are semi axises sizes (half size of your rectangle sides)
a
is angle of point you want to obtain
the region is usually selected by angle interval. The angles are usually determined by a line from center (x0,y0
) to actual mouse position (mx,my
) or some control point as
ai = atan2(my-y0,mx-x0)
so a = < a0,a1 >
where ai = { a0,a1 }
are your interval angles. for full ellipse a =< 0,2*M_PI> [rad]
That is just circle approximation of angle so if you want to get more precise angle look for
Or apply circle/ellipse correction scaling ...
Upvotes: 1