oriented minimum bounding box - java

I'm looking for a java code to create a oriented minimum bounding box with points, which have a lat/lon value. I've already created a minimum bounding box, like this:
public Mbb boundingBox() {
Point ll, ur;
Mbb bBox;
int id =1;
ll = new Point(id, Double.MAX_VALUE, Double.MAX_VALUE);
ur= new Point(id,-1*Double.MAX_VALUE, -1*Double.MAX_VALUE);
if (this.pg.size() <=1)
return null;
double minLat = Double.MAX_VALUE;
double minLong = Double.MAX_VALUE;
double maxLat = Double.MAX_VALUE*-1;
double maxLong = Double.MAX_VALUE*-1;
for (Point testPoint: this.pg) {
double lat = testPoint.getLat();
double lon = testPoint.getLon();
if(minLat>lat)
minLat=lat;
if(minLong>lon)
minLong=lon;
if(maxLat<lat)
maxLat=lat;
if(maxLong<lon)
maxLong=lon;
}
ll.setLat(minLat);
ll.setLon(minLong);
ur.setLat(maxLat);
ur.setLon(maxLong);
bBox= new Mbb(id, ll, ur);
return bBox;
}
But this is not an oriented one. Has anybody an idea how to orient my bounding box?

The computation if the minimum oriented bounding box is not so trivial. But one approach is described in an answer to https://gis.stackexchange.com/q/22895 . The answer links to a Java implementation, but this is obviously part of a larger framework. However, I implemented the approach here as an example:
The computation of the convex hull is made with a code snippet taken from convex-hull at Google code - it's not the nicest implementation, but was the first one that I found, and does the job.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MinOrientedBoundingBoxTest
{
public static void main(String[] args) throws IOException
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new MinOrientedBoundingBoxTestPanel());
f.setSize(500,500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class MinOrientedBoundingBoxTestPanel extends JPanel
implements MouseListener, MouseMotionListener
{
private final List<Point2D> points;
private Point2D draggedPoint = null;
MinOrientedBoundingBoxTestPanel()
{
points = new ArrayList<Point2D>();
Random r = new Random(0);
for (int i=0; i<8; i++)
{
double x = 200 + r.nextDouble() * 200;
double y = 200 + r.nextDouble() * 200;
points.add(new Point2D.Double(x,y));
}
addMouseListener(this);
addMouseMotionListener(this);
}
#Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
drawPoints(g, points);
boolean showConvexHull = false;
showConvexHull = true;
if (showConvexHull)
{
List<Point2D> convexHullPoints =
MinOrientedBoundingBoxComputer.computeConvexHullPoints(
points);
Path2D convexHullPath =
MinOrientedBoundingBoxComputer.createPath(
convexHullPoints);
g.setColor(Color.GRAY);
g.draw(convexHullPath);
}
List<Point2D> minObbCorners =
MinOrientedBoundingBoxComputer.computeCorners(points);
Path2D p = MinOrientedBoundingBoxComputer.createPath(minObbCorners);
g.setColor(Color.BLUE);
g.draw(p);
}
static void drawPoints(Graphics2D g, List<Point2D> points)
{
double r = 3;
for (Point2D point : points)
{
double x = point.getX();
double y = point.getY();
g.fill(new Ellipse2D.Double(
x-r, y-r, r+r, r+r));
}
}
#Override
public void mouseDragged(MouseEvent e)
{
if (draggedPoint != null)
{
draggedPoint.setLocation(e.getPoint());
repaint();
}
}
#Override
public void mouseMoved(MouseEvent e)
{
}
#Override
public void mouseClicked(MouseEvent e)
{
}
#Override
public void mousePressed(MouseEvent e)
{
draggedPoint = null;
double thresholdSquared = 10*10;
double minDs = Double.MAX_VALUE;
for (Point2D point : points)
{
double ds = point.distanceSq(e.getPoint());
if (ds < thresholdSquared && ds < minDs)
{
minDs = ds;
draggedPoint = point;
}
}
}
#Override
public void mouseReleased(MouseEvent e)
{
draggedPoint = null;
}
#Override
public void mouseEntered(MouseEvent e)
{
}
#Override
public void mouseExited(MouseEvent e)
{
}
}
class MinOrientedBoundingBoxComputer
{
static List<Point2D> computeCorners(List<Point2D> points)
{
List<Point2D> convexHullPoints =
computeConvexHullPoints(points);
int alignmentPointIndex =
computeAlignmentPointIndex(convexHullPoints);
Rectangle2D r = computeAlignedBounds(
convexHullPoints, alignmentPointIndex);
List<Point2D> alignedCorners = new ArrayList<Point2D>();
alignedCorners.add(new Point2D.Double(r.getMinX(), r.getMinY()));
alignedCorners.add(new Point2D.Double(r.getMaxX(), r.getMinY()));
alignedCorners.add(new Point2D.Double(r.getMaxX(), r.getMaxY()));
alignedCorners.add(new Point2D.Double(r.getMinX(), r.getMaxY()));
Point2D center = convexHullPoints.get(alignmentPointIndex);
double angleRad = computeEdgeAngleRad(
convexHullPoints, alignmentPointIndex);
AffineTransform at = new AffineTransform();
at.concatenate(
AffineTransform.getTranslateInstance(
center.getX(), center.getY()));
at.concatenate(
AffineTransform.getRotateInstance(angleRad));
List<Point2D> corners = transform(alignedCorners, at);
return corners;
}
private static int computeAlignmentPointIndex(
List<Point2D> points)
{
double minArea = Double.MAX_VALUE;
int minAreaIndex = -1;
for (int i=0; i<points.size(); i++)
{
Rectangle2D r = computeAlignedBounds(points, i);
double area = r.getWidth() * r.getHeight();
if (area < minArea)
{
minArea = area;
minAreaIndex = i;
}
}
return minAreaIndex;
}
private static double computeEdgeAngleRad(
List<Point2D> points, int index)
{
int i0 = index;
int i1 = (i0+1)%points.size();
Point2D p0 = points.get(i0);
Point2D p1 = points.get(i1);
double dx = p1.getX() - p0.getX();
double dy = p1.getY() - p0.getY();
double angleRad = Math.atan2(dy, dx);
return angleRad;
}
private static Rectangle2D computeAlignedBounds(
List<Point2D> points, int index)
{
Point2D p0 = points.get(index);
double angleRad = computeEdgeAngleRad(points, index);
AffineTransform at = createTransform(-angleRad, p0);
List<Point2D> transformedPoints = transform(points, at);
Rectangle2D bounds = computeBounds(transformedPoints);
return bounds;
}
private static AffineTransform createTransform(
double angleRad, Point2D center)
{
AffineTransform at = new AffineTransform();
at.concatenate(
AffineTransform.getRotateInstance(angleRad));
at.concatenate(
AffineTransform.getTranslateInstance(
-center.getX(), -center.getY()));
return at;
}
private static List<Point2D> transform(
List<Point2D> points, AffineTransform at)
{
List<Point2D> result = new ArrayList<Point2D>();
for (Point2D p : points)
{
Point2D tp = at.transform(p, null);
result.add(tp);
}
return result;
}
private static Rectangle2D computeBounds(
List<Point2D> points)
{
double minX = Double.MAX_VALUE;
double minY = Double.MAX_VALUE;
double maxX = -Double.MAX_VALUE;
double maxY = -Double.MAX_VALUE;
for (Point2D p : points)
{
double x = p.getX();
double y = p.getY();
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
}
return new Rectangle2D.Double(minX, minY, maxX-minX, maxY-minY);
}
static Path2D createPath(List<Point2D> points)
{
Path2D path = new Path2D.Double();
for (int i=0; i<points.size(); i++)
{
Point2D p = points.get(i);
double x = p.getX();
double y = p.getY();
if (i == 0)
{
path.moveTo(x, y);
}
else
{
path.lineTo(x, y);
}
}
path.closePath();
return path;
}
static List<Point2D> computeConvexHullPoints(List<Point2D> points)
{
// NOTE: Converting from Point2D to Point here
// because the FastConvexHull class expects
// the points with integer coordinates.
// This should be generalized to Point2D!
ArrayList<Point> ps = new ArrayList<Point>();
for (Point2D p : points)
{
ps.add(new Point((int)p.getX(), (int)p.getY()));
}
List<Point> convexHull = FastConvexHull.execute(ps);
List<Point2D> result = new ArrayList<Point2D>();
for (Point p : convexHull)
{
double x = p.getX();
double y = p.getY();
result.add(new Point2D.Double(x,y));
}
return result;
}
}
// From https://code.google.com/p/convex-hull/source/browse/
// Convex+Hull/src/algorithms/FastConvexHull.java?r=4
// Under GPL2 license
// (Not a "nice" implementation, but the first one that
// I found with a websearch. Maybe, when I'm bored, I'll
// replace it with another one...)
class FastConvexHull
{
public static ArrayList<Point> execute(ArrayList<Point> points)
{
ArrayList<Point> xSorted = (ArrayList<Point>) points.clone();
Collections.sort(xSorted, new XCompare());
int n = xSorted.size();
Point[] lUpper = new Point[n];
lUpper[0] = xSorted.get(0);
lUpper[1] = xSorted.get(1);
int lUpperSize = 2;
for (int i = 2; i < n; i++)
{
lUpper[lUpperSize] = xSorted.get(i);
lUpperSize++;
while (lUpperSize > 2 &&
!rightTurn(lUpper[lUpperSize - 3], lUpper[lUpperSize - 2],
lUpper[lUpperSize - 1]))
{
// Remove the middle point of the three last
lUpper[lUpperSize - 2] = lUpper[lUpperSize - 1];
lUpperSize--;
}
}
Point[] lLower = new Point[n];
lLower[0] = xSorted.get(n - 1);
lLower[1] = xSorted.get(n - 2);
int lLowerSize = 2;
for (int i = n - 3; i >= 0; i--)
{
lLower[lLowerSize] = xSorted.get(i);
lLowerSize++;
while (lLowerSize > 2 &&
!rightTurn(lLower[lLowerSize - 3], lLower[lLowerSize - 2],
lLower[lLowerSize - 1]))
{
// Remove the middle point of the three last
lLower[lLowerSize - 2] = lLower[lLowerSize - 1];
lLowerSize--;
}
}
ArrayList<Point> result = new ArrayList<Point>();
for (int i = 0; i < lUpperSize; i++)
{
result.add(lUpper[i]);
}
for (int i = 1; i < lLowerSize - 1; i++)
{
result.add(lLower[i]);
}
return result;
}
private static boolean rightTurn(Point a, Point b, Point c)
{
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) > 0;
}
private static class XCompare implements Comparator<Point>
{
#Override
public int compare(Point o1, Point o2)
{
return (new Integer(o1.x)).compareTo(new Integer(o2.x));
}
}
}

