bulge.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. # Copyright (c) 2018 Manfred Moitzi
  2. # License: MIT License
  3. # source: http://www.lee-mac.com/bulgeconversion.html
  4. # source: http://www.afralisp.net/archive/lisp/Bulges1.htm
  5. from typing import Any, TYPE_CHECKING, Tuple
  6. from .vector import Vec2
  7. import math
  8. if TYPE_CHECKING:
  9. from ezdxf.eztypes import Vertex
  10. def polar(p: Any, angle: float, distance: float) -> Vec2:
  11. """
  12. Returns the point at a specified `angle` and `distance` from point `p`.
  13. Args:
  14. p: point (x, y) as args accepted by Vec2()
  15. angle: angle in radians
  16. distance: distance
  17. """
  18. return Vec2(p) + Vec2.from_angle(angle, distance)
  19. def angle(p1: Any, p2: Any) -> float:
  20. """
  21. Returns an angle in radians of a line defined by two endpoints
  22. Args:
  23. p1: start point (x, y) as args accepted by Vec2()
  24. p2: end point (x, y) as args accepted by Vec2()
  25. """
  26. return (Vec2(p2) - Vec2(p1)).angle
  27. def arc_to_bulge(center: 'Vertex', start_angle: float, end_angle: float, radius: float) -> Tuple[Vec2, Vec2, float]:
  28. """
  29. Calculate bulge parameters from arc parameters.
  30. Args:
  31. center: circle center point (x, y) as args accepted by Vec2()
  32. start_angle: start angle in radians
  33. end_angle: end angle in radians
  34. radius: circle radius
  35. Returns: (start_point, end_point, bulge)
  36. """
  37. start_point = polar(center, start_angle, radius)
  38. end_point = polar(center, end_angle, radius)
  39. pi2 = math.pi * 2
  40. a = math.fmod((pi2 + (end_angle - start_angle)), pi2) / 4.
  41. bulge = math.sin(a) / math.cos(a)
  42. return start_point, end_point, bulge
  43. def bulge_3_points(start_point: 'Vertex', end_point: 'Vertex', point: 'Vertex') -> float:
  44. """
  45. Calculate bulge value defined by three points.
  46. Args:
  47. start_point: start point (x, y) of arc as args accepted by Vec2()
  48. end_point: end point (x, y) of arc as args accepted by Vec2()
  49. point: arbitrary point (x, y) on arc as args accepted by Vec2()
  50. Returns: bulge value
  51. Based on 3-Points to Bulge by Lee Mac
  52. """
  53. a = (math.pi - angle(point, start_point) + angle(point, end_point)) / 2
  54. return math.sin(a) / math.cos(a)
  55. def bulge_to_arc(start_point: 'Vertex', end_point: 'Vertex', bulge: float) -> Tuple[Vec2, float, float, float]:
  56. """
  57. Calculate arc parameters from bulge parameters.
  58. Based on Bulge to Arc by Lee Mac
  59. Args:
  60. start_point: start vertex (x, y) as args accepted by Vec2()
  61. end_point: end vertex (x, y) as args accepted by Vec2()
  62. bulge: bulge value
  63. Returns: (center, start_angle, end_angle, radius)
  64. """
  65. r = signed_bulge_radius(start_point, end_point, bulge)
  66. a = angle(start_point, end_point) + (math.pi / 2 - math.atan(bulge) * 2)
  67. c = polar(start_point, a, r)
  68. if bulge < 0:
  69. return c, angle(c, end_point), angle(c, start_point), abs(r)
  70. else:
  71. return c, angle(c, start_point), angle(c, end_point), abs(r)
  72. def bulge_center(start_point: 'Vertex', end_point: 'Vertex', bulge: float) -> Vec2:
  73. """
  74. Calculate center of arc described by the given bulge parameters.
  75. Based on Bulge Center by Lee Mac.
  76. Args:
  77. start_point: start point (x, y) as args accepted by Vec2()
  78. end_point: end point (x, y) as args accepted by Vec2()
  79. bulge: bulge value
  80. Returns: Vector
  81. """
  82. start_point = Vec2(start_point)
  83. a = angle(start_point, end_point) + (math.pi / 2. - math.atan(bulge) * 2.)
  84. return start_point + Vec2.from_angle(a, signed_bulge_radius(start_point, end_point, bulge))
  85. def signed_bulge_radius(start_point: 'Vertex', end_point: 'Vertex', bulge: float) -> float:
  86. return Vec2(start_point).distance(Vec2(end_point)) * (1. + (bulge * bulge)) / 4. / bulge
  87. def bulge_radius(start_point: 'Vertex', end_point: 'Vertex', bulge: float) -> float:
  88. """
  89. Calculate radius of arc defined by the given bulge parameters.
  90. Based on Bulge Radius by Lee Mac
  91. Args:
  92. start_point: start point (x, y) as args accepted by Vec2()
  93. end_point: end point (x, y) as args accepted by Vec2()
  94. bulge: bulge value
  95. """
  96. return abs(signed_bulge_radius(start_point, end_point, bulge))