Draw a circle on each edge of an n-polygon - java

Given a list of n circles, each of diameter d, I want to generate an n-gon (polygon of n lengths), with side lengths d, and draw a circle on each of its edges.
I encountered this problem while developing an application.
The formula for the radius of the polygon with N sides, given a length a for each side, is
My code
Game Frame
import javax.swing.JFrame;
public class gameFrame extends JFrame{
static int width = 400;
static int height = 400;
public static void main(String[] args) {
gameFrame frame = new gameFrame();
gamePanel panel = new gamePanel();
frame.add(panel);
frame.setTitle("Tutorial");
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setResizable(true);
panel.initializeList();
panel.fpsTimer.start();
}
}
Game Panel
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Arc2D;
import java.util.ArrayList;
import javax.swing.JPanel;
import javax.swing.Timer;
public class gamePanel extends JPanel{
static ArrayList<Point2D> coordinates = new ArrayList<Point2D>();
static int d = 20;
Timer fpsTimer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//paint the circles with the coordinates in list 'coordinates'
for(Point2D point : coordinates) {
g2d.setColor(Color.BLACK);
Shape circle = new Arc2D.Double(point.x,
point.y,
d,
d,
0 , 360, Arc2D.CHORD);
g2d.fill(circle);
}
}
public void initializeList() {
Point2D center = new Point2D(0,0);
int n = 15; // number of sides of polygon
float alpha = 360/ n; // angle of each triangle in the polygon
float angle = 0; // incremental angle for the loop
float side = d; // desired length of each side
float radius = (float) (side / (2*Math.sin(Math.PI / n))); // R = a / (2*(sin(PI/n))) formula
//verifying that the circle radius isn't larger than the frame
if(!(radius >= gameFrame.width || radius >= gameFrame.height)) {
//center of the circle
center.x = (gameFrame.width)/2;
center.y = (gameFrame.height)/2;
for(int i = 0 ; i < n ; i++) {
coordinates.add(new Point2D((center.x + Math.sin(angle)*radius),
(center.y -Math.cos(angle)*radius)));
angle += alpha;
}
}
}
}
Point2D (for simplicity)
public class Point2D {
double x;
double y;
public Point2D(double x , double y) {
this.x = x;
this.y = y;
}
}
The outputs and reflection
For n=15 and d=20 as shown above, the output is
Some circles overlap.
Surprisingly, if I modify angle += alpha to angle += alpha+0.295; in GamePanel initializeList(), I get the desired result :
For n=14 the output is even scarier :
I have spent a ridiculous amount of time on this bug. Does anyone have any idea what is going wrong?

Java Math uses angles in radians. So calculate alpha in radians like this:
double alpha = Math.toRadians(360.0/ n);
Just update the line and it should fix the issue.
Also, for more accuracy use double type instead of float for each variable.

Related

Need to draw projectile motion of a thrown ball