Related

How to make Java game more efficient?

I have been working on a flappy bird clone so I can get more practice programming. Everything in the game works, however the game has frame skips and lag drops, and I do not know how to make Java programs run more smoothly. Am I supposed to measure the amount of time a method takes and try to shorten that, or do I do something else? I have seen people explain how to program Java games, but there is hardly anything on improving the performance. Any advice would be helpful. Thank you.
Hazards class
package entity;
import java.util.ArrayList;
public class Hazards {
public ArrayList<Horizontal> hors;
public ArrayList<Vertical> verts;
public Hazards(int width, int height, int thickness) {
hors = new ArrayList<Horizontal>();
hors.add(new Horizontal(0, 0, width, thickness));
hors.add(new Horizontal(0, height-thickness, width, thickness));
verts = new ArrayList<Vertical>();
}
}
Horizontal class
package entity;
import java.awt.Rectangle;
public class Horizontal {
public int xPos, yPos, width, height;
public Rectangle bounds;
public Horizontal(int x, int y, int w, int h) {
this.xPos = x;
this.yPos = y;
this.width = w;
this.height = h;
this.bounds = new Rectangle(x, y, w, h);
}
public void updateBounds(int x, int y, int w, int h) {
this.xPos = x;
this.yPos = y;
this.width = w;
this.height = h;
this.bounds = new Rectangle(x, y, w, h);
}
}
Vertical class
package entity;
import java.awt.Rectangle;
import java.util.Random;
public class Vertical {
public int xPos, width, gapSize, gapPos;
public boolean scoredOn = false;
public Rectangle top, bottom;
public Vertical(int xPos, int width, int roofHeight, int floorHeight, int gapSize) {
this.xPos = xPos;
this.width = width;
this.gapPos = new Random().nextInt(floorHeight - gapSize) + roofHeight;
this.top = new Rectangle();
this.bottom = new Rectangle();
this.top.setBounds(xPos, 0, width, gapPos);
this.bottom.setBounds(xPos, gapPos + gapSize, width, floorHeight - roofHeight + top.height + gapSize);
}
}
Content class
package main;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.JPanel;
public class Content extends JPanel {
private static final long serialVersionUID = 1L;
private Engine e;
private Rectangle bounds;
public Content(Engine engine) {
e = engine;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.clearRect(0, 0, this.getWidth(), this.getHeight());
// Roof and floor
g.setColor(Color.black);
for (int x = 0; x < e.e.hors.size(); x++) {
bounds = e.e.hors.get(x).bounds;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
// Pipes
g.setColor(Color.black);
for(int x = 0; x < e.e.verts.size(); x++) {
bounds = e.e.verts.get(x).top;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
bounds = e.e.verts.get(x).bottom;
g.fillRect(bounds.x, bounds.y, bounds.width, bounds.height);
}
// Player
g.setColor(Color.black);
g.fillRect((int) e.p.xPos, (int) e.p.yPos, e.p.size, e.p.size);
// Score
g.setColor(Color.blue);
g.setFont(new Font("Monospaced", Font.PLAIN, 40));
g.drawString(Integer.toString(e.p.score), e.width/2, 80);
}
}
Engine class
package main;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import entity.Hazards;
import entity.Vertical;
import screen.TitleScreen;
public class Engine implements Runnable {
public JFrame f;
public String title = "Flappy Bird";
public int width = 500, height = 500;
public Content c;
public boolean running = false;
public boolean playing = false;
public Thread t;
public Player p;
public Hazards e;
public TitleScreen ts;
public JPanel mainPanel;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
Engine e = new Engine();
e.execute();
}
});
}
public void execute() {
ts = new TitleScreen(width, height);
e = new Hazards(width, height, 30);
p = new Player(this);
c = new Content(this);
c.setPreferredSize(new Dimension(width, height));
c.setLayout(null);
c.addKeyListener(p);
mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(width, height));
mainPanel.setLayout(null);
f = new JFrame();
f.setTitle(title);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setResizable(false);
f.add(c);
// f.add(mainPanel);
f.pack();
f.createBufferStrategy(2);
f.setLayout(null);
f.setLocationRelativeTo(null);
f.setVisible(true);
c.requestFocus();
//ts.setScreen(mainPanel);
start();
}
public synchronized void start() {
if (running)
return;
running = true;
t = new Thread(this);
t.start();
}
public synchronized void stop() {
if (!running)
return;
running = false;
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
long lastime = System.nanoTime();
double AmountOfTicks = 60;
double ns = 1000000000 / AmountOfTicks;
double delta = 0;
int tick = 0;
while (running) {
long now = System.nanoTime();
delta += (now - lastime) / ns;
lastime = now;
if (delta >= 1) {
// Call all updates here
if (playing) {
p.updatePos();
tick++;
if (tick == 60) {
tick = 0;
p.distance += p.speed;
System.out.println(p.distance);
if ((p.distance % 4) == 0) {
System.out.println("Making new pipes-----------------------------------------------------");
e.verts.add(new Vertical(600, 10, 30, height - 30, 100));
}
}
for (int x = 0; x < e.verts.size(); x++) {
e.verts.get(x).top.x -= p.speed;
e.verts.get(x).bottom.x -= p.speed;
if(e.verts.get(x).top.x<-50) {
e.verts.remove(x);
System.out.println("removed a pipe");
}
if(p.xPos>e.verts.get(x).top.x && !e.verts.get(x).scoredOn) {
e.verts.get(x).scoredOn = true;
p.score++;
}
}
}
mainPanel.revalidate();
mainPanel.repaint();
f.revalidate();
f.repaint();
delta--;
}
}
}
}
Player class
package main;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Player implements KeyListener {
public int size = 10;
public double xPos = 50;
public double yPos = 240;
public double gravity = 3.4;
public double jumpForce = 16.6;
public double weight = 1;
public int speed = 2;
public int score = 0;
public int distance = 0;
public boolean jumping = false;
public double jumpTime = 10;
public int timed = 0;
public Rectangle bounds, temp, top, bottom;
public Engine en;
public Player(Engine engine) {
en = engine;
bounds = new Rectangle((int)xPos, (int)yPos, size, size);
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W && en.playing) {
jumping = true;
} else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
en.playing = !en.playing;
}
if(jumping) {
timed = 0;
jumpForce = 16.6;
}
}
public void keyReleased(KeyEvent e) {
}
public void updatePos() {
// collide with floor or ceiling
for(int x = 0; x < en.e.hors.size(); x++) {
temp = en.e.hors.get(x).bounds;
if(bounds.intersects(temp)) {
en.playing = false;
jumping = false;
timed = 0;
jumpForce = 0;
yPos = 240;
score = 0;
en.e.verts.clear();
distance = 0;
gravity = 3.8;
}
}
// collide with pipe
for(int x =0; x <en.e.verts.size();x++) {
top = en.e.verts.get(x).top;
bottom = en.e.verts.get(x).bottom;
if(bounds.intersects(top)||bounds.intersects(bottom)) {
en.playing = false;
jumping = false;
timed = 0;
jumpForce = 0;
yPos = 240;
score = 0;
gravity =3.4;
en.e.verts.clear();
distance = 0;
}
}
if (jumping && en.playing) {
gravity = 3.4;
yPos -= jumpForce;
jumpForce -= weight;
if (jumpForce == 0) {
jumping = false;
jumpForce = 16.6;
}
}
//if(!jumping && en.playing) {
gravity += 0.1;
//}
System.out.println(gravity);
yPos += gravity;
bounds.setBounds((int)xPos, (int)yPos, size, size);
}
}

