Convert blender's 2d Bezier curve into a ShapePath

i have a 2d bezier curve with 4 handles in blender which looks like this:

using this python code i’m trying to convert it into a shape path

import bpy
curve = bpy.data.curves['BezierCircle']

path_string = "const shape = new Shape()\n"

for spline in curve.splines:
    if spline.type == 'BEZIER':
        start_point = spline.bezier_points[0].co
        path_string += ".moveTo(" + str(start_point[0]) + "," + str(start_point[1]) + ")\n"
        
        for i, point in enumerate(spline.bezier_points):
           
            x = point.co[0]
            y = point.co[1]

            handle_left_x=point.handle_left[0]
            handle_left_y = point.handle_left[1]
             
            handle_right_x = point.handle_right[0]
            handle_right_y= point.handle_right[1]
            
            path_string += ".bezierCurveTo(" + str(handle_left_x) + "," + str(handle_left_y) + "," + str(handle_right_x) + "," + str(handle_right_y) + "," + str(x) + "," + str(y) + ")\n"

print(path_string)

which prints


const shape = new Shape()
		.moveTo(-0.5, 0.0)
		.bezierCurveTo(-0.5, -0.2, -0.5, 0.2, -0.5, 0.0)
		.bezierCurveTo(-0.2, 0.5, 0.2, 0.5, 0.0, 0.5)
		.bezierCurveTo(0.5, 0.2, 0.5, -0.2, 0.5, 0.0)
		.bezierCurveTo(0.2, -0.5, -0.2, -0.5, 0.0, -0.5)
	

on using this as a shapeGeomtery in three js
the shape looks broken

are there any mistakes here ?

the syntax i’m using is

bezierCurveTo( handle_x1 ,handle_y1 ,handle_x2 ,handle_y2, x ,y )

Yes, there is a mistake. The control points are messed up. Try this. Does it show correctly?

.moveTo(-0.5, 0.0)
.bezierCurveTo(-0.5, -0.2, -0.2, -0.5, 0, -0.5)
.bezierCurveTo(0.2, -0.5, 0.5, -0.2, 0.5, 0)
.bezierCurveTo(0.5, 0.2, 0.2, 0.5, 0, 0.5)
.bezierCurveTo(-0.2, 0.5, -0.5, 0.2, -0.5, 0)

v2

indeed it looks correct now.

do you know where in the translation it went wrong ?

Yes.

Your input data is about handles (i.e. one central point, and two points from both sides).

The Bezier curve is defined by 4 points – two end points and two points between them. The command bezierCurveTo expects these 4 points in this way:

  • point 1 – it is the current point and is not included as parameter
  • point 2 – its coordinates give the first two parameters
  • point 3 – its coordinates give the next two parameters
  • point 4 – its coordinates give the last two parameters

The blue curve is one Bezier curve. You can see its 4 points with blue circles.

I’m a bit late to the party :slight_smile: https://codepen.io/prisoner849/pen/qByQRyX

ohhhhh !

when iterating over blender curve’s point i’m just dealing with a single coordinate point and it’s two handles .

i’ll update the python code to use two consecutive points to fill the constructor params

does not work without “.js” in imports (firefox)

Hm… works for me both in FF and in Chrome :thinking:
Also works with Opera.

i’m using firefox too, it runs fine for me

it might be time for you to do a factory reset on firefox (don’t forget to backup your bookmarks and stuff),

I also had issues with three js examples which got fixed after a fresh install

that image explanation was just what i needed !

New 2d bezier curve drawn in blender:

Updated python script code :

import bpy
curve = bpy.data.curves['BezierCircle']

path_string = "const shape = new Shape()\n"

for spline in curve.splines:
    if spline.type == 'BEZIER':
        start_point = spline.bezier_points[0].co
        path_string += ".moveTo(" + str(round(start_point[0],2)) + "," + str(round(start_point[1],2)) + ")\n"
        
        count=len(spline.bezier_points)
        for i in range(count):
            dat_a=spline.bezier_points[i]
           
            ax,ay=round(dat_a.co[0],3),round(dat_a.co[1],3)
            al1,al2=round(dat_a.handle_left[0],3),round(dat_a.handle_left[1],3)
            ar1,ar2=round(dat_a.handle_right[0],3),round(dat_a.handle_right[1],3)
       
            if i+1<count:
                dat_b=spline.bezier_points[i+1] # connect to next point
            else:
               dat_b=spline.bezier_points[0] # connect last to first
               
            bx,by=round(dat_b.co[0],3),round(dat_b.co[1],3)
            bl1,bl2=round(dat_b.handle_left[0],3),round(dat_b.handle_left[1],3)
            br1,br2=round(dat_b.handle_right[0],3),round(dat_b.handle_right[1],3)
            

            path_string += (".bezierCurveTo(" 
            + str(ar1) + "," + str(ar2) + "," 
            + str(bl1) + ","  + str(bl2) + "," 
            + str(bx) + "," + str(by) + ")\n")
                
print(path_string)

which prints

const shape = new Shape()
		.moveTo(-0.26, 0.3)
		.bezierCurveTo(-0.189, 0.336, -0.213, 0.162, -0.137, 0.137)
		.bezierCurveTo(0.031, 0.081, 0.221, 0.419, 0.3, 0.261)
		.bezierCurveTo(0.336, 0.189, 0.162, 0.213, 0.137, 0.137)
		.bezierCurveTo(0.081, -0.031, 0.419, -0.221, 0.261, -0.3)
		.bezierCurveTo(0.189, -0.336, 0.213, -0.162, 0.137, -0.137)
		.bezierCurveTo(-0.031, -0.081, -0.221, -0.419, -0.3, -0.261)
		.bezierCurveTo(-0.336, -0.189, -0.162, -0.213, -0.137, -0.137)
		.bezierCurveTo(-0.081, 0.031, -0.419, 0.221, -0.261, 0.3)

and in three js

thank you again @PavelBoytchev

CodePen of this shape (thank you @prisoner849 for the codepen)