@@ -2,31 +2,28 @@ use std::fs::File;
22use std:: io:: Write ;
33
44use clap:: Parser ;
5- use image;
6-
7- use string_bean;
85
96#[ derive( Parser ) ]
107struct CliArgs {
118 input_file : String ,
129 output_file : String ,
1310 #[ clap( short = 'c' , default_value_t = 500 ) ]
14- num_chords : u64 ,
11+ line_count : usize ,
1512 #[ clap( short = 'o' , default_value_t = 0.2 ) ]
1613 line_opacity : f64 ,
1714 #[ arg( short = 'a' , default_value_t = 288 ) ]
18- num_anchors : u64 ,
15+ anchor_count : u64 ,
1916 #[ arg( short = 'g' , default_value_t = 0 ) ]
20- num_anchor_gap : usize ,
17+ anchor_gap_count : usize ,
2118 #[ arg( short = 'r' , default_value_t = usize :: MAX ) ]
2219 radius : usize ,
2320 #[ arg( short = 'p' , default_value_t = 5.0 ) ]
2421 penalty : f64 ,
2522
26- #[ arg( short = 'w' , default_value_t = 850 ) ]
27- output_width : u64 ,
28- #[ arg( short = 'h' , default_value_t = 850 ) ]
29- output_height : u64 ,
23+ #[ arg( default_value_t = 850 ) ]
24+ width : u64 ,
25+ #[ arg( default_value_t = 850 ) ]
26+ height : u64 ,
3027}
3128
3229fn main ( ) -> Result < ( ) , std:: io:: Error > {
@@ -36,39 +33,48 @@ fn main() -> Result<(), std::io::Error> {
3633 let width = img. width ( ) as usize ;
3734 let height = img. height ( ) as usize ;
3835
36+ let ( x_mid, y_mid) = ( width / 2 , height / 2 ) ;
37+ let radius = args. radius . min ( x_mid. min ( y_mid) ) as f64 ;
38+
39+ let anchors: Vec < _ > = ( 0 ..args. anchor_count )
40+ . map ( |anchor| anchor as f64 * 2.0 * std:: f64:: consts:: PI / args. anchor_count as f64 )
41+ . map ( |angle| {
42+ (
43+ x_mid as f64 + radius * angle. cos ( ) ,
44+ y_mid as f64 * radius * angle. sin ( ) ,
45+ )
46+ } )
47+ . collect ( ) ;
48+
3949 let mut planner = string_bean:: ThreadPlanner :: new (
40- args. num_chords ,
4150 args. line_opacity ,
42- args. num_anchors ,
43- args. num_anchor_gap ,
44- args. radius ,
51+ & anchors,
52+ args. anchor_gap_count ,
4553 args. penalty ,
54+ grid_raytrace,
4655 width,
4756 height,
48- & mut img. into_vec ( ) ,
57+ & img. into_vec ( ) ,
4958 ) ;
5059
51- let anchors = planner. get_moves ( 0 ) . unwrap ( ) ;
60+ let anchors = planner. get_moves ( 0 , args . line_count ) . unwrap ( ) ;
5261
5362 write_svg ( & args, & anchors) ?;
5463
5564 Ok ( ( ) )
5665}
5766
58- fn write_svg ( args : & CliArgs , anchors : & Vec < usize > ) -> Result < ( ) , std:: io:: Error > {
59- let ( x_mid, y_mid) = (
60- args. output_width as f64 / 2.0 ,
61- args. output_height as f64 / 2.0 ,
62- ) ;
67+ fn write_svg ( args : & CliArgs , anchors : & [ usize ] ) -> Result < ( ) , std:: io:: Error > {
68+ let ( x_mid, y_mid) = ( args. width as f64 / 2.0 , args. height as f64 / 2.0 ) ;
6369 let radius = x_mid. min ( y_mid) ;
64- let degrees_per_anchor: f64 = 2.0 * std:: f64:: consts:: PI / args. num_anchors as f64 ;
70+ let degrees_per_anchor: f64 = 2.0 * std:: f64:: consts:: PI / args. anchor_count as f64 ;
6571
6672 let mut svg_file = File :: create ( & args. output_file ) ?;
6773
68- write ! (
74+ writeln ! (
6975 svg_file,
70- "<svg width=\" {}\" height=\" {}\" xmlns=\" http://www.w3.org/2000/svg\" >\n " ,
71- args. output_width , args. output_height
76+ "<svg width=\" {}\" height=\" {}\" xmlns=\" http://www.w3.org/2000/svg\" >" ,
77+ args. width , args. height
7278 ) ?;
7379
7480 for anchor_pairs in anchors. windows ( 2 ) {
@@ -79,14 +85,52 @@ fn write_svg(args: &CliArgs, anchors: &Vec<usize>) -> Result<(), std::io::Error>
7985 ) ;
8086 let ( x0, y0) = ( x_mid + radius * deg1. cos ( ) , y_mid + radius * deg1. sin ( ) ) ;
8187 let ( x1, y1) = ( x_mid + radius * deg2. cos ( ) , y_mid + radius * deg2. sin ( ) ) ;
82- write ! (
88+ writeln ! (
8389 svg_file,
84- "<line x1=\" {}\" y1=\" {}\" x2=\" {}\" y2=\" {}\" opacity=\" {}\" style=\" stroke:rgb(0,0,0); stroke-width:1\" />\n " ,
90+ "<line x1=\" {}\" y1=\" {}\" x2=\" {}\" y2=\" {}\" opacity=\" {}\" style=\" stroke:rgb(0,0,0); stroke-width:1\" />" ,
8591 x0, y0, x1, y1, args. line_opacity
8692 ) ?;
8793 }
8894
89- write ! ( svg_file, "</svg>" ) ?;
95+ writeln ! ( svg_file, "</svg>" ) ?;
9096
9197 Ok ( ( ) )
9298}
99+
100+ /// https://playtechs.blogspot.com/2007/03/raytracing-on-grid.html
101+ fn grid_raytrace (
102+ x0 : f64 ,
103+ y0 : f64 ,
104+ x1 : f64 ,
105+ y1 : f64 ,
106+ ) -> impl Iterator < Item = ( ( usize , usize ) , f64 ) > {
107+ let ( x0, y0) = ( x0 as i64 , y0 as i64 ) ;
108+ let ( x1, y1) = ( x1 as i64 , y1 as i64 ) ;
109+
110+ let mut dx = ( x1 - x0) . abs ( ) ;
111+ let mut dy = ( y1 - y0) . abs ( ) ;
112+ let mut x = x0;
113+ let mut y = y0;
114+
115+ let n = 1 + dx + dy;
116+ let x_inc = ( x1 - x0) . signum ( ) ;
117+ let y_inc = ( y1 - y0) . signum ( ) ;
118+
119+ let mut error = dx - dy;
120+ dx *= 2 ;
121+ dy *= 2 ;
122+
123+ ( 0 ..n) . map ( move |_| {
124+ let point = ( ( x as usize , y as usize ) , 1.0 ) ;
125+
126+ if error > 0 {
127+ x += x_inc;
128+ error -= dy;
129+ } else {
130+ y += y_inc;
131+ error += dx;
132+ }
133+
134+ point
135+ } )
136+ }
0 commit comments