Skip to content

Commit

Permalink
#4 (Adaptive layer heights) and #7 (png folder to photon)
Browse files Browse the repository at this point in the history
  • Loading branch information
NardJ committed Jan 26, 2019
1 parent 1b9aecc commit 0f223bf
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 61 deletions.
74 changes: 48 additions & 26 deletions GL_Stl2Slices.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def load_binary_stl(self,filename, scale=1):
z = np_points[:, 2]
self.cmin = (x.min(), y.min(), z.min())
self.cmax = (x.max(), y.max(), z.max())
self.modelheight = self.cmax[2] - self.cmin[2]

# align coordinates on grid
# this will reduce number of points and speed up loading
Expand Down Expand Up @@ -187,68 +188,89 @@ def __init__(self, stlfilename, scale=1,
sizestr="("+str(int(size[0]))+"x"+str(int(size[2]))+")"
areastr="(65x115)"
errmsg="Model is too big "+sizestr+" for build area "+areastr+". Maybe try another orientation, use the scale argument (-s or --scale) or cut up the model."
if not self.gui:
if not self.gui:
print (errmsg)
else:
sys.tracebacklimit = None
raise Exception(errmsg)
sys.tracebacklimit = 0
sys.exit() # quit() does not work if we make this an exe with cx_Freeze


# Load mesh
#print ("loading mesh")
self.viewport.loadMesh(points,normals,self.cmin,self.cmax);
#self.viewport.display() # this will loop until window is closed
self.viewport.draw()


# Create list with slice heights and exposures
sliceheights=[]
exposures=[]
# Check if layerheight is filename or number/float:
adaptiveLayers=False
try:
try:
layerheight=float(layerheight)
except:
adaptiveLayers=True
except:
adaptiveLayers=True
# a) if File we make slices from heights in files
if adaptiveLayers:
with open(layerheight) as f:
lines = f.readlines()
tmplines = f.readlines()
# remove all comments and black/empty lines
lines=[]
for line in tmplines:
l=line.split("#")[0]
l=l.strip()
if l: lines.append(l)

#file overrules vars for bottomlayers, bottomexposure and normal exposure
bottomlayers=int(lines[0])
bottomlayerheight=float(lines[1])/self.modelheight # convert layerheight to a relative layer height
bottomexposure=int(lines[2])
#print ("self.modelheight",self.modelheight)

# Make sure that we start at rel height 0
firstLine=lines[0]
firstLine=lines[3]
lastLine=lines[len(lines)-1]
firstH=float(firstLine.split()[0])
lastH=float(lastLine.split()[0])
# Store first layerheight for header
layerheight=float(firstLine.split()[1])
layerheight=float(firstLine.split()[1])
if firstH!=0:
print ("Layer Heights file does not start at height 0.")
sys.exit()
# Make sure that we end at rel height 1
if not lastH==1.0:
print ("Layer Heights file does not end at height 0.")
sys.exit()
# Process all lines
nrs=lines[0].split()
(prevRelY,prevSliceH,prevExposure) = (float(nrs[0]),float(nrs[1]),float(nrs[2]))
for line in lines:

# First set slices for bottom layers
relY_bottom=bottomlayers*bottomlayerheight
relY_bottom1000=1000*relY_bottom
for y in range(0,int(relY_bottom*1000),int(bottomlayerheight*1000)):
sliceheights.append(y/1000)
exposures.append(bottomexposure)

# Process all lines, converting layerheight to a relative layer height
(prevRelY,prevSliceH,prevExposure) = (bottomlayers,bottomlayerheight,bottomexposure)
for line in lines[3:]:
nrs=line.split()
(relY, sliceH, exposure) = (float(nrs[0]),float(nrs[1]),float(nrs[2]))
(relY, sliceH, exposure) = (float(nrs[0]),float(nrs[1])/self.modelheight,float(nrs[2])) # convert layerheight to a relative layer height
for y in range(int(prevRelY*1000),int(relY*1000),int(prevSliceH*1000)):
sliceheights.append(y/1000)
exposures.append(prevExposure)
(prevRelY,prevSliceH,prevExposure)=(relY, sliceH, exposure)
if y>relY_bottom1000: # ignore settings/slices below bottomlayers
sliceheights.append(y/1000)
exposures.append(prevExposure)
(prevRelY,prevSliceH,prevExposure)=(relY, sliceH, exposure)
# Add last height/exposure
sliceheights.append(relY)
sliceheights.append(relY)
exposures.append(exposure)

# b) If not file we received sliceheight in mm and use this to make slices
else:
microns = layerheight*1000 #document.getElementById("height").value;
bounds = self.viewport.getBounds()
zrange_mm=(bounds['zmax']-bounds['zmin']) / self.viewport.printer.getGLscale()
count=math.ceil(zrange_mm * 1000 / microns);
count=math.ceil(zrange_mm * 1000 / microns);
for i in range(0,count):
relheight=i/count
sliceheights.append(relheight)
Expand All @@ -263,11 +285,11 @@ def __init__(self, stlfilename, scale=1,
#data = self.viewport.getSliceAt(i / count)
img=data.reshape(2560,1440,4)
imgarr8=img[:,:,1]
if photonfilename==None:
if photonfilename==None:
Sstr = "%04d" % i
filename = outputpath+Sstr + ".png"
filename = outputpath+Sstr + ".png"
print (i,"/",count,filename)
cv2.imwrite(filename, imgarr8)
cv2.imwrite(filename, imgarr8)
else:
img1D=imgarr8.flatten(0)
rlestack.append(rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))
Expand All @@ -283,14 +305,14 @@ def __init__(self, stlfilename, scale=1,
photonfile.Header["# Bottom Layers"] = PhotonFile.int_to_bytes(bottomlayers)
photonfile.Header["Off time (s)"] = PhotonFile.float_to_bytes(offtime)
photonfile.replaceBitmaps(rlestack)

# If multiple layerheights we adjust photon file for this
if adaptiveLayers:
#nLayers=photonfile.nrLayers()
for layerNr,(layerheight,exposure) in enumerate(zip(sliceheights,exposures)):
photonfile.LayerDefs[layerNr]["Layer height (mm)"] =PhotonFile.float_to_bytes(layerheight)
photonfile.LayerDefs[layerNr]["Exp. time (s)"] =PhotonFile.float_to_bytes(exposure)
photonfile.LayerDefs[layerNr]["Layer height (mm)"] = PhotonFile.float_to_bytes(layerheight*self.modelheight)
photonfile.LayerDefs[layerNr]["Exp. time (s)"] = PhotonFile.float_to_bytes(exposure)

photonfile.writeFile(photonfilename)

print("Elapsed: ", "%.2f" % (time.time() - t1), "secs")
print("Elapsed: ", "%.2f" % (time.time() - t1), "secs")
9 changes: 3 additions & 6 deletions GL_Viewport.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
# Port of https:#github.com/Formlabs/hackathon-slicer/blob/master/app/js/viewport.js
#
# Bugs:
# are models imported at correct scale? (legocog.stl @ 0.05 produces only a few layers)
# if glutAvailable we still rely on pygame functions.... remove this reliability
#
# Windows Error 'glutInit undefined': If glutInit not found we must use pygame

#external
import OpenGL
from OpenGL.GL import *
Expand All @@ -19,12 +17,11 @@

#Test if glutInit available, if not we want to use pygame
#Even if bool(glutInit) wil return True the call on glutInit might still fail
glutAvailable=False #True
glutAvailable=True
try:
glutInit()
except Exception:
glutAvailable=False

if not glutAvailable:
print ("GLUT is not available.")
try:
Expand Down
28 changes: 21 additions & 7 deletions PhotonSlicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def _print_message(self,message,stderr):
# construct the argument parse and parse the arguments
ap = argparse_logger(description=
#ap = argparse.ArgumentParser(description=
"version : December 2, 2018 \n" +
"version : January 26, 2019 \n" +
#"0123456789001234567890012345678900123456789001234567890012345678900123456789001234567890\n"+
"description: Slices a STL (binary) or Slic3r SVG file to images or a photon file.\n"
"\n"+
Expand Down Expand Up @@ -269,8 +269,16 @@ def _print_message(self,message,stderr):
"'images' to generate images in directory with same name as stl\n"+
"these can be combined e.g. './subdir/photon'")
ap.add_argument("-l","--layerheight",
default=0.05,type=float,
help="layer height in mm")
default=0.05,#type=float,
help="layer height in mm OR \n"+
"filename with layerheights with following format: \n"+
" - each line has relative Y (0.0-1.0) and layerheight\n"+
" - to use until next relative Y in next line.\n"+
" e.g.: 0.0 0.05\n"+
" 0.2 0.02\n"+
" 0.8 0.05\n"+
" 1.0 0.05\n"+
" ONLY WORKS IN OPENGL mode with STL FILES (NOT SVG-FILES)")
ap.add_argument("-r", "--rescale", type=float, required=False,
help="scales model and offset")
ap.add_argument("-t", "--exposure", required=False,
Expand Down Expand Up @@ -322,7 +330,7 @@ def _print_message(self,message,stderr):
# set values for optional arguments
scale = float(args["rescale"]) if args["rescale"] else 1.0
if scale==0.0: scale=1.0
layerheight = float(args["layerheight"])
layerheight = args["layerheight"]#float(args["layerheight"])
normalexposure = float(args["exposure"])
bottomexposure = float(args["bottomexposure"])
bottomlayers = int(args["bottomlayers"])
Expand All @@ -348,6 +356,9 @@ def _print_message(self,message,stderr):
)

if filetype == ".svg":
if not isinstance(layerheight,float):
print ("With svg input you cannot use a file with layerheights.")
sys.exit()
S2I=Svg2Slices(svgfilename=filename,
outputpath=outputpath,
photonfilename=outputfile,
Expand All @@ -359,20 +370,23 @@ def _print_message(self,message,stderr):
offtime=offtime,
gui=gui
)
elif filetype == ".stl":

if filetype == ".stl":
if forceCPU:
if not isinstance(layerheight,float):
print ("In CPU mode you cannot use a file with layerheights.")
sys.exit()
S2I=Stl2Slices(stlfilename=filename,
outputpath=outputpath,
photonfilename=outputfile,
layerheight=layerheight,
layerheight=float(layerheight),
scale=scale,
normalexposure=normalexposure,
bottomexposure=bottomexposure,
bottomlayers=bottomlayers,
offtime=offtime,
gui=gui
)

else: #use GPU/OpenGL
S2I=GL_Stl2Slices(stlfilename=filename,
outputpath=outputpath,
Expand Down
5 changes: 3 additions & 2 deletions Png2Photon.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ def __init__(self, pngfolder,
# Read image
filepath=os.path.join(pngfolder[:-5],file)
img = cv2.imread(filepath)
# print (sliceNr,file,filepath)
# print (img.shape)

# Check if 8 image-depth
"""
Expand All @@ -73,10 +75,9 @@ def __init__(self, pngfolder,
"""

#Encode image
imgarr8 = img
imgarr8=img[:,:,1]
img1D=imgarr8.flatten(0)
rlestack.append(rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))
sliceNr=sliceNr+1

# Show progress in terminal
if not self.gui:
Expand Down
17 changes: 4 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,13 @@ Not yet ready:

## Installation

Download the repository. Depending on your setup do one of the following:
'Win64/' contains the install files for Windows 64-bits returning your slicing progress in a window. Just unpack and run! If you want to have your progress info displayed as plain text, replace PhotonSlicer.exe with the file in Con64/.

- **Windows**: 'Win64/' contains the 7Z files for Windows 64-bits returning your slicing progress in a window. Just unpack and run! If you want to have your progress info displayed as plain text, replace PhotonSlicer.exe with the file in Con64/.
You can test your install with:
`photonslicer.exe -s STLs\legocog.stl -g True -f False`
For Linux and OSX you have to install python and some libraries (Cython, numpy, opencv-python, PyOpenGL, PyOpenGL-accelerate, Pygame if glut not available).

- **Linux/OSX**: For Linux and OSX you have to install python and some libraries (Cython, numpy, opencv-python, PyOpenGL, PyOpenGL-accelerate, Pygame if glut not available). To test it:
`python3 photonslicer.py -s STLs\legocog.stl -g True -f False`

- **Linux & MeshMixer**: First make sure you already have Wine installed and use it to run MeshMixer 3.3. You should unpack the 'Win64/' 7Z files from the repository to e.g. 'Program Files'. You can test your it with:
`wine photonslicer.exe -s STLs\legocog.stl -g True -f False`
For Linux/MeshMixer user: You should already have wine up and running to use MeshMixer. You should install the Win64/ Zip files for PhotonSlicer in Wine too.

---

## Setup MeshMixer
1. Install MeshMixer (Linux users: First install Wine and install MeshMixer in Wine)
Expand Down Expand Up @@ -58,10 +53,6 @@ You can add an extra 'printer' for each resin / settings combo you need.
If you don't see a progress window and now file is added to 'C:/Program Files/PhotonSlicer/STLs/photon' check 'C:/Program Files/PhotonSlicer/log.txt' for error messages.


## YouTube tutorial
[![Tutorial](https://img.youtube.com/vi/KInOvXrpWXY/0.jpg)](https://www.youtube.com/watch?v=KInOvXrpWXY)


## MeshMixer Full Workflow

1. Open an STL file, check if fits the build volume and is not below it.
Expand Down
10 changes: 5 additions & 5 deletions Svg2Slices.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def __init__(self, svgfilename, scale=1,
if gui:
import tkinter as tk
from tkinter import ttk
# Construct window
# Construct window
self.popup = tk.Tk()#tk.Toplevel()
self.popup.geometry('240x32')
# Set window icon
Expand Down Expand Up @@ -130,14 +130,14 @@ def __init__(self, svgfilename, scale=1,
# Center numpy array of points which is returned for fast OGL model loading
pPoly = pPoly + trans
# Fill poly
cv2.fillPoly(img, numpy.array([pPoly],dtype='int32'), color=innerColor)
cv2.fillPoly(img, numpy.array([pPoly],dtype='int32'), color=innerColor)

if photonfilename==None:
cv2.imwrite(filename, img)
else:
imgarr8 = img
img1D=imgarr8.flatten(0)
rlestack.append(rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))
rlestack.append(rleEncode.encodedBitmap_Bytes_numpy1DBlock(img1D))

# Show progress in terminal
if not self.gui:
Expand All @@ -159,7 +159,7 @@ def __init__(self, svgfilename, scale=1,


if not self.gui: print () # close progress stdout and go to new line

if not photonfilename==None:
tempfilename=os.path.join(self.installpath,"newfile.photon")
photonfile=PhotonFile(tempfilename)
Expand All @@ -179,4 +179,4 @@ def __init__(self, svgfilename, scale=1,
# svgfilename='STLs/pikachu_repaired.svg',
# photonfilename="STLs/pikachu_svg.photon",
# gui=False
# )
# )
2 changes: 1 addition & 1 deletion consetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
sys.argv += ['--initial-target-dir', 'c:\PhotonSlicer']

setup( name = "PhotonSlicer_Console",
version = "0.2",
version = "0.1",
author= "Photonsters",
url="https://github.com/Photonsters",
description = "Converts STL (binary) files to Images or PhotonFile.",
Expand Down
2 changes: 1 addition & 1 deletion guisetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
sys.argv += ['--initial-target-dir', 'c:\PhotonSlicer']

setup( name = "PhotonSlicer_GUI",
version = "0.2",
version = "0.1",
author= "Photonsters",
url="https://github.com/Photonsters",
description = "Converts STL (binary) files to Images or PhotonFile.",
Expand Down

0 comments on commit 0f223bf

Please sign in to comment.