Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gizmos/src/primitives/dim2.rs
6596 views
1
//! A module for rendering each of the 2D [`bevy_math::primitives`] with [`GizmoBuffer`].
2
3
use core::f32::consts::{FRAC_PI_2, PI};
4
5
use super::helpers::*;
6
7
use bevy_color::Color;
8
use bevy_math::{
9
primitives::{
10
Annulus, Arc2d, Capsule2d, Circle, CircularSector, CircularSegment, Ellipse, Line2d,
11
Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle, RegularPolygon, Rhombus, Segment2d,
12
Triangle2d,
13
},
14
Dir2, Isometry2d, Rot2, Vec2,
15
};
16
17
use crate::{gizmos::GizmoBuffer, prelude::GizmoConfigGroup};
18
19
// some magic number since using directions as offsets will result in lines of length 1 pixel
20
const MIN_LINE_LEN: f32 = 50.0;
21
const HALF_MIN_LINE_LEN: f32 = 25.0;
22
// length used to simulate infinite lines
23
const INFINITE_LEN: f32 = 100_000.0;
24
25
/// A trait for rendering 2D geometric primitives (`P`) with [`GizmoBuffer`].
26
pub trait GizmoPrimitive2d<P: Primitive2d> {
27
/// The output of `primitive_2d`. This is a builder to set non-default values.
28
type Output<'a>
29
where
30
Self: 'a;
31
32
/// Renders a 2D primitive with its associated details.
33
fn primitive_2d(
34
&mut self,
35
primitive: &P,
36
isometry: impl Into<Isometry2d>,
37
color: impl Into<Color>,
38
) -> Self::Output<'_>;
39
}
40
41
// direction 2d
42
43
impl<Config, Clear> GizmoPrimitive2d<Dir2> for GizmoBuffer<Config, Clear>
44
where
45
Config: GizmoConfigGroup,
46
Clear: 'static + Send + Sync,
47
{
48
type Output<'a>
49
= ()
50
where
51
Self: 'a;
52
53
fn primitive_2d(
54
&mut self,
55
primitive: &Dir2,
56
isometry: impl Into<Isometry2d>,
57
color: impl Into<Color>,
58
) -> Self::Output<'_> {
59
if !self.enabled {
60
return;
61
}
62
let isometry = isometry.into();
63
let start = Vec2::ZERO;
64
let end = *primitive * MIN_LINE_LEN;
65
self.arrow_2d(isometry * start, isometry * end, color);
66
}
67
}
68
69
// arc 2d
70
71
impl<Config, Clear> GizmoPrimitive2d<Arc2d> for GizmoBuffer<Config, Clear>
72
where
73
Config: GizmoConfigGroup,
74
Clear: 'static + Send + Sync,
75
{
76
type Output<'a>
77
= ()
78
where
79
Self: 'a;
80
81
fn primitive_2d(
82
&mut self,
83
primitive: &Arc2d,
84
isometry: impl Into<Isometry2d>,
85
color: impl Into<Color>,
86
) -> Self::Output<'_> {
87
if !self.enabled {
88
return;
89
}
90
91
let isometry = isometry.into();
92
let start_iso = isometry * Isometry2d::from_rotation(Rot2::radians(-primitive.half_angle));
93
94
self.arc_2d(
95
start_iso,
96
primitive.half_angle * 2.0,
97
primitive.radius,
98
color,
99
);
100
}
101
}
102
103
// circle 2d
104
105
impl<Config, Clear> GizmoPrimitive2d<Circle> for GizmoBuffer<Config, Clear>
106
where
107
Config: GizmoConfigGroup,
108
Clear: 'static + Send + Sync,
109
{
110
type Output<'a>
111
= crate::circles::Ellipse2dBuilder<'a, Config, Clear>
112
where
113
Self: 'a;
114
115
fn primitive_2d(
116
&mut self,
117
primitive: &Circle,
118
isometry: impl Into<Isometry2d>,
119
color: impl Into<Color>,
120
) -> Self::Output<'_> {
121
self.circle_2d(isometry, primitive.radius, color)
122
}
123
}
124
125
// circular sector 2d
126
127
impl<Config, Clear> GizmoPrimitive2d<CircularSector> for GizmoBuffer<Config, Clear>
128
where
129
Config: GizmoConfigGroup,
130
Clear: 'static + Send + Sync,
131
{
132
type Output<'a>
133
= ()
134
where
135
Self: 'a;
136
137
fn primitive_2d(
138
&mut self,
139
primitive: &CircularSector,
140
isometry: impl Into<Isometry2d>,
141
color: impl Into<Color>,
142
) -> Self::Output<'_> {
143
if !self.enabled {
144
return;
145
}
146
147
let isometry = isometry.into();
148
let color = color.into();
149
150
let start_iso =
151
isometry * Isometry2d::from_rotation(Rot2::radians(-primitive.arc.half_angle));
152
let end_iso = isometry * Isometry2d::from_rotation(Rot2::radians(primitive.arc.half_angle));
153
154
// we need to draw the arc part of the sector, and the two lines connecting the arc and the center
155
self.arc_2d(
156
start_iso,
157
primitive.arc.half_angle * 2.0,
158
primitive.arc.radius,
159
color,
160
);
161
162
let end_position = primitive.arc.radius * Vec2::Y;
163
self.line_2d(isometry * Vec2::ZERO, start_iso * end_position, color);
164
self.line_2d(isometry * Vec2::ZERO, end_iso * end_position, color);
165
}
166
}
167
168
// circular segment 2d
169
170
impl<Config, Clear> GizmoPrimitive2d<CircularSegment> for GizmoBuffer<Config, Clear>
171
where
172
Config: GizmoConfigGroup,
173
Clear: 'static + Send + Sync,
174
{
175
type Output<'a>
176
= ()
177
where
178
Self: 'a;
179
180
fn primitive_2d(
181
&mut self,
182
primitive: &CircularSegment,
183
isometry: impl Into<Isometry2d>,
184
color: impl Into<Color>,
185
) -> Self::Output<'_> {
186
if !self.enabled {
187
return;
188
}
189
190
let isometry = isometry.into();
191
let color = color.into();
192
193
let start_iso =
194
isometry * Isometry2d::from_rotation(Rot2::radians(-primitive.arc.half_angle));
195
let end_iso = isometry * Isometry2d::from_rotation(Rot2::radians(primitive.arc.half_angle));
196
197
// we need to draw the arc part of the segment, and the line connecting the two ends
198
self.arc_2d(
199
start_iso,
200
primitive.arc.half_angle * 2.0,
201
primitive.arc.radius,
202
color,
203
);
204
205
let position = primitive.arc.radius * Vec2::Y;
206
self.line_2d(start_iso * position, end_iso * position, color);
207
}
208
}
209
210
// ellipse 2d
211
212
impl<Config, Clear> GizmoPrimitive2d<Ellipse> for GizmoBuffer<Config, Clear>
213
where
214
Config: GizmoConfigGroup,
215
Clear: 'static + Send + Sync,
216
{
217
type Output<'a>
218
= crate::circles::Ellipse2dBuilder<'a, Config, Clear>
219
where
220
Self: 'a;
221
222
fn primitive_2d<'a>(
223
&mut self,
224
primitive: &Ellipse,
225
isometry: impl Into<Isometry2d>,
226
color: impl Into<Color>,
227
) -> Self::Output<'_> {
228
self.ellipse_2d(isometry, primitive.half_size, color)
229
}
230
}
231
232
// annulus 2d
233
234
/// Builder for configuring the drawing options of [`Annulus`].
235
pub struct Annulus2dBuilder<'a, Config, Clear>
236
where
237
Config: GizmoConfigGroup,
238
Clear: 'static + Send + Sync,
239
{
240
gizmos: &'a mut GizmoBuffer<Config, Clear>,
241
isometry: Isometry2d,
242
inner_radius: f32,
243
outer_radius: f32,
244
color: Color,
245
inner_resolution: u32,
246
outer_resolution: u32,
247
}
248
249
impl<Config, Clear> Annulus2dBuilder<'_, Config, Clear>
250
where
251
Config: GizmoConfigGroup,
252
Clear: 'static + Send + Sync,
253
{
254
/// Set the number of line-segments for each circle of the annulus.
255
pub fn resolution(mut self, resolution: u32) -> Self {
256
self.outer_resolution = resolution;
257
self.inner_resolution = resolution;
258
self
259
}
260
261
/// Set the number of line-segments for the outer circle of the annulus.
262
pub fn outer_resolution(mut self, resolution: u32) -> Self {
263
self.outer_resolution = resolution;
264
self
265
}
266
267
/// Set the number of line-segments for the inner circle of the annulus.
268
pub fn inner_resolution(mut self, resolution: u32) -> Self {
269
self.inner_resolution = resolution;
270
self
271
}
272
}
273
274
impl<Config, Clear> GizmoPrimitive2d<Annulus> for GizmoBuffer<Config, Clear>
275
where
276
Config: GizmoConfigGroup,
277
Clear: 'static + Send + Sync,
278
{
279
type Output<'a>
280
= Annulus2dBuilder<'a, Config, Clear>
281
where
282
Self: 'a;
283
284
fn primitive_2d(
285
&mut self,
286
primitive: &Annulus,
287
isometry: impl Into<Isometry2d>,
288
color: impl Into<Color>,
289
) -> Self::Output<'_> {
290
Annulus2dBuilder {
291
gizmos: self,
292
isometry: isometry.into(),
293
inner_radius: primitive.inner_circle.radius,
294
outer_radius: primitive.outer_circle.radius,
295
color: color.into(),
296
inner_resolution: crate::circles::DEFAULT_CIRCLE_RESOLUTION,
297
outer_resolution: crate::circles::DEFAULT_CIRCLE_RESOLUTION,
298
}
299
}
300
}
301
302
impl<Config, Clear> Drop for Annulus2dBuilder<'_, Config, Clear>
303
where
304
Config: GizmoConfigGroup,
305
Clear: 'static + Send + Sync,
306
{
307
fn drop(&mut self) {
308
if !self.gizmos.enabled {
309
return;
310
}
311
312
let Annulus2dBuilder {
313
gizmos,
314
isometry,
315
inner_radius,
316
outer_radius,
317
inner_resolution,
318
outer_resolution,
319
color,
320
..
321
} = self;
322
323
gizmos
324
.circle_2d(*isometry, *outer_radius, *color)
325
.resolution(*outer_resolution);
326
gizmos
327
.circle_2d(*isometry, *inner_radius, *color)
328
.resolution(*inner_resolution);
329
}
330
}
331
332
// rhombus 2d
333
334
impl<Config, Clear> GizmoPrimitive2d<Rhombus> for GizmoBuffer<Config, Clear>
335
where
336
Config: GizmoConfigGroup,
337
Clear: 'static + Send + Sync,
338
{
339
type Output<'a>
340
= ()
341
where
342
Self: 'a;
343
344
fn primitive_2d(
345
&mut self,
346
primitive: &Rhombus,
347
isometry: impl Into<Isometry2d>,
348
color: impl Into<Color>,
349
) -> Self::Output<'_> {
350
if !self.enabled {
351
return;
352
};
353
let isometry = isometry.into();
354
let [a, b, c, d] =
355
[(1.0, 0.0), (0.0, 1.0), (-1.0, 0.0), (0.0, -1.0)].map(|(sign_x, sign_y)| {
356
Vec2::new(
357
primitive.half_diagonals.x * sign_x,
358
primitive.half_diagonals.y * sign_y,
359
)
360
});
361
let positions = [a, b, c, d, a].map(|vec2| isometry * vec2);
362
self.linestrip_2d(positions, color);
363
}
364
}
365
366
// capsule 2d
367
368
impl<Config, Clear> GizmoPrimitive2d<Capsule2d> for GizmoBuffer<Config, Clear>
369
where
370
Config: GizmoConfigGroup,
371
Clear: 'static + Send + Sync,
372
{
373
type Output<'a>
374
= ()
375
where
376
Self: 'a;
377
378
fn primitive_2d(
379
&mut self,
380
primitive: &Capsule2d,
381
isometry: impl Into<Isometry2d>,
382
color: impl Into<Color>,
383
) -> Self::Output<'_> {
384
let isometry = isometry.into();
385
let polymorphic_color: Color = color.into();
386
387
if !self.enabled {
388
return;
389
}
390
391
// transform points from the reference unit square to capsule "rectangle"
392
let [top_left, top_right, bottom_left, bottom_right, top_center, bottom_center] = [
393
[-1.0, 1.0],
394
[1.0, 1.0],
395
[-1.0, -1.0],
396
[1.0, -1.0],
397
// just reuse the pipeline for these points as well
398
[0.0, 1.0],
399
[0.0, -1.0],
400
]
401
.map(|[sign_x, sign_y]| Vec2::X * sign_x + Vec2::Y * sign_y)
402
.map(|reference_point| {
403
let scaling = Vec2::X * primitive.radius + Vec2::Y * primitive.half_length;
404
reference_point * scaling
405
})
406
.map(|vec2| isometry * vec2);
407
408
// draw left and right side of capsule "rectangle"
409
self.line_2d(bottom_left, top_left, polymorphic_color);
410
self.line_2d(bottom_right, top_right, polymorphic_color);
411
412
let start_angle_top = isometry.rotation.as_radians() - FRAC_PI_2;
413
let start_angle_bottom = isometry.rotation.as_radians() + FRAC_PI_2;
414
415
// draw arcs
416
self.arc_2d(
417
Isometry2d::new(top_center, Rot2::radians(start_angle_top)),
418
PI,
419
primitive.radius,
420
polymorphic_color,
421
);
422
self.arc_2d(
423
Isometry2d::new(bottom_center, Rot2::radians(start_angle_bottom)),
424
PI,
425
primitive.radius,
426
polymorphic_color,
427
);
428
}
429
}
430
431
// line 2d
432
//
433
/// Builder for configuring the drawing options of [`Line2d`].
434
pub struct Line2dBuilder<'a, Config, Clear>
435
where
436
Config: GizmoConfigGroup,
437
Clear: 'static + Send + Sync,
438
{
439
gizmos: &'a mut GizmoBuffer<Config, Clear>,
440
441
direction: Dir2, // Direction of the line
442
443
isometry: Isometry2d,
444
color: Color, // color of the line
445
446
draw_arrow: bool, // decides whether to indicate the direction of the line with an arrow
447
}
448
449
impl<Config, Clear> Line2dBuilder<'_, Config, Clear>
450
where
451
Config: GizmoConfigGroup,
452
Clear: 'static + Send + Sync,
453
{
454
/// Set the drawing mode of the line (arrow vs. plain line)
455
pub fn draw_arrow(mut self, is_enabled: bool) -> Self {
456
self.draw_arrow = is_enabled;
457
self
458
}
459
}
460
461
impl<Config, Clear> GizmoPrimitive2d<Line2d> for GizmoBuffer<Config, Clear>
462
where
463
Config: GizmoConfigGroup,
464
Clear: 'static + Send + Sync,
465
{
466
type Output<'a>
467
= Line2dBuilder<'a, Config, Clear>
468
where
469
Self: 'a;
470
471
fn primitive_2d(
472
&mut self,
473
primitive: &Line2d,
474
isometry: impl Into<Isometry2d>,
475
color: impl Into<Color>,
476
) -> Self::Output<'_> {
477
Line2dBuilder {
478
gizmos: self,
479
direction: primitive.direction,
480
isometry: isometry.into(),
481
color: color.into(),
482
draw_arrow: false,
483
}
484
}
485
}
486
487
impl<Config, Clear> Drop for Line2dBuilder<'_, Config, Clear>
488
where
489
Config: GizmoConfigGroup,
490
Clear: 'static + Send + Sync,
491
{
492
fn drop(&mut self) {
493
if !self.gizmos.enabled {
494
return;
495
}
496
497
let [start, end] = [1.0, -1.0]
498
.map(|sign| sign * INFINITE_LEN)
499
// offset the line from the origin infinitely into the given direction
500
.map(|length| self.direction * length)
501
// transform the line with the given isometry
502
.map(|offset| self.isometry * offset);
503
504
self.gizmos.line_2d(start, end, self.color);
505
506
// optionally draw an arrow head at the center of the line
507
if self.draw_arrow {
508
self.gizmos.arrow_2d(
509
self.isometry * (-self.direction * MIN_LINE_LEN),
510
self.isometry * Vec2::ZERO,
511
self.color,
512
);
513
}
514
}
515
}
516
517
// plane 2d
518
519
impl<Config, Clear> GizmoPrimitive2d<Plane2d> for GizmoBuffer<Config, Clear>
520
where
521
Config: GizmoConfigGroup,
522
Clear: 'static + Send + Sync,
523
{
524
type Output<'a>
525
= ()
526
where
527
Self: 'a;
528
529
fn primitive_2d(
530
&mut self,
531
primitive: &Plane2d,
532
isometry: impl Into<Isometry2d>,
533
color: impl Into<Color>,
534
) -> Self::Output<'_> {
535
let isometry = isometry.into();
536
let polymorphic_color: Color = color.into();
537
538
if !self.enabled {
539
return;
540
}
541
// draw normal of the plane (orthogonal to the plane itself)
542
let normal = primitive.normal;
543
let normal_segment = Segment2d::from_direction_and_length(normal, HALF_MIN_LINE_LEN * 2.);
544
self.primitive_2d(
545
&normal_segment,
546
// offset the normal so it starts on the plane line
547
Isometry2d::new(isometry * (HALF_MIN_LINE_LEN * normal), isometry.rotation),
548
polymorphic_color,
549
)
550
.draw_arrow(true);
551
552
// draw the plane line
553
let direction = Dir2::new_unchecked(-normal.perp());
554
self.primitive_2d(&Line2d { direction }, isometry, polymorphic_color)
555
.draw_arrow(false);
556
557
// draw an arrow such that the normal is always left side of the plane with respect to the
558
// planes direction. This is to follow the "counter-clockwise" convention
559
self.arrow_2d(
560
isometry * Vec2::ZERO,
561
isometry * (MIN_LINE_LEN * direction),
562
polymorphic_color,
563
);
564
}
565
}
566
567
// segment 2d
568
569
/// Builder for configuring the drawing options of [`Segment2d`].
570
pub struct Segment2dBuilder<'a, Config, Clear>
571
where
572
Config: GizmoConfigGroup,
573
Clear: 'static + Send + Sync,
574
{
575
gizmos: &'a mut GizmoBuffer<Config, Clear>,
576
577
point1: Vec2, // First point of the segment
578
point2: Vec2, // Second point of the segment
579
580
isometry: Isometry2d, // isometric transformation of the line segment
581
color: Color, // color of the line segment
582
583
draw_arrow: bool, // decides whether to draw just a line or an arrow
584
}
585
586
impl<Config, Clear> Segment2dBuilder<'_, Config, Clear>
587
where
588
Config: GizmoConfigGroup,
589
Clear: 'static + Send + Sync,
590
{
591
/// Set the drawing mode of the line (arrow vs. plain line)
592
pub fn draw_arrow(mut self, is_enabled: bool) -> Self {
593
self.draw_arrow = is_enabled;
594
self
595
}
596
}
597
598
impl<Config, Clear> GizmoPrimitive2d<Segment2d> for GizmoBuffer<Config, Clear>
599
where
600
Config: GizmoConfigGroup,
601
Clear: 'static + Send + Sync,
602
{
603
type Output<'a>
604
= Segment2dBuilder<'a, Config, Clear>
605
where
606
Self: 'a;
607
608
fn primitive_2d(
609
&mut self,
610
primitive: &Segment2d,
611
isometry: impl Into<Isometry2d>,
612
color: impl Into<Color>,
613
) -> Self::Output<'_> {
614
Segment2dBuilder {
615
gizmos: self,
616
point1: primitive.point1(),
617
point2: primitive.point2(),
618
619
isometry: isometry.into(),
620
color: color.into(),
621
622
draw_arrow: Default::default(),
623
}
624
}
625
}
626
627
impl<Config, Clear> Drop for Segment2dBuilder<'_, Config, Clear>
628
where
629
Config: GizmoConfigGroup,
630
Clear: 'static + Send + Sync,
631
{
632
fn drop(&mut self) {
633
if !self.gizmos.enabled {
634
return;
635
}
636
637
let segment = Segment2d::new(self.point1, self.point2).transformed(self.isometry);
638
639
if self.draw_arrow {
640
self.gizmos
641
.arrow_2d(segment.point1(), segment.point2(), self.color);
642
} else {
643
self.gizmos
644
.line_2d(segment.point1(), segment.point2(), self.color);
645
}
646
}
647
}
648
649
// polyline 2d
650
651
impl<Config, Clear> GizmoPrimitive2d<Polyline2d> for GizmoBuffer<Config, Clear>
652
where
653
Config: GizmoConfigGroup,
654
Clear: 'static + Send + Sync,
655
{
656
type Output<'a>
657
= ()
658
where
659
Self: 'a;
660
661
fn primitive_2d(
662
&mut self,
663
primitive: &Polyline2d,
664
isometry: impl Into<Isometry2d>,
665
color: impl Into<Color>,
666
) -> Self::Output<'_> {
667
if !self.enabled {
668
return;
669
}
670
671
let isometry = isometry.into();
672
673
self.linestrip_2d(
674
primitive
675
.vertices
676
.iter()
677
.copied()
678
.map(|vec2| isometry * vec2),
679
color,
680
);
681
}
682
}
683
684
// triangle 2d
685
686
impl<Config, Clear> GizmoPrimitive2d<Triangle2d> for GizmoBuffer<Config, Clear>
687
where
688
Config: GizmoConfigGroup,
689
Clear: 'static + Send + Sync,
690
{
691
type Output<'a>
692
= ()
693
where
694
Self: 'a;
695
696
fn primitive_2d(
697
&mut self,
698
primitive: &Triangle2d,
699
isometry: impl Into<Isometry2d>,
700
color: impl Into<Color>,
701
) -> Self::Output<'_> {
702
if !self.enabled {
703
return;
704
}
705
706
let isometry = isometry.into();
707
708
let [a, b, c] = primitive.vertices;
709
let positions = [a, b, c, a].map(|vec2| isometry * vec2);
710
self.linestrip_2d(positions, color);
711
}
712
}
713
714
// rectangle 2d
715
716
impl<Config, Clear> GizmoPrimitive2d<Rectangle> for GizmoBuffer<Config, Clear>
717
where
718
Config: GizmoConfigGroup,
719
Clear: 'static + Send + Sync,
720
{
721
type Output<'a>
722
= ()
723
where
724
Self: 'a;
725
726
fn primitive_2d(
727
&mut self,
728
primitive: &Rectangle,
729
isometry: impl Into<Isometry2d>,
730
color: impl Into<Color>,
731
) -> Self::Output<'_> {
732
if !self.enabled {
733
return;
734
}
735
736
let isometry = isometry.into();
737
738
let [a, b, c, d] =
739
[(1.0, 1.0), (1.0, -1.0), (-1.0, -1.0), (-1.0, 1.0)].map(|(sign_x, sign_y)| {
740
Vec2::new(
741
primitive.half_size.x * sign_x,
742
primitive.half_size.y * sign_y,
743
)
744
});
745
let positions = [a, b, c, d, a].map(|vec2| isometry * vec2);
746
self.linestrip_2d(positions, color);
747
}
748
}
749
750
// polygon 2d
751
752
impl<Config, Clear> GizmoPrimitive2d<Polygon> for GizmoBuffer<Config, Clear>
753
where
754
Config: GizmoConfigGroup,
755
Clear: 'static + Send + Sync,
756
{
757
type Output<'a>
758
= ()
759
where
760
Self: 'a;
761
762
fn primitive_2d(
763
&mut self,
764
primitive: &Polygon,
765
isometry: impl Into<Isometry2d>,
766
color: impl Into<Color>,
767
) -> Self::Output<'_> {
768
if !self.enabled {
769
return;
770
}
771
772
let isometry = isometry.into();
773
774
// Check if the polygon needs a closing point
775
let closing_point = {
776
let first = primitive.vertices.first();
777
(primitive.vertices.last() != first)
778
.then_some(first)
779
.flatten()
780
.cloned()
781
};
782
783
self.linestrip_2d(
784
primitive
785
.vertices
786
.iter()
787
.copied()
788
.chain(closing_point)
789
.map(|vec2| isometry * vec2),
790
color,
791
);
792
}
793
}
794
795
// regular polygon 2d
796
797
impl<Config, Clear> GizmoPrimitive2d<RegularPolygon> for GizmoBuffer<Config, Clear>
798
where
799
Config: GizmoConfigGroup,
800
Clear: 'static + Send + Sync,
801
{
802
type Output<'a>
803
= ()
804
where
805
Self: 'a;
806
807
fn primitive_2d(
808
&mut self,
809
primitive: &RegularPolygon,
810
isometry: impl Into<Isometry2d>,
811
color: impl Into<Color>,
812
) -> Self::Output<'_> {
813
if !self.enabled {
814
return;
815
}
816
817
let isometry = isometry.into();
818
819
let points = (0..=primitive.sides)
820
.map(|n| single_circle_coordinate(primitive.circumcircle.radius, primitive.sides, n))
821
.map(|vec2| isometry * vec2);
822
self.linestrip_2d(points, color);
823
}
824
}
825
826