geo_aid_script/unroll/library/
triangle.rs1use num_traits::FromPrimitive;
4
5use crate::{
6 token::{number::ProcNum, Span},
7 unroll::{figure::PCNode, PointCollection, PointCollectionData},
8};
9
10use super::{bisector, prelude::*};
11
12fn triangle(context: &CompileContext, mut props: Properties) -> Pc<3> {
13 let points = (0..3).map(|_| context.free_point()).collect::<Vec<_>>();
14
15 let mut expr = Expr {
16 data: Rc::new(PointCollection {
17 length: 3,
18 data: PointCollectionData::PointCollection(points.into()),
19 }),
20 span: Span::empty(),
21 node: None,
22 };
23
24 let node = PCNode {
25 display: props.get("display").maybe_unset(true),
26 children: (0..3).map(|_| None).collect(),
27 props: None,
28 expr: expr.clone_without_node(),
29 };
30 let mut node = HierarchyNode::new(node);
31 node.set_associated(super::polygon::Associated);
32 node.insert_data(
33 "display_segments",
34 props.get("displaysegments").maybe_unset(true),
35 );
36 node.insert_data("style", props.get("style").maybe_unset(Style::Solid));
37 node.root.props = Some(props);
38 expr.node = Some(node);
39
40 expr.into()
41}
42
43fn main_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
44 let pc = triangle(context, props);
45
46 let a_y = context.point_y(pc.index_without_node(0));
47 let a_x = context.point_x(pc.index_without_node(0));
48 let b_y = context.point_y(pc.index_without_node(1));
49 let b_x = context.point_x(pc.index_without_node(1));
50 let c_y = context.point_y(pc.index_without_node(2));
51 context.scalar_eq(a_y, b_y.clone_without_node(), false);
52 context.gt(c_y, b_y, false);
53 context.gt(b_x, a_x, false);
54
55 pc
56}
57
58fn isosceles_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
59 let pc = triangle(context, props);
60
61 let ac = context.distance_pp(pc.index_without_node(0), pc.index_without_node(2));
62 let bc = context.distance_pp(pc.index_without_node(1), pc.index_without_node(2));
63 context.scalar_eq(ac, bc, false);
64
65 pc
66}
67
68fn main_isosceles_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
69 let pc = isosceles_triangle(context, props);
70
71 let a_y = context.point_y(pc.index_without_node(0));
72 let a_x = context.point_x(pc.index_without_node(0));
73 let b_y = context.point_y(pc.index_without_node(1));
74 let b_x = context.point_x(pc.index_without_node(1));
75 let c_y = context.point_y(pc.index_without_node(2));
76 context.scalar_eq(a_y, b_y.clone_without_node(), false);
77 context.gt(c_y, b_y, false);
78 context.gt(b_x, a_x, false);
79
80 pc
81}
82
83fn equilateral_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
84 let pc = triangle(context, props);
85
86 let ac = context.distance_pp(pc.index_without_node(0), pc.index_without_node(2));
87 let bc = context.distance_pp(pc.index_without_node(1), pc.index_without_node(2));
88 let ab = context.distance_pp(pc.index_without_node(0), pc.index_without_node(1));
89 context.scalar_eq(ac.clone_without_node(), bc, false);
90 context.scalar_eq(ac, ab, false);
91
92 pc
93}
94
95fn main_equilateral_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
96 let pc = equilateral_triangle(context, props);
97
98 let a_y = context.point_y(pc.index_without_node(0));
99 let a_x = context.point_x(pc.index_without_node(0));
100 let b_y = context.point_y(pc.index_without_node(1));
101 let b_x = context.point_x(pc.index_without_node(1));
102 let c_y = context.point_y(pc.index_without_node(2));
103 context.scalar_eq(a_y, b_y.clone_without_node(), false);
104 context.gt(c_y, b_y, false);
105 context.gt(b_x, a_x, false);
106
107 pc
108}
109
110fn right_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
111 let pc = triangle(context, props);
112
113 let acb = context.angle_ppp(
114 pc.index_without_node(0),
115 pc.index_without_node(2),
116 pc.index_without_node(1),
117 );
118 context.scalar_eq(
119 acb,
120 number!(ANGLE ProcNum::pi() / &ProcNum::from_i8(2).unwrap()),
121 false,
122 );
123
124 pc
125}
126
127fn main_right_triangle(context: &mut CompileContext, props: Properties) -> Pc<3> {
128 let pc = right_triangle(context, props);
129
130 let a_y = context.point_y(pc.index_without_node(0));
131 let a_x = context.point_x(pc.index_without_node(0));
132 let b_y = context.point_y(pc.index_without_node(1));
133 let c_y = context.point_y(pc.index_without_node(2));
134 let c_x = context.point_x(pc.index_without_node(2));
135 context.scalar_eq(a_y, c_y.clone_without_node(), false);
136 context.gt(b_y, c_y, false);
137 context.gt(a_x, c_x, false);
138
139 pc
140}
141
142fn orthocenter(
143 mut a: Expr<Point>,
144 mut b: Expr<Point>,
145 mut c: Expr<Point>,
146 context: &CompileContext,
147 props: Properties,
148) -> Expr<Point> {
149 let a_node = a.take_node();
150 let b_node = b.take_node();
151 let c_node = c.take_node();
152 let mut alt1 = context.perpendicular_through(
153 context.line(a.clone_without_node(), b.clone_without_node()),
154 c.clone_without_node(),
155 );
156 let mut alt2 = context.perpendicular_through(context.line(b, c), a);
157
158 alt1.take_node();
160 alt2.take_node();
161
162 let mut expr = context.intersection_display(alt1, alt2, props);
163
164 if let Some(node) = expr.node.as_mut() {
165 node.extend_children([a_node, b_node, c_node].into_iter().flatten());
166 }
167
168 expr
169}
170
171fn circumcenter(
172 mut a: Expr<Point>,
173 mut b: Expr<Point>,
174 mut c: Expr<Point>,
175 context: &CompileContext,
176 props: Properties,
177) -> Expr<Point> {
178 let a_node = a.take_node();
179 let b_node = b.take_node();
180 let c_node = c.take_node();
181 let mut bis1 = bisector::point_point(
182 a.clone_without_node(),
183 b.clone_without_node(),
184 context,
185 Properties::default(),
186 );
187 let mut bis2 = bisector::point_point(c, b, context, Properties::default());
188
189 bis1.take_node();
191 bis2.take_node();
192
193 let mut expr = context.intersection_display(bis1, bis2, props);
194
195 if let Some(node) = expr.node.as_mut() {
196 node.extend_children([a_node, b_node, c_node].into_iter().flatten());
197 }
198
199 expr
200}
201
202fn incenter(
203 mut a: Expr<Point>,
204 mut b: Expr<Point>,
205 mut c: Expr<Point>,
206 context: &CompileContext,
207 props: Properties,
208) -> Expr<Point> {
209 let a_node = a.take_node();
210 let b_node = b.take_node();
211 let c_node = c.take_node();
212 let mut bis1 = bisector::point_point_point(
213 a.clone_without_node(),
214 b.clone_without_node(),
215 c.clone_without_node(),
216 context,
217 Properties::default(),
218 );
219 let mut bis2 = bisector::point_point_point(a, c, b, context, Properties::default());
220
221 bis1.take_node();
223 bis2.take_node();
224
225 let mut expr = context.intersection_display(bis1, bis2, props);
226
227 if let Some(node) = expr.node.as_mut() {
228 node.extend_children([a_node, b_node, c_node].into_iter().flatten());
229 }
230
231 expr
232}
233
234pub fn register(library: &mut Library) {
236 library
237 .add(
238 Function::new("orthocenter")
239 .alias("orthocentre")
240 .alias_method(ty::collection(3), "orthocenter")
241 .alias_method(ty::collection(3), "orthocentre")
242 .overload(orthocenter)
243 .overload(|mut col: Pc<3>, context: &CompileContext, props| {
244 orthocenter(
245 col.index_with_node(0),
246 col.index_with_node(1),
247 col.index_with_node(2),
248 context,
249 props,
250 )
251 }),
252 )
253 .add(
254 Function::new("circumcenter")
255 .alias("circumcentre")
256 .alias_method(ty::collection(3), "circumcenter")
257 .alias_method(ty::collection(3), "circumcentre")
258 .overload(circumcenter)
259 .overload(|mut col: Pc<3>, context: &CompileContext, props| {
260 circumcenter(
261 col.index_with_node(0),
262 col.index_with_node(1),
263 col.index_with_node(2),
264 context,
265 props,
266 )
267 }),
268 )
269 .add(
270 Function::new("incenter")
271 .alias("incentre")
272 .alias_method(ty::collection(3), "incenter")
273 .alias_method(ty::collection(3), "incentre")
274 .overload(incenter)
275 .overload(|mut col: Pc<3>, context: &CompileContext, props| {
276 incenter(
277 col.index_with_node(0),
278 col.index_with_node(1),
279 col.index_with_node(2),
280 context,
281 props,
282 )
283 }),
284 )
285 .add(Function::new("triangle").overload(triangle))
286 .add(Function::new("maintriangle").overload(main_triangle))
287 .add(
288 Function::new("isoscelestriangle")
289 .alias("isosceles")
290 .overload(isosceles_triangle),
291 )
292 .add(
293 Function::new("mainisoscelestriangle")
294 .alias("mainisosceles")
295 .overload(main_isosceles_triangle),
296 )
297 .add(
298 Function::new("equilateraltriangle")
299 .alias("equilateral")
300 .overload(equilateral_triangle),
301 )
302 .add(
303 Function::new("mainequilateraltriangle")
304 .alias("mainequilateral")
305 .overload(main_equilateral_triangle),
306 )
307 .add(
308 Function::new("righttriangle")
309 .alias("right")
310 .overload(right_triangle),
311 )
312 .add(
313 Function::new("mainrighttriangle")
314 .alias("mainright")
315 .overload(main_right_triangle),
316 );
317}