1
1
use crate :: BackendCoord ;
2
2
3
+ // Compute the tanginal and normal vectors of the given straight line.
3
4
fn get_dir_vector ( from : BackendCoord , to : BackendCoord , flag : bool ) -> ( ( f64 , f64 ) , ( f64 , f64 ) ) {
4
5
let v = ( i64:: from ( to. 0 - from. 0 ) , i64:: from ( to. 1 - from. 1 ) ) ;
5
6
let l = ( ( v. 0 * v. 0 + v. 1 * v. 1 ) as f64 ) . sqrt ( ) ;
@@ -13,10 +14,17 @@ fn get_dir_vector(from: BackendCoord, to: BackendCoord, flag: bool) -> ((f64, f6
13
14
}
14
15
}
15
16
16
- fn compute_polygon_vertex ( triple : & [ BackendCoord ; 3 ] , d : f64 ) -> BackendCoord {
17
+ // Compute the polygonized vertex of the given angle
18
+ // d is the distance between the polygon edge and the actual line.
19
+ // d can be negative, this will emit a vertex on the other side of the line.
20
+ fn compute_polygon_vertex ( triple : & [ BackendCoord ; 3 ] , d : f64 , buf : & mut Vec < BackendCoord > ) {
21
+ buf. clear ( ) ;
22
+
23
+ // Compute the tanginal and normal vectors of the given straight line.
17
24
let ( a_t, a_n) = get_dir_vector ( triple[ 0 ] , triple[ 1 ] , false ) ;
18
25
let ( b_t, b_n) = get_dir_vector ( triple[ 2 ] , triple[ 1 ] , true ) ;
19
26
27
+ // Compute a point that is d away from the line for line a and line b.
20
28
let a_p = (
21
29
f64:: from ( triple[ 1 ] . 0 ) + d * a_n. 0 ,
22
30
f64:: from ( triple[ 1 ] . 1 ) + d * a_n. 1 ,
@@ -26,12 +34,25 @@ fn compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64) -> BackendCoord {
26
34
f64:: from ( triple[ 1 ] . 1 ) + d * b_n. 1 ,
27
35
) ;
28
36
37
+ // If they are actually the same point, then the 3 points are colinear, so just emit the point.
38
+ if a_p. 0 as i32 == b_p. 0 as i32 && a_p. 1 as i32 == b_p. 1 as i32 {
39
+ buf. push ( ( a_p. 0 as i32 , a_p. 1 as i32 ) ) ;
40
+ return ;
41
+ }
42
+
43
+ // So we are actually computing the intersection of two lines:
44
+ // a_p + u * a_t and b_p + v * b_t.
45
+ // We can solve the following vector equation:
29
46
// u * a_t + a_p = v * b_t + b_p
47
+ //
48
+ // which is actually a equation system:
30
49
// u * a_t.0 - v * b_t.0 = b_p.0 - a_p.0
31
50
// u * a_t.1 - v * b_t.1 = b_p.1 - a_p.1
32
- if a_p. 0 as i32 == b_p. 0 as i32 && a_p. 1 as i32 == b_p. 1 as i32 {
33
- return ( a_p. 0 as i32 , a_p. 1 as i32 ) ;
34
- }
51
+
52
+ // The following vars are coefficients of the linear equation system.
53
+ // a0*u + b0*v = c0
54
+ // a1*u + b1*v = c1
55
+ // in which x and y are the coordinates that two polygon edges intersect.
35
56
36
57
let a0 = a_t. 0 ;
37
58
let b0 = -b_t. 0 ;
@@ -40,17 +61,30 @@ fn compute_polygon_vertex(triple: &[BackendCoord; 3], d: f64) -> BackendCoord {
40
61
let b1 = -b_t. 1 ;
41
62
let c1 = b_p. 1 - a_p. 1 ;
42
63
43
- // This is the coner case that
44
- if ( a0 * b1 - a1 * b0) . abs ( ) < 1e-10 {
45
- return ( a_p. 0 as i32 , a_p. 1 as i32 ) ;
46
- }
64
+ let mut x = f64:: INFINITY ;
65
+ let mut y = f64:: INFINITY ;
66
+
67
+ // Well if the determinant is not 0, then we can actuall get a intersection point.
68
+ if ( a0 * b1 - a1 * b0) . abs ( ) > f64:: EPSILON {
69
+ let u = ( c0 * b1 - c1 * b0) / ( a0 * b1 - a1 * b0) ;
47
70
48
- let u = ( c0 * b1 - c1 * b0) / ( a0 * b1 - a1 * b0) ;
71
+ x = a_p. 0 + u * a_t. 0 ;
72
+ y = a_p. 1 + u * a_t. 1 ;
73
+ }
49
74
50
- let x = a_p. 0 + u * a_t. 0 ;
51
- let y = a_p. 1 + u * a_t. 1 ;
75
+ let cross_product = a_t. 0 * b_t. 1 - a_t. 1 * b_t. 0 ;
76
+ if ( cross_product < 0.0 && d < 0.0 ) || ( cross_product > 0.0 && d > 0.0 ) {
77
+ // Then we are at the outter side of the angle, so we need to consider a cap.
78
+ let dist_square = ( x - triple[ 1 ] . 0 as f64 ) . powi ( 2 ) + ( y - triple[ 1 ] . 1 as f64 ) . powi ( 2 ) ;
79
+ // If the point is too far away from the line, we need to cap it.
80
+ if dist_square > d * d * 16.0 {
81
+ buf. push ( ( a_p. 0 . round ( ) as i32 , a_p. 1 . round ( ) as i32 ) ) ;
82
+ buf. push ( ( b_p. 0 . round ( ) as i32 , b_p. 1 . round ( ) as i32 ) ) ;
83
+ return ;
84
+ }
85
+ }
52
86
53
- ( x. round ( ) as i32 , y. round ( ) as i32 )
87
+ buf . push ( ( x. round ( ) as i32 , y. round ( ) as i32 ) ) ;
54
88
}
55
89
56
90
fn traverse_vertices < ' a > (
@@ -78,6 +112,7 @@ fn traverse_vertices<'a>(
78
112
) ) ;
79
113
80
114
let mut recent = [ ( 0 , 0 ) , * a, * b] ;
115
+ let mut vertex_buf = Vec :: with_capacity ( 3 ) ;
81
116
82
117
for p in vertices {
83
118
if * p == recent[ 2 ] {
@@ -86,7 +121,8 @@ fn traverse_vertices<'a>(
86
121
recent. swap ( 0 , 1 ) ;
87
122
recent. swap ( 1 , 2 ) ;
88
123
recent[ 2 ] = * p;
89
- op ( compute_polygon_vertex ( & recent, f64:: from ( width) / 2.0 ) ) ;
124
+ compute_polygon_vertex ( & recent, f64:: from ( width) / 2.0 , & mut vertex_buf) ;
125
+ vertex_buf. iter ( ) . cloned ( ) . for_each ( |v| op ( v) ) ;
90
126
}
91
127
92
128
let b = recent[ 1 ] ;
0 commit comments