Objects Used In PathTransition In JavaFx Moving Too Fast

I have a group of triangles which move around based on a flocking algorithm. I have used a path transition from JavaFX so that they move along a set pathway while retaining the flocking behavior within that pathway. However, when I try to slow down the path transition by setting the duration in milliseconds, the triangles either move very quickly or remain stuck in one place. I have tried looking for other solutions to this but haven't been able to find any and so I am posing this here.
package model;
import utility.Vector2d;
import java.util.Random;
import javafx.animation.PathTransition;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.util.Duration;
public class BusinessPersonBoid extends Circle{
public Vector2d position;
protected Vector2d position2;
protected Vector2d position3;
protected Vector2d position4;
protected Vector2d position5;
protected Vector2d velocity;
protected final int speedLimit = 2;
protected String name;
protected ImageView display;
protected Circle circle;
public LineTo line1;
public LineTo line2;
public LineTo line3;
public LineTo line4;
public BusinessPersonBoid(int x, int y, String n, Circle c) {
this.display = new ImageView();
this.display.setX(x);
this.display.setY(y);
this.display.setSmooth(true);
this.display.setCache(true);
this.display.setImage(new Image("images2/boid-green.png"));
this.circle = new Circle(15,Color.BLUE);
this.position = new Vector2d(x, y);
this.velocity = new Vector2d(0,0);
if( n != null) {
this.name = n;
}
}
public Vector2d getPosition() {
return new Vector2d(position.xPos, position.yPos);
}
public Vector2d getVelocity() {
return velocity;
}
public void setVelocity(Vector2d velocity) {
if ( velocity.xPos > speedLimit) {
velocity.xPos = speedLimit;
}
if ( velocity.yPos > speedLimit) {
velocity.yPos = speedLimit;
}
this.velocity = velocity;
}
public void setPosition(Vector2d pos) {
setAngle(this.position, pos);
this.display.setX(pos.xPos);
this.display.setY(pos.yPos);
this.position = pos;
}
public void setPosition2(Vector2d pos, Vector2d pos2) {
setAngle(this.position, pos);
this.display.setX(pos.xPos);
this.display.setY(pos.yPos);
this.display.setX(pos.xPos);
this.display.setY(pos.yPos);
this.position = pos;
}
public void setPathway() {
Random randNum = new Random();
Path path = new Path();
MoveTo moveTo = new MoveTo(108, 71);
LineTo line1 = new LineTo(150, 140);
LineTo line2 = new LineTo(550, 140);
LineTo line3 = new LineTo(750, 140);
LineTo line4 = new LineTo(910, -40);
path.getElements().add(moveTo);
path.getElements().addAll(line1, line2, line3, line4);
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(100));
pathTransition.setNode(display);
pathTransition.setPath(path);
pathTransition.play();
}
public void setAngle(Vector2d current, Vector2d next) {
double delta_x = next.xPos - current.xPos;
double delta_y = next.yPos - current.yPos;
Double theta = Math.atan2(delta_y, delta_x);
double angle = theta*180/Math.PI;
this.display.setRotate(angle);
}
public String getName() {
return this.name;
}
public ImageView getDisplay() {
return this.display;
}
}
Here is the flocking class:
package model;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import utility.Vector2d;
import javafx.animation.PathTransition;
import javafx.animation.Timeline;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CubicCurveTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
public class Flock2 {
public ArrayList<BusinessPersonBoid> boids2;
private double movementFactor = 1000;
private double boundingFactor = 10;
private int seperationDistance = 43;
private double seperationFactor = 50;
public BusinessPersonBoid cBoid;
public Vector2d Checkin;
public Vector2d CurrencyExchange;
public Vector2d Lounge;
public Vector2d Shop;
public Vector2d BoardingGate;
Circle c = new Circle();
Circle c2 = new Circle();
public Flock2() {
boids2 = new ArrayList<BusinessPersonBoid>();
Random randNum = new Random();
RandomName randName = new RandomName();
for(int i = 0; i < 10; i++) {
int x = randNum.nextInt(50) + 1;
int y = randNum.nextInt(140) + 1;
boids2.add(new BusinessPersonBoid(x,y, randName.getName(), c ));
}
}
public void updateBoidsPostion() {
Vector2d v1, v2, v3, v4, v5 = new Vector2d();
for (BusinessPersonBoid cBoid : boids2) {
v1 = groupFlock(cBoid);
v2 = collisionAvoidance(cBoid);
v3 = matchFlockVelocity(cBoid);
v4 = bounding(cBoid);
v5 = positionTend(cBoid);
Vector2d v12 = new Vector2d(-50,140);
Vector2d sum = new Vector2d();
sum = sum.add(v1);
sum = sum.add(v2);
sum = sum.add(v3);
sum = sum.add(v4);
sum = sum.add(v5);
cBoid.setPathway();
cBoid.setVelocity(cBoid.getVelocity().add(sum));
Vector2d next = new Vector2d( cBoid.getPosition().add(cBoid.getVelocity()) );
cBoid.setPosition(next);
}
}
private Vector2d groupFlock(BusinessPersonBoid cBoid) {
Vector2d center = new Vector2d();
for (BusinessPersonBoid aBoid : boids2) {
if(!aBoid.equals(cBoid)) {
center = center.add(aBoid.getPosition());
}
}
center = center.division(boids2.size() - 1 );
center = center.subtract(cBoid.getPosition());
center = center.division(movementFactor);
return center;
}
private Vector2d collisionAvoidance(BusinessPersonBoid cBoid) {
Vector2d correction = new Vector2d();
Vector2d cPosition = new Vector2d(cBoid.getPosition());
for (BusinessPersonBoid aBoid : boids2) {
if (!aBoid.equals(cBoid)) {
Vector2d aPosition = aBoid.getPosition();
Vector2d xD = new Vector2d(aPosition.xPos - cPosition.xPos, aPosition.yPos - cPosition.yPos);
if(Math.abs(xD.xPos) < seperationDistance && Math.abs(xD.yPos) < seperationDistance) {
correction = correction.subtract(xD).division(seperationFactor);
}
}
}
return correction;
}
private Vector2d matchFlockVelocity(BusinessPersonBoid cBoid) {
Vector2d perceivedVelocity = new Vector2d();
for(BusinessPersonBoid aBoid : boids2) {
if(!aBoid.equals(cBoid)) {
perceivedVelocity = perceivedVelocity.add(aBoid.getVelocity());
}
}
perceivedVelocity = perceivedVelocity.division(boids2.size() - 1);
perceivedVelocity = perceivedVelocity.subtract(cBoid.getVelocity());
perceivedVelocity = perceivedVelocity.division(8);
return perceivedVelocity;
}
private Vector2d bounding(BusinessPersonBoid cBoid) {
Vector2d bound = new Vector2d();
int xMin = 0, xMax = 1400, yMin = 0, yMax = 320;
Vector2d cPos = cBoid.getPosition();
if (cPos.xPos < xMin) {
bound.xPos += 1;
cPos.xPos = bound.xPos;
} else if (cPos.xPos > xMax){
bound.xPos += -100;
cPos.xPos = bound.xPos;
}
if (cPos.yPos < yMin) {
bound.yPos += 1;
cPos.yPos = bound.yPos;
} else if (cPos.yPos > yMax){
bound.yPos += -100;
cPos.yPos = bound.yPos;
}
bound = bound.division(boundingFactor);
return bound;
}
private Vector2d positionTend(BusinessPersonBoid cBoid) {
Vector2d place = new Vector2d(900,600);
Vector2d tend = new Vector2d();
tend = new Vector2d(place.subtract(cBoid.getPosition()));
tend.division(6000);
return tend;
}
public List<ImageView> getBoidsRepresentation() {
List<ImageView> circles = new ArrayList<ImageView>();
for(BusinessPersonBoid aBoid : boids2) {
circles.add( aBoid.getDisplay() );
}
return circles;
}
private Vector2d bounding2(BusinessPersonBoid cBoid) {
Vector2d bound = new Vector2d();
int xMin = 0, xMax = 600, yMin = 0, yMax = 600;
Vector2d cPos = cBoid.getPosition();
bound.xPos = 100;
cPos.xPos = bound.xPos;
bound.yPos = 100;
cPos.yPos = bound.yPos;
bound = bound.division(boundingFactor);
return bound;
}
private Vector2d pathway(BusinessPersonBoid cBoid) {
Vector2d pathway = new Vector2d();
Path path = new Path();
path.getElements().add(new MoveTo(20,20));
path.getElements().add(new CubicCurveTo(380, 0, 380, 120, 200, 120));
path.getElements().add(new CubicCurveTo(0, 120, 0, 240, 380, 240));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(4000));
pathTransition.setPath(path);
pathTransition.setNode(cBoid);
return pathway;
}
public int tendToPlace(BusinessPersonBoid cBoid) {
Vector2d place = new Vector2d(-50,140);
return place.minus(cBoid.position)/100;
}
My question is how do I slow the triangles down to a speed where you can actually see them moving properly?
RandomName class:
package model;
import java.util.ArrayList;
import java.util.Random;
public class RandomName {
private Random randomGenerator;
private ArrayList<Integer> usedList;
private String[] nameBank = { "Alpha",
"Bravo",
"Charlie",
"Delta",
"Echo",
"Foxtrot",
"Golf",
"Hotel",
"India",
"Juliet",
"Kilo",
"Lima",
"Mike",
"November",
"Oscar",
"Papa",
"Quebec",
"Romeo",
"Sierra",
"Tango",
"Uniform",
"Victor",
"Whiskey",
"X-ray",
"Yankee",
"Zulu" };
public RandomName() {
randomGenerator = new Random();
usedList = new ArrayList<Integer>();
}
public String getName() {
return nameBank[getIndex()];
}
private int getIndex() {
int i = randomGenerator.nextInt(nameBank.length);
while(usedList.contains(i)) {
if(usedList.size() >= nameBank.length ) {
usedList.clear();
}
i = randomGenerator.nextInt(nameBank.length);
}
usedList.add(i);
return i;
}
public void addName(String add) {
nameBank[nameBank.length+1+1] = add;
}
public void addName(String[] add) {
for(int i = 0; i < add.length; i++) {
nameBank[nameBank.length+1] = add[i];
}
}
}
Vector2d class:
package utility;
public class Vector2d {
public double xPos;
public double yPos;
public Vector2d(){
this.xPos = 0;
this.yPos = 0;
}
public Vector2d(Vector2d v){
this.xPos = v.xPos;
this.yPos = v.yPos;
}
public Vector2d(double x, double y){
this.xPos = x;
this.yPos = y;
}
public Vector2d add(Vector2d addVector){
return new Vector2d(this.xPos += addVector.xPos, this.yPos += addVector.yPos );
}
public Vector2d add(double x, double y){
return new Vector2d(this.xPos += x, this.yPos += y );
}
public Vector2d subtract(double x, double y){
return new Vector2d(this.xPos += x, this.yPos += y );
}
public Vector2d subtract(Vector2d subVector){
return new Vector2d(this.xPos = (this.xPos - subVector.xPos), this.yPos = (this.yPos - subVector.yPos));
}
public Vector2d division(double divider) {
return new Vector2d(this.xPos =( xPos / divider), this.yPos =( yPos / divider));
}
public double absX() {
return Math.sqrt(Math.pow(this.xPos, 2));
}
public double absY() {
return Math.sqrt(Math.pow(this.yPos, 2));
}
public double abs() {
return Math.sqrt(Math.pow(this.xPos, 2) + Math.pow(this.yPos, 2));
}
public int minus(Vector2d position) {
// TODO Auto-generated method stub
return 0;
}
}

