We get the cosine of the angle between two vectors if we divide the dot product of the two vectors by the product of the lengths of the two vectors. To figure that out we need some mathematics. To implement this, we need to figure out in which direction the path points at each position and then rotate the circle to match that direction. However, it would be much nicer if the circles would tilt according to the local orientation of the path. Theoretically, we could now connect the circles pairwise using the hull transformation and would obtain an already quite passable 3D geometry. The circle geometry recognizably follows a curved path and is scaled in the process. : Displacement of a 2D basic shape along a path (left) and its corresponding orthogonal side view (right)įigure 9. The chain of calls to children() forwards this outer element down into the submodule flame. If we look at its instance, we see that here the first subsequent element is a circle with a diameter of 60. As subsequent element we have used children(0) again! This children(0) refers now to the element that follows the instance of the module flames (plural!). Below the definition of the submodule flame we have instantiated a test instance of the module. the element that follows the instance of the submodule flame. We create the actual scaling vector as a linear interpolation between scaling_start and scaling_end, taking the interpolation ratio from the s_factors array.īetween scaling and translation we perform a linear extrusion to transform the 2D geometry into a 3D geometry. We define a submodule flame and inside this module we use a single for-loop to go through the positions array and the s_factors array in parallel and use their values to scale and translate the 2D geometry. Before we continue, let’s create a temporary version of a single flame to see if we are on the right track: Like the positions, we calculate the scaling factors using a generative for-loop and store them in the s_factors array.
gives an impression of the effect different values for steepness and transition have on the output of the function. These two parameters also expect values between 0 and 1. Furthermore, we scale the function so that we can set the relative position and slope of the sigmoidal transition by means of the parameters steepness and transition. In addition, we parameterize our function in such a way that the sigmoidal transition lies in the interval 0 to 1 of the parameter x.
We define our sigmoid function by means of the exponential function exp and the well-known scheme 1 / (1 + exp(-x) ). ) 1 / ( 1 + exp( -( x / increment + starting_point) ) ) ġ.0 - sigmoid( i / slices, steepness, transition ) Since OpenSCAD does not offer a “ready-made” sigmoid function, we have to create one ourselves:įunction sigmoid(x, steepness = 0.5, transition = 0.5) = let ( Instead of scaling linearly we will use a sigmoid function. : Height distortion based on power functionīesides positioning, we also want to scale our basic shape along the path. gives an impression of how the power function behaves for different values of the parameter height_distortion. Instead of letting the Z-coordinate grow linearly, we use a power function to be able to influence the distribution of points along the Z-axis with the parameter height_distortion. Here, the X- and Y-coordinates of our positions move along an elliptical circular path with radii x_radius and y_radius while the Z-coordinate moves upwards. We compute the array using a generative for-loop.
We store the positions along our path as three-dimensional vectors within an array. Analogously, we derive a rotation increment rot_inc. From this we can determine an increment as an internal variable, which we will need later. The parameter slices specifies the number of steps we want to calculate along the path. The parameter height specifies the height of the path we want to create. Pow( i / slices, height_distortion) * height