Repository: GraphiteEditor/Graphite
File: node-graph/gcore/src/graphic_element/renderer.rs (Rust)

Code before:
mod quad;
mod rect;

use crate::raster::image::ImageFrameTable;
use crate::raster::{BlendMode, Image};
use crate::transform::{Footprint, Transform};
use crate::uuid::{NodeId, generate_uuid};
use crate::vector::style::{Fill, Stroke, ViewMode};
use crate::vector::{PointId, VectorDataTable};
use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable, RasterFrame};
use base64::Engine;
use bezier_rs::{ManipulatorGroup, Subpath};
use dyn_any::DynAny;
use glam::{DAffine2, DMat2, DVec2};
use num_traits::Zero;
pub use quad::Quad;
pub use rect::Rect;
use std::collections::{HashMap, HashSet};
use std::fmt::Write;
#[cfg(feature = "vello")]
use vello::*;

#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum ClickTargetGroup {
	Subpath(bezier_rs::Subpath<PointId>),
	PointGroup(ManipulatorGroup<PointId>),
}

/// Represents a clickable target for the layer
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ClickTarget {
	target_group: ClickTargetGroup,
	stroke_width: f64,
	bounding_box: Option<[DVec2; 2]>,
}

impl ClickTarget {
	pub fn new_with_subpath(subpath: bezier_rs::Subpath<PointId>, stroke_width: f64) -> Self {
		let bounding_box = subpath.loose_bounding_box();
		Self {
			target_group: ClickTargetGroup::Subpath(subpath),
			stroke_width,
			bounding_box,
		}
	}

	pub fn new_with_point_group(point: ManipulatorGroup<PointId>) -> Self {
		let stroke_width = 10.;
		let bounding_box = Some([point.anchor - DVec2::splat(stroke_width / 2.), point.anchor + DVec2::splat(stroke_width / 2.)]);

		Self {

Review comment (suggestion):
I don't really understand why this data structure is used anyway? An unconnected point won't have any handles. It would be far more ergonomic just to use a DVec2 and a PointId.

Code after:
mod quad;
mod rect;

use crate::raster::image::RasterDataTable;
use crate::raster::{BlendMode, Image};
use crate::transform::{Footprint, Transform};
use crate::uuid::{NodeId, generate_uuid};
use crate::vector::style::{Fill, Stroke, ViewMode};
use crate::vector::{PointId, VectorDataTable};
use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable};
use base64::Engine;
use bezier_rs::Subpath;
use dyn_any::DynAny;
use glam::{DAffine2, DMat2, DVec2};
use num_traits::Zero;
pub use quad::Quad;
pub use rect::Rect;
use std::collections::{HashMap, HashSet};
use std::fmt::Write;
#[cfg(feature = "vello")]
use vello::*;

#[derive(Copy, Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct FreePoint {
	pub id: PointId,
	pub position: DVec2,
}

impl FreePoint {
	pub fn new(id: PointId, position: DVec2) -> Self {
		Self { id, position }
	}

	pub fn apply_transform(&mut self, transform: DAffine2) {
		self.position = transform.transform_point2(self.position);
	}
}

#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub enum ClickTargetType {
	Subpath(bezier_rs::Subpath<PointId>),
	FreePoint(FreePoint),
}

/// Represents a clickable target for the layer
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ClickTarget {
	target_type: ClickTargetType,
	stroke_width: f64,
	bounding_box: Option<[DVec2; 2]>,
}