Reputation: 327
I have a program where I need to recursively generate new lines off of parent lines so that it ends up looking like a tree. The problem I'm having is that I don't know how to make the child line at angle A, where A is between 10 and 80 or 100 and 170 degrees, relative to its parent line.
My current algorithm steps are the following:
At this point, I need to calculate (x2, y2) that is at angle A relative to the parent line. Any suggestions?
EDIT: Also, my program will randomly choose which side of the parent line to draw the new line. So, sometimes it will be angle A, other times it will be A + 90.
Upvotes: 2
Views: 2415
Reputation: 67311
With a class like this you could do the calculations first and draw the whole thing in a third step.
This code is completely untestet. There will be some errors, but you might get an idea how one could do this...
public class MyLine {
private Random random;
public MyLine(int Level, PointF Start, PointF End, int Angle) {
this.random = new Random();
this.Level = Level;
this.Start = Start;
this.End = End;
this.Angle = Angle;
}
public int Level{get;set;}
public PointF Start { get; set; }
public PointF End { get; set; }
public float MyLength {
get {
return (float)Math.Sqrt(Math.Pow(End.X - Start.X, 2) + Math.Pow(End.Y - Start.Y, 2));
}
}
public int Angle { get; set; }
public MyLine MySideLine { get; set; }
public void CalculateSideLine() {
float middleX = Start.X + (End.X - Start.X) / 2f;
float k = (End.Y - Start.Y) / (End.X - Start.X);
float d = (End.X * Start.Y - Start.X * End.Y) / (End.X - Start.X);
float middleY = k * middleX + d;
PointF newStart = new PointF(middleX, middleY);
int angle = random.Next(10, 80);
if (random.Next(0, 1) == 0)
angle = angle + 90;
float LengthPercentage = (float)random.NextDouble();
if (LengthPercentage < 0.5)
LengthPercentage = 0.5f;
float newLength = MyLength * LengthPercentage;
//Now we know the starting point of the new line, its angle and the length
//I do not have enough time to write the complete calculation down but it's result would be a new endPoint
//You think of a circle with its middle on "newStart" and its radius = "newLength".
//This circle you'll have to intersect with the line through "newStart" with the given angle.
//There are two results, you have to choose the one in the right direction
PointF newEnd = new PointF(0, 0); //This you'll have to find yourself...
this.MySideLine = new MyLine(this.Level++, newStart, newEnd, angle);
//this will calculate a new nested side line and - kind of recursively - go deeper and deeper.
//you'll have to find a break condition on a certain level.
this.MySideLine.CalculateSideLine();
//Be aware of randomly angle of 90 or 0. you might want to calculate two side lines on each twig (otherwise it will not look like a tree)
}
//This will draw the line to a Graphics (e.g. look at Form.CreateGraphics() )
//it will kind of recursively draw down the full tree.
public void DrawMeAndMySideLine(Graphics g){
g.DrawLine(Pens.Black,this.Start,this.End);
this.MySideLine.DrawMeAndMySideLine(g);
}
}
Upvotes: 2
Reputation:
you would need to know the angle of the parent line as well as the angle of the child line. Your terms are confusing so I am going to use a little different. And it needs to be noted that the angles of all the branches should be stored as angles relative to horizontal, although you will need to calculate them relative to the parent branch to do your 10-80,100-170 thing. But the calculation for the angle from horizontal is easy enough and given below:
1. figure out origin of the new branch<p>
a. BreakOffDistance = a random number less than the parent length (random distance from the start of the parent branch)
b. NewBranchOriginX = ParentBranchOriginX + BreakOffDistance * cos(ParentBranchAngle);
c. NewBranchOriginY = ParentBranchOriginY + BreakOffDistance * sin(ParentBranchAngle);
2. figure out a random angle to the new, child line;
a. figure out random angle between 10 and 80 or 100 and 170.
b. NewBranchAngle = ParentBranchAngle - 90 + RandomAngle.
(all branch angles relative to horizontal, right?)
3. figure out random length of new branch - less than parent?
4. The previous steps determine the new branch - origin point, angle and length. But to figure out its endpoint so you can draw it:
a. NewBranchEndX = NewBranchOriginX + NewBranchLength * cos(NewBranchAngle);
b. NewBranchEndY = NewBranchOriginY + NewBranchLength * sin(NewBranchAngle);
Because screen coordinates are turned upside down, you might need to replace the plus signs in steps 1b, 1c, and 4a, and 4b with minus signs.
Also, if you are trying to simulate a tree, I don't think it is right to choose the angle of a new branch as 10-80 or 100-170. Branches in a tree prefer to grow out and up, and it is not hard to do that in figuring out the angle for each new branch. Finally, your tree would be much more realistic if you thought of it in three dimensions. Have a tree that grows branches towards and away from you as well as to the sides. That too would be fairly simple, but more than you asked for.
Upvotes: 2
Reputation: 39250
Making some assumption on the result, as I'm not clear exactly what you're aiming for, I'd say that the calculation is as follows.
int x2 = x1 + newBranchDist * Math.Cos(a);
int y2 = y1 + newBranchDist * Math.Sin(a);
Then, you can verify the length by Pythagorean theorem.
double lengthSquared = Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2);
double lengthRooted = Math.Pow(lengthSquared, 0.5);
Upvotes: 3