71 segment: Line, |
66 segment: Line, |
72 distance_divisor: u32, |
67 distance_divisor: u32, |
73 random_numbers: &mut I, |
68 random_numbers: &mut I, |
74 ) -> Option<Point> { |
69 ) -> Option<Point> { |
75 #[inline] |
70 #[inline] |
76 fn intersect(p: Point, m: Point, p1: Point, p2: Point) -> bool { |
71 fn intersects(ray: &Ray, edge: &Line) -> bool { |
77 let t1 = (m - p1).cross(p); |
72 ray.orientation(edge.start) != ray.orientation(edge.end) |
78 let t2 = (m - p2).cross(p); |
|
79 |
|
80 (t1 > 0) != (t2 > 0) |
|
81 } |
73 } |
82 |
74 |
83 #[inline] |
75 #[inline] |
84 fn solve_intersection( |
76 fn solve_intersection(intersections_box: &Rect, ray: &Ray, edge: &Line) -> Option<(i32, u32)> |
85 intersections_box: &Rect, |
77 { |
86 p: Point, |
78 let edge_dir = edge.scaled_direction(); |
87 m: Point, |
79 let aqpb = ray.direction.cross(edge_dir) as i64; |
88 s: Point, |
|
89 e: Point, |
|
90 ) -> Option<(i32, u32)> { |
|
91 let f = e - s; |
|
92 let aqpb = p.cross(f) as i64; |
|
93 |
80 |
94 if aqpb != 0 { |
81 if aqpb != 0 { |
95 let mut iy = ((((s.x - m.x) as i64 * p.y as i64 + m.y as i64 * p.x as i64) |
82 let mut iy = |
96 * f.y as i64 |
83 ((((edge.start.x - ray.start.x) as i64 * ray.direction.y as i64 |
97 - s.y as i64 * f.x as i64 * p.y as i64) |
84 + ray.start.y as i64 * ray.direction.x as i64) |
|
85 * edge_dir.y as i64 |
|
86 - edge.start.y as i64 * edge_dir.x as i64 * ray.direction.y as i64) |
98 / aqpb) as i32; |
87 / aqpb) as i32; |
99 |
88 |
100 // is there better way to do it? |
89 // is there better way to do it? |
101 if iy < intersections_box.top() { |
90 if iy < intersections_box.top() { |
102 iy = intersections_box.top(); |
91 iy = intersections_box.top(); |
103 } else if iy > intersections_box.bottom() { |
92 } else if iy > intersections_box.bottom() { |
104 iy = intersections_box.bottom(); |
93 iy = intersections_box.bottom(); |
105 } |
94 } |
106 |
95 |
107 let ix = if p.y.abs() > f.y.abs() { |
96 let ix = if ray.direction.y.abs() > edge_dir.y.abs() { |
108 (iy - m.y) * p.x / p.y + m.x |
97 (iy - ray.start.y) * ray.direction.cotangent() + ray.start.x |
109 } else { |
98 } else { |
110 (iy - s.y) * f.x / f.y + s.x |
99 (iy - edge.start.y) * edge_dir.cotangent() + edge.start.x |
111 }; |
100 }; |
112 |
101 |
113 let intersection_point = Point::new(ix, iy); |
102 let intersection_point = Point::new(ix, iy); |
114 let diff_point = m - intersection_point; |
103 let diff_point = ray.start - intersection_point; |
115 let t = p.dot(diff_point); |
104 let t = ray.direction.dot(diff_point); |
116 if diff_point.max_norm() >= std::i16::MAX as i32 { |
105 if diff_point.max_norm() >= std::i16::MAX as i32 { |
117 Some((t, std::i32::MAX as u32)) |
106 Some((t, std::i32::MAX as u32)) |
118 } else { |
107 } else { |
119 let d = diff_point.integral_norm(); |
108 let d = diff_point.integral_norm(); |
120 |
109 |
127 |
116 |
128 let min_distance = 40; |
117 let min_distance = 40; |
129 // new point should fall inside this box |
118 // new point should fall inside this box |
130 let map_box = self.play_box.with_margin(min_distance); |
119 let map_box = self.play_box.with_margin(min_distance); |
131 |
120 |
132 let p = segment.scaled_normal(); |
121 let normal = segment.scaled_normal(); |
133 let p_norm = p.integral_norm(); |
122 let normal_len = normal.integral_norm(); |
134 let mid_point = segment.center(); |
123 let mid_point = segment.center(); |
135 |
124 |
136 if (p_norm < min_distance as u32 * 3) || !map_box.contains_inside(mid_point) { |
125 if (normal_len < min_distance as u32 * 3) || !map_box.contains_inside(mid_point) { |
137 return None; |
126 return None; |
138 } |
127 } |
139 |
128 |
|
129 let normal_ray = Ray::new(mid_point, normal); |
140 let mut dist_left = (self.size.width + self.size.height) as u32; |
130 let mut dist_left = (self.size.width + self.size.height) as u32; |
141 let mut dist_right = dist_left; |
131 let mut dist_right = dist_left; |
142 |
132 |
143 // find distances to map borders |
133 // find distances to map borders |
144 if p.x != 0 { |
134 if normal.x != 0 { |
145 // where the normal line intersects the left map border |
135 // where the normal line intersects the left map border |
146 let left_intersection = Point::new( |
136 let left_intersection = Point::new( |
147 map_box.left(), |
137 map_box.left(), |
148 (map_box.left() - mid_point.x) * p.y / p.x + mid_point.y, |
138 (map_box.left() - mid_point.x) * normal.tangent() + mid_point.y, |
149 ); |
139 ); |
150 dist_left = (mid_point - left_intersection).integral_norm(); |
140 dist_left = (mid_point - left_intersection).integral_norm(); |
151 |
141 |
152 // same for the right border |
142 // same for the right border |
153 let right_intersection = Point::new( |
143 let right_intersection = Point::new( |
154 map_box.right(), |
144 map_box.right(), |
155 (map_box.right() - mid_point.x) * p.y / p.x + mid_point.y, |
145 (map_box.right() - mid_point.x) * normal.tangent() + mid_point.y, |
156 ); |
146 ); |
157 dist_right = (mid_point - right_intersection).integral_norm(); |
147 dist_right = (mid_point - right_intersection).integral_norm(); |
158 |
148 |
159 if p.x > 0 { |
149 if normal.x > 0 { |
160 std::mem::swap(&mut dist_left, &mut dist_right); |
150 std::mem::swap(&mut dist_left, &mut dist_right); |
161 } |
151 } |
162 } |
152 } |
163 |
153 |
164 if p.y != 0 { |
154 if normal.y != 0 { |
165 // where the normal line intersects the top map border |
155 // where the normal line intersects the top map border |
166 let top_intersection = Point::new( |
156 let top_intersection = Point::new( |
167 (map_box.top() - mid_point.y) * p.x / p.y + mid_point.x, |
157 (map_box.top() - mid_point.y) * normal.cotangent() + mid_point.x, |
168 map_box.top(), |
158 map_box.top(), |
169 ); |
159 ); |
170 let dl = (mid_point - top_intersection).integral_norm(); |
160 let dl = (mid_point - top_intersection).integral_norm(); |
171 |
161 |
172 // same for the bottom border |
162 // same for the bottom border |
173 let bottom_intersection = Point::new( |
163 let bottom_intersection = Point::new( |
174 (map_box.bottom() - mid_point.y) * p.x / p.y + mid_point.x, |
164 (map_box.bottom() - mid_point.y) * normal.cotangent() + mid_point.x, |
175 map_box.bottom(), |
165 map_box.bottom(), |
176 ); |
166 ); |
177 let dr = (mid_point - bottom_intersection).integral_norm(); |
167 let dr = (mid_point - bottom_intersection).integral_norm(); |
178 |
168 |
179 if p.y < 0 { |
169 if normal.y < 0 { |
180 dist_left = min(dist_left, dl); |
170 dist_left = min(dist_left, dl); |
181 dist_right = min(dist_right, dr); |
171 dist_right = min(dist_right, dr); |
182 } else { |
172 } else { |
183 dist_left = min(dist_left, dr); |
173 dist_left = min(dist_left, dr); |
184 dist_right = min(dist_right, dl); |
174 dist_right = min(dist_right, dl); |
186 } |
176 } |
187 |
177 |
188 // now go through all other segments |
178 // now go through all other segments |
189 for s in self.segments_iter() { |
179 for s in self.segments_iter() { |
190 if s != segment { |
180 if s != segment { |
191 if intersect(p, mid_point, s.start, s.end) { |
181 if intersects(&normal_ray, &s) { |
|
182 if let Some((t, d)) = |
|
183 solve_intersection(&self.intersections_box, &normal_ray, &s) |
|
184 { |
|
185 if t > 0 { |
|
186 dist_right = min(dist_right, d); |
|
187 } else { |
|
188 dist_left = min(dist_left, d); |
|
189 } |
|
190 } |
|
191 } |
|
192 } |
|
193 } |
|
194 |
|
195 // go through all points, including fill points |
|
196 for pi in self.iter().cloned() { |
|
197 if pi != segment.start && pi != segment.end { |
|
198 if intersects(&pi.ray_to(normal), &segment) { |
|
199 // ray from segment.start |
192 if let Some((t, d)) = solve_intersection( |
200 if let Some((t, d)) = solve_intersection( |
193 &self.intersections_box, |
201 &self.intersections_box, &normal_ray, &segment.start.line_to(pi), |
194 p, |
|
195 mid_point, |
|
196 s.start, |
|
197 s.end, |
|
198 ) { |
202 ) { |
199 if t > 0 { |
203 if t > 0 { |
200 dist_right = min(dist_right, d); |
204 dist_right = min(dist_right, d); |
201 } else { |
205 } else { |
202 dist_left = min(dist_left, d); |
206 dist_left = min(dist_left, d); |
203 } |
207 } |
204 } |
208 } |
205 } |
209 |
206 } |
210 // ray from segment.end |
207 } |
|
208 |
|
209 // go through all points, including fill points |
|
210 for pi in self.iter().cloned() { |
|
211 if pi != segment.start && pi != segment.end { |
|
212 if intersect(p, pi, segment.start, segment.end) { |
|
213 // ray from segment.start |
|
214 if let Some((t, d)) = solve_intersection( |
211 if let Some((t, d)) = solve_intersection( |
215 &self.intersections_box, |
212 &self.intersections_box, &normal_ray, &segment.end.line_to(pi) |
216 p, |
|
217 mid_point, |
|
218 segment.start, |
|
219 pi, |
|
220 ) { |
213 ) { |
221 if t > 0 { |
214 if t > 0 { |
222 dist_right = min(dist_right, d); |
215 dist_right = min(dist_right, d); |
223 } else { |
216 } else { |
224 dist_left = min(dist_left, d); |
217 dist_left = min(dist_left, d); |
225 } |
218 } |
226 } |
219 } |
227 |
220 } |
228 // ray from segment.end |
221 } |
229 if let Some((t, d)) = solve_intersection( |
222 } |
230 &self.intersections_box, |
223 |
231 p, |
224 let max_dist = normal_len * 100 / distance_divisor; |
232 mid_point, |
|
233 segment.end, |
|
234 pi, |
|
235 ) { |
|
236 if t > 0 { |
|
237 dist_right = min(dist_right, d); |
|
238 } else { |
|
239 dist_left = min(dist_left, d); |
|
240 } |
|
241 } |
|
242 } |
|
243 } |
|
244 } |
|
245 |
|
246 let max_dist = p_norm * 100 / distance_divisor; |
|
247 dist_left = min(dist_left, max_dist); |
225 dist_left = min(dist_left, max_dist); |
248 dist_right = min(dist_right, max_dist); |
226 dist_right = min(dist_right, max_dist); |
249 |
227 |
250 if dist_right + dist_left < min_distance as u32 * 2 + 10 { |
228 if dist_right + dist_left < min_distance as u32 * 2 + 10 { |
251 // limits are too narrow, just divide |
229 // limits are too narrow, just divide |