New nodes: 'Point Inside Shape' and 'Close Path' (#2673)

* add point inside shape,close path,and disabled node to layer conversion

* removed the usage one_instance

* code review
This commit is contained in:
0SlowPoke0 2025-05-26 14:45:31 +05:30 committed by GitHub
parent 3496e22f55
commit f6e592da5b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 6 deletions

View file

@ -1214,11 +1214,6 @@ impl<'a> MessageHandler<NodeGraphMessage, NodeGraphHandlerData<'a>> for NodeGrap
if is_stack_wire(&wire) { stack_wires.push(wire) } else { node_wires.push(wire) }
}
// Auto convert node to layer when inserting on a single stack wire
if stack_wires.len() == 1 && node_wires.is_empty() {
network_interface.set_to_node_or_layer(&selected_node_id, selection_network_path, true)
}
let overlapping_wire = if network_interface.is_layer(&selected_node_id, selection_network_path) {
if stack_wires.len() == 1 {
stack_wires.first()

View file

@ -2,7 +2,7 @@ mod attributes;
mod indexed;
mod modification;
use super::misc::point_to_dvec2;
use super::misc::{dvec2_to_point, point_to_dvec2};
use super::style::{PathStyle, Stroke};
use crate::instances::Instances;
use crate::{AlphaBlending, Color, GraphicGroupTable};
@ -12,6 +12,7 @@ use core::borrow::Borrow;
use dyn_any::DynAny;
use glam::{DAffine2, DVec2};
pub use indexed::VectorDataIndex;
use kurbo::{Affine, Shape};
pub use modification::*;
use std::collections::HashMap;
@ -193,6 +194,23 @@ impl VectorData {
vector_data
}
pub fn close_subpaths(&mut self) {
let segments_to_add: Vec<_> = self
.stroke_bezier_paths()
.filter(|subpath| !subpath.closed)
.filter_map(|subpath| {
let (first, last) = subpath.manipulator_groups().first().zip(subpath.manipulator_groups().last())?;
let (start, end) = self.point_domain.resolve_id(first.id).zip(self.point_domain.resolve_id(last.id))?;
Some((start, end))
})
.collect();
for (start, end) in segments_to_add {
let segment_id = self.segment_domain.next_id().next_id();
self.segment_domain.push(segment_id, start, end, bezier_rs::BezierHandles::Linear, StrokeId::ZERO);
}
}
/// Compute the bounding boxes of the subpaths without any transform
pub fn bounding_box(&self) -> Option<[DVec2; 2]> {
self.bounding_box_with_transform(DAffine2::IDENTITY)
@ -316,6 +334,34 @@ impl VectorData {
self.point_domain.resolve_id(point).map_or(0, |point| self.segment_domain.connected_count(point))
}
pub fn check_point_inside_shape(&self, vector_data_transform: DAffine2, point: DVec2) -> bool {
let bez_paths: Vec<_> = self
.stroke_bezpath_iter()
.map(|mut bezpath| {
// TODO: apply transform to points instead of modifying the paths
bezpath.apply_affine(Affine::new(vector_data_transform.to_cols_array()));
bezpath.close_path();
let bbox = bezpath.bounding_box();
(bezpath, bbox)
})
.collect();
// Check against all paths the point is contained in to compute the correct winding number
let mut number = 0;
for (shape, bbox) in bez_paths {
if bbox.x0 > point.x || bbox.y0 > point.y || bbox.x1 < point.x || bbox.y1 < point.y {
continue;
}
let winding = shape.winding(dvec2_to_point(point));
number += winding;
}
// Non-zero fill rule
number != 0
}
/// Points that can be extended from.
///
/// This is usually only points with exactly one connection unless vector meshes are enabled.

View file

@ -1715,6 +1715,23 @@ fn bevel(_: impl Ctx, source: VectorDataTable, #[default(10.)] distance: Length)
result
}
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
fn close_path(_: impl Ctx, source: VectorDataTable) -> VectorDataTable {
let mut new_table = VectorDataTable::empty();
for mut source_instance in source.instance_iter() {
source_instance.instance.close_subpaths();
new_table.push(source_instance);
}
new_table
}
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
fn point_inside(_: impl Ctx, source: VectorDataTable, point: DVec2) -> bool {
source.instance_iter().any(|instance| instance.instance.check_point_inside_shape(instance.transform, point))
}
#[node_macro::node(name("Merge by Distance"), category("Vector"), path(graphene_core::vector))]
fn merge_by_distance(_: impl Ctx, source: VectorDataTable, #[default(10.)] distance: Length) -> VectorDataTable {
let source_transform = source.transform();