Change contents of BufferedImage, then update JFrame to reflect it

I am trying to make a Mandelbrot Set renderer with a GUI where you can click and drag to zoom into a specific area. When run, it will do the initial calculations and rendering fine, but when you try to click and drag to zoom in, the console says it is doing the calculations, but the content of the JFrame is not updated.
However, I'm not even positive that it is recalculating, because the initial calculation takes about 8 seconds but when you click/drag to zoom it takes about 6 ms.
I have posted my code below.
Complex Numbers Class
public class Complex {
private double real, imag;
// Constructors
public Complex(){
real=0.0;
imag=0.0;
}
public Complex(double real, double imag) {
this.real=real;
this.imag=imag;
}
// add given complex number to this one, returning the Complex result
public Complex add(Complex other) {
return new Complex(this.real+other.real, this.imag+other.imag);
}
// multiply given complex number by this one, returning the Complex result
public Complex multiply(Complex other) {
return new Complex((this.real*other.real)-(this.imag*other.imag), (this.imag*other.real)+(this.real*other.imag));
}
// get the magnitude of this complex number
public double getMagnitude() {
return Math.sqrt((real*real)+(imag*imag));
}
}
Runnable MandelbrotTask Class
public class MandelbrotTask implements Runnable {
private double x1, y1, x2, y2;
private int startCol, endCol, startRow, endRow, maxIters;
private int[][] iterCounts;
public MandelbrotTask(int maxIters, double x1, double y1, double x2, double y2, int startCol, int endCol, int startRow, int endRow, int[][] iterCounts) {
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.startCol = startCol;
this.endCol = endCol;
this.startRow = startRow;
this.endRow = endRow;
this.iterCounts = iterCounts;
this.maxIters=maxIters;
}
#Override
public void run() {
for (int i = startRow; i < endRow; i++) {
for (int j = startCol; j < endCol; j++) {
Complex c = getComplex(i, j);
int iterCount = countIters(c);
iterCounts[i][j] = iterCount;
}
}
}
public Complex getComplex(int i, int j){
//output image is 600 X 600 pixels
double incrementX;
double incrementY;
if(x2!=x1){
incrementX=(Math.abs(x2-x1)/600);
}
else{
throw new ArithmeticException("Error: area=0");
}
if(y2!=y1){
incrementY=(Math.abs(y2-y1)/600);
}
else{
throw new ArithmeticException("Error: area=0");
}
return new Complex(x1+((double)i*incrementX), y1+((double)j*incrementY));
}
public int countIters(Complex c){
Complex z=new Complex(0, 0);
int iters=0;
while(z.getMagnitude()<2 && iters<=maxIters){
z=z.multiply(z).add(c);
iters++;
}
return iters;
}
}
Main Mandelbrot Class
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Mandelbrot {
private static final int HEIGHT = 600;
private static final int WIDTH = 600;
private static final int maxIters=50000;
private static Rectangle zoomBox;
private static Point initialClick;
private static JLabel content; //bufferedImage will be put into this JLabel
private static int[][] iterCounts;
private static BufferedImage bufferedImage; //rendering will be written to this bufferedImage
private static JFrame frame;
public static void main(String[] args) throws IOException {
zoomBox=null;
Scanner keyboard = new Scanner(System.in);
double x1 = -2;
double y1 = -2;
double x2 = 2;
double y2 = 2;
/*System.out.print("Max iterations (16,581,375 supported): ");
int maxIters=50000;
if(maxIters>16581375){
throw new UnsupportedOperationException("Error: Max Iterations: Overflow.");
}
System.out.print("Output filename: ");
String fileName = keyboard.next();
if(!fileName.endsWith(".png") && !fileName.endsWith(".PNG")){
fileName=fileName + ".png";
}*/
// TODO: create the rendering, save it to a file
iterCounts=new int[WIDTH][HEIGHT];
recalculate(x1, y1, x2, y2, iterCounts);
bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
MouseAdapter listener = new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
handleMousePressed(e);
}
#Override
public void mouseDragged(MouseEvent e) {
handleMouseDragged(e);
}
#Override
public void mouseReleased(MouseEvent e) {
handleMouseReleased(e);
}
};
content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, true)));
content.addMouseListener(listener);
content.addMouseMotionListener(listener);
/*OutputStream os = new BufferedOutputStream(new FileOutputStream(fileName));
try {
ImageIO.write(bufferedImage, "PNG", os);
} finally {
os.close();
}*/
frame = new JFrame("Mandelbrot Viewer");
frame.getContentPane().add(content);
frame.pack();
frame.setSize(new Dimension(WIDTH, HEIGHT));
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static BufferedImage render(int[][] iterCounts, BufferedImage bufferedImage, Rectangle zoomBox, boolean updated){
bufferedImage = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
Graphics g = bufferedImage.getGraphics();
Graphics2D g2=(Graphics2D) g;
if(updated){
for(int i=0; i<WIDTH; i++){
for(int j=0; j<HEIGHT; j++){
if(iterCounts[i][j]<maxIters){
String hexCode= String.format("#%06x", (0xFFFFFF & (32*iterCounts[i][j])));
g.setColor(Color.decode(hexCode));
}
else{
g.setColor(Color.CYAN);
}
g.drawLine(i, j, i, j);
}
}
}
else{
if(zoomBox!=null){
g2.setStroke(new BasicStroke(7));
g2.draw(zoomBox);
}
}
return bufferedImage;
}
public static int[][] recalculate(double x1, double y1, double x2, double y2, int[][] iterCounts){
MandelbrotTask[] tasks=new MandelbrotTask[4];
tasks[0]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 0, HEIGHT/4, iterCounts);
tasks[1]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, HEIGHT/4, 2*(HEIGHT/4), iterCounts);
tasks[2]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 2*(HEIGHT/4), 3*(HEIGHT/4), iterCounts);
tasks[3]=new MandelbrotTask(maxIters, x1, y1, x2, y2, 0, WIDTH, 3*(HEIGHT/4), 4*(HEIGHT/4), iterCounts);
//parallelize computation
Thread[] threads=new Thread[4];
for(int i=0; i<4; i++){
threads[i]=new Thread(tasks[i]);
}
System.out.println("Working...");
//start timer, start computation
long start=System.currentTimeMillis();
for(int i=0; i<4; i++){
threads[i].start();
}
for(int i=0; i<4; i++){
try {
threads[i].join();
} catch (InterruptedException e) {
System.err.println("A thread was interrupted.");
}
}
//end timer
long end=System.currentTimeMillis();
long elapsed=end-start;
System.out.println("Done.");
System.out.println("Took " + elapsed + " ms.");
return iterCounts;
}
protected static void handleMousePressed(MouseEvent e) {
initialClick=e.getPoint();
}
protected static void handleMouseDragged(MouseEvent e) {
if(e.getX()>e.getY()){
zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getX()), (int)(e.getY()-initialClick.getX()));
}
else if(e.getY()>e.getX()){
zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getY()), (int)(e.getY()-initialClick.getY()));
}
else{
zoomBox=new Rectangle((int)initialClick.getX(), (int)initialClick.getY(), (int)(e.getX()-initialClick.getX()), (int)(e.getY()-initialClick.getY()));
}
content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false)));
content.repaint();
}
protected static void handleMouseReleased(MouseEvent e) {
recalculate(initialClick.getX(), initialClick.getY(), e.getX(), e.getY(), iterCounts);
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run() {
zoomBox=null;
content=new JLabel(new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false)));
content.repaint();
}
});
}
}
For one, you're creating a new JLabel with each re-iteration, and this JLabel is being added to nothing.
Instead use the same JLabel but rather create a new ImageIcon and set the viewed JLabel's Icon.
ImageIcon icon = new ImageIcon(render(iterCounts, bufferedImage, zoomBox, false));
content.setIcon(icon);
You also don't seem to be doing anything with the int arrays returned from recalculate.
Shouldn't your handleMouseReleased method have:
iterCounts = recalculate(initialClick.getX(), initialClick.getY(),
e.getX(), e.getY(), iterCounts);
Also, you still have bad threading -- you're calling join on your Threads from within the Swing event thread, something almost sure to freeze your GUI. Use a SwingWorker and then after getting notified from the worker when it's done, use its data. Also you're grossly over using static variables in your GUI. Make your GUI components instance fields, not static fields.
There are more logical errors that I've yet to find I'm afraid...
Second iteration of program -- With the Mandelbrot calculations:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import javax.swing.*;
#SuppressWarnings("serial")
public class Mandel2 extends JPanel {
private static final int GUI_HEIGHT = 600;
private static final int GUI_WIDTH = 600;
private static final int MAX_ITERS = 50000;
private BufferedImage image = new BufferedImage(GUI_WIDTH, GUI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
private Rectangle zoomRect;
private double myX0 = -2.5;
private double myY0 = -2.0;
private double myX1 = 1.5;
private double myY1 = 2.0;
private JDialog waitDialog;
public Mandel2() {
final MyMouse myMouse = new MyMouse();
int delayStartingCalc = 2 * 1000; // 2 second delay
Timer timer = new Timer(delayStartingCalc, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
addMouseListener(myMouse);
addMouseMotionListener(myMouse);
Rectangle myRect = new Rectangle(0, 0, GUI_WIDTH, GUI_HEIGHT);
createMandel(myRect);
}
});
timer.setRepeats(false);
timer.start();
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(GUI_WIDTH, GUI_HEIGHT);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (image != null) {
g.drawImage(image, 0, 0, this);
}
Graphics2D g2 = (Graphics2D) g;
if (zoomRect == null) {
return;
}
g2.setXORMode(Color.gray);
g2.draw(zoomRect);
}
private double screenToLogicalX(double screenX) {
return myX0 + (screenX * (myX1 - myX0)) / GUI_WIDTH;
}
private double screenToLogicalY(double screenY) {
return myY0 + ((GUI_HEIGHT - screenY) * (myY1 - myY0)) / GUI_HEIGHT;
}
private void createMandel(Rectangle myRect) {
double x0 = screenToLogicalX(myRect.x);
double y0 = screenToLogicalY(myRect.y + myRect.height);
double x1 = screenToLogicalX(myRect.x + myRect.width);
double y1 = screenToLogicalY(myRect.y);
myX0 = x0;
myY0 = y0;
myX1 = x1;
myY1 = y1;
MandelWorker mandelWorker = new MandelWorker(MAX_ITERS, x0, y0, x1, y1);
mandelWorker.addPropertyChangeListener(new MandelWorkerListener());
mandelWorker.execute();
if (waitDialog == null) {
Window win = SwingUtilities.getWindowAncestor(Mandel2.this);
JProgressBar jProgressBar = new JProgressBar();
jProgressBar.setIndeterminate(true);
waitDialog = new JDialog(win, "Please Wait", ModalityType.APPLICATION_MODAL);
waitDialog.add(jProgressBar);
waitDialog.pack();
waitDialog.setLocationRelativeTo(win);
}
waitDialog.setVisible(true);
}
private class MyMouse extends MouseAdapter {
private Point p;
#Override
public void mousePressed(MouseEvent e) {
p = e.getPoint();
}
public void mouseDragged(MouseEvent e) {
zoomRect = createRect(e);
repaint();
};
#Override
public void mouseReleased(MouseEvent e) {
zoomRect = createRect(e);
repaint();
createMandel(zoomRect);
}
private Rectangle createRect(MouseEvent e) {
int x = Math.min(p.x, e.getX());
int y = Math.min(p.y, e.getY());
int width = Math.abs(p.x - e.getX());
int height = Math.abs(p.y - e.getY());
return new Rectangle(x, y, width, height);
}
}
private class MandelWorkerListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
waitDialog.setVisible(false);
waitDialog.dispose();
MandelWorker worker = (MandelWorker) evt.getSource();
try {
image = worker.get();
zoomRect = null;
repaint();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
}
private class MandelWorker extends SwingWorker<BufferedImage, Void> {
private int maxIters;
private double x1;
private double y1;
private double x2;
private double y2;
public MandelWorker(int maxIters, double x1, double y1, double x2, double y2) {
this.maxIters = maxIters;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
#Override
protected BufferedImage doInBackground() throws Exception {
int[][] iterGrid = new int[GUI_HEIGHT][GUI_WIDTH];
for (int i = 0; i < GUI_HEIGHT; i++) {
double y = y1 + i * (y2 - y1) / GUI_HEIGHT;
for (int j = 0; j < GUI_WIDTH; j++) {
double x = x1 + j * (x2 - x1) / GUI_WIDTH;
int iIndex = GUI_HEIGHT - i - 1;
iterGrid[iIndex][j] = calcMandel(x, y);
}
}
return render(iterGrid);
}
private BufferedImage render(int[][] iterGrid) {
int w = GUI_WIDTH;
int h = GUI_HEIGHT;
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
if (iterGrid[i][j] < maxIters) {
String hexCode = String.format("#%06x", (0xFFFFFF & (32 * iterGrid[i][j])));
g2.setColor(Color.decode(hexCode));
} else {
g2.setColor(Color.CYAN);
}
g2.drawLine(j, i, j, i);
}
}
g2.dispose();
return img;
}
private int calcMandel(double x, double y) {
Complex c = new Complex(x, y);
Complex z = new Complex();
int iters = 0;
while (z.getMagnitude() < 2 && iters <= maxIters) {
z = z.multiply(z).add(c);
iters++;
}
return iters;
}
}
private class Complex {
private double real, imag;
// Constructors
public Complex() {
real = 0.0;
imag = 0.0;
}
public Complex(double real, double imag) {
this.real = real;
this.imag = imag;
}
// add given complex number to this one, returning the Complex result
public Complex add(Complex other) {
return new Complex(this.real + other.real, this.imag + other.imag);
}
// multiply given complex number by this one, returning the Complex
// result
public Complex multiply(Complex other) {
return new Complex((this.real * other.real) - (this.imag * other.imag),
(this.imag * other.real) + (this.real * other.imag));
}
// get the magnitude of this complex number
public double getMagnitude() {
return Math.sqrt((real * real) + (imag * imag));
}
}
private static void createAndShowGui() {
Mandel2 mainPanel = new Mandel2();
JFrame frame = new JFrame("Mandel2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Second iteration -- it does the calculations, but is not very efficient at it.

How to turn a String into a Algebraic Expression

So I am trying to write a program that gets a function like 3x^2 + x + 8 and then graphs said function. I am using the eval() method to turn a String into a expression but it keeps throwing a NullPointerException.
package Function;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;
public class FunctionGrapherTest
{
public static void main(String[] args)
{
JFrame frame = new JFrame();
FunctionGrapherComponent comp = new FunctionGrapherComponent();
frame.setSize(600, 600);
frame.setTitle("Function");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.add(comp);
frame.getContentPane().add(comp.control(), BorderLayout.SOUTH);
Dimension dimension = Toolkit.getDefaultToolkit().getScreenSize();
int x = (int)((dimension.getWidth() - frame.getWidth()) / 2);
int y = (int)((dimension.getHeight() - frame.getHeight()) / 2);
frame.setLocation(x, y);
}
}
package Function;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
public class FunctionGrapherComponent extends JPanel
{
private static final long serialVersionUID = 1L;
public FunctionGrapherComponent()
{
JPanel field = new JPanel();
JLabel y = new JLabel("y = ", SwingConstants.RIGHT);
field.add(y);
equaField = new JTextField(15);
field.add(equaField);
control = new JPanel();
control.setLayout(new GridLayout(1, 3));
control.add(field);
JButton draw = makeButton("Graph");
control.add(draw);
count = 0;
}
public JPanel control()
{
return control;
}
public JButton makeButton(String label)
{
JButton button = new JButton(label);
class ButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
String equation = equaField.getText();
if(!equation.equals("") || equation != null)
{
equa = equation;
count = 1;
repaint();
}
equaField.setText("");
}
}
ActionListener listener = new ButtonListener();
button.addActionListener(listener);
return button;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Axes axes = new Axes(xPixel(XMIN), xPixel(XMAX), yPixel(YMIN), yPixel(YMAX),
xPixel(0), yPixel(0), sWidth(1), sHeight(1));
axes.drawAxes(g2);
axes.drawTicks(g2);
if(count == 1)
{
Function func = new Function();
delta = (XMAX - XMIN) / 100;
for(double i = XMIN; i <= (XMAX - delta); i = i + delta)
{
x1 = xPixel(i);
y1 = yPixel(func.functionVal(i, equa));
x2 = xPixel(i + delta);
y2 = yPixel(func.functionVal(i + delta, equa));
func.plot(g2, x1, y1, x2, y2);
}
count = 0;
}
}
public double xPixel(double xuser)
{
return (xuser - XMIN) * (getWidth( ) - 1) / (XMAX - XMIN);
}
public double yPixel(double yuser)
{
return (yuser - YMAX) * (getHeight( ) - 1) / (YMIN - YMAX);
}
public double sHeight(double yuser)
{
return yuser * (getHeight() - 1) / (YMAX - YMIN);
}
public double sWidth(double xuser)
{
return xuser * (getWidth() - 1) / (XMAX - XMIN);
}
private static final double XMIN = -100;
private static final double XMAX = 100;
private static final double YMIN = -100;
private static final double YMAX = 100;
private double delta;
private double x1;
private double y1;
private double x2;
private double y2;
private int count;
private JPanel control;
private JTextField equaField;
private String equa;
}
package Function;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class Function
{
public Function()
{
}
public void plot(Graphics2D g2, double x1, double y1, double x2, double y2)
{
Line2D.Double seg = new Line2D.Double(x1, y1, x2, y2);
g2.draw(seg);
}
public double functionVal(double x, String equa)
{
ScriptEngineManager mgr = new ScriptEngineManager();
ScriptEngine engine = mgr.getEngineByName("Java");
try
{
funcVal = (double)engine.eval(equa);
}
catch (ScriptException e)
{}
return funcVal;
}
private double funcVal;
}
package Function;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
public class Axes
{
public Axes(double xmin, double xmax, double ymin, double ymax,
double xzero, double yzero, double xunit, double yunit)
{
xMin = xmin;
xMax = xmax;
yMin = ymin;
yMax = ymax;
xZero = xzero;
yZero = yzero;
xUnit = xunit;
yUnit = yunit;
}
public void drawAxes(Graphics2D g2)
{
Line2D.Double xAxis = new Line2D.Double(xMin, yZero, xMax, yZero);
Line2D.Double yAxis = new Line2D.Double(xZero, yMin, xZero, yMax);
g2.draw(xAxis);
g2.draw(yAxis);
}
public void drawTicks(Graphics2D g2)
{
for(double i = xZero + xUnit; i <= xMax; i = i + xUnit)
{
Line2D.Double tick = new Line2D.Double(i, yZero + TICK_LENGTH, i, yZero - TICK_LENGTH);
g2.draw(tick);
}
for(double i = xZero - xUnit; i >= xMin; i = i - xUnit)
{
Line2D.Double tick = new Line2D.Double(i, yZero + TICK_LENGTH, i, yZero - TICK_LENGTH);
g2.draw(tick);
}
for(double i = yZero + yUnit; i <= yMin; i = i + yUnit)
{
Line2D.Double tick = new Line2D.Double(xZero + TICK_LENGTH, i, xZero - TICK_LENGTH, i);
g2.draw(tick);
}
for(double i = yZero - yUnit; i >= yMax; i = i - yUnit)
{
Line2D.Double tick = new Line2D.Double(xZero + TICK_LENGTH, i, xZero - TICK_LENGTH, i);
g2.draw(tick);
}
}
private double xMin;
private double xMax;
private double yMin;
private double yMax;
private double xZero;
private double yZero;
private double xUnit;
private double yUnit;
private static final double TICK_LENGTH = 3;
}
Start by changing ScriptEngine engine = mgr.getEngineByName("Java"); to ScriptEngine engine = mgr.getEngineByName("javascript");, despite what some people think, Java isn't a scripting language and there is a difference between Java and JavaScript
Also, you shouldn't ignoring the exceptions thrown by the engine...
try {
System.out.println(equa);
funcVal = ((Number) engine.eval(equa)).doubleValue();
} catch (ScriptException e) {
e.printStackTrace();
}
You'll also find it faster if you don't re-create the ScriptEngine each time you call functionVal
public static class Function {
private final ScriptEngine engine;
public Function() {
ScriptEngineManager mgr = new ScriptEngineManager();
engine = mgr.getEngineByName("javascript");
}
public void plot(Graphics2D g2, double x1, double y1, double x2, double y2) {
Line2D.Double seg = new Line2D.Double(x1, y1, x2, y2);
g2.draw(seg);
}
public double functionVal(double x, String equa) {
try {
System.out.println(equa);
funcVal = ((Number) engine.eval(equa)).doubleValue();
} catch (ScriptException e) {
}
return funcVal;
}
private double funcVal;
}
Updated
So, assuming you want to solve the equation 3x^2 + x + 8, you need to give x some value...
engine.put("x", 10);
Then you can use 3*2^+x+8 as you equation...
funcVal = ((Number) engine.eval("3*2^+x+8")).doubleValue();
For example...
public double functionVal(double x, String equa) {
try {
System.out.println(equa);
engine.put("x", 10);
funcVal = ((Number) engine.eval(equa)).doubleValue();
System.out.println(equa + " = " + funcVal);
} catch (ScriptException e) {
e.printStackTrace();
}
return funcVal;
}

