There are several issues with this code:
Nobody is calling the paint(Graphics g, int a, int b, int c)
method. When you inherit from a Swing component like this, there are several methods that are invoked "automatically" (among them a paint(Graphics g)
method). But in order to perform custom painting, you should usually override the paintComponent(Graphics g)
method.
You are generating random numbers while you are painting. This will have some odd effects. The most obvious one: When you resize the frame (or something else happens that causes the frame to be repainted), a new random vine will appear. It will have nothing in common with the previous one, causing a flickering mess, in the best case.
In order to create reporoducible results that are still "random", I generally recommend to not use Math.random()
. (In fact, I never use this, at all). The java.util.Random
class is usually preferable. It allows creating reproducible random number sequences (which is helpful for debugging), and it offers convenient methods like Random#nextBoolean()
, which has exactly the effect that you probably wanted to achieve with the (somewhat oddly implemented) TF()
method. This leads to the next point...:
Use better variable- and method names. Naming variables like the c
in your example, or methods TF()
, will make the code unreadable. You may call them x
and y
if they refer to screen coordinates, but the c
should probably be called age
, and the TF()
method ... heck, I don't know how this should be called, maybe something like shouldBranch()
?
If you have to perform "extensive" computations (like the random branching, in your example), it is usually better to pull this computation out of the painting process. You can assemble the desired lines and paintings in various ways. For the given example, a simple Path2D
should be sufficient.
So far, the technical things. Apart from that: The algorithm itself will not lead to "nice" results. The random branching for each pixel will cause the lines to clob together to a black, fuzzy spot.
In fact, it can be pretty hard to tweak this to create "nice" results. It is hard to exactly say how the "randomness" should influence the overall appearance. The branching should be random, the angles should be random, the branch lengths should be random. Additionally, it will always look a bit odd when all the lines are drawn with the same thickness. The thickness of the lines should probably decrease at each branch, and along the branches in general.
In some practical applications, this generation of random plant-like structures is done with Lindenmayer systems - this may be a starting point for further research.
However, here is a very simple example of how simple lines can be assembled, somewhat randomly, to create something that resembles a plant:

Of course, this looks like cr*p compared to what one could do, given enough time and incentive. But it consists only of a few lines of code that randomly assemble a few branching lines, so this is as good as it gets without considering all the possible improvements.
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class VinePainting
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
private void createAndShowGUI()
{
JFrame f = new JFrame("Vine");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
VinePanel panel = new VinePanel();
Container c = f.getContentPane();
panel.setBackground(Color.WHITE);
c.add(panel);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
});
}
}
class VinePanel extends JPanel
{
private static final Random RANDOM = new Random(0);
private Path2D vine;
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
if (vine == null)
{
vine = createVine(getWidth()/2, getHeight());
}
g.setColor(Color.BLACK);
g.draw(vine);
}
private Path2D createVine(int x, int y)
{
Path2D path = new Path2D.Double();
double angleRad = Math.toRadians(-90);
grow(path, x, y, angleRad, 10.0, 0, 30);
return path;
}
private static void grow(Path2D path,
double x, double y, double angleRad,
double stepSize, int step, int steps)
{
if (step == steps)
{
return;
}
path.moveTo(x, y);
double dirX = Math.cos(angleRad);
double dirY = Math.sin(angleRad);
double distance = random(stepSize, stepSize + stepSize);
double newX = x + dirX * distance;
double newY = y + dirY * distance;
path.lineTo(newX, newY);
final double angleRadDeltaMin = -Math.PI * 0.2;
final double angleRadDeltaMax = Math.PI * 0.2;
double progress = (double)step / steps;
double branchProbability = 0.3;
double branchValue = RANDOM.nextDouble();
if (branchValue + 0.1 < branchProbability)
{
double angleRadDelta = random(angleRadDeltaMin, angleRadDeltaMax);
double newAngleRad = angleRad + angleRadDelta;
double newStepSize = (1.0 - progress * 0.1) * stepSize;
grow(path, newX, newY, newAngleRad, newStepSize, step+1, steps);
}
double angleRadDelta = random(angleRadDeltaMin, angleRadDeltaMax);
double newAngleRad = angleRad + angleRadDelta;
double newStepSize = (1.0 - progress * 0.1) * stepSize;
grow(path, newX, newY, newAngleRad, newStepSize, step+1, steps);
}
private static double random(double min, double max)
{
return min + RANDOM.nextDouble() * (max - min);
}
}
A side note: This is somewhat similiar to this question. But there, randomness did not play a role, so the recursion is done while painting the tree. (Therefore, it allows playing around with some sliders, to modify the parameters and observe the effects).