( _: impl Ctx, /// The `List` of vector paths to perform the boolean operation on. Nested `List`s are automatically flattened. #[implementations(List<Graphic>, List<Vector>)] content: I, /// Whic
| 24 | /// Combines the geometric forms of one or more closed paths into a new vector path that results from cutting or joining the paths by the chosen method. |
| 25 | #[node_macro::node(category("Vector: Modifier"), memoize)] |
| 26 | async fn boolean_operation<I: graphic_types::IntoGraphicList>( |
| 27 | _: impl Ctx, |
| 28 | /// The `List` of vector paths to perform the boolean operation on. Nested `List`s are automatically flattened. |
| 29 | #[implementations(List<Graphic>, List<Vector>)] |
| 30 | content: I, |
| 31 | /// Which boolean operation to perform on the paths. |
| 32 | /// |
| 33 | /// Union combines all paths while cutting out overlapping areas (even the interiors of a single path). |
| 34 | /// Subtraction cuts overlapping areas out from the last (Subtract Front) or first (Subtract Back) path. |
| 35 | /// Intersection cuts away all but the overlapping areas shared by every path. |
| 36 | /// Difference cuts away the overlapping areas shared by every path, leaving only the non-overlapping areas. |
| 37 | operation: BooleanOperation, |
| 38 | ) -> List<Vector> { |
| 39 | let content = content.into_graphic_list(); |
| 40 | |
| 41 | // The first index is the bottom of the stack |
| 42 | let flattened = flatten_vector(&content); |
| 43 | let mut result_vector_list = boolean_operation_on_vector_list(&flattened, operation); |
| 44 | |
| 45 | // Replace the transformation matrix with a mutation of the vector points themselves |
| 46 | if result_vector_list.element_mut(0).is_some() { |
| 47 | let transform: DAffine2 = result_vector_list.attribute_cloned_or_default(ATTR_TRANSFORM, 0); |
| 48 | result_vector_list.set_attribute(ATTR_TRANSFORM, 0, DAffine2::IDENTITY); |
| 49 | |
| 50 | let result_vector = result_vector_list.element_mut(0).unwrap(); |
| 51 | Vector::transform(result_vector, transform); |
| 52 | result_vector.set_stroke_transform(DAffine2::IDENTITY); |
| 53 | |
| 54 | // Snapshot the input layers as the `editor:merged_layers` attribute so the renderer can recurse into them |
| 55 | // for editor click-target preservation. |
| 56 | result_vector_list.set_attribute(ATTR_EDITOR_MERGED_LAYERS, 0, content.clone()); |
| 57 | |
| 58 | // Clean up the boolean operation result by merging duplicated points |
| 59 | let merge_transform: DAffine2 = result_vector_list.attribute_cloned_or_default(ATTR_TRANSFORM, 0); |
| 60 | result_vector_list.element_mut(0).unwrap().merge_by_distance_spatial(merge_transform, 0.0001); |
| 61 | } |
| 62 | |
| 63 | result_vector_list |
| 64 | } |
| 65 | |
| 66 | #[derive(Clone, Debug, Default, PartialEq, Eq)] |
| 67 | struct WindingNumber { |
nothing calls this directly
no test coverage detected