275 ($n: tt / $d: tt) => { FPNum::new($n, $d) }; |
284 ($n: tt / $d: tt) => { FPNum::new($n, $d) }; |
276 (-$n: tt) => { FPNum::from(-$n) }; |
285 (-$n: tt) => { FPNum::from(-$n) }; |
277 ($n: tt) => { FPNum::from($n) }; |
286 ($n: tt) => { FPNum::from($n) }; |
278 } |
287 } |
279 |
288 |
|
289 const LINEARIZE_TRESHOLD: u64 = 0x1_0000; |
|
290 |
|
291 #[derive(Clone, Copy, Debug)] |
|
292 struct FPPoint { |
|
293 x_is_negative: bool, |
|
294 y_is_negative: bool, |
|
295 x_value: u64, |
|
296 y_value: u64, |
|
297 } |
|
298 |
|
299 impl FPPoint { |
|
300 #[inline] |
|
301 fn new(x: FPNum, y: FPNum) -> Self { |
|
302 Self { |
|
303 x_is_negative: x.is_negative, |
|
304 y_is_negative: y.is_negative, |
|
305 x_value: x.value, |
|
306 y_value: y.value |
|
307 } |
|
308 } |
|
309 |
|
310 #[inline] |
|
311 fn zero() -> FPPoint { FPPoint::new(fp!(0), fp!(0)) } |
|
312 |
|
313 #[inline] |
|
314 fn unit_x() -> FPPoint { FPPoint::new(fp!(1), fp!(0)) } |
|
315 |
|
316 #[inline] |
|
317 fn unit_y() -> FPPoint { FPPoint::new(fp!(0), fp!(1)) } |
|
318 |
|
319 #[inline] |
|
320 fn x(&self) -> FPNum { |
|
321 FPNum { |
|
322 is_negative: self.x_is_negative, |
|
323 value: self.x_value |
|
324 } |
|
325 } |
|
326 |
|
327 #[inline] |
|
328 fn y(&self) -> FPNum { |
|
329 FPNum { |
|
330 is_negative: self.y_is_negative, |
|
331 value: self.y_value |
|
332 } |
|
333 } |
|
334 |
|
335 #[inline] |
|
336 fn sqr_distance(&self) -> FPNum { |
|
337 self.x().sqr() + self.y().sqr() |
|
338 } |
|
339 |
|
340 #[inline] |
|
341 fn distance(&self) -> FPNum { |
|
342 let r = self.x_value | self.y_value; |
|
343 if r < LINEARIZE_TRESHOLD { |
|
344 FPNum::from(r as u32) |
|
345 } else { |
|
346 self.sqr_distance().sqrt() |
|
347 } |
|
348 } |
|
349 |
|
350 #[inline] |
|
351 fn is_in_range(&self, radius: FPNum) -> bool { |
|
352 std::cmp::max(self.x(), self.y()) < radius |
|
353 && self.sqr_distance() < radius.sqr() |
|
354 } |
|
355 |
|
356 #[inline] |
|
357 fn dot(&self, other: &FPPoint) -> FPNum { |
|
358 self.x() * other.x() + self.y() * other.y() |
|
359 } |
|
360 } |
|
361 |
|
362 impl PartialEq for FPPoint { |
|
363 #[inline] |
|
364 fn eq(&self, other: &Self) -> bool { |
|
365 self.x() == other.x() && self.y() == other.y() |
|
366 } |
|
367 } |
|
368 |
|
369 impl Eq for FPPoint {} |
|
370 |
|
371 impl ops::Neg for FPPoint { |
|
372 type Output = Self; |
|
373 |
|
374 #[inline] |
|
375 fn neg(self) -> Self { |
|
376 Self::new(-self.x(), -self.y()) |
|
377 } |
|
378 } |
|
379 |
|
380 macro_rules! bin_op_impl { |
|
381 ($op: path, $name: tt) => { |
|
382 impl $op for FPPoint { |
|
383 type Output = Self; |
|
384 |
|
385 #[inline] |
|
386 fn $name(self, rhs: Self) -> Self { |
|
387 Self::new(self.x().$name(rhs.x()), |
|
388 self.y().$name(rhs.y())) |
|
389 } |
|
390 } |
|
391 } |
|
392 } |
|
393 |
|
394 bin_op_impl!(ops::Add, add); |
|
395 bin_op_impl!(ops::Sub, sub); |
|
396 bin_op_impl!(ops::Mul, mul); |
|
397 |
|
398 #[inline] |
|
399 fn distance<T>(x: T, y: T) -> FPNum |
|
400 where T: ops::Add + ops::Mul + Copy + |
|
401 From<<T as ops::Add>::Output> + |
|
402 From<<T as ops::Mul>::Output> + |
|
403 Into<FPNum> |
|
404 { |
|
405 let sqr: FPNum = T::from(T::from(x * x) + T::from(y * y)).into(); |
|
406 sqr.sqrt() |
|
407 } |
|
408 |
280 /* TODO: |
409 /* TODO: |
281 Distance |
|
282 DistanceI |
|
283 SignAs |
|
284 AngleSin |
410 AngleSin |
285 AngleCos |
411 AngleCos |
286 */ |
412 */ |
287 |
413 |
288 #[cfg(test)] |
414 #[cfg(test)] |
311 assert!(z.is_zero()); |
437 assert!(z.is_zero()); |
312 assert!(z.is_positive()); |
438 assert!(z.is_positive()); |
313 assert!((-z).is_negative); |
439 assert!((-z).is_negative); |
314 assert_eq!(n - n, z); |
440 assert_eq!(n - n, z); |
315 assert_eq!(-n + n, z); |
441 assert_eq!(-n + n, z); |
|
442 assert_eq!(z.with_sign_as(-n), -z); |
316 } |
443 } |
317 |
444 |
318 #[test] |
445 #[test] |
319 fn ord() { |
446 fn ord() { |
320 let z = fp!(0); |
447 let z = fp!(0); |
350 |
477 |
351 assert_eq!(n2_25.sqrt(), n1_5); |
478 assert_eq!(n2_25.sqrt(), n1_5); |
352 |
479 |
353 assert_eq!((n1_5 * n1_5 * n1_5.sqr()).sqrt(), n2_25); |
480 assert_eq!((n1_5 * n1_5 * n1_5.sqr()).sqrt(), n2_25); |
354 } |
481 } |
|
482 |
|
483 #[test] |
|
484 fn point() { |
|
485 let z = FPPoint::zero(); |
|
486 let p = FPPoint::new(fp!(1), fp!(-2)); |
|
487 |
|
488 assert_eq!(p.sqr_distance(), fp!(5)); |
|
489 assert_eq!(p + -p, FPPoint::zero()); |
|
490 assert_eq!(p * z, z); |
|
491 assert_eq!(p.dot(&z), fp!(0)); |
|
492 assert_eq!(distance(4, 3), fp!(5)); |
|
493 } |