So I'm writing a code that allows a user to throw an imaginary object at an initial angle and speed to see if they can come close to hitting a ball (that is positioned based on user input).
However, I'm having trouble drawing the curve of the users inputted angle and speed of the imaginary object.
I've used a mathematical formula to calculate the total time and range of said object. That is:
π‘Ÿπ‘Žπ‘›π‘”π‘’= 𝑣02sin⁑(2πœƒπœ‹/180)𝑔
π‘‘π‘œπ‘‘π‘Žπ‘™ π‘‘π‘–π‘šπ‘’= 2𝑣0sin⁑(πœƒπœ‹/180)𝑔
I've already tried attempting to put range and total time into an arc and plotting it that way. But that didn't seem to work.
Here's the code:
import java.awt.AWTEvent;
import java.awt.*;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.util.Scanner;
import java.awt.geom.QuadCurve2D;
public class BallGame extends JFrame {
public static void main (String[]args)
{
Scanner cool= new Scanner(System.in);
double angle, speed, range, totalTime;
{
JFrame frame = new JFrame (" Throwing Ball");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,700);
}
{
System.out.println("Please enter the location of the ball (0 < X < 1)");
StdDraw.setPenRadius(0.06);
StdDraw.setPenColor(StdDraw.BLUE);
double x, y;
y = 0;
x = cool.nextDouble();
StdDraw.point(x, y);
}
System.out.println("Please enter an angle of your choosing:");
angle = cool.nextDouble();
System.out.println("Please enter the speed at wish you which to throw the ball");
speed = cool.nextDouble();
double g;
g = 9.8;
range = Math.pow(speed, 2) * Math.sin(2 * angle * (Math.PI / 180) / g);
totalTime = (2 * speed * Math.sin(angle * Math.PI / 180)) / g;
For drawing a curve you need to calculate horizontal (x) and vertical (y) position, as a function of time, start point, start speed and angle.
In other words, calculate the horizontal distance, and vertical distance.
The equations are well known and widely available.
You use these equations to repeatedly calculate x,y and then repaint.
See the following demonstration. Not the comments :
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BalisticCurve extends JFrame {
private static final double G = 9.8; //positive because Y axis is positive going down
private int animationSpeed = 5; //millis. The smaller the faster
private static int size = 900, ballDiameter = 10;
private double startX, startY, ballX, ballY;
private double xSpeed, ySpeed, lastPointX, lastPointY;
private double time, deltaTime = 0.01 ; //in seconds
private List<Point2D> curvePoints= new ArrayList<>();
private Timer timer;
BalisticCurve(){
super("Balistic Curve");
DrawBoard board = new DrawBoard();
add(board, BorderLayout.CENTER);
ballX= lastPointX = startX = 50;
ballY = lastPointY = startY = size - 100;
getUserInput();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
timer = new Timer(animationSpeed, new ActionListener() {
#Override
public void actionPerformed(ActionEvent event) {
board.moveBall();
board.repaint();
if(! inBounds()) {
timer.stop();
}
}
});
timer.start();
}
private void getUserInput() {
double angle = 45;//todo replace with user input + verification
double speed = 100;
xSpeed = speed * Math.cos(angle * (Math.PI / 180));
ySpeed = speed * Math.sin(angle * (Math.PI / 180));
}
private boolean inBounds() {
//ignore if ball exceeds height
if((ballX < 0) || (ballX > (getWidth()))
|| ( ballY > (getHeight() - ballDiameter) ) ) {
return false;
}
return true;
}
class DrawBoard extends JPanel {
public DrawBoard() {
setPreferredSize(new Dimension(size, size));
}
#Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.RED);
g2d.fillOval((int)ballX,(int)ballY,ballDiameter,ballDiameter);
if((Math.abs(lastPointX - ballX)>=1) && (Math.abs(lastPointY - ballY)>=1) ) {
curvePoints.add(new Point2D.Double(ballX, ballY));
lastPointX = ballX; lastPointY = ballY;
}
drawCurve(g2d);
}
private void drawCurve(Graphics2D g2d) {
g2d.setColor(Color.BLUE);
for(int i=0; i < (curvePoints.size()-1); i++) {
Point2D from = curvePoints.get(i);
Point2D to = curvePoints.get(i+1);
g2d.drawLine((int)from.getX(),(int)from.getY(), (int)to.getX(), (int)to.getY());
}
}
private void moveBall() {
ballX = startX + (xSpeed * time);
ballY = startY - ((ySpeed *time)-(0.5 *G * Math.pow(time, 2))) ;
time += deltaTime;
}
}
public static void main(String[] args) {
new BalisticCurve();
}
}
Don't hesitate to ask what is not clear enough.

How to find y-intercept of a parallel line with a certain distance from another line