problem with extending classes

I'm making Braid. I have a class Wall that prevents that an object goes into a wall.
Everything with Wall is working. But now I'm trying to make the same with the ceilings.
My ceiling class extends Wall. I've simply made a constructor like this:
public Ceiling(boolean deadly, int[] xPositions, int[] yPositions)
{
super(deadly,
Direction.Down, //Enum: the direction you have to leave the wall (Left, Right)
//Here of course down
xPositions, yPositions);
}
Now I have in my level-class an ArrayList of all the Walls and an ArrayList of all the Ceilings.
I have to add the Walls on this way:
walls.add(new Wall(false, Direction.Right, ..., ...));
And the Ceilings on this way:
ceilings.add(new Ceiling(false, ..., ...));
The ... replaces the coordinates.
If I check if there is an object in a Ceiling: there has nothing happened: the object goes through the ceiling. And if I use this way to add a Ceiling, it works:
ceilings.add(new Wall(false, Direction.Down, ..., ...));
I hope I've explained well.
Does somebody know what the problem is??
Thanks
Edit:
This is my collition code:
public boolean intersects(Rectangle r)
{
if (!bounds.intersects(r))
{
return false;
}
for (int i = 1; i < yPositions.length; i++) {
Line l = new Line(xPositions[i - 1], yPositions[i - 1], xPositions[i], yPositions[i]);
if (r.intersectsLine(l)) {
return true;
}
}
return false;
}
My Code
'doodelijk' means deadly
Wall:
package levels;
import domein.Direction;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
public class Wall
{
public boolean doodelijk;
public int[] yPositions;
public int[] xPositions;
private Rectangle bounds;
public Direction directionToLeave;
public Wall(boolean doodelijk, Direction directionToLeave, int[] yPositions, int[] xPositions)
{
this.doodelijk = doodelijk;
this.yPositions = yPositions;
this.xPositions = xPositions;
this.directionToLeave = directionToLeave;
createRectangle();
}
public boolean intersects(Rectangle r)
{
if (!bounds.intersects(r))
{
return false;
}
for (int i = 1; i < yPositions.length; i++) {
Line l = new Line(xPositions[i - 1], yPositions[i - 1], xPositions[i], yPositions[i]);
if (r.intersectsLine(l)) {
return true;
}
}
return false;
}
private void createRectangle()
{
int x = Integer.MAX_VALUE;
int y = Integer.MAX_VALUE;
int x1 = 0;
int y1 = 0;
for (int i = 0; i < xPositions.length; i++)
{
int tx = xPositions[i];
int ty = yPositions[i];
if (x > tx)
{
x = tx;
}
if (y > ty)
{
y = ty;
}
if (x1 < tx)
{
x1 = tx;
}
if (y1 < ty)
{
y1 = ty;
}
}
bounds = new Rectangle(x, y, x1 - x + 1, y1 - y +1);
System.out.println("Rect: " + bounds);
}
class Line extends Line2D
{
Point2D p1;
Point2D p2;
public Line()
{
p1 = new Point();
p2 = new Point();
}
public Line(Point2D p1, Point2D p2)
{
this.p1 = p1;
this.p2 = p2;
}
public Line(double X1, double Y1, double X2, double Y2)
{
this();
setLine(X1, Y1, X2, Y2);
}
#Override
public double getX1()
{
return p1.getX();
}
#Override
public double getY1()
{
return p1.getY();
}
#Override
public Point2D getP1()
{
return p1;
}
#Override
public double getX2()
{
return p2.getX();
}
#Override
public double getY2()
{
return p2.getY();
}
#Override
public Point2D getP2()
{
return p2;
}
#Override
public void setLine(double X1, double Y1, double X2, double Y2)
{
p1.setLocation(X1, Y1);
p2.setLocation(X2, Y2);
}
public Rectangle2D getBounds2D()
{
return new Rectangle((int) getX1(), (int) getY1(), (int) (getX2() - getX1()), (int) (getX2() - getY1()));
}
}
public void setXpositions(int ... xPos)
{
this.xPositions = xPos;
}
public void setYpositions(int ... yPos)
{
this.yPositions = yPos;
}
public void setPositions(int[] yPos, int[] xPos)
{
setXpositions(xPos);
setYpositions(yPos);
}
}
Ceiling:
package levels;
import domein.Direction;
public class Ceiling extends Wall
{
public Ceiling(boolean doodelijk, int[] xPositions, int[] yPositions)
{
super(doodelijk, Direction.Down, yPositions, xPositions);
}
}
Are you sure about your settings of the xposition and yposition arguments? That is, is the ceiling really where you think it is? Is it the same in your two variants of the constructor?
I guess the problem is in the code that checks for the "collision". I cant see any problem in the one you've given.
I don't see any obvious problems with your classes. There might be a bug somewhere else and you would have to post the complete classes for us to identify it.

Categories

Resources