1
- use super :: algorithms:: bezpath_algorithms:: { self , position_on_bezpath, sample_points_on_bezpath, tangent_on_bezpath} ;
1
+ use super :: algorithms:: bezpath_algorithms:: { self , position_on_bezpath, sample_points_on_bezpath, split_bezpath , tangent_on_bezpath} ;
2
2
use super :: algorithms:: offset_subpath:: offset_subpath;
3
3
use super :: algorithms:: spline:: { solve_spline_first_handle_closed, solve_spline_first_handle_open} ;
4
4
use super :: misc:: { CentroidType , point_to_dvec2} ;
5
5
use super :: style:: { Fill , Gradient , GradientStops , Stroke } ;
6
6
use super :: { PointId , SegmentDomain , SegmentId , StrokeId , VectorData , VectorDataTable } ;
7
7
use crate :: instances:: { Instance , InstanceMut , Instances } ;
8
- use crate :: raster_types:: { CPU , RasterDataTable } ;
8
+ use crate :: raster_types:: { CPU , GPU , RasterDataTable } ;
9
9
use crate :: registry:: types:: { Angle , Fraction , IntegerCount , Length , Multiplier , Percentage , PixelLength , PixelSize , SeedValue } ;
10
10
use crate :: renderer:: GraphicElementRendered ;
11
11
use crate :: transform:: { Footprint , ReferencePoint , Transform } ;
@@ -1314,6 +1314,45 @@ async fn sample_points(_: impl Ctx, vector_data: VectorDataTable, spacing: f64,
1314
1314
result_table
1315
1315
}
1316
1316
1317
+ #[ node_macro:: node( category( "Vector" ) , path( graphene_core:: vector) ) ]
1318
+ async fn split_path ( _: impl Ctx , mut vector_data : VectorDataTable , t_value : f64 , parameterized_distance : bool , reverse : bool ) -> VectorDataTable {
1319
+ let euclidian = !parameterized_distance;
1320
+
1321
+ let bezpaths = vector_data
1322
+ . instance_ref_iter ( )
1323
+ . enumerate ( )
1324
+ . flat_map ( |( instance_row_index, vector_data) | vector_data. instance . stroke_bezpath_iter ( ) . map ( |bezpath| ( instance_row_index, bezpath) ) . collect :: < Vec < _ > > ( ) )
1325
+ . collect :: < Vec < _ > > ( ) ;
1326
+
1327
+ let bezpath_count = bezpaths. len ( ) as f64 ;
1328
+ let t_value = t_value. clamp ( 0. , bezpath_count) ;
1329
+ let t_value = if reverse { bezpath_count - t_value } else { t_value } ;
1330
+ let index = if t_value >= bezpath_count { ( bezpath_count - 1. ) as usize } else { t_value as usize } ;
1331
+
1332
+ if let Some ( ( instance_row_index, bezpath) ) = bezpaths. get ( index) . cloned ( ) {
1333
+ let mut result_vector_data = VectorData {
1334
+ style : vector_data. get ( instance_row_index) . unwrap ( ) . instance . style . clone ( ) ,
1335
+ ..Default :: default ( )
1336
+ } ;
1337
+
1338
+ for ( _, ( _, bezpath) ) in bezpaths. iter ( ) . enumerate ( ) . filter ( |( i, ( ri, _) ) | * i != index && * ri == instance_row_index) {
1339
+ result_vector_data. append_bezpath ( bezpath. clone ( ) ) ;
1340
+ }
1341
+ let t = if t_value == bezpath_count { 1. } else { t_value. fract ( ) } ;
1342
+
1343
+ if let Some ( ( first, second) ) = split_bezpath ( & bezpath, t, euclidian) {
1344
+ result_vector_data. append_bezpath ( first) ;
1345
+ result_vector_data. append_bezpath ( second) ;
1346
+ } else {
1347
+ result_vector_data. append_bezpath ( bezpath) ;
1348
+ }
1349
+
1350
+ * vector_data. get_mut ( instance_row_index) . unwrap ( ) . instance = result_vector_data;
1351
+ }
1352
+
1353
+ vector_data
1354
+ }
1355
+
1317
1356
/// Determines the position of a point on the path, given by its progress from 0 to 1 along the path.
1318
1357
/// If multiple subpaths make up the path, the whole number part of the progress value selects the subpath and the decimal part determines the position along it.
1319
1358
#[ node_macro:: node( name( "Position on Path" ) , category( "Vector" ) , path( graphene_core:: vector) ) ]
@@ -1870,6 +1909,29 @@ fn point_inside(_: impl Ctx, source: VectorDataTable, point: DVec2) -> bool {
1870
1909
source. instance_iter ( ) . any ( |instance| instance. instance . check_point_inside_shape ( instance. transform , point) )
1871
1910
}
1872
1911
1912
+ #[ node_macro:: node( category( "Vector" ) , path( graphene_core:: vector) ) ]
1913
+ async fn count_elements < I > ( _: impl Ctx , #[ implementations( GraphicGroupTable , VectorDataTable , RasterDataTable <CPU >, RasterDataTable <GPU >) ] source : Instances < I > ) -> u64 {
1914
+ source. instance_iter ( ) . count ( ) as u64
1915
+ }
1916
+
1917
+ #[ node_macro:: node( category( "Vector" ) , path( graphene_core:: vector) ) ]
1918
+ async fn path_length ( _: impl Ctx , source : VectorDataTable ) -> f64 {
1919
+ source
1920
+ . instance_iter ( )
1921
+ . map ( |vector_data_instance| {
1922
+ let transform = vector_data_instance. transform ;
1923
+ vector_data_instance
1924
+ . instance
1925
+ . stroke_bezpath_iter ( )
1926
+ . map ( |mut bezpath| {
1927
+ bezpath. apply_affine ( Affine :: new ( transform. to_cols_array ( ) ) ) ;
1928
+ bezpath. perimeter ( DEFAULT_ACCURACY )
1929
+ } )
1930
+ . sum :: < f64 > ( )
1931
+ } )
1932
+ . sum ( )
1933
+ }
1934
+
1873
1935
#[ node_macro:: node( category( "Vector" ) , path( graphene_core:: vector) ) ]
1874
1936
async fn area ( ctx : impl Ctx + CloneVarArgs + ExtractAll , vector_data : impl Node < Context < ' static > , Output = VectorDataTable > ) -> f64 {
1875
1937
let new_ctx = OwnedContextImpl :: from ( ctx) . with_footprint ( Footprint :: default ( ) ) . into_context ( ) ;
@@ -1942,6 +2004,7 @@ mod test {
1942
2004
use super :: * ;
1943
2005
use crate :: Node ;
1944
2006
use bezier_rs:: Bezier ;
2007
+ use kurbo:: Rect ;
1945
2008
use std:: pin:: Pin ;
1946
2009
1947
2010
#[ derive( Clone ) ]
@@ -1959,6 +2022,24 @@ mod test {
1959
2022
VectorDataTable :: new ( VectorData :: from_subpath ( data) )
1960
2023
}
1961
2024
2025
+ fn create_vector_data_instance ( bezpath : BezPath , transform : DAffine2 ) -> Instance < VectorData > {
2026
+ let mut instance = VectorData :: default ( ) ;
2027
+ instance. append_bezpath ( bezpath) ;
2028
+ Instance {
2029
+ instance,
2030
+ transform,
2031
+ ..Default :: default ( )
2032
+ }
2033
+ }
2034
+
2035
+ fn vector_node_from_instances ( data : Vec < Instance < VectorData > > ) -> VectorDataTable {
2036
+ let mut vector_data_table = VectorDataTable :: default ( ) ;
2037
+ for instance in data {
2038
+ vector_data_table. push ( instance) ;
2039
+ }
2040
+ vector_data_table
2041
+ }
2042
+
1962
2043
#[ tokio:: test]
1963
2044
async fn repeat ( ) {
1964
2045
let direction = DVec2 :: X * 1.5 ;
@@ -2085,12 +2166,24 @@ mod test {
2085
2166
}
2086
2167
}
2087
2168
#[ tokio:: test]
2088
- async fn lengths ( ) {
2169
+ async fn segment_lengths ( ) {
2089
2170
let subpath = Subpath :: from_bezier ( & Bezier :: from_cubic_dvec2 ( DVec2 :: ZERO , DVec2 :: ZERO , DVec2 :: X * 100. , DVec2 :: X * 100. ) ) ;
2090
2171
let lengths = subpath_segment_lengths ( Footprint :: default ( ) , vector_node ( subpath) ) . await ;
2091
2172
assert_eq ! ( lengths, vec![ 100. ] ) ;
2092
2173
}
2093
2174
#[ tokio:: test]
2175
+ async fn path_length ( ) {
2176
+ let bezpath = Rect :: new ( 100. , 100. , 201. , 201. ) . to_path ( DEFAULT_ACCURACY ) ;
2177
+ let transform = DAffine2 :: from_scale ( DVec2 :: new ( 2. , 2. ) ) ;
2178
+ let instance = create_vector_data_instance ( bezpath, transform) ;
2179
+ let instances = ( 0 ..5 ) . map ( |_| instance. clone ( ) ) . collect :: < Vec < Instance < VectorData > > > ( ) ;
2180
+
2181
+ let length = super :: path_length ( Footprint :: default ( ) , vector_node_from_instances ( instances) ) . await ;
2182
+
2183
+ // 4040 equals 101 * 4 (rectangle perimeter) * 2 (scale) * 5 (number of rows)
2184
+ assert_eq ! ( length, 4040. ) ;
2185
+ }
2186
+ #[ tokio:: test]
2094
2187
async fn spline ( ) {
2095
2188
let spline = super :: spline ( Footprint :: default ( ) , vector_node ( Subpath :: new_rect ( DVec2 :: ZERO , DVec2 :: ONE * 100. ) ) ) . await ;
2096
2189
let spline = spline. instance_ref_iter ( ) . next ( ) . unwrap ( ) . instance ;
0 commit comments