why are my cones upside down using the blender api? I'm trying to create some supports dropping down from the face of a shape.
However when creating cones at the base they are all upside down.
If I copy the output text for one of the cones back into the console it creates a cone in exactly the same spot but up the correct way.
What am I doing wrong?

import bpy
import math

import bmesh


#The relevant faces should already have been selected in edit mode
#The context can be edit or object mode

# get current mesh
current_mesh = bpy.context.object.data

# create empty bmesh, add current mesh into empty bmesh
current_bm = bmesh.new()
current_bm.from_mesh(current_mesh)

#bpy.ops.object.mode_set(mode = 'EDIT')
wX =  bpy.context.object.matrix_world[0][3]
wY =  bpy.context.object.matrix_world[1][3]
wZ =  bpy.context.object.matrix_world[2][3]

print(wX,wY,wZ)

def support_below(x1, y1, z1, x2, y2, z2, r):

    dx = x2 - x1
    dy = y2 - y1
    dz = z2 - z1    
    dist = math.sqrt(dx**2 + dy**2 + dz**2)

    bpy.ops.mesh.primitive_cylinder_add(
        vertices=3,
        radius = r, 
        depth = dist,
        location = (dx/2 + x1, dy/2 + y1, dz/2 + z1)   
        ) 
        
    ## really strange - these cones are all inverted, but if I paste the context output into the console they're correct
    bpy.ops.mesh.primitive_cone_add(
        depth=dist/10, 
        location=(x2, y2, z2),
        scale=(1, 1, 1),
        )

    phi = math.atan2(dy, dx) 
    theta = math.acos(dz/dist) 

    bpy.context.object.rotation_euler[1] = theta 
    bpy.context.object.rotation_euler[2] = phi 

        
selected_face_locations = []
for face in current_bm.faces:
    if face.select:
        selected_face_locations.append(face.calc_center_median())

curMode = bpy.ops.object.mode
bpy.ops.object.mode_set(mode = 'OBJECT')
userSelection = bpy.context.selected_objects
for face_location in selected_face_locations:
    x = face_location[0] + wX
    y = face_location[1] + wY
    z = face_location[2] + wZ
    support_below(x,y,z,x,y,0,0.1)        

# return back to original
#userSelection.select    
# bpy.ops.object.mode_set(mode = curMode)  # sadly this doesn't work :-(
#print (curMode)
#if curMode == 'EDIT':
#    bpy.ops.object.mode_set(mode = 'EDIT')
Code re-jig.

Don't think deletion is required, will however run thru an alternative route or in other terms FWIW:  &quot;How I would go about it&quot;.  BTW also really appreciate questions like this one where the OP has had a red hot go at creating a script. Please take this in the spirit of offering an alternate way
Some tips.

Use Vector math. There is never a reason to include the Euclidean distance formula when dealing with vectors.  It is the vector length. Rarely do we need to split the vectors component wise. For example the 6 components passed to the create support method, should it be the case that x2, y2, z2 is not on vertical line then q code would not create an angled strut in any case.

Multiplying local coordinates by the matrix world of their object will put them into global space, which allow for all transforms including scale.

Avoid edit mode toggling. Here I've created the struts using lower level bmesh operators, enabling no edit mode toggling.  Could also consider making a support only once and copying and scaling when more are required.


Test code.
import bpy
import bmesh
from mathutils import Vector, Matrix

from bpy import context


ob = context.edit_object
me = ob.data
bm = bmesh.from_edit_mesh(me)
mw = ob.matrix_world
coll = context.collection

strut_radius = 0.1
cone_radius = 0.4

coords = (mw @ f.calc_center_median() for f in bm.faces if f.select)
bm = bmesh.new()
for co in coords:
    bm.clear()
    cone_mesh = bpy.data.meshes.new(&quot;Cone&quot;)    
    bmesh.ops.create_cone(
            bm,
            segments=16,
            diameter1=cone_radius,
            depth=co.z / 10,
            cap_ends=True,
            cap_tris=True, # tri fan fill.
            matrix=Matrix.Translation((0, 0, co.z / 20))
            )
    bm.to_mesh(cone_mesh)        
    cone = bpy.data.objects.new(&quot;Cone&quot;, cone_mesh)
    cone.location = (co.x, co.y, 0)
    coll.objects.link(cone)
        
    bm.clear()
    strut_mesh = bpy.data.meshes.new(&quot;Strut&quot;)
    
    bmesh.ops.create_cone(
            bm,
            segments=3,
            diameter1=strut_radius,
            diameter2=strut_radius,
            depth=co.z,
            cap_ends=True,
            matrix=Matrix.Translation((0, 0, co.z / 2)),
            )
    bm.to_mesh(strut_mesh)        
    strut = bpy.data.objects.new(&quot;Strut&quot;, strut_mesh)
    strut.location = (co.x, co.y, 0)
    coll.objects.link(strut)