Skip to content

Instantly share code, notes, and snippets.

@DeadlySurgeon
Last active Apr 28, 2022
Embed
What would you like to do?
SVG Dice Generator for Fusion Project
package main
import (
"fmt"
"math"
"reflect"
"strings"
)
// COLORBLACK ...
const COLORBLACK = "black"
const dotSize = 1.5
func main() {
height := 157.08
width := 15.0
b := &Body{
Width: width,
Height: height,
XMLNS: "http://www.w3.org/2000/svg",
children: combine(
generateLines(2, height, 6),
generateDice(height, width, 6),
),
}
text := svgWriter(b, 0)
fmt.Println(text)
}
func combine[T any](d ...[]T) []T {
var data []T
for _, svgs := range d {
data = append(data, svgs...)
}
return data
}
// Shorthand rounding.
func r(x float64) float64 { return math.Round(x*100) / 100 }
// Potential Abstraction for later.
func hasChildren(svg SVG) bool { return len(svg.Children()) > 0 }
func svgStart(svg SVG, indent int) string {
s := strings.Repeat("\t", indent) + "<" + svg.Type() + " " + svgFields(svg)
if !hasChildren(svg) {
s += "/"
}
s += ">\n"
return s
}
func svgEnd(svg SVG, indent int) string {
if hasChildren(svg) {
return strings.Repeat("\t", indent) + "</" + svg.Type() + ">\n"
}
return ""
}
// svgWriter used for recursion
func svgWriter(svg SVG, indent int) string {
s := svgStart(svg, indent)
for _, child := range svg.Children() {
s += svgWriter(child, indent+1)
}
s += svgEnd(svg, indent)
return s
}
// SVG will allow us to do bullshit god this is dumb.
type SVG interface {
Type() string
Children() []SVG
}
// Body represents a svg body
type Body struct {
Width float64 `svg:"width" unit:"mm"`
Height float64 `svg:"height" unit:"mm"`
Fill string `svg:"fill"`
XMLNS string `svg:"xmlns"`
children []SVG
}
// Children ...
func (b *Body) Children() []SVG { return b.children }
//Type ...
func (b *Body) Type() string { return "svg" }
// Line ...
type Line struct {
X1 float64 `svg:"x1" unit:"mm"`
X2 float64 `svg:"x2" unit:"mm"`
Y1 float64 `svg:"y1" unit:"mm"`
Y2 float64 `svg:"y2" unit:"mm"`
Width float64 `svg:"stroke-width" unit:"mm"`
Stroke string `svg:"stroke"`
}
// Children ...
func (l *Line) Children() []SVG { return nil }
//Type ...
func (l *Line) Type() string { return "line" }
// Circle ...
type Circle struct {
CX float64 `svg:"cx" unit:"mm"`
CY float64 `svg:"cy" unit:"mm"`
Radius float64 `svg:"r" unit:"mm"`
Fill string `svg:"fill"`
Stroke string `svg:"stroke"`
}
// Children ...
func (c *Circle) Children() []SVG { return nil }
//Type ...
func (c *Circle) Type() string { return "circle" }
func svgFields(svg SVG) string {
var fields []string
v := reflect.ValueOf(svg)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
svgTag := t.Field(i).Tag.Get("svg")
if svgTag == "" {
continue
}
unit := t.Field(i).Tag.Get("unit")
f := v.Field(i)
if f.IsZero() {
continue
}
fields = append(
fields,
fmt.Sprintf(
"%s=\"%v%v\"",
svgTag,
f.Interface(),
unit,
),
)
}
// Lazy as fuck
return strings.Join(fields, " ")
}
func generateLines(thickness float64, size float64, amount int) []SVG {
var svgs []SVG
pad := size / float64(amount)
for i := 0.0; i <= float64(amount); i++ {
svgs = append(
svgs,
&Line{
X1: 2, X2: 13,
Y1: r(pad * i), Y2: r(pad * i),
Width: thickness, Stroke: COLORBLACK,
},
)
}
return svgs
}
/*
D = pos
157.08/6 == 26.18 * (D/100)
*/
var dice = [][][]float64{
{
{50, 50},
},
{
{25, 25},
{75, 75},
},
{
{25, 25},
{50, 50},
{75, 75},
},
{
{25, 25},
{25, 75},
{75, 75},
{75, 25},
},
{
{25, 25},
{25, 75},
{50, 50},
{75, 75},
{75, 25},
},
{
{25, 25},
{25, 50},
{25, 75},
{75, 75},
{75, 50},
{75, 25},
},
}
func generateDice(height float64, width float64, amount int) []SVG {
var svgs []SVG
padHeight := height / float64(amount)
// Algs:
// Even with Height: r((float64(i) * padHeight) + (padHeight * (circle[1] / 100)))
// Scaled for Height
/*
firstPAD = i * padHeight
rPad = padHeight - width
circle[i] * width/100
r((i * padHeight) + ((padHeight-width)/2) + (circle[1] * width/100))
*/
for i, dice := range dice {
for _, circle := range dice {
svgs = append(svgs, &Circle{
CX: circle[0] * (width / 100),
CY: r((float64(i) * padHeight) + ((padHeight - width) / 2) + (circle[1] * width / 100)),
// TODO:
// - Bigger dot for less dots?
Radius: dotSize,
Stroke: COLORBLACK,
Fill: COLORBLACK,
})
}
}
return svgs
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment