Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
BlenderGcodeImport
==================

Python script to load gcode files produced by Slic3r into Blender
Python script to load gcode files produced by Slic3r*(Cura & IdeaMaker) into Blender

This work was based on the plugin (now defunct?) by Simon Kirkby. I wrote this because the previous one
did not work with more recent (2.7.0) versions of Blender.
This work was based on the plugin (now defunct?) by Simon Kirkby. It was modified to work with more recent (2.83.4) versions of Blender.

To use this download the plugin and start Blender

Expand Down
129 changes: 105 additions & 24 deletions ioImportGcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
bl_info = {
'name': 'Import Slic3r GCode',
'author': 'Lee Butler',
'version': (0,1,0),
'blender': (2, 7, 0),
'version': (0,1,1),
'blender': (2, 83, 4),
'api': 32738,
'location': 'File > Import-Export > Gcode',
'description': 'Import and visualize gcode files generated by Slic3r (.gcode)',
"wiki_url": "https://github.com/iraytrace/BlenderGcodeImport/wiki",
Expand Down Expand Up @@ -59,14 +60,16 @@ def __init__(self):
# set of polylines
self.polys = []

# each layer is a set of polylines at a constant Z
self.layers = []
# each layer is a set of polylines at a constant Z or float (z-hop)
self.layers = {}

# set of Z elevation changes. Most common is layer height
self.thickness = { }

self.ySquash = 0.5
self.xOoze = 1.65
self.xOoze = 1.15

self.Prusa=False


##### DRAW #####
Expand Down Expand Up @@ -98,6 +101,8 @@ def parse(self, fileName):
f = open(fileName)
for line in f.readlines():
# remove comments and leading/trailing whitespace
if 'PrusaSlicer' in line:
self.Prusa=True
line = line.split(';', 1)[0].strip()

# skip the blank lines
Expand All @@ -109,7 +114,7 @@ def parse(self, fileName):

self.dispatch(tokens)
f.close()
self.newLayer(-1.0)
self.newLayer(-1.0, -1.0)

#print ('---------- build ------------')
#print (' %d slices' % len(self.layers) )
Expand Down Expand Up @@ -143,20 +148,20 @@ def parse(self, fileName):
#print (dir(profilePoly))
profileObject = bpy.data.objects.new(profileName, profileData)

scn = bpy.context.scene
scn.objects.link(profileObject)
scn = bpy.context.view_layer
scn.update()
bpy.context.collection.objects.link(profileObject)
scn.objects.active = profileObject


for layerNum,layer in enumerate(self.layers):

layerName = self.obName + '_slice_%d' % layerNum
curveData = bpy.data.curves.new(layerName, type='CURVE')
curveData.dimensions = '3D'
curveData.bevel_object = profileObject
#print (layerName + ':')

for poly in layer:
for poly in self.layers[layer]:
pointNum = 0
for point in poly:
if pointNum == 0:
Expand All @@ -173,7 +178,7 @@ def parse(self, fileName):
polyline.points[1].co = newPt
oldPt = newPt
layerObject = bpy.data.objects.new(layerName, curveData)
scn.objects.link(layerObject)
bpy.context.collection.objects.link(layerObject)
scn.objects.active = layerObject


Expand All @@ -200,15 +205,20 @@ def newPoly(self):
self.polys.append( self.points[:] )
self.points = []

##### newLayer #####
def newLayer(self, delta):
##### newLayer ##### // zetta
def newLayer(self, delta, zetta):
# stash existing points into curve
self.newPoly()

# stash existing set of polys into layer
if len(self.polys) > 0:
#print( 'new layer with %d polys' % len(self.polys) )
self.layers.append( self.polys[:] )
if zetta in self.layers:
t = self.layers[zetta]
t.extend( self.polys[:] )
self.layers[zetta] = t
else:
self.layers[zetta] = self.polys[:]

self.polys = []

Expand All @@ -218,16 +228,30 @@ def newLayer(self, delta):
else:
self.thickness[delta] = 1

##### moveTo #####
##### moveTo ##### modificat E newlayer
def moveTo(self, newPos):
if newPos['Z'] != self.pos['Z']:
delta = newPos['Z'] - self.pos['Z']
self.newLayer(delta)
zetta = self.pos['Z']
self.newLayer(delta, zetta)

if newPos['E'] <= self.pos['E'] or newPos['E'] <= 0.0:
self.newPoly()
# modificat or newPos['E'] <= self.pos['E']
if self.Prusa:
if newPos['E'] is None or newPos['E'] <= 0.0:
self.newPoly()
else:
if newPos['E'] is None or newPos['E'] <= 0.0 or newPos['E'] <= self.pos['E']:
self.newPoly()

if newPos['E'] > 0 and newPos['E'] >= self.pos['E']:
# modificat or and newPos['E'] >= self.pos['E']
if newPos['E'] is not None and newPos['E'] > 0 :
# adaugat conditii x, y, z
if newPos['Z'] is None :
newPos['Z']=self.pos['Z']
if newPos['X'] is None :
newPos['X']=self.pos['X']
if newPos['Y'] is None :
newPos['Y']=self.pos['Y']
self.points.append([newPos['X'],
newPos['Y'],
newPos['Z']])
Expand Down Expand Up @@ -273,6 +297,10 @@ def G1(self, tokens):
'''move to'''
self.G0(tokens)

def G4(self, tokens):
'''wait'''
pass

def G21(self,tokens):
'''set units mm'''
pass
Expand All @@ -290,6 +318,10 @@ def G28(self, tokens):
# no matter what we won't be extruding
npos['E'] = 0.0
self.moveTo(npos)

def G80(self, tokens):
'''Mesh-based Z probe'''
pass

def G90(self, tokens):
'''set absolute positioning'''
Expand All @@ -306,11 +338,19 @@ def G92(self, tokens):
self.newPoly()

self.pos = newPos

def M73(self, tokens):
'''Set Print Progress'''
pass

def M82(self, tokens):
'''set extruder absolute mode'''
pass

def M83(self, tokens):
'''E Relative'''
pass

def M84(self, tokens):
'''stop idle hold'''
pass
Expand All @@ -330,20 +370,61 @@ def M107(self,tokens):
def M109(self,tokens):
'''set extruder temperature and wait'''
pass

def M115(self,tokens):
'''Firmware Info'''
pass
def M140(self,tokens):
'''Set Bed Temperature'''
pass
def M190(self,tokens):
'''Wait for Bed Temperature'''
pass
def M201(self,tokens):
'''Set Print Max Acceleration'''
pass
def M203(self,tokens):
'''Set Max Feedrate'''
pass
def M204(self,tokens):
'''Set Starting Acceleration'''
pass
def M205(self,tokens):
'''Set Advanced Settings'''
pass
def M221(self,tokens):
'''Set Flow Percentage'''
pass
def M900(self,tokens):
'''Linear Advance Factor'''
pass
def M907(self,tokens):
'''Set Motor Current'''
pass
def M862(self,tokens):
'''PRUSA FW'''



def menu_func(self, context):
self.layout.operator(IMPORT_OT_gcode.bl_idname, text="Slic3r GCode (.gcode)", icon='PLUGIN')

def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_file_import.append(menu_func)
classes = (
IMPORT_OT_gcode,
)
from bpy.utils import register_class
for cls in classes:
register_class(cls)
bpy.types.TOPBAR_MT_file_import.append(menu_func)

def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.INFO_MT_file_import.remove(menu_func)
classes = (
IMPORT_OT_gcode,
)
from bpy.utils import unregister_class
for cls in classes:
unregister_class(cls)
bpy.types.TOPBAR_MT_file_import.remove(menu_func)

if __name__ == "__main__":
register()
Expand Down