| 309 | /// Generates a rectangular or isometric grid with the chosen number of columns and rows. Line segments connect the points, forming a vector mesh. |
| 310 | #[node_macro::node(category("Vector: Shape"), properties("grid_properties"))] |
| 311 | fn grid<T: GridSpacing>( |
| 312 | _: impl Ctx, |
| 313 | _primary: (), |
| 314 | grid_type: GridType, |
| 315 | #[unit(" px")] |
| 316 | #[hard(0..)] |
| 317 | #[default(10)] |
| 318 | #[implementations(f64, DVec2)] |
| 319 | spacing: T, |
| 320 | #[default(10)] columns: u32, |
| 321 | #[default(10)] rows: u32, |
| 322 | #[default(30., 30.)] angles: DVec2, |
| 323 | ) -> List<Vector> { |
| 324 | let (x_spacing, y_spacing) = spacing.as_dvec2().into(); |
| 325 | let (angle_a, angle_b) = angles.into(); |
| 326 | |
| 327 | let mut vector = Vector::default(); |
| 328 | let mut segment_id = SegmentId::ZERO; |
| 329 | let mut point_id = PointId::ZERO; |
| 330 | |
| 331 | match grid_type { |
| 332 | GridType::Rectangular => { |
| 333 | // Create rectangular grid points and connect them with line segments |
| 334 | for y in 0..rows { |
| 335 | for x in 0..columns { |
| 336 | // Add current point to the grid |
| 337 | let current_index = vector.point_domain.ids().len(); |
| 338 | vector.point_domain.push(point_id.next_id(), DVec2::new(x_spacing * x as f64, y_spacing * y as f64)); |
| 339 | |
| 340 | // Helper function to connect points with line segments |
| 341 | let mut push_segment = |to_index: Option<usize>| { |
| 342 | if let Some(other_index) = to_index { |
| 343 | vector |
| 344 | .segment_domain |
| 345 | .push(segment_id.next_id(), other_index, current_index, subpath::BezierHandles::Linear, StrokeId::ZERO); |
| 346 | } |
| 347 | }; |
| 348 | |
| 349 | // Connect to the point to the left (horizontal connection) |
| 350 | push_segment((x > 0).then(|| current_index - 1)); |
| 351 | |
| 352 | // Connect to the point above (vertical connection) |
| 353 | push_segment(current_index.checked_sub(columns as usize)); |
| 354 | } |
| 355 | } |
| 356 | } |
| 357 | GridType::Isometric => { |
| 358 | // Calculate isometric grid spacing based on angles |
| 359 | let tan_a = angle_a.to_radians().tan(); |
| 360 | let tan_b = angle_b.to_radians().tan(); |
| 361 | let spacing = DVec2::new(y_spacing / (tan_a + tan_b), y_spacing); |
| 362 | |
| 363 | // Create isometric grid points and connect them with line segments |
| 364 | for y in 0..rows { |
| 365 | for x in 0..columns { |
| 366 | // Add current point to the grid with offset for odd columns |
| 367 | let current_index = vector.point_domain.ids().len(); |
| 368 | |