我目前有一个使用递归绘制分形树的工作代码。但是,当我尝试迭代绘制它时,它无法正常工作。
let width = image.size.width
let height = image.size.height
let size = min(width, height)
let x1 = (width - size) / 2
let y1 = (height - size) / 2
let x2 = x1 + size
let y2 = y1 + size
答案 0 :(得分:2)
忽略分形数学:如果要保留递归绘图,请使用SwingWorker扭曲长进程(递归计算),并让它更新GUI。这是一个例子:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class RecursiveDraw extends JFrame {
private int x1A, y1A, x2A, y2A;
private final int W = 700, H = 500;
private Random random = new Random();
private Color randomColor = Color.BLUE;
private JPanel panel;
public RecursiveDraw() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
panel = new MyPanel();
add(panel, BorderLayout.CENTER);
pack();
setVisible(true);
new Task().run();
}
public void recursiveDraw(int x1A, int y1A, int depth){
if(depth > 15) { return;}
this.x1A = x1A; this.y1A = y1A;
x2A = random.nextInt(W);
y2A = random.nextInt(H);
randomColor = new Color(random.nextInt(0xFFFFFF));
panel.repaint();
try {
Thread.sleep(1000); //delay
} catch (InterruptedException ex) { ex.printStackTrace();}
recursiveDraw(x2A, y2A, ++depth );
}
class MyPanel extends JPanel{
public MyPanel() {
setPreferredSize(new Dimension(W,H));
}
@Override
public void paintComponent(Graphics g) {
//super.paintComponent(g); //requires storing all points calculated
//so they can be redrawn. recommended
g.setColor(randomColor);
g.drawLine(x1A, y1A, x2A, y2A);
}
}
class Task extends SwingWorker<Void,Void> {
@Override
public Void doInBackground() {
recursiveDraw(W/2, H/2, 0);
return null;
}
}
public static void main(String[] args) {
new RecursiveDraw();
}
}
@MadProgrammer提出的使用Timer的迭代绘图的基本结构可能如下所示:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
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 TimerIterativeDraw extends JFrame {
private final static int W = 700, H = 500;
private final static int DELAY= 1000;
private final static int NUMBER_OF_DRAWS_LIMIT = 50;
private int x2A = W/2, y2A = H/2, x1A, y1A, numberOfDraws;
private Random random = new Random();
private Color randomColor = Color.BLUE;
private JPanel panel;
private Timer timer;
public TimerIterativeDraw() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
panel = new MyPanel();
add(panel, BorderLayout.CENTER);
pack();
setVisible(true);
timer = new Timer(DELAY,new Task());
timer.start();
}
public void upDateGui(){
if(numberOfDraws++ >= NUMBER_OF_DRAWS_LIMIT){
timer.stop();
}
x1A = x2A; y1A = y2A;
x2A = random.nextInt(W);
y2A = random.nextInt(H);
randomColor = new Color(random.nextInt(0xFFFFFF));
//for better implementation store all points in an array list
//so they can be redrawn
panel.repaint();
}
class MyPanel extends JPanel{
public MyPanel() {
setPreferredSize(new Dimension(W,H));
}
@Override
public void paintComponent(Graphics g) {
//super.paintComponent(g); //requires storing all points calculated
//so they can be redrawn. recommended
g.setColor(randomColor);
g.drawLine(x1A, y1A, x2A, y2A);
}
}
class Task implements ActionListener {
@Override
public void actionPerformed(ActionEvent arg0) {
upDateGui();
}
}
public static void main(String[] args) {
new TimerIterativeDraw();
}
}
答案 1 :(得分:1)
可能有几种方法可以做到这一点,但是......
所以,首先,我们需要某种方式以某种阶梯方式创建分支。我们的想法是每次告知课程更新时才生成新的分支。
该课程将包含它唯一的州和管理层,但会提供对其创建的List
点的访问权限,可能类似......
public class Generator {
private List<Point> points;
private double angle;
private double delta;
private int depth = 9;
private Timer timer;
public Generator(Point startPoint, double startAngle, double delta) {
points = new ArrayList<>(25);
points.add(startPoint);
angle = startAngle;
this.delta = delta;
}
public List<Point> getPoints() {
return new ArrayList<Point>(points);
}
public boolean tick() {
Point next = updateTree(points.get(points.size() - 1), angle);
angle += delta;
depth--;
if (next != null) {
points.add(next);
}
return next != null;
}
public Point updateTree(Point p, double angle) {
if (depth == 6) {
return null;
}
System.out.println("depth = " + depth + "; angle = " + angle);
//embedded portion '(Math.toRadians(angle) * depth * 10.0)'represents angle...
int x2 = p.x + (int) (Math.cos(Math.toRadians(angle)) * depth * 10.0); //vertical shift calculated using the Sine...PARSED to int because method drawLine() accepts only ints as params
int y2 = p.y + (int) (Math.sin(Math.toRadians(angle)) * depth * 10.0); //hor. shift calculated using the Cos..PARSED to int
return new Point(x2, y2);
}
}
现在,这个类只生成一个分支,为了创建一个树,你需要这个类的两个实例,具有不同的delta
s
接下来,我们需要一定要求这个生成器在常规基础上生成下一步。对我来说,这通常使用Swing Timer
调用。
原因是:
将这两件事放在一个简单的JPanel
中,它控制Timer
并绘制点......
public class TestPane extends JPanel {
private Generator left;
private Generator right;
public TestPane() {
Point startPoint = new Point(200, 400);
left = new Generator(startPoint, -90, -20);
right = new Generator(startPoint, -90, 20);
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
boolean shouldContinue = left.tick() && right.tick();
if (!shouldContinue) {
((Timer)(e.getSource())).stop();
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(Color.RED);
render(g2d, left.getPoints());
g2d.setColor(Color.BLUE);
render(g2d, right.getPoints());
g2d.dispose();
}
protected void render(Graphics2D g2d, List<Point> points) {
Point start = points.remove(0);
while (points.size() > 0) {
Point end = points.remove(0);
g2d.draw(new Line2D.Double(start, end));
start = end;
}
}
}