# Cannot extrude or render some meshes created from imported SVG paths

I've been working on a script that will invoke LaTeX under the hood to generate mathematical expressions, which are then imported into Blender as SVG paths. I then convert the paths to meshes and extrude to give them some depth. However, I sometimes encounter specific cases of these objects not being extruded and not appearing in the final render, such as the fraction bar in the screenshot (with the problematic object selected), either via script or manual manipulation in the GUI. Attempting to extrude it as a region via the GUI simply results in the object moving. It is as if these pathological objects are stuck as one-dimensional objects. Any clues as to what might be going wrong?

EDIT: Low and behold, examining the object's vertices from the console, it appears that the fraction bar is a bloody line with only two vertices:

>>> so = bpy.context.active_object
>>> verts = so.data.vertices
>>> edges = so.data.edges
>>> faces = so.data.polygons
>>> for v in verts:
...     print(v.co)
...
<Vector (0.0120, 0.0106, 0.0000)>
<Vector (0.0375, 0.0106, 0.0000)>


It is still unclear why this is happening and how best to detect and address it from within my script. For detection, I suppose I could check for the case of an object where faces.items() is an empty set, or where verts.items() has only two entries. From there, it is not clear what actions I should take to fix the pathological object.

Final Edit Finally found a workaround. When iterating through the objects, I identify the pathological cases and replace the two vertices with 4:

            verts=ob.data.vertices
if len(verts) <= 2: # Is this an object with only two verts?
newverts = [(verts[0].co.x - 0.0001,verts[0].co.y + 0.0001,0),(verts[1].co.x + 0.0001,verts[1].co.y + 0.0001,0),(verts[1].co.x + 0.0001,verts[1].co.y - 0.0001,0),(verts[0].co.x - 0.0001,verts[0].co.y - 0.0001,0)]
newfaces = [[0,1,2,3]]
newedges = []
ob.data.clear_geometry()
ob.data.from_pydata(newverts,newedges,newfaces)


Here is the code that I am using:

bl_info = {
"name": "Equation Panel",
"author": "Glen Martin",
"version": (1, 0),
"blender": (2, 92, 0),
"location": "View3D > Sidebar > Equation Panel",
"description": "Automated workflow for animating LaTeX equations.",
"warning": "",
"wiki_url": "",
"category": "3D View"}

import bpy
import os

class TEST_OT_test_op(bpy.types.Operator):
bl_idname = "test.test_op"

def execute(self, context):
# Create the file
myEqnString = "$$" + context.scene.my_string_prop + "$$"
f = open("C:/temp/TMP_EQN.tex", "w+")
fstring = "\\documentclass{standalone} \n" + \
"\\usepackage{lmodern} %or whatever you like \n" + \
"\\usepackage[intlimits]{amsmath} \n" + \
"\\usepackage{graphicx} \n" + \
"\\usepackage{amsthm, amssymb, amsfonts} %Useful stuff \n" + \
"\\begin{document} \n \\huge \n \\resizebox{.9\\hsize}{!}{" + myEqnString + "} \n" + \
"\\end{document} "
f.write(fstring)
f.close()
os.system("wsl cd /mnt/c/temp ; pdflatex ./TMP_EQN.tex ; pdftocairo -svg ./TMP_EQN.pdf ./EQN.svg")
self.report({'INFO'}, f"Generated LaTeX SVG object {self.bl_idname}")
# Import SVG file into Blender

C = bpy.context

# Names of all objects before importing the SVG
names_pre_import = set([ o.name for o in C.scene.objects ])

# Import SVG as curve
fp = '/temp/EQN.svg'
bpy.ops.import_curve.svg(filepath = fp)

# Names of all objects after importing the SVG
names_post_import = set([ o.name for o in C.scene.objects ])

# Perform set difference to find the new name and store it
new_object_name = names_post_import - names_pre_import

bpy.ops.object.select_all(action='DESELECT')

for o in bpy.data.objects:
# Check for given object names
if o.name in new_object_name:
o.select_set(True)

# Convert to Mesh and set attributes
bpy.context.area.ui_type='VIEW_3D'
bpy.ops.view3d.snap_cursor_to_selected()
bpy.ops.transform.resize(value=(50, 50, 500), orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=True, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False)
bpy.context.area.ui_type='VIEW_3D'

mat = bpy.data.materials.get("VioletMetal")
for ob in C.selected_objects:
C.view_layer.objects.active = ob
bpy.ops.object.convert(target='MESH',keep_original=False)
# Go to edit mode, face selection mode and select all faces
bpy.ops.object.mode_set( mode   = 'EDIT'   )
bpy.ops.mesh.select_mode( type  = 'FACE'   )
bpy.ops.mesh.select_all( action = 'SELECT' )

bpy.ops.mesh.extrude_region_move(
TRANSFORM_OT_translate={"value":(0, 0, 0.003)}
)
bpy.ops.object.mode_set( mode = 'OBJECT' )

if len(ob.data.materials) == 0:
ob.data.materials.append(mat)
else:
ob.data.materials[0]=mat

# Rename collection to EQN

# Clean up
os.system("wsl cd /mnt/c/temp ; rm TMP_EQN.*; rm EQN.svg")

return {'FINISHED'}

class MY_PT_EqnPanel(bpy.types.Panel):
bl_label = "Equation Panel"
bl_idname = "MY_PT_EqnPanel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = 'Eqn'

def draw(self, context):
layout = self.layout

row = layout.row()
row.label(text = "Add an equation", icon = 'TEXT')
row = layout.row()
col = self.layout.column(align = True)
col.prop(context.scene, "my_string_prop")
row = layout.row()
row.operator("TEST_OT_test_op")

classes = (TEST_OT_test_op, MY_PT_EqnPanel)

def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.my_string_prop = bpy.props.StringProperty \
(
name = "LaTeX String",
description = "LaTeX String",
default = "default"
)

def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.my_string_prop

if __name__== "__main__":
register()

$$$$

• given the effort you put into debugging and providing an updated code describing both the original problem and how to fix it in your post I would suggest you provide the update as an answer to your question and mark as accepted so that the post is retained longer and searches will show that there is an answer.
– Ratt
Apr 20 '21 at 21:12

            verts=ob.data.vertices
`