209 let &Loc([xd, yd]) = d; |
209 let &Loc([xd, yd]) = d; |
210 let tx = xd - x; |
210 let tx = xd - x; |
211 let ty = yd - y; |
211 let ty = yd - y; |
212 |
212 |
213 // Move towards tangent as (x + s tx, y + s ty) for the largest s<=1.0 for which |
213 // Move towards tangent as (x + s tx, y + s ty) for the largest s<=1.0 for which |
214 // both coordinates is within [0, 1]. |
214 // both coordinates is within [0, 1]. Also gives the direction of move along |
215 let sx = match tx.partial_cmp(&0.0) { |
215 // each coordinate. |
216 Some(Less) => 1.0f64.min(-x/tx), |
216 let (sx, dirx) = match tx.partial_cmp(&0.0) { |
217 Some(Greater) => 1.0f64.min((1.0-x)/tx), |
217 Some(Less) => (1.0f64.min(-x/tx), Less), |
218 _ => 1.0, |
218 Some(Greater) => (1.0f64.min((1.0-x)/tx), Greater), |
|
219 _ => (1.0, Equal) |
219 }; |
220 }; |
220 let sy = match ty.partial_cmp(&0.0) { |
221 let (sy, diry) = match ty.partial_cmp(&0.0) { |
221 Some(Less) => 1.0f64.min(-y/ty), |
222 Some(Less) => (1.0f64.min(-y/ty), Less), |
222 Some(Greater) => 1.0f64.min((1.0-y)/ty), |
223 Some(Greater) => (1.0f64.min((1.0-y)/ty), Greater), |
223 _ => 1.0, |
224 _ => (1.0, Equal), |
224 }; |
225 }; |
225 // We use the point where one coordinate comes within the range to decide on |
226 |
226 // the edge. |
227 // TODO: how to properly handle corners? Just throw an error? |
227 let s = sx.max(sy); |
228 let (crossing, c) = match (sx < sy, dirx, diry) { |
228 // But move such that both coordinates are within the range. |
229 // x move is less than y move, so crossing is either on left or right edge |
229 let c = sx.min(sy); |
230 (true, Less, _) => (self.adjacent_faces()[0], sx), |
230 let (cx, cy) = (x + c*tx, y + c*ty); |
231 (true, Greater, _) => (self.adjacent_faces()[1], sx), |
231 |
232 (true, Equal, _) => (*self, sx), |
232 let crossing = |t| match (0.0 <= t, t <= 1.0) { |
233 // y move is less than x move, so crossing is either on bottom or top edge |
233 (false, _) => Less, |
234 (false, _, Less) => (self.adjacent_faces()[2], sy), |
234 (_, false) => Greater, |
235 (false, _, Greater) => (self.adjacent_faces()[3], sy), |
235 _ => Equal, |
236 (false, _, Equal) => (*self, sy), |
236 }; |
237 }; |
237 |
238 (crossing, Loc([x + c*tx, y + c*ty])) |
238 // TODO: how to properly handle corners? Just throw an error? |
|
239 let crossing = match (crossing(x + s*tx), crossing(y + s*ty)) { |
|
240 (Equal, Equal) => *self, |
|
241 (Less, _) => self.adjacent_faces()[0], |
|
242 (Greater, _) => self.adjacent_faces()[1], |
|
243 (Equal, Less) => self.adjacent_faces()[2], |
|
244 (Equal, Greater) => self.adjacent_faces()[3], |
|
245 }; |
|
246 (crossing, Loc([cx, cy])) |
|
247 } |
239 } |
248 |
240 |
249 /// Get embedded 3D coordinates |
241 /// Get embedded 3D coordinates |
250 pub fn embedded_coords(&self, p : &Point) -> Loc<f64, 3> { |
242 pub fn embedded_coords(&self, p : &Point) -> Loc<f64, 3> { |
251 let &Loc([x, y]) = p; |
243 let &Loc([x, y]) = p; |