Branch Curve
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © kaigouthro
//@version=5

import RicardoSantos/CommonTypesMath/1

//@description Generates a branch made of segments with a starting angle
// and a turning angle for each segment. The branch is generated from a starting point
// and a number of nodes to generate. The length of each segment and angle of each segment
// can be adjusted. The branch can be generated in 2D or 3D, render as you wish.
library("branch")

//@function # Branch Generation.
// - `origin`: CommonTypesMath.Vector3 - The starting point of the branch. If the z value is not zero, it will be used as the starting angle.
// - `nodes`: int - The number of nodes to generate.
// - `segment_length`: float - The length of each segment.
// - `segment_growth`: float - The growth of each segment. 0 = no growth, 100 = double the length of the previous segment.
// - `angle_start`: float - The starting angle of the branch in degrees.
// - `angle_turn`: float - The turning angle of each segment in degrees.
// @param origin The starting point of the branch. If the z value is not zero, it will be used as the starting angle.
// @param nodes The number of nodes to generate.
// @param segment_length The length of each segment.
// @param segment_growth The growth of each segment. 0 = no growth, 100 = double the length of the previous segment.
// @param angle_start The starting angle of the branch in degrees.
// @param angle_turn The turning angle of each segment in degrees.
// @return segments The list of segments that make up the branch.
export method branch(CommonTypesMath.Vector3 origin, int nodes, float segment_length, float segment_growth, float angle_start, float angle_turn) => 
    // create a list of Point objects
    points= array.new<CommonTypesMath.Vector3>()
    // set the initial point
    points.push(CommonTypesMath.Vector3.new(origin.x, origin.y, origin.z))
    // set the initial angle, if origin includes a value, use it, otherise angle start
    prev_angle = origin.z
    angle=  0.
    angle:= na(prev_angle) ? math.toradians(angle_start + 180) : prev_angle
    // set the initial distance // resets to zero for gennerating muliples
    distance=  0.
    distance:= segment_length
    // create a list of segments
    segments= array.new<CommonTypesMath.Segment3>()
    // loop until we have enough points
    while points.size() < nodes
        // get the prev CommonTypesMath.Vector3
        last_point= points.last()
        // calculate the next CommonTypesMath.Vector3
        next_point= CommonTypesMath.Vector3.new(last_point.x + distance * math.cos(angle), last_point.y + distance * math.sin(angle), angle)
        // adjust the angle
        last_point.z := angle
        angle += math.toradians(angle_turn)
        next_point.z := angle
        // add the next CommonTypesMath.Vector3
        points.push(next_point)
        // add a segment to the list
        segments.push(CommonTypesMath.Segment3.new(last_point, next_point))
        // adjust the distance
        distance *= 1 + segment_growth/100
    // return the segments
    segments
