@@ -18,7 +18,7 @@ use arrayvec::ArrayVec;
18
18
use pathfinder_geometry:: line_segment:: LineSegment2F ;
19
19
use pathfinder_geometry:: rect:: RectF ;
20
20
use pathfinder_geometry:: util:: lerp;
21
- use pathfinder_geometry:: vector:: { Vector2F , Vector4F } ;
21
+ use pathfinder_geometry:: vector:: { Vector2F , Vector4F , vec2f } ;
22
22
use smallvec:: SmallVec ;
23
23
use std:: fmt:: Debug ;
24
24
use std:: mem;
@@ -490,6 +490,80 @@ pub(crate) fn rect_is_inside_polygon(rect: RectF, polygon_points: &[Vector2F]) -
490
490
true
491
491
}
492
492
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
+
493
567
bitflags ! {
494
568
struct Outcode : u8 {
495
569
const LEFT = 0x01 ;
0 commit comments