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 )

1 Like

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)
2 Likes

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.

2 Likes

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

2 Likes

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

1 Like

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

1 Like

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)

3 Likes