commit
1270f0cbc9
12 changed files with 1050 additions and 0 deletions
Split View
Diff Options
-
55cfg/config.go
-
62cmd/gamepad/gamepad.go
-
45cmd/plotter/plotter.go
-
22cmd/setup/setup.go
-
97drawing.svg
-
96font-default.xml
-
7go.mod
-
6go.sum
-
38main.go
-
250pkg/comm/main.go
-
78pkg/plotter/font.go
-
294pkg/plotter/svg.go
@ -0,0 +1,55 @@ |
|||
package cfg |
|||
|
|||
import "math" |
|||
|
|||
// CFG returns the configuration
|
|||
func CFG() Config { |
|||
cfg := Config{ |
|||
CircleResolution: 30, |
|||
MachineWidth: 1225, |
|||
MachineHeight: 800, |
|||
MachineMmPerRev: 37.7, |
|||
MachineStepsPerRev: 200, |
|||
MachineMotorAccel: 400, |
|||
MachineMotorSpeed: 800, |
|||
MachineStepMultiplier: 1, |
|||
DrawingArea: Area{ |
|||
TopLeft: Point{X: 400, Y: 250}, |
|||
BottomRight: Point{X: 800, Y: 500}, |
|||
Home: Point{X: 612.44, Y: 217.61}, |
|||
}, |
|||
} |
|||
|
|||
cfg.DrawingArea.Width = math.Abs(cfg.DrawingArea.BottomRight.X - cfg.DrawingArea.TopLeft.X) |
|||
cfg.DrawingArea.Height = math.Abs(cfg.DrawingArea.BottomRight.Y - cfg.DrawingArea.TopLeft.Y) |
|||
|
|||
return cfg |
|||
} |
|||
|
|||
// Point ...
|
|||
type Point struct { |
|||
X float64 |
|||
Y float64 |
|||
} |
|||
|
|||
// Area ...
|
|||
type Area struct { |
|||
Home Point |
|||
TopLeft Point |
|||
BottomRight Point |
|||
Width float64 |
|||
Height float64 |
|||
} |
|||
|
|||
// Config ...
|
|||
type Config struct { |
|||
DrawingArea Area |
|||
MachineWidth float64 |
|||
MachineHeight float64 |
|||
MachineMmPerRev float64 |
|||
MachineStepsPerRev float64 |
|||
MachineMotorSpeed float64 |
|||
MachineMotorAccel float64 |
|||
MachineStepMultiplier float64 |
|||
CircleResolution float64 |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
package gamepad |
|||
|
|||
import ( |
|||
"codeisalie/gono/pkg/comm" |
|||
"log" |
|||
"time" |
|||
|
|||
"github.com/splace/joysticks" |
|||
) |
|||
|
|||
// Run initializes the plotter
|
|||
func Run(c *comm.Comm) { |
|||
motorsState := false |
|||
|
|||
device := joysticks.Connect(1) |
|||
|
|||
if device == nil { |
|||
panic("no HIDs") |
|||
} |
|||
|
|||
// using Connect allows a device to be interrogated
|
|||
log.Printf("HID#1:- Buttons:%d, Hats:%d\n", len(device.Buttons), len(device.HatAxes)/2) |
|||
|
|||
// get/assign channels for specific events
|
|||
b1press := device.OnClose(1) |
|||
b7press := device.OnClose(7) |
|||
b8press := device.OnClose(8) |
|||
b10press := device.OnClose(10) |
|||
h1move := device.OnMove(3) |
|||
|
|||
// start feeding OS events onto the event channels.
|
|||
go device.ParcelOutEvents() |
|||
|
|||
// handle event channels
|
|||
go func() { |
|||
for { |
|||
select { |
|||
case <-b1press: |
|||
log.Println("button #1 pressed") |
|||
case <-b7press: |
|||
log.Println("button #7 pressed") |
|||
case <-b8press: |
|||
log.Println("button #8 pressed") |
|||
case <-b10press: |
|||
log.Println("button #10 pressed", motorsState) |
|||
if motorsState == false { |
|||
// c.Send(comm.EnableMotors)
|
|||
motorsState = true |
|||
} else { |
|||
// c.Send(comm.DisableMotors)
|
|||
motorsState = false |
|||
} |
|||
case h := <-h1move: |
|||
hpos := h.(joysticks.CoordsEvent) |
|||
log.Println(".hat #1 moved too:", hpos) |
|||
} |
|||
} |
|||
}() |
|||
|
|||
time.Sleep(time.Second * 60) |
|||
log.Println("Shutting down due to timeout.") |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
package plotter |
|||
|
|||
import ( |
|||
"codeisalie/gono/pkg/comm" |
|||
"codeisalie/gono/pkg/plotter" |
|||
"fmt" |
|||
"time" |
|||
) |
|||
|
|||
// Run ...
|
|||
func Run(c *comm.Comm) { |
|||
|
|||
svg := plotter.SvgParser{} |
|||
svg.Parse("drawing.svg", c.Cfg) |
|||
|
|||
// for _, path := range svg.Paths {
|
|||
// fmt.Printf("%+v\n", path)
|
|||
// for _, point := range path.List {
|
|||
// fmt.Printf("-- %+v\n", point)
|
|||
// }
|
|||
// }
|
|||
|
|||
// svg.Paths
|
|||
fmt.Println(svg.Root.ViewBox) |
|||
c.Send(comm.EnableMotors) |
|||
c.Send(comm.GetReportPosition) |
|||
for _, path := range svg.Paths { |
|||
fmt.Printf("%+v\n", path) |
|||
// if len(path.List) <= 1 {
|
|||
// continue
|
|||
// }
|
|||
c.Send(comm.SetPenUp) |
|||
for idx, point := range path.List { |
|||
c.Send(comm.DrawLine, point.X, point.Y, 1) |
|||
if idx == 0 && len(path.List) > 1 { |
|||
c.Send(comm.SetPenDown) |
|||
} |
|||
} |
|||
c.Send(comm.SetPenUp) |
|||
} |
|||
c.Send(comm.DrawLine, c.Cfg.DrawingArea.Home.X, c.Cfg.DrawingArea.Home.Y, 1) |
|||
c.Send(comm.DisableMotors) |
|||
|
|||
time.Sleep(2 * time.Second) |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package setup |
|||
|
|||
import ( |
|||
"codeisalie/gono/pkg/comm" |
|||
"time" |
|||
) |
|||
|
|||
// List ...
|
|||
type List []comm.SetCMD |
|||
|
|||
// Run initializes the plotter
|
|||
func Run(c *comm.Comm) { |
|||
|
|||
c.Send(comm.SetMachineSize, c.Cfg.MachineWidth, c.Cfg.MachineHeight) |
|||
c.Send(comm.SetMachineMmPerRev, c.Cfg.MachineMmPerRev) |
|||
c.Send(comm.SetMachineStepsPerRev, c.Cfg.MachineStepsPerRev) |
|||
c.Send(comm.SetMachineMotorSpeed, c.Cfg.MachineMotorSpeed) |
|||
c.Send(comm.SetMachineMotorAccel, c.Cfg.MachineMotorAccel) |
|||
c.Send(comm.SetMachineStepMultiplier, c.Cfg.MachineStepMultiplier) |
|||
|
|||
time.Sleep(5 * time.Second) |
|||
} |
|||
@ -0,0 +1,97 @@ |
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|||
<!-- Created with Inkscape (http://www.inkscape.org/) --> |
|||
|
|||
<svg |
|||
xmlns:dc="http://purl.org/dc/elements/1.1/" |
|||
xmlns:cc="http://creativecommons.org/ns#" |
|||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
|||
xmlns:svg="http://www.w3.org/2000/svg" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
|||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
|||
width="200cm" |
|||
height="120cm" |
|||
viewBox="0 0 7086.614 4251.9685" |
|||
id="svg2" |
|||
version="1.1" |
|||
inkscape:version="0.91 r" |
|||
sodipodi:docname="drawing.svg"> |
|||
<defs |
|||
id="defs4" /> |
|||
<sodipodi:namedview |
|||
id="base" |
|||
pagecolor="#ffffff" |
|||
bordercolor="#666666" |
|||
borderopacity="1.0" |
|||
inkscape:pageopacity="0.0" |
|||
inkscape:pageshadow="2" |
|||
inkscape:zoom="0.175" |
|||
inkscape:cx="3198.9842" |
|||
inkscape:cy="2091.4294" |
|||
inkscape:document-units="px" |
|||
inkscape:current-layer="svg2" |
|||
showgrid="false" |
|||
units="cm" |
|||
inkscape:window-width="1920" |
|||
inkscape:window-height="1023" |
|||
inkscape:window-x="0" |
|||
inkscape:window-y="0" |
|||
inkscape:window-maximized="1" /> |
|||
<metadata |
|||
id="metadata7"> |
|||
<rdf:RDF> |
|||
<cc:Work |
|||
rdf:about=""> |
|||
<dc:format>image/svg+xml</dc:format> |
|||
<dc:type |
|||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
|||
<dc:title /> |
|||
</cc:Work> |
|||
</rdf:RDF> |
|||
</metadata> |
|||
<path |
|||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
|||
d="M 199.99976,4080.5397 6554.2855,337.68255" |
|||
id="path3370" |
|||
inkscape:connector-curvature="0" /> |
|||
<path |
|||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
|||
d="m 4319.9998,2566.254 1291.4286,-11.4286 11.4285,-1080 1051.4286,62.8572" |
|||
id="path3372" |
|||
inkscape:connector-curvature="0" /> |
|||
<circle |
|||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1" |
|||
id="path3368-3" |
|||
cx="3805.7141" |
|||
cy="1806.2543" |
|||
r="1005.7143" /> |
|||
<path |
|||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
|||
d="M 565.71405,1131.9685 1262.8569,343.39708 1759.9998,1183.3971 542.8569,3086.2542" |
|||
id="path3384" |
|||
inkscape:connector-curvature="0" /> |
|||
<path |
|||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
|||
d="m 2845.7141,320.53993 -17.1429,331.42857 1880,-177.14285 z" |
|||
id="path3386" |
|||
inkscape:connector-curvature="0" /> |
|||
<flowRoot |
|||
xml:space="preserve" |
|||
id="flowRoot3483" |
|||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:112.99999952%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
|||
transform="translate(-2.4414063e-4,0)"><flowRegion |
|||
id="flowRegion3485"><rect |
|||
id="rect3487" |
|||
width="1011.4288" |
|||
height="148.57152" |
|||
x="217.14285" |
|||
y="360.53995" |
|||
style="line-height:112.99999952%" /></flowRegion><flowPara |
|||
id="flowPara3489" |
|||
style="font-size:125px;line-height:112.99999952%">HALLO WORLD</flowPara></flowRoot> <circle |
|||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1" |
|||
id="path3368-3-6" |
|||
cx="2588.5713" |
|||
cy="2686.2542" |
|||
r="1005.7143" /> |
|||
</svg> |
|||
@ -0,0 +1,96 @@ |
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
|||
|
|||
<root name="default" width="10" height="20" space="2"> |
|||
<letter id=" "> |
|||
<path>0,0</path> |
|||
</letter> |
|||
<letter id="A"> |
|||
<path>0,20 5,0 10,20</path> |
|||
<path>3,10 7,10</path> |
|||
</letter> |
|||
<letter id="B"> |
|||
<path>0,0 0,20 10,20 10,10 0,10</path> |
|||
<path>0,0 6,0 6,10</path> |
|||
</letter> |
|||
<letter id="C"> |
|||
<path>10,0 0,0 0,20 10,20</path> |
|||
</letter> |
|||
<letter id="D"> |
|||
<path>0,0 7,0 10,3 10,17 8,20 0,20 0,0</path> |
|||
</letter> |
|||
<letter id="E"> |
|||
<path>10,0 0,0 0,10 10,10 0,10 0,20 10,20</path> |
|||
</letter> |
|||
<letter id="F"> |
|||
<path>10,0 0,0 0,10 10,10 0,10 0,20</path> |
|||
</letter> |
|||
<letter id="G"> |
|||
<path>10,0 0,0 0,20 10,20 10,10 5,10</path> |
|||
</letter> |
|||
<letter id="H"> |
|||
<path>0,0 0,20 0,10 10,10 10,0 10,20</path> |
|||
</letter> |
|||
<letter id="I"> |
|||
<path>2,0 8,0 5,0 5,20 2,20 8,20</path> |
|||
</letter> |
|||
<letter id="J"> |
|||
<path>0,10 0,20 10,20 10,0</path> |
|||
</letter> |
|||
<letter id="K"> |
|||
<path>0,0 0,20</path> |
|||
<path>10,0 0,10 10,20</path> |
|||
</letter> |
|||
<letter id="L"> |
|||
<path>0,0 0,20 10,20</path> |
|||
</letter> |
|||
<letter id="M"> |
|||
<path>0,20 0,0 5,10 10,0 10,20</path> |
|||
</letter> |
|||
<letter id="N"> |
|||
<path>0,20 0,0 10,20 10,0</path> |
|||
</letter> |
|||
<letter id="O"> |
|||
<path>0,2 2,0 8,0 10,2 10,18 8,20 2,20 0,18 0,2</path> |
|||
</letter> |
|||
<letter id="P"> |
|||
<path>0,20 0,0 8,0 10,2 10,8 8,10 0,10</path> |
|||
</letter> |
|||
<letter id="Q"> |
|||
<path>0,2 2,0 8,0 10,2 10,18 8,20 2,20 0,18 0,2</path> |
|||
<path>7,17 10,20</path> |
|||
</letter> |
|||
<letter id="R"> |
|||
<path>0,20 0,0 8,0 10,2 10,8 8,10 0,10</path> |
|||
<path>8,10 10,12 10,20</path> |
|||
</letter> |
|||
<letter id="S"> |
|||
<path>10,0 2,0 0,2 0,8 2,10 8,10 10,12 10,18 8,20 0,20</path> |
|||
</letter> |
|||
<letter id="T"> |
|||
<path>0,0 10,0</path> |
|||
<path>5,0 5,20</path> |
|||
</letter> |
|||
<letter id="U"> |
|||
<path>0,2 0,18 2,20 8,20 10,18 10,2</path> |
|||
</letter> |
|||
<letter id="V"> |
|||
<path>0,0 5,20 10,0</path> |
|||
</letter> |
|||
<letter id="W"> |
|||
<path>0,0 3,20 5,10 7,20 10,0</path> |
|||
</letter> |
|||
<letter id="X"> |
|||
<path>0,0 10,20</path> |
|||
<path>10,0 0,20</path> |
|||
</letter> |
|||
<letter id="Y"> |
|||
<path>0,0 5,10 10,0</path> |
|||
<path>5,10 5,20</path> |
|||
</letter> |
|||
<letter id="Z"> |
|||
<path>0,0 10,0 0,20 10,20</path> |
|||
</letter> |
|||
<letter id="b"> |
|||
<path>0,0 0,7 10,12 10,18 8,20 0,20 0,0</path> |
|||
</letter> |
|||
</root> |
|||
@ -0,0 +1,7 @@ |
|||
module codeisalie/gono |
|||
|
|||
require ( |
|||
github.com/splace/joysticks v0.0.0-20180907185707-7416f8bb58bd |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 |
|||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 // indirect |
|||
) |
|||
@ -0,0 +1,6 @@ |
|||
github.com/splace/joysticks v0.0.0-20180907185707-7416f8bb58bd h1:WO95lkUpx1EbYOnppBa8i/fEY6t2itFxK5LCCRcgzKQ= |
|||
github.com/splace/joysticks v0.0.0-20180907185707-7416f8bb58bd/go.mod h1:PQPCtmjcD4hfFT4yHSY7zomN8fvov8fFvQWYSth8L34= |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= |
|||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg= |
|||
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
@ -0,0 +1,38 @@ |
|||
package main |
|||
|
|||
import ( |
|||
"codeisalie/gono/cfg" |
|||
"codeisalie/gono/cmd/gamepad" |
|||
"codeisalie/gono/cmd/plotter" |
|||
"codeisalie/gono/cmd/setup" |
|||
"codeisalie/gono/pkg/comm" |
|||
"flag" |
|||
"log" |
|||
) |
|||
|
|||
func main() { |
|||
var setupMode, gameMode bool |
|||
flag.BoolVar(&setupMode, "setup", false, "Setup plotter machine") |
|||
flag.BoolVar(&gameMode, "game", false, "Gamepad mode") |
|||
flag.Parse() |
|||
|
|||
CFG := cfg.CFG() |
|||
|
|||
if setupMode { |
|||
log.Println("[>] Running mode: gamepad") |
|||
} else if gameMode { |
|||
log.Println("[>] Running mode: setup") |
|||
} else { |
|||
log.Println("[>] Running mode: plotter") |
|||
} |
|||
|
|||
c := comm.Init("", CFG) |
|||
|
|||
if gameMode { |
|||
gamepad.Run(c) |
|||
} else if setupMode { |
|||
setup.Run(c) |
|||
} else { |
|||
plotter.Run(c) |
|||
} |
|||
} |
|||
@ -0,0 +1,250 @@ |
|||
package comm |
|||
|
|||
import ( |
|||
"codeisalie/gono/cfg" |
|||
"fmt" |
|||
"log" |
|||
"math" |
|||
"regexp" |
|||
"sync" |
|||
"time" |
|||
|
|||
"github.com/tarm/serial" |
|||
) |
|||
|
|||
const ( |
|||
// SetPenDown ...
|
|||
SetPenDown string = "C13" |
|||
// SetPenUp ... - args = 0
|
|||
SetPenUp string = "C14" |
|||
// SetMachineSize saves machine width and height - args = 2
|
|||
SetMachineSize string = "C24" |
|||
// SetMachineMmPerRev ... - args = 1
|
|||
SetMachineMmPerRev string = "C29" |
|||
// SetMachineStepsPerRev ... - args = 1
|
|||
SetMachineStepsPerRev string = "C30" |
|||
// SetMachineMotorSpeed ... - args = 1
|
|||
SetMachineMotorSpeed string = "C31" |
|||
// SetMachineMotorAccel ... - args = 1
|
|||
SetMachineMotorAccel string = "C32" |
|||
// SetMachineStepMultiplier ... - args = 1
|
|||
SetMachineStepMultiplier string = "C37" |
|||
// GetMachineDetails ... - args = 0
|
|||
GetMachineDetails string = "C26" |
|||
// DisableMotors ...
|
|||
DisableMotors string = "CA0" |
|||
// EnableMotors ...
|
|||
EnableMotors string = "CA1" |
|||
// DrawLine ... - args = 0
|
|||
DrawLine string = "C17" |
|||
// DrawCircle ... - args = 0
|
|||
DrawCircle string = "CB0" |
|||
// GetReportPosition ...
|
|||
GetReportPosition string = "CC0" |
|||
) |
|||
|
|||
// SetCMD saves one EEPROM command
|
|||
type SetCMD struct { |
|||
Cmd string |
|||
Args []float64 |
|||
} |
|||
|
|||
// Comm context
|
|||
type Comm struct { |
|||
isReady bool |
|||
mutex sync.Mutex |
|||
sync chan int |
|||
list chan string |
|||
com string |
|||
Cfg cfg.Config |
|||
serialCfg *serial.Config |
|||
handler *serial.Port |
|||
} |
|||
|
|||
// Init returns an initialized serial handler
|
|||
// Def: /dev/ttyACM0
|
|||
func Init(com string, cfg cfg.Config) *Comm { |
|||
|
|||
c := Comm{} |
|||
c.list = make(chan string) |
|||
c.sync = make(chan int) |
|||
c.Cfg = cfg |
|||
|
|||
if com == "" { |
|||
com = "/dev/ttyACM0" |
|||
} |
|||
|
|||
c.com = com |
|||
|
|||
c.serialCfg = &serial.Config{Name: c.com, Baud: 57600} |
|||
handler, err := serial.OpenPort(c.serialCfg) |
|||
if err != nil { |
|||
log.Println(err) |
|||
return &c |
|||
} |
|||
|
|||
log.Printf("[-] comm | %v opened\n", c.com) |
|||
|
|||
c.handler = handler |
|||
|
|||
go c.readSerial() |
|||
log.Printf("[-] comm | Waiting plotter stating\n") |
|||
<-c.sync |
|||
log.Printf("[-] comm | Plotter ready\n") |
|||
go c.sendMsg() |
|||
|
|||
// q := make(chan os.Signal, 1)
|
|||
// signal.Notify(q, os.Interrupt)
|
|||
// go func() {
|
|||
// for sig := range q {
|
|||
// fmt.Println(sig)
|
|||
// close(c.list)
|
|||
// close(c.sync)
|
|||
// }
|
|||
// }()
|
|||
|
|||
return &c |
|||
} |
|||
|
|||
// Queue one new message to send to serial interface
|
|||
func (c *Comm) Queue(msg string) { |
|||
c.list <- msg |
|||
} |
|||
|
|||
// Send ...
|
|||
func (c *Comm) Send(cmd string, args ...float64) { |
|||
msg := cmd |
|||
switch cmd { |
|||
case DrawLine: |
|||
r1, r2 := c.convertCartToPolar(args[0], args[1]) |
|||
args[0] = math.Floor(r1*100) / 100 |
|||
args[1] = math.Floor(r2*100) / 100 |
|||
} |
|||
for _, arg := range args { |
|||
msg += fmt.Sprintf(",%v", arg) |
|||
} |
|||
msg += ",END;" |
|||
// fmt.Println(msg)
|
|||
c.Queue(msg) |
|||
} |
|||
|
|||
// SendPPP one message to machine
|
|||
func (c *Comm) SendPPP(cmd SetCMD) { |
|||
msg := cmd.Cmd |
|||
switch cmd.Cmd { |
|||
case DrawLine: |
|||
r1, r2 := c.convertCartToPolar(cmd.Args[0], cmd.Args[1]) |
|||
cmd.Args[0] = r1 |
|||
cmd.Args[1] = r2 |
|||
} |
|||
for _, arg := range cmd.Args { |
|||
msg += fmt.Sprintf(",%v", arg) |
|||
} |
|||
msg += ",END;" |
|||
// fmt.Println(msg)
|
|||
c.Queue(msg) |
|||
} |
|||
|
|||
func (c *Comm) convertCartToPolar(x, y float64) (float64, float64) { |
|||
r1 := math.Sqrt(math.Pow(x, 2) + math.Pow(y, 2)) |
|||
r2 := math.Sqrt(math.Pow(c.Cfg.MachineWidth-x, 2) + math.Pow(y, 2)) |
|||
return r1, r2 |
|||
} |
|||
|
|||
// Send a message when it's serial com is ready
|
|||
func (c *Comm) sendMsg() { |
|||
log.Printf("[-] comm | routine sendMsg started\n") |
|||
for { |
|||
<-c.sync |
|||
c.mutex.Lock() |
|||
c.isReady = true |
|||
c.mutex.Unlock() |
|||
time.Sleep(100 * time.Millisecond) |
|||
msg := <-c.list |
|||
log.Printf("[-] comm | Sending: %v\n", msg) |
|||
_, err := c.handler.Write([]byte(msg)) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} else { |
|||
// log.Println("written", n)
|
|||
} |
|||
} |
|||
} |
|||
|
|||
func (c *Comm) GetIsReady() { |
|||
isReady := false |
|||
c.mutex.Lock() |
|||
isReady = c.isReady |
|||
c.mutex.Unlock() |
|||
|
|||
return isReady |
|||
} |
|||
|
|||
func (c *Comm) processSerialMsg(msg string) { |
|||
reReady := regexp.MustCompile("READY") |
|||
if reReady.MatchString(msg) { |
|||
c.sync <- 0 |
|||
} |
|||
} |
|||
|
|||
func (c *Comm) readSerial() { |
|||
log.Printf("[-] comm | routine readSerial started\n") |
|||
|
|||
var char byte |
|||
var msg string |
|||
cr := byte('\r') |
|||
eol := byte('\n') |
|||
baf := make([]byte, 1) |
|||
buf := make([]byte, 128) |
|||
ptr := 0 |
|||
for { |
|||
n, err := c.handler.Read(baf) |
|||
if err != nil { |
|||
log.Fatal(err) |
|||
} |
|||
|
|||
if n != 1 { |
|||
continue |
|||
} |
|||
|
|||
char = baf[0] |
|||
|
|||
if char == cr || char == eol { |
|||
if ptr > 0 { |
|||
msg = string(buf[:ptr]) |
|||
fmt.Println(msg) |
|||
c.processSerialMsg(msg) |
|||
} |
|||
ptr = 0 |
|||
} else { |
|||
buf[ptr] = char |
|||
ptr++ |
|||
} |
|||
} |
|||
} |
|||
|
|||
// codeReady := []byte("READY")
|
|||
// reReady := regexp.MustCompile("READY")
|
|||
// reSync := regexp.MustCompile("SYNC,(.*),(.*),END")
|
|||
|
|||
// n, err := s.Read(buf)
|
|||
// if err != nil {
|
|||
// log.Fatal(err)
|
|||
// }
|
|||
// msg := string(buf[:n])
|
|||
// fmt.Printf("%v", msg)
|
|||
|
|||
// if reReady.Match(buf) {
|
|||
// // fmt.Print("READY FROM RE")
|
|||
// sync <- 0
|
|||
// } else {
|
|||
// // match := reSync.FindAllSubmatch(buf, -1)
|
|||
// // if len(match) > 0 {
|
|||
// // r1 := string(match[0][1])
|
|||
// // r2 := string(match[0][2])
|
|||
// // r1i, _ := strconv.Atoi(r1)
|
|||
// // r2i, _ := strconv.Atoi(r2)
|
|||
// // x, y := getXY(float64(r1i), float64(r2i))
|
|||
// // fmt.Printf("R1: %v, R2:%v - X:%v - Y:%v\n", r1i, r2i, x, y)
|
|||
// // }
|
|||
// }
|
|||
@ -0,0 +1,78 @@ |
|||
package plotter |
|||
|
|||
import ( |
|||
"encoding/xml" |
|||
"fmt" |
|||
"io/ioutil" |
|||
"os" |
|||
"strconv" |
|||
"strings" |
|||
) |
|||
|
|||
type OneChar struct { |
|||
Letter rune |
|||
Root XMLFont |
|||
Path []*Point |
|||
} |
|||
|
|||
// XMLChar ...
|
|||
type XMLChar struct { |
|||
XMLName xml.Name `xml:"letter"` |
|||
ID string `xml:"id,attr"` |
|||
Paths []string `xml:"path"` |
|||
// XMLName xml.Name `xml:"bite"`
|
|||
// ID rune `xml:"id,attr"`
|
|||
// Paths []XMLPath `xml:"path"`
|
|||
} |
|||
|
|||
// XMLFont ...
|
|||
type XMLFont struct { |
|||
XMLName xml.Name `xml:"root"` |
|||
Name string `xml:"name,attr"` |
|||
Width float64 `xml:"width,attr"` |
|||
Height float64 `xml:"height,attr"` |
|||
Space float64 `xml:"space,attr"` |
|||
Letters []XMLChar `xml:"letter"` |
|||
} |
|||
|
|||
type FontParser struct { |
|||
Root XMLFont |
|||
ByLetter map[rune][]*OnePath |
|||
} |
|||
|
|||
// Parse one font file
|
|||
func (f *FontParser) Parse(fontPath string) { |
|||
// Open our xmlFile
|
|||
xmlFile, err := os.Open(fontPath) |
|||
// if we os.Open returns an error then handle it
|
|||
if err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
|
|||
fmt.Println("Successfully Opened " + fontPath) |
|||
// defer the closing of our xmlFile so that we can parse it later on
|
|||
defer xmlFile.Close() |
|||
|
|||
// read our opened xmlFile as a byte array.
|
|||
byteValue, _ := ioutil.ReadAll(xmlFile) |
|||
|
|||
xml.Unmarshal(byteValue, &f.Root) |
|||
|
|||
f.ByLetter = make(map[rune][]*OnePath) |
|||
|
|||
for _, letter := range f.Root.Letters { |
|||
for _, path := range letter.Paths { |
|||
onePath := OnePath{} |
|||
onePath.Type = TypeText |
|||
for _, pt := range strings.Split(path, " ") { |
|||
ptSt := strings.Split(pt, ",") |
|||
point := Point{} |
|||
point.X, _ = strconv.ParseFloat(ptSt[0], 64) |
|||
point.Y, _ = strconv.ParseFloat(ptSt[1], 64) |
|||
onePath.List = append(onePath.List, &point) |
|||
} |
|||
letterID := []rune(letter.ID)[0] |
|||
f.ByLetter[letterID] = append(f.ByLetter[letterID], &onePath) |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,294 @@ |
|||
package plotter |
|||
|
|||
import ( |
|||
"codeisalie/gono/cfg" |
|||
"encoding/xml" |
|||
"fmt" |
|||
"io/ioutil" |
|||
"math" |
|||
"os" |
|||
"regexp" |
|||
"strconv" |
|||
"strings" |
|||
) |
|||
|
|||
// XMLSvg ...
|
|||
type XMLSvg struct { |
|||
XMLName xml.Name `xml:"svg"` |
|||
Width string `xml:"width,attr"` |
|||
Height string `xml:"height,attr"` |
|||
ViewBox string `xml:"viewBox,attr"` |
|||
Paths []XMLPath `xml:"path"` |
|||
Circles []XMLCircle `xml:"circle"` |
|||
Texts []XMLFlowRoot `xml:"flowRoot"` |
|||
} |
|||
|
|||
// XMLPath ...
|
|||
type XMLPath struct { |
|||
XMLName xml.Name `xml:"path"` |
|||
Style string `xml:"style,attr"` |
|||
Data string `xml:"d,attr"` |
|||
} |
|||
|
|||
// XMLCircle ...
|
|||
type XMLCircle struct { |
|||
XMLName xml.Name `xml:"circle"` |
|||
CenterX float64 `xml:"cx,attr"` |
|||
CenterY float64 `xml:"cy,attr"` |
|||
Radius float64 `xml:"r,attr"` |
|||
} |
|||
|
|||
// XMLFlowRoot ...
|
|||
type XMLFlowRoot struct { |
|||
XMLName xml.Name `xml:"flowRoot"` |
|||
Rec XMLFlowRec `xml:"flowRegion>rect"` |
|||
Text string `xml:"flowPara"` |
|||
Transform string `xml:"transform,attr"` |
|||
} |
|||
|
|||
type XMLFlowRec struct { |
|||
XMLName xml.Name `xml:"rect"` |
|||
X float64 `xml:"x,attr"` |
|||
Y float64 `xml:"y,attr"` |
|||
Width float64 `xml:"width,attr"` |
|||
Height float64 `xml:"height,attr"` |
|||
} |
|||
|
|||
// Svg ...
|
|||
type Svg struct { |
|||
OriginX float64 |
|||
OriginY float64 |
|||
Width float64 |
|||
Height float64 |
|||
} |
|||
|
|||
// Point ...
|
|||
type Point struct { |
|||
X float64 |
|||
Y float64 |
|||
} |
|||
|
|||
// OnePath ...
|
|||
type OnePath struct { |
|||
// StartAt Point
|
|||
Center Point |
|||
Type int |
|||
List []*Point |
|||
} |
|||
|
|||
// SvgParser struct
|
|||
type SvgParser struct { |
|||
Root XMLSvg |
|||
Svg Svg |
|||
Font FontParser |
|||
cfg cfg.Config |
|||
Paths []OnePath |
|||
} |
|||
|
|||
const ( |
|||
ModeAbsolute int = 100 + iota |
|||
ModeRelative |
|||
TypePath int = 200 + iota |
|||
TypeCircle |
|||
TypeText |
|||
) |
|||
|
|||
func rads(deg float64) float64 { |
|||
return deg * math.Pi / 180.0 |
|||
} |
|||
|
|||
// Parse on SVG file
|
|||
func (s *SvgParser) Parse(svgPath string, cfg cfg.Config) { |
|||
// Open our xmlFile
|
|||
xmlFile, err := os.Open(svgPath) |
|||
// if we os.Open returns an error then handle it
|
|||
if err != nil { |
|||
fmt.Println(err) |
|||
} |
|||
|
|||
fmt.Println("Successfully Opened " + svgPath) |
|||
// defer the closing of our xmlFile so that we can parse it later on
|
|||
defer xmlFile.Close() |
|||
|
|||
// read our opened xmlFile as a byte array.
|
|||
byteValue, _ := ioutil.ReadAll(xmlFile) |
|||
|
|||
// we unmarshal our byteArray which contains our
|
|||
// xmlFiles content into 'users' which we defined above
|
|||
xml.Unmarshal(byteValue, &s.Root) |
|||
|
|||
s.Font = FontParser{} |
|||
s.Font.Parse("font-default.xml") |
|||
|
|||
s.cfg = cfg |
|||
|
|||
s.Svg = Svg{} |
|||
reViewboxSrc := regexp.MustCompile("(.*) (.*) (.*) (.*)") |
|||
reViewboxRes := reViewboxSrc.FindAllStringSubmatch(s.Root.ViewBox, -1) |
|||
|
|||
s.Svg.OriginX, _ = strconv.ParseFloat(reViewboxRes[0][1], 64) |
|||
s.Svg.OriginY, _ = strconv.ParseFloat(reViewboxRes[0][2], 64) |
|||
s.Svg.Width, _ = strconv.ParseFloat(reViewboxRes[0][3], 64) |
|||
s.Svg.Height, _ = strconv.ParseFloat(reViewboxRes[0][4], 64) |
|||
|
|||
// fmt.Println(s.Root.Texts)
|
|||
|
|||
s.ProcessPaths() |
|||
s.ProcessCircles() |
|||
s.ProcessTexts() |
|||
|
|||
for _, path := range s.Paths { |
|||
for _, point := range path.List { |
|||
point.X = point.X*s.cfg.DrawingArea.Width/s.Svg.Width + s.cfg.DrawingArea.TopLeft.X |
|||
point.Y = -point.Y*s.cfg.DrawingArea.Height/s.Svg.Height + s.cfg.DrawingArea.BottomRight.Y |
|||
path.Center.X += point.X |
|||
path.Center.Y += point.Y |
|||
} |
|||
|
|||
path.Center.X /= float64(len(path.List)) |
|||
path.Center.Y /= float64(len(path.List)) |
|||
} |
|||
} |
|||
|
|||
func (s *SvgParser) ProcessTexts() { |
|||
reTranslate := regexp.MustCompile(`translate\((.*),(.*)\)`) |
|||
for _, text := range s.Root.Texts { |
|||
msg := text.Text |
|||
zoomH := text.Rec.Height / s.Font.Root.Height |
|||
zoomW := zoomH * s.Font.Root.Width / s.Font.Root.Width |
|||
origin := Point{ |
|||
X: text.Rec.X, |
|||
Y: s.Svg.Height - (text.Rec.Y - s.Font.Root.Height), |
|||
} |
|||
posX := 0.0 |
|||
posY := 0.0 |
|||
|
|||
values := reTranslate.FindAllStringSubmatch(text.Transform, -1) |
|||
if values != nil { |
|||
tPoint := Point{} |
|||
tPoint.X, _ = strconv.ParseFloat(values[0][1], 64) |
|||
tPoint.Y, _ = strconv.ParseFloat(values[0][2], 64) |
|||
origin.X += tPoint.X |
|||
origin.Y += tPoint.Y |
|||
} |
|||
|
|||
// fmt.Println("ORIGIN", origin)
|
|||
|
|||
for _, char := range msg { |
|||
seq, ok := s.Font.ByLetter[char] |
|||
if !ok { |
|||
fmt.Println("Unknown char", char) |
|||
seq = s.Font.ByLetter[' '] |
|||
} |
|||
|
|||
for _, path := range seq { |
|||
fmt.Println(path) |
|||
onePath := OnePath{ |
|||
Type: TypeText, |
|||
} |
|||
for _, pt := range path.List { |
|||
point := Point{ |
|||
X: pt.X*zoomW + posX + origin.X, |
|||
Y: (s.Font.Root.Height-pt.Y)*zoomH + posY + origin.Y, |
|||
} |
|||
// fmt.Println("POINT", point)
|
|||
onePath.List = append(onePath.List, &point) |
|||
} |
|||
s.Paths = append(s.Paths, onePath) |
|||
} |
|||
posX += (s.Font.Root.Width + s.Font.Root.Space) * zoomW |
|||
} |
|||
} |
|||
} |
|||
|
|||
func (s *SvgParser) ProcessCircles() { |
|||
for _, circle := range s.Root.Circles { |
|||
var angle float64 |
|||
onePath := OnePath{} |
|||
onePath.Type = TypeCircle |
|||
segments := s.cfg.CircleResolution |
|||
for angle = 360 / segments; angle <= 360; angle += 360 / segments { |
|||
point := Point{} |
|||
point.X = circle.CenterX + circle.Radius*math.Cos(rads(angle)) |
|||
point.Y = s.Svg.Height - circle.CenterY + circle.Radius*math.Sin(rads(angle)) |
|||
// s.Scale(&point)
|
|||
onePath.List = append(onePath.List, &point) |
|||
} |
|||
pointEnd := Point{ |
|||
X: onePath.List[0].X, |
|||
Y: onePath.List[0].Y, |
|||
} |
|||
onePath.List = append(onePath.List, &pointEnd) |
|||
s.Paths = append(s.Paths, onePath) |
|||
} |
|||
} |
|||
|
|||
func (s *SvgParser) ProcessPaths() { |
|||
rePosSrc := regexp.MustCompile("(.*),(.*)") |
|||
for _, path := range s.Root.Paths { |
|||
var mode int |
|||
var size int |
|||
onePath := OnePath{} |
|||
onePath.Type = TypePath |
|||
segs := strings.Split(path.Data, " ") |
|||
for _, seg := range segs { |
|||
switch { |
|||
case seg == "M": |
|||
// fmt.Println("Absolute")
|
|||
mode = ModeAbsolute |
|||
case seg == "m": |
|||
// fmt.Println("Relative")
|
|||
mode = ModeRelative |
|||
case seg == "z": |
|||
// fmt.Println("Zero")
|
|||
point := Point{ |
|||
X: onePath.List[0].X, |
|||
Y: onePath.List[0].Y, |
|||
} |
|||
onePath.List = append(onePath.List, &point) |
|||
default: |
|||
point := Point{} |
|||
seqRes := rePosSrc.FindAllStringSubmatch(seg, -1) |
|||
if seqRes == nil { |
|||
fmt.Printf("Unknown seg: %v\n", seg) |
|||
continue |
|||
} |
|||
point.X, _ = strconv.ParseFloat(seqRes[0][1], 64) |
|||
point.Y, _ = strconv.ParseFloat(seqRes[0][2], 64) |
|||
size = len(onePath.List) |
|||
|
|||
if mode == ModeRelative && size > 0 { |
|||
prevPoint := onePath.List[size-1] |
|||
// fmt.Println(prevPoint, point)
|
|||
point.X = point.X + prevPoint.X |
|||
point.Y = prevPoint.Y - point.Y |
|||
} else { |
|||
point.Y = s.Svg.Height - point.Y |
|||
} |
|||
|
|||
onePath.List = append(onePath.List, &point) |
|||
} |
|||
} |
|||
s.Paths = append(s.Paths, onePath) |
|||
} |
|||
} |
|||
|
|||
func (s *SvgParser) ScalePath(path *OnePath) { |
|||
// var point *Point
|
|||
// for idx := range path.List {
|
|||
// pX := (*path).List[idx]
|
|||
// pointCell := path.List[idx]
|
|||
// fmt.Printf(">%v %p\n", idx, point)
|
|||
// path.List[idx].X = path.List[idx].X*s.cfg.DrawingArea.Width/s.Svg.Width + s.cfg.DrawingArea.TopLeft.X
|
|||
// path.List[idx].Y = -path.List[idx].Y*s.cfg.DrawingArea.Height/s.Svg.Height + s.cfg.DrawingArea.BottomRight.Y
|
|||
// }
|
|||
} |
|||
|
|||
func (s *SvgParser) Scale(point *Point) { |
|||
(*point).X = point.X*s.cfg.DrawingArea.Width/s.Svg.Width + s.cfg.DrawingArea.TopLeft.X |
|||
(*point).Y = -point.Y*s.cfg.DrawingArea.Height/s.Svg.Height + s.cfg.DrawingArea.BottomRight.Y |
|||
} |
|||
|
|||
func (path *OnePath) process(cfg cfg.Config) { |
|||
|
|||
} |
|||
Write
Preview
Loading…
Cancel
Save