The algorithm used is fairly simple: just draw a branch (a segment) and then attach some others branches to it calling recursively the same branch method. Recursive calls are stopped when branch length falls below a giver value. to make the final result a little more realistic a little randomness is added and branch color is decided on the basis of branch length.
The result is far from being satisfying (and lightyears far from artistic results as in here) but I don't think I'll get something better before Christmas.
Here is the code of the tree drawing class while the user interface was generated by the Netbeans plugin with only minimal manual coding needed.
package ph.mm.demo.fractals; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.Random; /** * * @author user */ public class TreePainter { Graphics2D graphics = null; private double scale = 0.42; private double scale2 = 0.49; private double angle =115; private double minLength = 3; private double rangle = 0; private double split = 0.6; private double noise = 0.05; private long seed = 3214; private Random rnd=null; private double x0=200; private double y0=350; private double x1=200; private double y1=200; float colScale = 0; public TreePainter(Graphics g) { graphics = (Graphics2D)g; graphics.setBackground(Color.BLACK); graphics.clearRect(0, 0, 500, 500); rangle=Math.toRadians(angle); rnd = new Random(seed); colScale = (float)(1/(y0-y1)); } public void paint(){ Line2D l = new Line2D.Double(x0, y0, x1, y1); branch(l); } public void branch(Line2D l){ Rectangle2D r = l.getBounds2D(); double size = Math.sqrt(r.getWidth()*r.getWidth() + r.getHeight()*r.getHeight()); graphics.setColor(getCol(size)); graphics.draw(l); if(size>minLength){ double cAngle=0; cAngle = Math.acos((l.getX2()-l.getX1())/size); System.out.println(size+ ", " + Math.toDegrees(cAngle)); if(l.getY1()>l.getY2()) cAngle=-cAngle; Point2D pSplit = new Point2D.Double(l.getX1() + (l.getX2()-l.getX1())*split, l.getY1() + (l.getY2()-l.getY1())*split); Point2D pEnd1 = new Point2D.Double(l.getX2() + size*scale*getNoise()*Math.cos(cAngle), l.getY2() + size*scale*getNoise()*Math.sin(cAngle)); Point2D pEnd2 = new Point2D.Double(l.getX2() + size*scale*getNoise()* Math.cos(cAngle*getNoise()+rangle), l.getY2() + size*scale*getNoise()*Math.sin(cAngle*getNoise()+rangle)); Point2D pEnd3 = new Point2D.Double(l.getX2() + size*scale*getNoise()* Math.cos(cAngle*getNoise()-rangle), l.getY2() + size*scale*getNoise()*Math.sin(cAngle*getNoise()-rangle)); Point2D pEnd4 = new Point2D.Double(pSplit.getX() + size*scale2*getNoise()* Math.cos(cAngle*getNoise()+rangle), pSplit.getY() + size*scale2*getNoise()*Math.sin(cAngle*getNoise()+rangle)); Point2D pEnd5 = new Point2D.Double(pSplit.getX() + size*scale2*getNoise()* Math.cos(cAngle*getNoise()-rangle), pSplit.getY() + size*scale2*getNoise()*Math.sin(cAngle*getNoise()-rangle)); branch(new Line2D.Double(l.getP2(), pEnd1)); branch(new Line2D.Double(l.getP2(), pEnd2)); branch(new Line2D.Double(l.getP2(), pEnd3)); branch(new Line2D.Double(pSplit, pEnd4)); branch(new Line2D.Double(pSplit, pEnd5)); } } private double getNoise(){ return (rnd.nextDouble()-0.5)*2*noise+1; } private Color getCol(double size){ if(size<minLength) return new Color(0.05F, 0.5F, 0.2F); else if(size<minLength*2) return new Color(0.05F,0.4F, 0.1F); else if(size<minLength*10) return new Color(0.05F,0.3F, 0.3F); else return new Color(0.3F,0.3F, 0.1F); } } |
No comments :
Post a Comment