Skip to content

Commit

Permalink
Implement new 'pipeline' command structure
Browse files Browse the repository at this point in the history
  • Loading branch information
ezrec committed Jan 26, 2020
1 parent 8ff7198 commit 899e06b
Show file tree
Hide file tree
Showing 11 changed files with 695 additions and 128 deletions.
63 changes: 63 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,65 @@
# uv3dp
Tools for UV Resin based 3D Printers (in Go)

## Supported File Formats

This tool is for devices that use the Prusa SL1 (`*.sla`) and ChiTuBox DLP (`*.cbddlp`) format files.

Printers known to work with this tool:

| Printer | File Formats | Issues |
| ------------ | ------------ | --------------------------------------------------|
| EPAX X-1 | cbddlp | None |

## Command Line Tool (`uv3dp`)

The command line tool (available as a binary release at
[https://github.com/ezrec/uv3dp/releases](github.com/ezrec/uv3dp) ) is designed to be used in a 'pipeline'
style, for example:

uv3dp foo.sl1 info # Shows information about the SL1 file
uv3dp foo.sl1 decimate bar.cbddlp # Converts and decimates a SL1 files to a CBDDLP file
uv3dp foo.sl1 qux.cbddlp --version 1 # Converts a SL1 files to a CBDDLP file, forcing verion 1 CBDDLP file format

### Command summary:

Usage:

uv3dp [options] INFILE [command [options] | OUTFILE]...

Options:

-v, --verbose count Verbosity

Commands:

(none) Translates input file to output file
info Dumps information about the printable
decimate Remove outmost pixels of all islands in each layer (reduces over-curing on edges)
exposure Alters exposure times

Options for 'info':

-e, --exposure Show summary of the exposure settings (default true)
-l, --layers Show summary of the layers (default true)

Options for 'decimate':


Options for 'exposure':

--bottom-count uint Bottom layer count
--bottom-exposure duration Bottom layer light-on time
--exposure duration Normal layer light-on time

Options for '*.cbddlp':

--version uint32 Override header Version (default 2)

Options for '*.photon':

--version uint32 Override header Version (default 1)

Options for '*.sl1':

-m, --material-name string config.init entry 'materialName' (default "3DM-ABS @")
82 changes: 62 additions & 20 deletions cbddlp/format.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"encoding/binary"

"github.com/go-restruct/restruct"
"github.com/spf13/pflag"

"github.com/ezrec/uv3dp"
)
Expand Down Expand Up @@ -109,8 +110,39 @@ func align4(in uint32) (out uint32) {
return
}

type CbddlpFormatter struct {
*pflag.FlagSet

Version uint32 // Version of file to use, one of [1,2]
}

func NewCbddlpFormatter(suffix string) (cf *CbddlpFormatter) {
var version uint32

switch suffix {
case ".cbddlp":
version = 2
case ".photon":
version = 1
default:
version = 1
}

flagSet := pflag.NewFlagSet(suffix, pflag.ContinueOnError)
flagSet.SetInterspersed(false)

cf = &CbddlpFormatter{
FlagSet: flagSet,
Version: version,
}

cf.Uint32Var(&cf.Version, "version", version, "Override header Version")

return
}

// Save a uv3dp.Printable in CBD DLP format
func Encoder(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {
func (cf *CbddlpFormatter) Encode(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {
properties := p.Properties()

size := &properties.Size
Expand All @@ -127,7 +159,7 @@ func Encoder(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {

headerBase := uint32(0)
header := cbddlpHeader{
Version: 2,
Version: cf.Version,
}
headerSize, _ := restruct.SizeOf(&header)

Expand Down Expand Up @@ -177,6 +209,11 @@ func Encoder(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {
paramSize, _ := restruct.SizeOf(&param)

layerDefBase := paramBase + uint32(paramSize)
if header.Version < 2 {
// Omit param items
layerDefBase = paramBase
}

layerDef := make([]cbddlpLayerDef, size.Layers)
layerDefSize, _ := restruct.SizeOf(&layerDef[0])

Expand Down Expand Up @@ -225,22 +262,26 @@ func Encoder(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {
header.LayerDefs = layerDefBase
header.LayerCount = uint32(size.Layers)
header.PreviewLow = previewTinyBase
botTime := bot.Exposure.Duration() * time.Duration(bot.Count)
expTime := exp.Duration() * time.Duration(size.Layers-int(bot.Count))
header.PrintTime = uint32((botTime + expTime) / time.Second)
header.PrintTime = uint32(properties.Duration() / time.Second)
header.Projector = 1 // LCD_X_MIRROR
header.ParamOffset = paramBase
header.ParamSize = uint32(paramSize)
header.AntiAliasLevel = 0

if header.Version >= 2 {
header.ParamOffset = paramBase
header.ParamSize = uint32(paramSize)
header.AntiAliasLevel = 0
}

header.LightPWM = 255
header.BottomLightPWM = 255

// cbddlpParam
param.BottomLiftSpeed = bot.Exposure.LiftSpeed
param.BottomLiftHeight = bot.Exposure.LiftHeight
param.LiftHeight = exp.LiftHeight
param.LiftSpeed = exp.LiftSpeed
param.RetractSpeed = exp.RetractSpeed
if header.Version >= 2 {
// cbddlpParam
param.BottomLiftSpeed = bot.Exposure.LiftSpeed
param.BottomLiftHeight = bot.Exposure.LiftHeight
param.LiftHeight = exp.LiftHeight
param.LiftSpeed = exp.LiftSpeed
param.RetractSpeed = exp.RetractSpeed
}

// Compute total cubic millimeters (== milliliters) of all the on pixels
bedArea := float64(header.BedSizeMM[0] * header.BedSizeMM[1])
Expand All @@ -260,10 +301,12 @@ func Encoder(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {
return
}

data, _ = restruct.Pack(binary.LittleEndian, &param)
_, err = writer.WriteAt(data, int64(paramBase))
if err != nil {
return
if header.Version >= 2 {
data, _ = restruct.Pack(binary.LittleEndian, &param)
_, err = writer.WriteAt(data, int64(paramBase))
if err != nil {
return
}
}

for n, layer := range layerDef {
Expand Down Expand Up @@ -297,7 +340,7 @@ func Encoder(writer uv3dp.WriteAtSeeker, p uv3dp.Printable) (err error) {
return
}

func Decoder(file uv3dp.ReadAtSeeker, filesize int64) (printable uv3dp.Printable, err error) {
func (cf *CbddlpFormatter) Decode(file uv3dp.ReadAtSeeker, filesize int64) (printable uv3dp.Printable, err error) {
// Collect file
data, err := ioutil.ReadAll(file)
if err != nil {
Expand Down Expand Up @@ -470,7 +513,6 @@ func (cbd *CbdDlp) Layer(index int) (layer uv3dp.Layer) {
layerImage, err := rleDecodeBitmap(bounds, cbd.rleMap[layerDef.ImageOffset])
if err != nil {
panic(err)
return
}

layer = uv3dp.Layer{
Expand Down
11 changes: 11 additions & 0 deletions cbddlp/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,14 @@

// Package cbddlp handle input and output of Chitubox DLP/LCD printables
package cbddlp

import (
"github.com/ezrec/uv3dp"
)

func init() {
newFormatter := func(suffix string) (format uv3dp.Formatter) { return NewCbddlpFormatter(suffix) }

uv3dp.RegisterFormatter(".cbddlp", newFormatter)
uv3dp.RegisterFormatter(".photon", newFormatter)
}
32 changes: 32 additions & 0 deletions cmd/uv3dp/decimate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// Copyright (c) 2020 Jason S. McMullan <jason.mcmullan@gmail.com>
//

package main

import (
"github.com/spf13/pflag"

"github.com/ezrec/uv3dp"
)

type DecimateCommand struct {
*pflag.FlagSet
}

func NewDecimateCommand() (info *DecimateCommand) {
flagSet := pflag.NewFlagSet("info", pflag.ContinueOnError)
flagSet.SetInterspersed(false)

info = &DecimateCommand{
FlagSet: flagSet,
}

return
}

func (info *DecimateCommand) Filter(input uv3dp.Printable) (output uv3dp.Printable, err error) {
output = uv3dp.NewDecimatedPrintable(input)

return
}
87 changes: 87 additions & 0 deletions cmd/uv3dp/exposure.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Copyright (c) 2020 Jason S. McMullan <jason.mcmullan@gmail.com>
//

package main

import (
"time"

"github.com/spf13/pflag"

"github.com/ezrec/uv3dp"
)

type ExposureCommand struct {
*pflag.FlagSet

Exposure time.Duration // Time to expose a normal layer

BottomCount uint // Number of bottom layers
BottomExposure time.Duration
}

func NewExposureCommand() (ec *ExposureCommand) {
ec = &ExposureCommand{
FlagSet: pflag.NewFlagSet("exposure", pflag.ContinueOnError),
}

ec.DurationVar(&ec.Exposure, "exposure", time.Duration(0), "Normal layer light-on time")
ec.UintVar(&ec.BottomCount, "bottom-count", 0, "Bottom layer count")
ec.DurationVar(&ec.BottomExposure, "bottom-exposure", time.Duration(0), "Bottom layer light-on time")
ec.SetInterspersed(false)

return
}

type exposureModifier struct {
uv3dp.Printable
properties uv3dp.Properties
}

func (em *exposureModifier) Properties() (prop uv3dp.Properties) {
prop = em.properties
return
}

func (em *exposureModifier) Layer(index int) (layer uv3dp.Layer) {
layer = em.Printable.Layer(index)

exp := &em.properties.Exposure
bot := &em.properties.Bottom.Exposure
bottomCount := em.properties.Bottom.Count

if index < bottomCount {
layer.Exposure = bot
} else {
layer.Exposure = exp
}

return
}

func (ec *ExposureCommand) Filter(input uv3dp.Printable) (output uv3dp.Printable, err error) {
em := &exposureModifier{
Printable: input,
properties: input.Properties(),
}

if ec.Changed("exposure") {
TraceVerbosef(VerbosityNotice, " Setting default exposure time to %v", ec.Exposure)
em.properties.Exposure.LightExposure = ec.Exposure
}

if ec.Changed("bottom-count") {
TraceVerbosef(VerbosityNotice, " Setting default bottom layer count %v", ec.BottomCount)
em.properties.Bottom.Count = int(ec.BottomCount)
}

if ec.Changed("bottom-exposure") {
TraceVerbosef(VerbosityNotice, " Setting default bottom time to %v", ec.BottomExposure)
em.properties.Bottom.Exposure.LightExposure = ec.BottomExposure
}

output = em

return
}
Loading

0 comments on commit 899e06b

Please sign in to comment.