@@ -789,74 +789,59 @@ async fn box_warp(_: impl Ctx, content: Table<Vector>, #[expose] rectangle: Tabl
789789 let Some ( ( target, target_transform) ) = rectangle. get ( 0 ) . map ( |rect| ( rect. element , rect. transform ) ) else {
790790 return content;
791791 } ;
792+ //calculate the minumum and max corner of all the shapes
793+ let mut min_corner = DVec2 :: new ( f64:: MAX , f64:: MAX ) ;
794+ let mut max_corner = DVec2 :: new ( f64:: MIN , f64:: MIN ) ;
792795
793- content
794- . into_iter ( )
795- . map ( |mut row| {
796- let transform = row. transform ;
797- let vector = row. element ;
798-
799- // Get the bounding box of the source vector geometry
800- let source_bbox = vector. bounding_box_with_transform ( transform) . unwrap_or ( [ DVec2 :: ZERO , DVec2 :: ONE ] ) ;
801-
802- // Extract first 4 points from target shape to form the quadrilateral
803- // Apply the target's transform to get points in world space
804- let target_points: Vec < DVec2 > = target. point_domain . positions ( ) . iter ( ) . map ( |& p| target_transform. transform_point2 ( p) ) . take ( 4 ) . collect ( ) ;
805-
806- // If we have fewer than 4 points, use the corners of the source bounding box
807- // This handles the degenerative case
808- let dst_corners = if target_points. len ( ) >= 4 {
809- [ target_points[ 0 ] , target_points[ 1 ] , target_points[ 2 ] , target_points[ 3 ] ]
810- } else {
811- warn ! ( "Target shape has fewer than 4 points. Using source bounding box instead." ) ;
812- [
813- source_bbox[ 0 ] ,
814- DVec2 :: new ( source_bbox[ 1 ] . x , source_bbox[ 0 ] . y ) ,
815- source_bbox[ 1 ] ,
816- DVec2 :: new ( source_bbox[ 0 ] . x , source_bbox[ 1 ] . y ) ,
817- ]
818- } ;
819-
820- // Apply the warp
821- let mut result = vector. clone ( ) ;
822-
823- // Precompute source bounding box size for normalization
824- let source_size = source_bbox[ 1 ] - source_bbox[ 0 ] ;
825-
826- // Transform points
827- for ( _, position) in result. point_domain . positions_mut ( ) {
828- // Get the point in world space
829- let world_pos = transform. transform_point2 ( * position) ;
830-
831- // Normalize coordinates within the source bounding box
832- let t = ( ( world_pos - source_bbox[ 0 ] ) / source_size) . clamp ( DVec2 :: ZERO , DVec2 :: ONE ) ;
833-
834- // Apply bilinear interpolation
835- * position = bilinear_interpolate ( t, & dst_corners) ;
836- }
837-
838- // Transform handles in bezier curves
839- for ( _, handles, _, _) in result. handles_mut ( ) {
840- * handles = handles. apply_transformation ( |pos| {
841- // Get the handle in world space
842- let world_pos = transform. transform_point2 ( pos) ;
843-
844- // Normalize coordinates within the source bounding box
845- let t = ( ( world_pos - source_bbox[ 0 ] ) / source_size) . clamp ( DVec2 :: ZERO , DVec2 :: ONE ) ;
796+ for row in content. iter ( ) {
797+ if let Some ( bbox) = row. element . bounding_box_with_transform ( * row. transform ) {
798+ min_corner = min_corner. min ( bbox[ 0 ] ) ;
799+ max_corner = max_corner. max ( bbox[ 1 ] ) ;
800+ }
801+ }
802+ let source_bbox = [ min_corner, max_corner] ;
803+ let source_size = source_bbox[ 1 ] - source_bbox[ 0 ] ;
846804
847- // Apply bilinear interpolation
848- bilinear_interpolate ( t, & dst_corners)
849- } ) ;
850- }
805+ let target_points: Vec < DVec2 > = target. point_domain . positions ( ) . iter ( ) . map ( |& p| target_transform. transform_point2 ( p) ) . take ( 4 ) . collect ( ) ;
851806
852- result. style . set_stroke_transform ( DAffine2 :: IDENTITY ) ;
807+ let dst_corners = if target_points. len ( ) >= 4 {
808+ [ target_points[ 0 ] , target_points[ 1 ] , target_points[ 2 ] , target_points[ 3 ] ]
809+ } else {
810+ warn ! ( "Target shape has fewer than 4 points. Using source bounding box instead." ) ;
811+ [
812+ source_bbox[ 0 ] ,
813+ DVec2 :: new ( source_bbox[ 1 ] . x , source_bbox[ 0 ] . y ) ,
814+ source_bbox[ 1 ] ,
815+ DVec2 :: new ( source_bbox[ 0 ] . x , source_bbox[ 1 ] . y ) ,
816+ ]
817+ } ;
853818
854- // Add this to the table and reset the transform since we've applied it directly to the points
855- row. element = result;
856- row. transform = DAffine2 :: IDENTITY ;
857- row
858- } )
859- . collect ( )
819+ content
820+ . into_iter ( )
821+ . map ( |mut row| {
822+ let transform = row. transform ;
823+ let vector = & row. element ;
824+ let mut result = vector. clone ( ) ;
825+
826+ for ( _, position) in result. point_domain . positions_mut ( ) {
827+ let world_pos = transform. transform_point2 ( * position) ;
828+ let t = ( ( world_pos - source_bbox[ 0 ] ) / source_size) . clamp ( DVec2 :: ZERO , DVec2 :: ONE ) ;
829+ * position = bilinear_interpolate ( t, & dst_corners) ;
830+ }
831+
832+ for ( _, handles, _, _) in result. handles_mut ( ) {
833+ * handles = handles. apply_transformation ( |pos| {
834+ let world_pos = transform. transform_point2 ( pos) ;
835+ let t = ( ( world_pos - source_bbox[ 0 ] ) / source_size) . clamp ( DVec2 :: ZERO , DVec2 :: ONE ) ;
836+ bilinear_interpolate ( t, & dst_corners)
837+ } ) ;
838+ }
839+ result. style . set_stroke_transform ( DAffine2 :: IDENTITY ) ;
840+ row. element = result;
841+ row. transform = DAffine2 :: IDENTITY ;
842+ row
843+ } )
844+ . collect ( )
860845}
861846
862847// Interpolate within a quadrilateral using normalized coordinates (0-1)
0 commit comments