I am using Java and a JPanel to draw a red line. The red line can have any slope and y-intercept, but both are calculated.
A yellow parallel line needs to be drawn 250px away from from the red line. How would one calculate the y-intercept of the yellow parallel line?
The following picture is an example of what the red and yellow lines could look like. Also since this is a JPanel, the origin is in the top left and the y values are all positive.
y-intercept diagram:
From the slope, you can compute the angle that the line has to the x-axis, as
double angleRad = Math.atan(slope);
This is also the angle at the 0,?? corner of the little triangle in your image (the angle that you painted in gray is a right angle).
Recalling that
side adjacent to angle a
cos(a) = -------------------------
hypotenuse
and given that you have the desired length of the side adjacent to angle a (namely, the length of your blue line, which should be 250), you can compute the length of the hypotenuse as
hypotenuse = 250 / cos(a)
which is basically how much you have to shift the red line in (negative) y-direction to obtain the yellow line. Note that this will obviously approach infinity when the angle approaches 90Β°....
An MCVE, for a quick test:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class ParallelLineInterceptTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ParallelLineInterceptTestPanel p = new ParallelLineInterceptTestPanel();
JPanel controlPanel = new JPanel(new GridLayout(1,0));
controlPanel.add(new JLabel("slope: ", SwingConstants.RIGHT));
JSlider slopeSlider = new JSlider(0, 1000, 50);
slopeSlider.addChangeListener(e ->
{
int slopeValue = slopeSlider.getValue();
p.setSlope(slopeValue / 100.0);
});
controlPanel.add(slopeSlider);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(controlPanel, BorderLayout.NORTH);
f.getContentPane().add(p, BorderLayout.CENTER);
f.setSize(1200,800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ParallelLineInterceptTestPanel extends JPanel
{
private double slope;
private double yIntercept;
public ParallelLineInterceptTestPanel()
{
this.slope = 0.5;
this.yIntercept = 500;
}
public void setSlope(double slope)
{
this.slope = slope;
repaint();
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
double x0 = 0;
double y0 = yIntercept;
double x1 = getWidth();
double y1 = y0 + slope * getWidth();
g.setColor(Color.RED);
g.draw(new Line2D.Double(x0, y0, x1, y1));
double distance = 250.0;
double angleRad = Math.atan(slope);
double offsetY = distance / Math.cos(angleRad);
double px0 = x0;
double py0 = y0 - offsetY;
double px1 = x1;
double py1 = y1 - offsetY;
g.setColor(Color.ORANGE);
g.draw(new Line2D.Double(px0, py0, px1, py1));
}
}

Drawing a Line - Maximum Point

I drew a line that is at an angle based on a slider.
I am trying to make the line's end Y coordinate a certain number (let's say 300), even if it is at an angle.
Any ideas on how to do this? Here is the work on my line so far:
double angle = intAngle;
angle = angle * Math.PI / 180;
double length = 300;
graphics.setColor(Color.RED);
double startX = 300;
double startY = 100;
double endX = startX + length * Math.cos(angle);
double endY = startY + length * Math.sin(angle);
double end2X;
double end2Y;
double dblAngle;
double angle2;
int intAngle2;
double start2X = endX;
double start2Y = endY;
intAngle2 = 180 - intAngle;
angle2 = intAngle2;
angle2 = (angle2 * Math.PI / 180);
end2X = (start2X - length * Math.cos(angle2));
end2Y = (start2Y - length * Math.sin(angle2));
int intEndX = (int)endX;
int intEndY = (int)endY;
if(blnButton == true){
graphics.draw(new Line2D.Double(startX, startY, endX, endY));
graphics.draw(new Line2D.Double(start2X, start2Y, end2X, end2Y));
}
There's probably a simpler way, but basically, you can calculate two points on a circle based on the angle and the inverse of the angle (angle - 360)
With a circle with a radius of 150, this will give you a line of 300, for example
The red line is the line from the center of the circle to point on the circle represented by the given angel. The blue is the inverse. Each line is 150 pixels line, meaning together, they are 300 pixels in length.
This examples draws the separately, but realistically, they could be draw as a single line
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
DrawPane drawPane = new DrawPane();
add(drawPane);
JSlider slider = new JSlider(0, 100);
add(slider, BorderLayout.SOUTH);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
drawPane.setAngleInDegrees(360d * (slider.getValue() / 100d));
}
});
slider.setValue(0);
}
}
public class DrawPane extends JPanel {
private double angle;
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
// Radius of the circle
double r = 150;
// Degrees to radians...
double radians = Math.toRadians(angle);
// The end point on the circle...
int endX = (int) Math.round(r * Math.cos(radians));
int endY = (int) Math.round(r * Math.sin(radians));
// The start point on the circle, 360 degress from the
// start angle
radians = Math.toRadians(angle - 360);
int startX = (int) Math.round(r * Math.cos(radians));
int startY = (int) Math.round(r * Math.sin(radians));
// Offset for the ellipse (center of the screen)
double x = (getWidth() / 2d) - r;
double y = (getWidth() / 2d) - r;
g2d.setColor(Color.LIGHT_GRAY);
g2d.draw(new Ellipse2D.Double(x, y, r * 2, r * 2));
// Center of the circle...
x = (getWidth() / 2d);
y = (getWidth() / 2d);
// One single line
//g2d.setColor(Color.BLACK);
//g2d.draw(new Line2D.Double(x - startX, y - startY, x + endX, y + endY));
g2d.setColor(Color.RED);
g2d.draw(new Line2D.Double(x, y, x - startX, y - startY));
g2d.setColor(Color.BLUE);
g2d.draw(new Line2D.Double(x, y, x + endX, y + endY));
g2d.dispose();
}
public void setAngleInDegrees(double value) {
if (angle != value) {
angle = Math.min(Math.max(value, 0), 360);
repaint();
}
}
}
}
or something along those lines...

