3
$\begingroup$

I'm quite new to blender-python so forgive me if there are some things I don't get right...

I try to model some cables with the Blender Python API. I came to the point where I need to inset the ends of the cables and extrude them (represents the copper ends of a wire). I searched online but could not find a good solution for my problem.

This is my code so far:

import bpy 
import math 
import random
import bmesh


#define number of Cables
numberOfCables = 2
count = 0

#clean scene (delete all objects inside
def clean_scene():
    for things in bpy.data.objects:
        bpy.data.objects.remove(things)

clean_scene()
#bpy.ops.object.select_all(action='SELECT')
#bpy.ops.object.delete(use_global=False, confirm=False)

#Main Programm
for i in range(numberOfCables):

    #define random values for location and size
    X = random.uniform(0,5)
    Y = random.uniform(0,5)
    randomRadius = random.randrange(15,50,5)/10000 #random thickness ranging from 3mm to 8mm
    randomLength = random.uniform(0.3,1) #random length ranging from 30cm to 1m
    randomSeed = random.uniform(0,10)
    #print(randomRadius)
    
    #create Curve
    def create_Curve():
        bpy.ops.curve.primitive_nurbs_path_add(radius = randomRadius, 
                enter_editmode = True, 
                location=(X,Y,1))
        return bpy.context.object
    
    obj = create_Curve()
        
    #randomly place vertecies to have different "cables"
    bpy.ops.transform.vertex_random(offset=.5, 
            uniform=5, 
            normal=5, 
            seed=randomSeed, 
            wait_for_input=True)
        
    bpy.ops.object.editmode_toggle()
    
    #defining a volume for the cable
    def create_Cable():    
        bpy.ops.mesh.primitive_cylinder_add(radius=randomRadius, 
                depth=randomLength,
                enter_editmode=True,
                location=(X,Y,1))
        return bpy.context.object
    
    cable = create_Cable()
        
    #loopcutting the Cylinders for flexibility
            
    def view3d_find( return_area = False ):
    # returns first 3d view, normally we get from context
        for area in bpy.context.window.screen.areas:
            if area.type == 'VIEW_3D':
                v3d = area.spaces[0]
                rv3d = v3d.region_3d
                for region in area.regions:
                    if region.type == 'WINDOW':
                        if return_area: return region, rv3d, v3d, area
                        return region, rv3d, v3d
        return None, None
    
    region, rv3d, v3d, area = view3d_find(True)
    
    override = {
        'scene'  : bpy.context.scene,
        'region' : region,
        'area'   : area,
        'space'  : v3d
    }
    
    bpy.ops.mesh.loopcut_slide(
        override, 
        MESH_OT_loopcut = {
            "number_cuts"           : 100,
            "smoothness"            : 0,     
            "falloff"               : 'SMOOTH', 
            "edge_index"            : 2,
            "mesh_select_mode_init" : (True, False, False),
            "object_index"          : 0
        },
        TRANSFORM_OT_edge_slide = {
            "value"           : 0,
            "mirror"          : False, 
            "snap"            : False,
            "snap_target"     : 'CLOSEST',
            "snap_point"      : (0, 0, 0),
            "snap_align"      : False,
            "snap_normal"     : (0, 0, 0),
            "correct_uv"      : False,
            "release_confirm" : False
        }
    )
    #back into OBJECT Mode    
    bpy.ops.object.editmode_toggle()
    
    #apply Cylinder to shape of the Curve
    cable.modifiers.new(type='CURVE', name='applyShape')
    #Select Curve
    #Still Problem with NurbsCurve
    if count == 0:
        cable.modifiers["applyShape"].object =  bpy.data.objects["NurbsPath"]
        cable.modifiers["applyShape"].deform_axis = 'POS_Z'
    else:
        a = "NurbsPath."
        b = str(count).zfill(3)
        cable.modifiers["applyShape"].object =  bpy.data.objects[str(a+b)]
        cable.modifiers["applyShape"].deform_axis = 'POS_Z'
        
    #Increase Count by 1 to go into else loop in line 115
    count += 1
    
    #move Cable along Z axis to align more with Curve
    bpy.ops.transform.translate(value=(0, 0, 0.6))

Please be patient I know it is kinda messy...

And everything after the for loop (under #Main Programm) should be indented but something is messed up here so I can't indent it.

This is what it looks like so far

Now as I said I need to inset the end caps and extrude them so that it looks like this.

enter image description here

If here is anyone out there helping me I would really appreciate that! Thank you very much!

P.S. I also have a Problem with randomising the vertices only in X and Y direction (I want the cable to be "flat") I only found the bpy.ops.transform.vertex_random function but it also randomises the vertecies along the Z axis. So if there is a solution to this as well I would really appreciate that!

$\endgroup$

1 Answer 1

2
$\begingroup$

I've written a library called Blogo (https://github.com/mlewis109/blogo) which (I think) will help you a lot with what you want to do. It allows Blender python to be written in a similar way to the Logo programming language. You define a cross section - such as a circle for a wire - and then this is swept through space using commands like "forward", "left", "right", "up", etc. You can easily change the cross section to put the cap on the end how you want.

For example:

# Draw a wire with a random squiggle in it in the xy plane
def create_wire(wire_radius, wire_length, wire_colour, cap_colour):
    wire = Blogo()
    # store starting position
    pos = wire.get_pos()
    # turn around to draw the connector
    wire.right(180)
    draw_end(wire, wire_radius, cap_colour)
    # turn back and go back to start
    wire.right(180)
    wire.pen_up()
    wire.set_pos(pos)
    wire.pen_down()

    wire.set_texture(wire_colour)
    wire.set_cross_section("circle", wire_radius)
    direction = 0
    step_length = 0.01
    # make lots of turns, each similar to the last but randomly different
    for turns in range(int(wire_length/step_length)):
        min = -1
        max = 1
        # bias the turns back towards straight
        if (direction > 2):
            max = 2/direction
        elif (direction < -2):
            min = 2/direction
        direction += random.uniform(min, max)
        # turn by a small amount then go forward by a small amount
        wire.right(direction)
        wire.forward(step_length)
    draw_end(wire, wire_radius, cap_colour)
    return wire

# Draws either end of the wire, with a plastic protector and metal connector
def draw_end(wire, wire_radius, cap_colour):
    wire.set_texture(cap_colour)
    # make cap slightly bigger than the wire
    wire.set_cross_section("circle", wire_radius*1.1)
    # make the end of the cap narrower
    wire.add_width_func("all", "curve_end", curve_length=0.3, curve_width=wire_radius)
    # cap is 1cm long
    wire.forward(0.01)
    # remove the narrowing end
    wire.add_width_func("all")

    # add a metal connector
    wire.set_texture("grey")
    # Cross section shape of the metal connector, these coordinates represent a trapezium, 
    wire.set_cross_section([(-0.5,-0.25),(0.5,-0.25),(0.3,0.25),(-0.3,0.25),(-0.5,-0.25),(-0.29,0.24),(0.29,0.24),(0.49,-0.24),(-0.49,-0.24)], wire_radius*0.9)
    # go back into the wire by 5mm to get a good connection and then forward 1cm
    wire.backward(0.005)
    wire.forward(0.01)

# draw a red wire 5mm thick, 1m long with a blue cap
create_wire(0.005, 1, "red", "blue")

Results in: random wire with cap

$\endgroup$
1
  • $\begingroup$ Wow I don't know what to say! That result is truly amazing! The work and effort you put into this is insane thank you. You created a very useful tool for many people out there! This will definitely boost the quality of my work! $\endgroup$
    – SchmidtiT
    May 21, 2021 at 10:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.