@@ -18,7 +18,7 @@ use arrayvec::ArrayVec;
1818use pathfinder_geometry:: line_segment:: LineSegment2F ;
1919use pathfinder_geometry:: rect:: RectF ;
2020use pathfinder_geometry:: util:: lerp;
21- use pathfinder_geometry:: vector:: { Vector2F , Vector4F } ;
21+ use pathfinder_geometry:: vector:: { Vector2F , Vector4F , vec2f } ;
2222use smallvec:: SmallVec ;
2323use std:: fmt:: Debug ;
2424use std:: mem;
@@ -490,6 +490,80 @@ pub(crate) fn rect_is_inside_polygon(rect: RectF, polygon_points: &[Vector2F]) -
490490 true
491491}
492492
493+ /// Clips a line segment to an axis-aligned rectangle using Cohen-Sutherland clipping.
494+ pub fn clip_line_segment_to_rect ( mut line_segment : LineSegment2F , rect : RectF )
495+ -> Option < LineSegment2F > {
496+ let mut outcode_from = compute_outcode ( line_segment. from ( ) , rect) ;
497+ let mut outcode_to = compute_outcode ( line_segment. to ( ) , rect) ;
498+
499+ loop {
500+ if outcode_from. is_empty ( ) && outcode_to. is_empty ( ) {
501+ return Some ( line_segment) ;
502+ }
503+ if !( outcode_from & outcode_to) . is_empty ( ) {
504+ return None ;
505+ }
506+
507+ let clip_from = outcode_from. bits ( ) > outcode_to. bits ( ) ;
508+ let ( mut point, outcode) = if clip_from {
509+ ( line_segment. from ( ) , outcode_from)
510+ } else {
511+ ( line_segment. to ( ) , outcode_to)
512+ } ;
513+
514+ if outcode. contains ( Outcode :: LEFT ) {
515+ point = vec2f ( rect. min_x ( ) ,
516+ lerp ( line_segment. from_y ( ) ,
517+ line_segment. to_y ( ) ,
518+ ( line_segment. min_x ( ) - line_segment. from_x ( ) ) /
519+ ( line_segment. max_x ( ) - line_segment. min_x ( ) ) ) ) ;
520+ } else if outcode. contains ( Outcode :: RIGHT ) {
521+ point = vec2f ( rect. max_x ( ) ,
522+ lerp ( line_segment. from_y ( ) ,
523+ line_segment. to_y ( ) ,
524+ ( line_segment. max_x ( ) - line_segment. from_x ( ) ) /
525+ ( line_segment. max_x ( ) - line_segment. min_x ( ) ) ) ) ;
526+ } else if outcode. contains ( Outcode :: TOP ) {
527+ point = vec2f ( lerp ( line_segment. from_x ( ) ,
528+ line_segment. to_x ( ) ,
529+ ( line_segment. min_y ( ) - line_segment. from_y ( ) ) /
530+ ( line_segment. max_y ( ) - line_segment. min_y ( ) ) ) ,
531+ rect. min_y ( ) ) ;
532+ } else if outcode. contains ( Outcode :: LEFT ) {
533+ point = vec2f ( lerp ( line_segment. from_x ( ) ,
534+ line_segment. to_x ( ) ,
535+ ( line_segment. max_y ( ) - line_segment. from_y ( ) ) /
536+ ( line_segment. max_y ( ) - line_segment. min_y ( ) ) ) ,
537+ rect. min_y ( ) ) ;
538+ }
539+
540+ if clip_from {
541+ line_segment. set_from ( point) ;
542+ outcode_from = compute_outcode ( point, rect) ;
543+ } else {
544+ line_segment. set_to ( point) ;
545+ outcode_to = compute_outcode ( point, rect) ;
546+ }
547+ }
548+
549+ fn compute_outcode ( point : Vector2F , rect : RectF ) -> Outcode {
550+ let mut outcode = Outcode :: empty ( ) ;
551+ if point. x ( ) < rect. min_x ( ) {
552+ outcode. insert ( Outcode :: LEFT ) ;
553+ }
554+ if point. y ( ) < rect. min_y ( ) {
555+ outcode. insert ( Outcode :: TOP ) ;
556+ }
557+ if point. x ( ) > rect. max_x ( ) {
558+ outcode. insert ( Outcode :: RIGHT ) ;
559+ }
560+ if point. y ( ) > rect. max_y ( ) {
561+ outcode. insert ( Outcode :: BOTTOM ) ;
562+ }
563+ outcode
564+ }
565+ }
566+
493567bitflags ! {
494568 struct Outcode : u8 {
495569 const LEFT = 0x01 ;
0 commit comments