forked from ezrec/uv3dp
-
Notifications
You must be signed in to change notification settings - Fork 1
/
properties.go
144 lines (118 loc) · 3.78 KB
/
properties.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//
// Copyright (c) 2020 Jason S. McMullan <[email protected]>
//
package uv3dp
import (
"image"
"math"
"time"
)
type SizeMillimeter struct {
X, Y float32
}
type Size struct {
X, Y int // Printable size in pixels (x,y)
Millimeter SizeMillimeter // Printable size in mm
Layers int
LayerHeight float32 // Height of an individual layer
}
// Per-layer exposure
type Exposure struct {
LightOnTime float32 // Exposure time
LightOffTime float32 // Cool down time
LightPWM uint8 `json:",omitempty"` // PWM from 1..255
LiftHeight float32 // mm
LiftSpeed float32 // mm/min
RetractHeight float32 `json:",omitempty"` // mm
RetractSpeed float32 `json:",omitempty"` // mm/min
}
// Total duration of an exposure
func (exp *Exposure) Duration() (total time.Duration) {
totalSec := exp.LightOnTime + exp.LightOffTime
// Motion is lift; then retract -> move back to start at retract speed
if exp.LiftSpeed > 0 {
totalSec += exp.LiftHeight / exp.LiftSpeed * 60
}
if exp.RetractSpeed > 0 {
totalSec += (exp.LiftHeight + exp.RetractHeight*2) / exp.RetractSpeed * 60
} else {
if exp.LiftSpeed > 0 {
totalSec += exp.LiftHeight / exp.LiftSpeed * 60
}
}
total = time.Duration(totalSec * float32(time.Second))
return
}
// Interpolate scales settings between this and another Exposure
// scale of 0.0 = this exposure, 1.0 = target exposure
func (exp *Exposure) Interpolate(target Exposure, scale float32) (result Exposure) {
result.LightOnTime = exp.LightOnTime + float32(float64(target.LightOnTime-exp.LightOnTime)*float64(scale))
result.LightOffTime = exp.LightOffTime + float32(float64(target.LightOffTime-exp.LightOffTime)*float64(scale))
result.LiftHeight = exp.LiftHeight + (target.LiftHeight-exp.LiftHeight)*scale
result.LiftSpeed = exp.LiftSpeed + (target.LiftSpeed-exp.LiftSpeed)*scale
result.RetractHeight = exp.RetractHeight + (target.RetractHeight-exp.RetractHeight)*scale
result.RetractSpeed = exp.RetractSpeed + (target.RetractSpeed-exp.RetractSpeed)*scale
return
}
// Bottom layer exposure
type Bottom struct {
Exposure // Exposure
Count int // Number of bottom layers
Transition int // Number of transition layers above the bottom layer
}
type PreviewType uint
const (
PreviewTypeTiny = PreviewType(iota)
PreviewTypeHuge
)
type Properties struct {
Size Size
Exposure Exposure
Bottom Bottom
Preview map[PreviewType]image.Image `json:",omitempty"`
Metadata map[string](interface{}) `json:",omitempty"`
}
// Get metadata
func (prop *Properties) GetMetadataUint8(attr string, defValue uint8) (value uint8) {
value = defValue
tmp, found := prop.Metadata[attr]
if found {
u8, ok := tmp.(uint8)
if ok {
value = u8
}
}
return
}
func (prop *Properties) MetadataKeys() (keys []string) {
for key := range prop.Metadata {
keys = append(keys, key)
}
return
}
// Get image bounds
func (prop *Properties) Bounds() image.Rectangle {
return image.Rect(0, 0, prop.Size.X, prop.Size.Y)
}
// Exposure gets the default exposure by layer index
func (prop *Properties) LayerExposure(index int) (exposure Exposure) {
switch {
case index < prop.Bottom.Count:
exposure = prop.Bottom.Exposure
case index < prop.Bottom.Count+prop.Bottom.Transition:
// Scaling is a bit odd, but we don't want to include 0.0 (same as bottom) or 1.0 (same as top) in our range
scale := float32(index-prop.Bottom.Count+1) / float32(prop.Bottom.Transition+1)
exposure = prop.Bottom.Exposure.Interpolate(prop.Exposure, scale)
default:
exposure = prop.Exposure
}
// Validate LightPWM
if exposure.LightPWM == 0 {
exposure.LightPWM = 255
}
return
}
// Z get the default Z height at a layer index
func (prop *Properties) LayerZ(index int) (z float32) {
return float32(math.Round(float64(prop.Size.LayerHeight)*float64(index+1)*100) / 100.0)
}