-
Notifications
You must be signed in to change notification settings - Fork 2
/
around.go
120 lines (100 loc) · 3.28 KB
/
around.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
package components
import (
"fmt"
"github.com/dustismo/heavyfishdesign/dom"
"github.com/dustismo/heavyfishdesign/dynmap"
"github.com/dustismo/heavyfishdesign/path"
"github.com/dustismo/heavyfishdesign/transforms"
)
type AroundComponentFactory struct{}
type AroundComponent struct {
*dom.BasicComponent
Repeatable dom.Component // the thing to be repeated
}
func (ccf AroundComponentFactory) CreateComponent(componentType string, mp *dynmap.DynMap, dc *dom.DocumentContext) (dom.Component, error) {
factory := dom.AppContext()
dm := mp.Clone()
repeatDM := dm.MustDynMap("repeatable", dynmap.New())
repeat, err := factory.MakeComponent(repeatDM, dc)
if err != nil {
return nil, err
}
// remember to add components to the map
dm.Put("repeatable", repeat)
bc := factory.MakeBasicComponent(dm)
rc := &AroundComponent{
BasicComponent: bc,
Repeatable: repeat,
}
repeat.SetParent(rc)
rc.SetChildren([]dom.Element{repeat})
return rc, nil
}
// The list of component types this Factory should be used for
func (ccf AroundComponentFactory) ComponentTypes() []string {
return []string{"around"}
}
func (rc *AroundComponent) Render(ctx dom.RenderContext) (path.Path, dom.RenderContext, error) {
rc.RenderStart(ctx)
attr := rc.Attr()
numEdges := attr.MustInt("num_edges", 0)
if numEdges == 0 {
return nil, ctx, fmt.Errorf("Error, Around component (%s) must have 'num_edges' attribute", rc.Id())
}
radius := attr.MustFloat64("radius", 0.0)
if radius == 0 {
return nil, ctx, fmt.Errorf("Error, Around component (%s) must have 'radius' attribute", rc.Id())
}
// figure out the angle and width of each segment
centerPoint := attr.MustPoint("center_point", ctx.Cursor)
degrees := 360.0 / float64(numEdges)
startPoint := path.NewLineSegmentAngle(centerPoint, radius, -(degrees/2)-90).End()
endPoint := path.NewLineSegmentAngle(centerPoint, radius, (degrees/2)-90).End()
line := path.LineSegment{
StartPoint: startPoint,
EndPoint: endPoint,
}
// fmt.Printf("Center point %s\nStart point %s\nEnd Point %s\nWidth %.3f\ndegrees %.3f\n",
// centerPoint.StringPrecision(3),
// startPoint.StringPrecision(3),
// endPoint.StringPrecision(3),
// line.Length(),
// degrees,
// )
// trianglePth := path.NewPathFromSegments([]path.Segment{
// path.LineSegment{centerPoint, startPoint},
// line,
// path.LineSegment{endPoint, centerPoint},
// })
// now render a single path (this is the horizontal top path)
rCtx := ctx.Clone()
rc.SetLocalVariable("around__length", line.Length())
rCtx.Cursor = path.NewPoint(0, 0)
paths := []path.Path{}
for i := 0; i < numEdges; i++ {
rc.SetLocalVariable("around__index", 0)
p, c, err := rc.Repeatable.Render(rCtx)
if err != nil {
return p, c, err
}
pth, err := path.MultiTransform(
p,
transforms.MoveTransform{
Point: startPoint,
Handle: path.Origin,
SegmentOperators: dom.AppContext().SegmentOperators(),
},
transforms.RotateTransform{
Degrees: degrees * float64(i),
Axis: path.ToPathAttrFromPoint(centerPoint, dom.AppContext().Precision()),
SegmentOperators: dom.AppContext().SegmentOperators(),
},
)
if err != nil {
return pth, ctx, err
}
paths = append(paths, pth)
}
p := transforms.SimpleJoin{}.JoinPaths(paths...)
return p, rCtx, nil
}