+114
-34
src/doodler.gleam
+114
-34
src/doodler.gleam
···
18
18
}
19
19
20
20
fn init(_flags) {
21
-
Model(starting_points(), [], None)
21
+
Model(starting_points(), [], None, Both)
22
22
}
23
23
24
24
type Model {
25
-
Model(points: Set(Point), edges: List(Edge), selected: Option(Point))
25
+
Model(
26
+
points: Set(Point),
27
+
edges: List(Edge),
28
+
selected: Option(Point),
29
+
mirroring: Mirroring,
30
+
)
26
31
}
27
32
28
33
type Point {
···
33
38
Edge(a: Point, b: Point)
34
39
}
35
40
41
+
type Mirroring {
42
+
Off
43
+
Vertical
44
+
Horizontal
45
+
Both
46
+
}
47
+
36
48
type Msg {
37
49
UserClickedPoint(Point)
38
50
// TODO: implement mirror toggle
39
51
// For horizontal / vertical mirroring
52
+
UserClickedToggleMirror
40
53
// TODO: implement 'shape verification mode' toggle
41
54
}
42
55
43
56
fn starting_points() {
44
-
set.from_list([
45
-
Point(0, 0),
46
-
Point(0, 1),
47
-
Point(0, -1),
48
-
Point(-1, 0),
49
-
Point(-1, -1),
50
-
Point(1, 0),
51
-
Point(1, -1),
52
-
])
57
+
set.from_list(add_point_neighbors(set.new(), Point(0, 0)) |> set.to_list())
53
58
}
54
59
55
60
fn update(model: Model, msg: Msg) {
···
58
63
UserClickedPoint(clicked_point) -> {
59
64
case model {
60
65
// no point selected, select the clicked one
61
-
Model(points: _, edges:, selected: None) -> {
66
+
Model(points: _, edges:, selected: None, mirroring:) -> {
62
67
let points =
63
-
update_points(edges)
68
+
edges
69
+
|> update_points
64
70
|> add_point_neighbors(clicked_point)
65
71
66
-
Model(points:, edges:, selected: Some(clicked_point))
72
+
Model(points:, edges:, selected: Some(clicked_point), mirroring:)
67
73
}
68
74
// same point clicked again, deselect it
69
-
Model(points: _, edges:, selected: Some(first_point))
75
+
Model(points: _, edges:, selected: Some(first_point), mirroring:)
70
76
if clicked_point == first_point
71
77
-> {
72
78
let points = update_points(edges)
73
-
Model(points, edges, selected: None)
79
+
Model(points, edges, selected: None, mirroring:)
74
80
}
75
81
76
82
// different point selected, add / remove that edge
77
-
Model(_, _, Some(first_point)) -> {
78
-
// doesnt work
79
-
let thing =
83
+
Model(_, _, Some(first_point), mirroring:) -> {
84
+
let filtered_edges =
80
85
model.edges
81
-
|> list.partition(fn(edge) {
82
-
{
83
-
points_equal(edge.a, first_point)
84
-
&& points_equal(edge.b, clicked_point)
85
-
}
86
-
|| {
87
-
points_equal(edge.a, clicked_point)
88
-
&& points_equal(edge.b, first_point)
89
-
}
90
-
})
86
+
|> list.partition(filter_edge(
87
+
_,
88
+
first_point,
89
+
clicked_point,
90
+
mirroring,
91
+
))
91
92
92
-
let edges = case thing {
93
+
let edges = case filtered_edges {
93
94
// the new edge wasnt found in the existing ones, add it
94
-
#([], edges) -> [Edge(first_point, clicked_point), ..edges]
95
+
#([], edges) ->
96
+
add_new_edge(first_point, clicked_point, edges, mirroring)
95
97
// the new edge was found in the existing ones, remove it
96
98
#([_, ..], edges) -> edges
97
99
}
98
100
let points = update_points(edges)
99
101
// let points = model.points
100
102
101
-
Model(points:, edges:, selected: None)
103
+
Model(points:, edges:, selected: None, mirroring:)
102
104
}
103
105
}
104
106
}
107
+
// cycle mirroring
108
+
UserClickedToggleMirror ->
109
+
case model {
110
+
Model(_, _, _, Off) -> Model(..model, mirroring: Vertical)
111
+
Model(_, _, _, Vertical) -> Model(..model, mirroring: Horizontal)
112
+
Model(_, _, _, Horizontal) -> Model(..model, mirroring: Both)
113
+
Model(_, _, _, Both) -> Model(..model, mirroring: Off)
114
+
}
115
+
}
116
+
}
117
+
118
+
fn add_new_edge(
119
+
point_a: Point,
120
+
point_b: Point,
121
+
edges: List(Edge),
122
+
mirroring: Mirroring,
123
+
) -> List(Edge) {
124
+
case mirroring {
125
+
Off -> [Edge(point_a, point_b)]
126
+
Vertical -> [
127
+
Edge(point_a, point_b),
128
+
Edge(point_a, point_b) |> invert_y,
129
+
]
130
+
Horizontal -> [
131
+
Edge(point_a, point_b),
132
+
Edge(point_a, point_b) |> invert_x,
133
+
]
134
+
Both -> [
135
+
Edge(point_a, point_b),
136
+
Edge(point_a, point_b) |> invert_x,
137
+
Edge(point_a, point_b) |> invert_y,
138
+
Edge(point_a, point_b) |> invert_x |> invert_y(),
139
+
]
140
+
}
141
+
|> list.append(edges)
142
+
}
143
+
144
+
fn invert_x(edge: Edge) -> Edge {
145
+
let Edge(a, b) = edge
146
+
147
+
Edge(Point(-a.x, a.y), Point(-b.x, b.y))
148
+
}
149
+
150
+
fn invert_y(edge: Edge) -> Edge {
151
+
let Edge(a, b) = edge
152
+
153
+
Edge(Point(a.x, -a.y), Point(b.x, -b.y))
154
+
}
155
+
156
+
fn filter_edge(edge: Edge, point_a, point_b, mirroring) {
157
+
{
158
+
points_equal_respect_mirror(edge.a, point_a, mirroring)
159
+
&& points_equal_respect_mirror(edge.b, point_b, mirroring)
160
+
}
161
+
|| {
162
+
points_equal_respect_mirror(edge.a, point_b, mirroring)
163
+
&& points_equal_respect_mirror(edge.b, point_a, mirroring)
105
164
}
106
165
}
107
166
···
147
206
first_point.x == second_point.x && first_point.y == second_point.y
148
207
}
149
208
209
+
/// compare two points for equality; while respecting Mirroring
210
+
///
211
+
fn points_equal_respect_mirror(
212
+
first_point: Point,
213
+
second_point: Point,
214
+
mirroring: Mirroring,
215
+
) -> Bool {
216
+
case mirroring {
217
+
Off -> first_point.x == second_point.x && first_point.y == second_point.y
218
+
Vertical ->
219
+
first_point.x == second_point.x
220
+
&& int.absolute_value(first_point.y) == int.absolute_value(second_point.y)
221
+
Horizontal ->
222
+
int.absolute_value(first_point.x) == int.absolute_value(second_point.x)
223
+
&& first_point.y == second_point.y
224
+
Both ->
225
+
int.absolute_value(first_point.x) == int.absolute_value(second_point.x)
226
+
&& int.absolute_value(first_point.y) == int.absolute_value(second_point.y)
227
+
}
228
+
}
229
+
150
230
/// get #(min_x, min_y, max_x, max_y) from a list of points
151
231
///
152
232
fn min_max(points) {
···
189
269
div([], [
190
270
svg.svg(
191
271
[
192
-
attribute.attribute("width", "100vw"),
193
-
attribute.attribute("height", "100vh"),
272
+
attribute.attribute("width", "100%"),
273
+
attribute.attribute("height", "100%"),
194
274
attribute.attribute("viewBox", viewbox),
195
275
],
196
276
list.append(