1pub(crate) mod curve;
72pub(crate) mod dynamic;
73pub(crate) mod ellipse;
74pub(crate) mod image;
75pub(crate) mod text;
76
77pub use self::image::*;
78pub use curve::*;
79pub use dynamic::*;
80pub use ellipse::*;
81use na::{Point2, Rotation2, Scale2, Vector2};
82use nalgebra::{self as na, Transform2, Translation2};
83use std::{fmt, marker::PhantomData, sync::Arc};
84pub use text::*;
85
86pub trait ShapeOp {
92	fn transform(&mut self, transform_matrix: Transform2<f32>) -> &mut Self;
96
97	#[inline]
99	fn translate<T: Into<Translation2<f32>>>(&mut self, translation: T) -> &mut Self {
100		self.transform(na::convert::<_, Transform2<f32>>(translation.into()));
101		self
102	}
103	#[inline]
105	fn scale<S: Into<Scale2<f32>>>(&mut self, scale: S) -> &mut Self {
106		self.transform(na::convert::<_, Transform2<f32>>(scale.into()));
107		self
108	}
109	#[inline]
111	fn rotate<R: Into<Rotation2<f32>>>(&mut self, rotation: R) -> &mut Self {
112		self.transform(na::convert::<_, Transform2<f32>>(rotation.into()));
113		self
114	}
115
116	fn local_transform(&self) -> &Transform2<f32>;
119	#[inline]
121	fn global_transform(&self, parent_transform: &Transform2<f32>) -> Transform2<f32> {
122		parent_transform * self.local_transform()
123	}
124}
125
126pub trait ShapeOpWith: ShapeOp + Sized {
129	#[inline]
131	fn with_transform(mut self, transform_matrix: Transform2<f32>) -> Self {
132		self.transform(transform_matrix);
133		self
134	}
135
136	#[inline]
138	fn with_translate<T: Into<Translation2<f32>>>(mut self, translation: T) -> Self {
139		self.translate(translation);
140		self
141	}
142	#[inline]
144	fn with_resize<S: Into<Scale2<f32>>>(mut self, scale: S) -> Self {
145		self.scale(scale);
146		self
147	}
148	#[inline]
150	fn with_rotate<R: Into<Rotation2<f32>>>(mut self, rotation: R) -> Self {
151		self.rotate(rotation);
152		self
153	}
154}
155impl<T: ShapeOp> ShapeOpWith for T {}
156
157#[derive(Debug, Clone, Copy, PartialEq)]
160pub struct UnParticular;
161#[derive(Debug, Clone, Copy, PartialEq)]
164pub struct Straight;
165
166#[derive(Debug, Clone, Copy, PartialEq)]
169pub struct BoundingBox<Type> {
170	_ty: PhantomData<Type>,
171	top_left: Point2<f32>,
172	top_right: Point2<f32>,
173	bottom_right: Point2<f32>,
174	bottom_left: Point2<f32>,
175}
176impl<T> BoundingBox<T> {
177	#[inline]
182	pub fn top(&self) -> f32 {
183		self.top_left.y
184	}
185
186	#[inline]
191	pub fn bottom(&self) -> f32 {
192		self.bottom_left.y
193	}
194
195	#[inline]
200	pub fn left(&self) -> f32 {
201		self.bottom_left.x
202	}
203
204	#[inline]
209	pub fn right(&self) -> f32 {
210		self.bottom_right.x
211	}
212
213	#[inline]
218	pub fn top_left(&self) -> Point2<f32> {
219		self.top_left
220	}
221
222	#[inline]
227	pub fn top_right(&self) -> Point2<f32> {
228		self.top_right
229	}
230
231	#[inline]
236	pub fn bottom_right(&self) -> Point2<f32> {
237		self.bottom_right
238	}
239
240	#[inline]
245	pub fn bottom_left(&self) -> Point2<f32> {
246		self.bottom_left
247	}
248
249	pub fn transform(self, transform: &Transform2<f32>) -> BoundingBox<UnParticular> {
251		BoundingBox {
252			_ty: PhantomData,
253			top_left: transform * self.top_left,
254			top_right: transform * self.top_right,
255			bottom_right: transform * self.bottom_right,
256			bottom_left: transform * self.bottom_left,
257		}
258	}
259
260	pub fn width(&self) -> f32 {
262		(self.top_right - self.top_left).magnitude()
263	}
264
265	pub fn height(&self) -> f32 {
267		(self.top_right - self.bottom_right).magnitude()
268	}
269}
270
271impl BoundingBox<UnParticular> {
272	pub fn new(
274		top_left: Point2<f32>,
275		top_right: Point2<f32>,
276		bottom_right: Point2<f32>,
277		bottom_left: Point2<f32>,
278	) -> Self {
279		BoundingBox {
280			_ty: PhantomData,
281			top_left,
282			top_right,
283			bottom_right,
284			bottom_left,
285		}
286	}
287
288	pub fn center(&self) -> Point2<f32> {
291		let x =
292			(self.bottom_left.x + self.bottom_right.x + self.top_left.x + self.top_right.x) / 4.;
293		let y =
294			(self.bottom_left.y + self.bottom_right.y + self.top_left.y + self.top_right.y) / 4.;
295
296		Point2::new(x, y)
297	}
298
299	pub fn straigthen(&self) -> BoundingBox<Straight> {
301		let top = self
302			.top_left
303			.y
304			.max(self.top_right.y)
305			.max(self.bottom_left.y)
306			.max(self.bottom_right.y);
307		let bottom = self
308			.top_left
309			.y
310			.min(self.top_right.y)
311			.min(self.bottom_left.y)
312			.min(self.bottom_right.y);
313
314		let right = self
315			.top_left
316			.x
317			.max(self.top_right.x)
318			.max(self.bottom_left.x)
319			.max(self.bottom_right.x);
320		let left = self
321			.top_left
322			.x
323			.min(self.top_right.x)
324			.min(self.bottom_left.x)
325			.min(self.bottom_right.x);
326
327		BoundingBox {
328			_ty: PhantomData,
329			top_left: Point2::new(left, top),
330			top_right: Point2::new(right, top),
331			bottom_right: Point2::new(right, bottom),
332			bottom_left: Point2::new(left, bottom),
333		}
334	}
335
336	#[inline]
338	pub fn into_straight(self) -> BoundingBox<Straight> {
339		self.straigthen()
340	}
341}
342
343impl BoundingBox<Straight> {
344	pub fn zero() -> Self {
346		BoundingBox {
347			_ty: PhantomData,
348			top_left: Point2::origin(),
349			top_right: Point2::origin(),
350			bottom_right: Point2::origin(),
351			bottom_left: Point2::origin(),
352		}
353	}
354
355	pub fn at<P: Into<Point2<f32>>>(p: P) -> Self {
357		let p = p.into();
358		BoundingBox {
359			_ty: PhantomData,
360			top_left: p,
361			top_right: p,
362			bottom_right: p,
363			bottom_left: p,
364		}
365	}
366
367	pub fn mins_maxs(min_x: f32, min_y: f32, max_x: f32, max_y: f32) -> Self {
369		BoundingBox {
370			_ty: PhantomData,
371			top_left: [min_x, max_y].into(),
372			top_right: [max_x, max_y].into(),
373			bottom_right: [max_x, min_y].into(),
374			bottom_left: [min_x, min_y].into(),
375		}
376	}
377
378	pub fn centered<V: Into<Vector2<f32>>>(size: V) -> Self {
380		let size = size.into() / 2.;
381		BoundingBox {
382			_ty: PhantomData,
383			top_left: Point2::new(-size.x, size.y),
384			top_right: Point2::new(size.x, size.y),
385			bottom_right: Point2::new(size.x, -size.y),
386			bottom_left: Point2::new(-size.x, -size.y),
387		}
388	}
389
390	#[inline]
392	pub fn as_unparticular(self) -> BoundingBox<UnParticular> {
393		BoundingBox {
394			_ty: PhantomData,
395			top_left: self.top_left,
396			top_right: self.top_right,
397			bottom_right: self.bottom_right,
398			bottom_left: self.bottom_left,
399		}
400	}
401
402	pub fn straigthen(&self) -> BoundingBox<Straight> {
404		*self
405	}
406
407	#[inline]
409	pub fn into_straight(self) -> BoundingBox<Straight> {
410		self
411	}
412
413	#[inline]
415	pub fn scale_difference(&self, other: &BoundingBox<Straight>) -> Vector2<f32> {
416		Vector2::new(other.width() / self.width(), other.height() / self.height())
417	}
418
419	pub fn join(mut self, other: BoundingBox<Straight>) -> BoundingBox<Straight> {
423		let min_x = self.bottom_left.x.min(other.bottom_left.x);
424		let min_y = self.bottom_left.y.min(other.bottom_left.y);
425		let max_x = self.top_right.x.max(other.top_right.x);
426		let max_y = self.top_right.y.max(other.top_right.y);
427
428		self.top_left.x = min_x;
429		self.top_left.y = max_y;
430
431		self.top_right.x = max_x;
432		self.top_right.y = max_y;
433
434		self.bottom_right.x = max_x;
435		self.bottom_right.y = min_y;
436
437		self.bottom_left.x = min_x;
438		self.bottom_left.y = min_y;
439
440		self
441	}
442
443	pub fn intersect(mut self, other: BoundingBox<Straight>) -> BoundingBox<Straight> {
447		let (min_x, max_x) = if self.bottom_right.x <= other.bottom_left.x
448			|| self.bottom_left.x >= other.bottom_right.x
449		{
450			(0., 0.)
451		} else {
452			(
453				self.bottom_left.x.max(other.bottom_left.x),
454				self.top_right.x.min(other.top_right.x),
455			)
456		};
457
458		let (min_y, max_y) =
459			if self.top_left.y <= other.bottom_left.y || self.bottom_right.y >= other.top_left.y {
460				(0., 0.)
461			} else {
462				(
463					self.bottom_left.y.max(other.bottom_left.y),
464					self.top_right.y.min(other.top_right.y),
465				)
466			};
467
468		self.top_left.x = min_x;
469		self.top_left.y = max_y;
470		self.top_right.x = max_x;
471		self.top_right.y = max_y;
472		self.bottom_right.x = max_x;
473		self.bottom_right.y = min_y;
474		self.bottom_left.x = min_x;
475		self.bottom_left.y = min_y;
476
477		self
478	}
479
480	pub fn center(&self) -> Point2<f32> {
482		let x = (self.bottom_left.x + self.top_right.x) / 2.;
483		let y = (self.bottom_left.y + self.top_right.y) / 2.;
484
485		Point2::new(x, y)
486	}
487}
488
489pub trait ShapeBoundingBox {
491	fn local_bounding_box(&self) -> BoundingBox<UnParticular>;
493	fn global_bounding_box(&self, parent_transform: &Transform2<f32>) -> BoundingBox<UnParticular> {
495		self.local_bounding_box().transform(parent_transform)
496	}
497}
498
499#[derive(Default, Debug, Clone, PartialEq)]
501pub struct Group {
502	pub local_transform: Transform2<f32>,
504	pub shapes: Vec<Shape>,
506	pub metadata: Vec<(String, String)>,
508}
509
510#[derive(Clone)]
514pub enum Shape {
515	Group(Group),
517	Style {
519		fill: Option<crate::style::Fill>,
521		stroke: Option<crate::style::Stroke>,
523		shape: Box<Shape>,
525	},
526	Ellipse(Ellipse),
528	Image(Image),
530	Text(Text),
532	Curve(Curve),
534	Dynamic {
540		local_transform: Transform2<f32>,
542		shaper: Arc<Shaper>,
544	},
545}
546impl PartialEq for Shape {
547	fn eq(&self, other: &Self) -> bool {
548		match (self, other) {
549			(Shape::Group(g1), Shape::Group(g2)) => g1 == g2,
550			(
551				Shape::Style {
552					fill: fill1,
553					stroke: stroke1,
554					shape: shape1,
555				},
556				Shape::Style {
557					fill: fill2,
558					stroke: stroke2,
559					shape: shape2,
560				},
561			) => fill1 == fill2 && stroke1 == stroke2 && shape1 == shape2,
562			(Shape::Ellipse(e1), Shape::Ellipse(e2)) => e1 == e2,
563			(Shape::Image(i1), Shape::Image(i2)) => i1 == i2,
564			(Shape::Text(t1), Shape::Text(t2)) => t1 == t2,
565			(Shape::Curve(c1), Shape::Curve(c2)) => c1 == c2,
566			(
567				Shape::Dynamic {
568					local_transform: local_transform1,
569					shaper: shaper1,
570				},
571				Shape::Dynamic {
572					local_transform: local_transform2,
573					shaper: shaper2,
574				},
575			) => local_transform1 == local_transform2 && shaper1() == shaper2(),
576			_ => false,
577		}
578	}
579}
580
581impl Shape {
582	pub fn get_or_mutate_as_group(&mut self) -> &mut Group {
585		if let Shape::Group(g) = self {
586			g
587		} else {
588			let mut dummy = Shape::Group(Group {
589				local_transform: Default::default(),
590				shapes: Default::default(),
591				metadata: Default::default(),
592			});
593
594			std::mem::swap(self, &mut dummy);
595
596			let mut group = Shape::Group(Group {
597				local_transform: Default::default(),
598				shapes: vec![dummy],
599				metadata: vec![],
600			});
601
602			std::mem::swap(self, &mut group);
603			self.get_or_mutate_as_group()
604		}
605	}
606
607	pub fn extend_metadata<K: ToString, V: ToString, E: IntoIterator<Item = (K, V)>>(
609		&mut self,
610		extend: E,
611	) {
612		self.get_or_mutate_as_group().metadata.extend(
613			extend
614				.into_iter()
615				.map(|(k, v)| (k.to_string(), v.to_string())),
616		);
617	}
618
619	pub fn add_metadata<K: ToString, V: ToString>(&mut self, (key, value): (K, V)) {
621		let key = key.to_string();
622		let value = value.to_string();
623
624		self.get_or_mutate_as_group().metadata.push((key, value));
625	}
626}
627
628impl fmt::Debug for Shape {
629	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
630		match self {
631			Self::Group(Group {
632				local_transform,
633				shapes,
634				metadata,
635			}) => f
636				.debug_struct("Group")
637				.field("local_transform", local_transform)
638				.field("shapes", shapes)
639				.field("metadata", metadata)
640				.finish(),
641			Self::Style {
642				fill,
643				stroke,
644				shape,
645			} => f
646				.debug_struct("Style")
647				.field("fill", fill)
648				.field("stroke", stroke)
649				.field("shape", shape)
650				.finish(),
651			Self::Ellipse(arg0) => f.debug_tuple("Ellipse").field(arg0).finish(),
652			Self::Image(arg0) => f.debug_tuple("Image").field(arg0).finish(),
653			Self::Text(arg0) => f.debug_tuple("Text").field(arg0).finish(),
654			Self::Curve(arg0) => f.debug_tuple("Curve").field(arg0).finish(),
655			Self::Dynamic {
656				local_transform,
657				shaper: _,
658			} => f
659				.debug_struct("Dynamic")
660				.field("local_transform", local_transform)
661				.field("shaper", &"Arc<Fn() -> Shape>")
662				.finish(),
663		}
664	}
665}
666
667impl Default for Shape {
668	fn default() -> Self {
669		Shape::Group(Group {
670			local_transform: Transform2::default(),
671			shapes: vec![],
672			metadata: vec![],
673		})
674	}
675}
676
677impl ShapeOp for Shape {
678	fn transform(&mut self, transform_matrix: Transform2<f32>) -> &mut Self {
679		match self {
680			Shape::Group(Group {
681				local_transform, ..
682			}) => {
683				*local_transform = transform_matrix * *local_transform;
684			}
685			Shape::Style { shape, .. } => {
686				shape.transform(transform_matrix);
687			}
688			Shape::Ellipse(v) => {
689				v.transform(transform_matrix);
690			}
691			Shape::Image(v) => {
692				v.transform(transform_matrix);
693			}
694			Shape::Text(v) => {
695				v.transform(transform_matrix);
696			}
697			Shape::Curve(v) => {
698				v.transform(transform_matrix);
699			}
700			Shape::Dynamic {
701				local_transform, ..
702			} => {
703				*local_transform = transform_matrix * *local_transform;
704			}
705		};
706
707		self
708	}
709
710	#[inline]
711	fn local_transform(&self) -> &Transform2<f32> {
712		match self {
713			Shape::Group(Group {
714				local_transform, ..
715			}) => local_transform,
716			Shape::Style { shape, .. } => shape.local_transform(),
717			Shape::Ellipse(v) => v.local_transform(),
718			Shape::Image(v) => v.local_transform(),
719			Shape::Text(v) => v.local_transform(),
720			Shape::Curve(v) => v.local_transform(),
721			Shape::Dynamic {
722				local_transform, ..
723			} => local_transform,
724		}
725	}
726}
727
728impl ShapeBoundingBox for Shape {
729	fn local_bounding_box(&self) -> BoundingBox<UnParticular> {
730		match self {
731			Shape::Group(Group {
732				local_transform,
733				shapes,
734				..
735			}) => shapes
736				.iter()
737				.map(|v| v.global_bounding_box(local_transform).straigthen())
738				.reduce(BoundingBox::join)
739				.unwrap_or_else(|| BoundingBox::zero())
740				.as_unparticular(),
741			Shape::Style { shape, .. } => shape.local_bounding_box(),
742			Shape::Ellipse(e) => e.local_bounding_box(),
743			Shape::Image(i) => i.local_bounding_box(),
744			Shape::Text(t) => t.local_bounding_box(),
745			Shape::Curve(c) => c.local_bounding_box(),
746			Shape::Dynamic {
747				local_transform,
748				shaper,
749			} => shaper().local_bounding_box().transform(local_transform),
750		}
751	}
752}
753
754#[cfg(test)]
755mod tests {
756	use crate::prelude::*;
757	use nalgebra::{Point2, Rotation2, Transform2};
758	use std::f32::consts::FRAC_PI_2;
759
760	const EPS: f32 = 10e-6;
761
762	#[test]
763	fn parent_rotate_child_scale() {
764		let base = dessin!(Image(scale = [2., 4.], translate = [1., 2.]));
765
766		let base_position = base.position(&Transform2::default());
767		assert!(
768			(base_position.bottom_left - Point2::new(0., 0.)).magnitude() < EPS,
769			"left = {}, right = [0., 0.]",
770			base_position.bottom_left,
771		);
772		assert!(
773			(base_position.top_left - Point2::new(0., 4.)).magnitude() < EPS,
774			"left = {}, right = [0., 4.]",
775			base_position.top_left,
776		);
777		assert!(
778			(base_position.top_right - Point2::new(2., 4.)).magnitude() < EPS,
779			"left = {}, right = [2., 4.]",
780			base_position.top_right,
781		);
782
783		let transform = nalgebra::convert(Rotation2::new(FRAC_PI_2));
784		let transform_position = base.position(&transform);
785		assert!(
786			(transform_position.bottom_left - Point2::new(0., 0.)).magnitude() < EPS,
787			"left = {}, right = [0., 0.]",
788			transform_position.bottom_left,
789		);
790		assert!(
791			(transform_position.top_left - Point2::new(-4., 0.)).magnitude() < EPS,
792			"left = {}, right = [-4., 0.]",
793			transform_position.top_left,
794		);
795		assert!(
796			(transform_position.top_right - Point2::new(-4., 2.)).magnitude() < EPS,
797			"left = {}, right = [-4., 2.]",
798			transform_position.top_right,
799		);
800	}
801}