How does Affine Transform works in this code?

The following code works correctly, but I'm having trouble understanding some of the details. Can somebody help me understand how the AffineTransform is working to rotate the image?
package pks;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class rotate {
public static void main(String[] args) {
new rotate();
}
public rotate() {
EventQueue.invokeLater(new Runnable() {
public void run() {
final RotationPane rotationPane = new RotationPane(); // initilize object of RotationPane class
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(rotationPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RotationPane extends JPanel {
private BufferedImage img;
private BufferedImage rotated;
private double angle;
public RotationPane() {
try {
img = ImageIO.read(new File("C:\\Users\\pardeep\\Desktop\\tomb1.jpg")); // path of the image to be rotated
setAngle(45);
}
catch (IOException ex) {
}
}
public void setAngle(double angle) {
this.angle = angle;
// Using Affine transform we will calculate the new values
//x=vcos (theta)+wsin(theta)
//y=vcos(theta)+ wsin(theta)
double rads = Math.toRadians(angle); // calculating angle in radian
double sin = Math.abs(Math.sin(rads)), //calculating sin theta
cos = Math.abs(Math.cos(rads)); // calculating cos theta
int w = img.getWidth();
int h = img.getHeight();
int newWidth = (int) Math.floor(w * cos + h * sin); //using affine transform
int newHeight = (int) Math.floor(h * cos + w * sin);
rotated = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = rotated.createGraphics(); //rotating planes.....
AffineTransform plane = new AffineTransform();
plane.translate((newWidth - w) / 2, (newHeight - h) / 2);
int x=w/2;
int y=h/2;
plane.rotate(Math.toRadians(45), x, y);
g2d.setTransform(plane);
g2d.drawImage(img, 0, 0, this);
}
public Dimension getPreferredSize() {
return new Dimension(800, // setting the window size
800);
}
protected void paintComponent(Graphics g) {
// super.paintComponent(g); no need for it
if (rotated != null) { // drawing image on 2 dimentional size surface
Graphics2D g2d = (Graphics2D) g.create();
int x = (getWidth() - rotated.getWidth()) / 2;
int y = (getHeight() - rotated.getHeight()) / 2;
g2d.drawImage(rotated, x, y, this); // overriding the method......
}
}
}
}
What exactly don't you understand? plane.rotate(Math.toRadians(45), x, y); rotates the image around the center point clockwise by 45 degrees. plane.translate((newWidth - w) / 2, (newHeight - h) / 2); is the same as plane.translate(newWidth/2 - w/2, newHeight/2 - h/2); so it calculates the difference between the new center and the old center and moves the entire picture by that difference.
I should mention that AffineTransform applies the transformations in the opposite order.
So if you write this
plane.translate((newWidth - w) / 2, (newHeight - h) / 2);
int x=w/2;
int y=h/2;
plane.rotate(Math.toRadians(45), x, y);
Then every pixel of of the image is first rotated by 45 degrees clockwise and then shifted, not the other way around. It's done this way because the transformations are supposed to be applied to the coordinate system. Applying transformation A followed by tranformation B to the coordinate system is mathematically equivalent to applying B followed by A to the pixels of the image.

Explanation for the bulge effect algorithm

I am a beginner at Java, only been coding for a year. My task is to create distortions to any image given. I have been having a lot of trouble with the bulge effect lately. I have been researching all around google and I found these links very helpful:
https://math.stackexchange.com/questions/266250/explanation-of-this-image-warping-bulge-filter-algorithm
Image Warping - Bulge Effect Algorithm
I tried the algorithm that these two links gave me, but I ended up with nothing.
Let's say I have imported an image that is 100 pixels by 100 pixels, from the code below, am I using the algorithm correctly:
//modifiedImage is a global variable and contains the image that is 100x100
public BufferedImage buldge(){
double X = 0;
double Y = 0;
BufferedImage anImage = new BufferedImage (1000, 1000, BufferedImage.TYPE_INT_ARGB);
for(int x = 0; x < modifiedImage.getWidth(); x++){
for(int y = 0; y < modifiedImage.getHeight(); y++){
int rgb = modifiedImage.getRGB(x, y);
double newRadius = 0;
X = x - x/2;
Y = y - y/2;
double radius = Math.sqrt(X*X + Y*Y);
double angle = Math.atan2(X, Y);
newRadius = Math.pow(radius,1.5);
X = (int)(newRadius*Math.sin(angle));
Y = (int)(newRadius*Math.cos(angle));
anImage.setRGB((int)X, (int)Y,rgb);
}
}
return anImage;
}
The problem is that this code doesn't really bulge the image in the middle. I have made a new BufferedImage of dimensions 1000x1000 because the pixels from the original one gets extended really far and some are extended beyond 1000x1000. If anyone would help me show the problems in this code concerning the bulge effect, I would greatly appreciate it.
I think one (main) part of the problem is that you are computing the radius of the bulge effect in pixels. Although I have not read all anwers in the threads that you linked, it seems like they are referring to texture coordinates - that is, to values between 0 and 1.
Apart from that: With the current approach, you will have a sampling problem. Imagine that one pixel at the center of the input image will be "stretched" so that it covers an area of, say, 10x10 pixels in the output image. But still, you are only computing one new position for this pixel.
Imagine it like you are taking pixels from the input image, and move them to a new position in the output image - but you have to do it the other way around: You have to check each pixel in the output image, and compute which pixel of the input image was moved there.
I created a small example: It allows moving a "magnifying glass" over the image with the mouse. With the mouse wheel, you can change the strength of the distortion. With SHIFT+MouseWheel, you can change the size of the magnifying glass.
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferedImage;
import java.beans.Transient;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ImageBulgeTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new GridLayout(1, 1));
frame.getContentPane().add(new ImageBulgePanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class ImageBulgePanel extends JPanel
{
private BufferedImage input;
private BufferedImage output;
private double bulgeStrength = 0.3;
private double bulgeRadius = 100;
ImageBulgePanel()
{
try
{
input = ImageIO.read(new File("lena512color.png"));
}
catch (IOException e1)
{
e1.printStackTrace();
}
addMouseMotionListener(new MouseAdapter()
{
#Override
public void mouseMoved(MouseEvent e)
{
updateImage(e.getX(), e.getY());
}
});
addMouseWheelListener(new MouseWheelListener()
{
#Override
public void mouseWheelMoved(MouseWheelEvent e)
{
if ((e.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) ==
InputEvent.SHIFT_DOWN_MASK)
{
bulgeRadius += 10 * e.getWheelRotation();
System.out.println("bulgeRadius "+bulgeRadius);
}
else
{
bulgeStrength += 0.1 * e.getWheelRotation();
bulgeStrength = Math.max(0, bulgeStrength);
System.out.println("bulgeStrength "+bulgeStrength);
}
updateImage(e.getX(), e.getY());
}
});
}
#Override
#Transient
public Dimension getPreferredSize()
{
if (isPreferredSizeSet())
{
return super.getPreferredSize();
}
return new Dimension(input.getWidth(), input.getHeight());
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
if (output != null)
{
g.drawImage(output, 0, 0, null);
}
}
private void updateImage(int x, int y)
{
if (output == null)
{
output = new BufferedImage(
input.getWidth(), input.getHeight(),
BufferedImage.TYPE_INT_ARGB);
}
computeBulgeImage(input, x, y,
bulgeStrength, bulgeRadius,
output);
repaint();
}
private static void computeBulgeImage(
BufferedImage input, int cx, int cy,
double bulgeStrength, double bulgeRadius,
BufferedImage output)
{
int w = input.getWidth();
int h = input.getHeight();
for(int x = 0; x < w; x++)
{
for(int y = 0; y < h; y++)
{
int dx = x-cx;
int dy = y-cy;
double distanceSquared = dx * dx + dy * dy;;
int sx = x;
int sy = y;
if (distanceSquared < bulgeRadius * bulgeRadius)
{
double distance = Math.sqrt(distanceSquared);
boolean otherMethod = false;
otherMethod = true;
if (otherMethod)
{
double r = distance / bulgeRadius;
double a = Math.atan2(dy, dx);
double rn = Math.pow(r, bulgeStrength)*distance;
double newX = rn*Math.cos(a) + cx;
double newY = rn*Math.sin(a) + cy;
sx += (newX - x);
sy += (newY - y);
}
else
{
double dirX = dx / distance;
double dirY = dy / distance;
double alpha = distance / bulgeRadius;
double distortionFactor =
distance * Math.pow(1-alpha, 1.0 / bulgeStrength);
sx -= distortionFactor * dirX;
sy -= distortionFactor * dirY;
}
}
if (sx >= 0 && sx < w && sy >= 0 && sy < h)
{
int rgb = input.getRGB(sx, sy);
output.setRGB(x, y, rgb);
}
}
}
}
}

Categories

Resources