From ed13176370c27c9b54cfbd8a2f423969b4df245f Mon Sep 17 00:00:00 2001 From: Wouter Horlings Date: Tue, 12 Apr 2022 23:43:35 +0200 Subject: [PATCH] first commit --- cmd/basispatroon_broek/basispatroon_broek.go | 33 +++++ go.mod | 5 + go.sum | 29 ++++ pkg/patroon/basispatroon_broek.go | 60 +++++++++ pkg/util/point.go | 134 +++++++++++++++++++ pkg/util/point_list.go | 73 ++++++++++ pkg/util/svg_helper.go | 13 ++ 7 files changed, 347 insertions(+) create mode 100644 cmd/basispatroon_broek/basispatroon_broek.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pkg/patroon/basispatroon_broek.go create mode 100644 pkg/util/point.go create mode 100644 pkg/util/point_list.go create mode 100644 pkg/util/svg_helper.go diff --git a/cmd/basispatroon_broek/basispatroon_broek.go b/cmd/basispatroon_broek/basispatroon_broek.go new file mode 100644 index 0000000..e8233b1 --- /dev/null +++ b/cmd/basispatroon_broek/basispatroon_broek.go @@ -0,0 +1,33 @@ +package main + +import ( + svg "github.com/ajstarks/svgo/float" + "naaipatroon/pkg/patroon" + "os" +) + +func main() { + broek := patroon.Basispatroonbroek{ + Heupwijdte: 103, + Taillewijdte: 85, + Zithoogte: 31, + Tussenbeenlengte: 83, + Pijpbreedte: 25, + Taillebandbreedte: 4, + Eenheid: patroon.CentiMeter, + Eigenaar: "Wouter Horlings", + } + + points := broek.GeneratePoints() + + f, err := os.OpenFile("broek.svg", os.O_RDWR|os.O_CREATE, 0o755) + if err != nil { + panic(err) + } + + _, max := points.Normalize().Box() + canvas := svg.New(f) + canvas.Start(max.X, max.Y) + broek.Voorbeen(canvas) + canvas.End() +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..43b0da7 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module naaipatroon + +go 1.17 + +require github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..38027ba --- /dev/null +++ b/go.sum @@ -0,0 +1,29 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY= +github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= +github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= diff --git a/pkg/patroon/basispatroon_broek.go b/pkg/patroon/basispatroon_broek.go new file mode 100644 index 0000000..a7e96c8 --- /dev/null +++ b/pkg/patroon/basispatroon_broek.go @@ -0,0 +1,60 @@ +package patroon + +import ( + svg "github.com/ajstarks/svgo/float" + "math" + "naaipatroon/pkg/util" +) + +const ( + MilliMeter SvgScale = 3.7795 + CentiMeter SvgScale = 37.795 +) + +type SvgScale float64 + +type Basispatroonbroek struct { + Heupwijdte float64 + Taillewijdte float64 + Zithoogte float64 + Tussenbeenlengte float64 + Pijpbreedte float64 + Taillebandbreedte float64 + Eenheid SvgScale + Eigenaar string +} + +func (b *Basispatroonbroek) GeneratePoints() util.PointMap { + p := make(util.PointMap, 30) + p[0] = util.Point{} + p[1] = p[0].Below(b.Zithoogte + 1 - b.Taillebandbreedte) + p[2] = p[1].Below(b.Tussenbeenlengte) + p[3] = p[2].Above(p[1].Distance(p[2])/2 + 5) + p[4] = p[1].Above(b.Zithoogte / 4) + p[5] = p[1].Left(b.Heupwijdte / 12) + p[6] = p[4].Left(b.Heupwijdte / 12) + p[8] = p[6].Right(b.Heupwijdte/4 + 2) + p[9] = p[5].Left(b.Heupwijdte/16 + 5) + p[10] = p[7].Right(1) + p[11] = p[10].Right(b.Taillewijdte/4 + 2.5) + p[12] = p[2].Right(b.Pijpbreedte / 2) + p[13] = p[2].Left(b.Pijpbreedte / 2) + p[14] = p[3].Right(b.Pijpbreedte / 2) + p[15] = p[3].Left(b.Pijpbreedte / 2) + + return p.Scale(float64(b.Eenheid)) +} + +func (b *Basispatroonbroek) Voorbeen(canvas *svg.SVG) { + p := b.GeneratePoints().Normalize() + p.Draw(canvas) + p.Line(canvas, 15, 13, 12, 14) + p.Line(canvas, 10, 11) + pa := p[14].Above(p[14].Distance(p[8]) / 3) + pb := p[8].Below(p[14].Distance(p[8]) / 3) + util.Bezier(canvas, p[14], pa, pb, p[8]) + p15p9half := p[9].Subtract(p[15]).Divide(2) + pc := p[15].Add(p15p9half).Add(p15p9half.Unit().Rotate(math.Pi / 2).Multiply(3 * float64(b.Eenheid))) + + util.Qbez(canvas, p[9], pc, p[15]) +} diff --git a/pkg/util/point.go b/pkg/util/point.go new file mode 100644 index 0000000..c75a7fb --- /dev/null +++ b/pkg/util/point.go @@ -0,0 +1,134 @@ +package util + +import ( + "fmt" + "math" +) + +// Point represents a 2 dimensional Point +type Point struct { + X, Y float64 +} + +// Abs returns a Point with the absolute value of X and Y. +// Should not be confused with Magnitude due to its notation ||A||. +func (p Point) Abs() Point { + return Point{ + math.Abs(p.X), + math.Abs(p.Y), + } +} + +// Add returns a Point with the value of Point p plus Point q. +func (p Point) Add(q Point) Point { + return Point{ + p.X + q.X, + p.Y + q.Y, + } +} + +// Subtract returns a Point with the value of Point p minus Point q. +func (p Point) Subtract(q Point) Point { + return Point{ + X: p.X - q.X, + Y: p.Y - q.Y, + } +} + +// Multiply returns a Point with the value of Point p multiplied by f. +func (p Point) Multiply(f float64) Point { + return Point{X: p.X * f, Y: p.Y * f} +} + +// Divide returns a Point with the value of Point p divided by f. +func (p Point) Divide(f float64) Point { + return Point{X: p.X / f, Y: p.Y / f} +} + +// Round returns a Point with the rounded value of Point p. +func (p Point) Round() Point { + return Point{X: math.Round(p.X), Y: math.Round(p.Y)} +} + +// Floor returns a Point with the floored value of Point p. +func (p Point) Floor() Point { + return Point{X: math.Floor(p.X), Y: math.Floor(p.Y)} +} + +// Ceil returns a Point with the rounded up value of Point p. +func (p Point) Ceil() Point { + return Point{X: math.Ceil(p.X), Y: math.Ceil(p.Y)} +} + +// Scale returns a Point with the values of Point p scaled up by the values of Point q. +func (p Point) Scale(q Point) Point { + return Point{ + X: p.X * q.X, + Y: p.Y * q.Y, + } +} + +// ScaleDown returns a Point with the values of Point p scaled down by the values of Point q. +func (p Point) ScaleDown(q Point) Point { + return Point{ + X: p.X / q.X, + Y: p.Y / q.Y, + } +} + +// Min returns a Point with the smallest values of X and Y for Point p and q. +func (p Point) Min(q Point) Point { + return Point{ + X: math.Min(p.X, q.X), + Y: math.Min(p.Y, q.Y), + } +} + +// Max returns a Point with the largest values of X and Y for Point p and q. +func (p Point) Max(q Point) Point { + return Point{ + X: math.Max(p.X, q.X), + Y: math.Max(p.Y, q.Y), + } +} + +// String returns a string with comma separated values of Point p. +func (p Point) String() string { + return fmt.Sprintf("%v,%v", p.X, p.Y) +} + +// Magnitude returns a float64 with the length/magnitude of Point p. +func (p Point) Magnitude() float64 { + return math.Sqrt(math.Pow(p.X, 2) + math.Pow(p.Y, 2)) +} + +func (p Point) Unit() Point { + return p.Divide(p.Magnitude()) +} + +func (p Point) Rotate(a float64) Point { + return Point{ + X: math.Cos(a)*p.X - math.Sin(a)*p.Y, + Y: math.Sin(a)*p.X + math.Cos(a)*p.Y, + } +} + +func (p Point) Distance(q Point) float64 { + return p.Subtract(q).Magnitude() +} + +func (p Point) Above(l float64) Point { + return p.Subtract(Point{Y: l}) +} + +func (p Point) Below(l float64) Point { + return p.Add(Point{Y: l}) +} + +func (p Point) Right(l float64) Point { + return p.Add(Point{X: l}) +} + +func (p Point) Left(l float64) Point { + return p.Subtract(Point{X: l}) +} diff --git a/pkg/util/point_list.go b/pkg/util/point_list.go new file mode 100644 index 0000000..786ee65 --- /dev/null +++ b/pkg/util/point_list.go @@ -0,0 +1,73 @@ +package util + +import ( + "fmt" + "strconv" + + svg "github.com/ajstarks/svgo/float" +) + +type PointMap map[int]Point + +func (pm PointMap) Scale(s float64) PointMap { + pointMap := make(PointMap, len(pm)) + + for i, p := range pm { + pointMap[i] = p.Multiply(s) + } + + return pointMap + +} + +func (pm PointMap) Box() (Point, Point) { + min := Point{} + max := Point{} + + for _, p := range pm { + min = min.Min(p) + max = max.Max(p) + } + + return min, max +} + +func (pm PointMap) Offset(point Point) PointMap { + pointMap := make(PointMap, len(pm)) + + for i, p := range pm { + pointMap[i] = p.Subtract(point) + } + + return pointMap +} + +func (pm PointMap) Normalize() PointMap { + min, _ := pm.Box() + return pm.Offset(min) +} + +func (pm PointMap) Draw(canvas *svg.SVG) { + for i, point := range pm.Normalize() { + canvas.Circle(point.X, point.Y, 2.0, "stroke:black;fill:black") + canvas.Text(point.X+2, point.Y+2, strconv.Itoa(i)) + } +} + +func (pm PointMap) Line(canvas *svg.SVG, lines ...int) { + for i := 0; i < len(lines)-1; i++ { + start := lines[i] + end := lines[i+1] + canvas.Line(pm[start].X, pm[start].Y, pm[end].X, pm[end].Y, "stroke:black;stroke-width:3") + } +} + +func (pm PointMap) Bezier(canvas *svg.SVG, lines ...int) error { + if len(lines) != 4 { + return fmt.Errorf("expected 4 line definitons, got %d instead", len(lines)) + } + + canvas.Bezier(pm[lines[0]].X, pm[lines[0]].Y, pm[lines[1]].X, pm[lines[1]].Y, pm[lines[2]].X, pm[lines[2]].Y, pm[lines[3]].X, pm[lines[3]].Y, "stroke:black;fill:none") + + return nil +} diff --git a/pkg/util/svg_helper.go b/pkg/util/svg_helper.go new file mode 100644 index 0000000..fa76411 --- /dev/null +++ b/pkg/util/svg_helper.go @@ -0,0 +1,13 @@ +package util + +import ( + svg "github.com/ajstarks/svgo/float" +) + +func Bezier(canvas *svg.SVG, start, c1, c2, end Point) { + canvas.Bezier(start.X, start.Y, c1.X, c1.Y, c2.X, c2.Y, end.X, end.Y, "fill:none;stroke:black;stroke-width:3") +} + +func Qbez(canvas *svg.SVG, start, control, end Point) { + canvas.Qbez(start.X, start.Y, control.X, control.Y, end.X, end.Y, "fill:none;stroke:black;stroke-width:3") +}